fhir-persistence 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.md +1 -1
- package/dist/cjs/index.cjs +719 -0
- package/dist/cjs/index.cjs.map +4 -4
- package/dist/cjs/index.d.ts +214 -0
- package/dist/esm/index.d.ts +214 -0
- package/dist/esm/index.mjs +712 -0
- package/dist/esm/index.mjs.map +4 -4
- package/dist/index.d.ts +214 -0
- package/dist/lib/conformance/concept-hierarchy-repo.d.ts +38 -0
- package/dist/lib/conformance/concept-hierarchy-repo.d.ts.map +1 -0
- package/dist/lib/conformance/element-index-repo.d.ts +40 -0
- package/dist/lib/conformance/element-index-repo.d.ts.map +1 -0
- package/dist/lib/conformance/expansion-cache-repo.d.ts +32 -0
- package/dist/lib/conformance/expansion-cache-repo.d.ts.map +1 -0
- package/dist/lib/conformance/ig-import-orchestrator.d.ts +69 -0
- package/dist/lib/conformance/ig-import-orchestrator.d.ts.map +1 -0
- package/dist/lib/conformance/ig-resource-map-repo.d.ts +41 -0
- package/dist/lib/conformance/ig-resource-map-repo.d.ts.map +1 -0
- package/dist/lib/conformance/index.d.ts +29 -0
- package/dist/lib/conformance/index.d.ts.map +1 -0
- package/dist/lib/conformance/sd-index-repo.d.ts +35 -0
- package/dist/lib/conformance/sd-index-repo.d.ts.map +1 -0
- package/dist/lib/conformance/search-param-index-repo.d.ts +33 -0
- package/dist/lib/conformance/search-param-index-repo.d.ts.map +1 -0
- package/dist/lib/index.d.ts +8 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -31,14 +31,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
BetterSqlite3Adapter: () => BetterSqlite3Adapter,
|
|
34
|
+
ConceptHierarchyRepo: () => ConceptHierarchyRepo,
|
|
34
35
|
DEFAULT_SEARCH_COUNT: () => DEFAULT_SEARCH_COUNT,
|
|
35
36
|
DELETED_SCHEMA_VERSION: () => DELETED_SCHEMA_VERSION,
|
|
37
|
+
ElementIndexRepo: () => ElementIndexRepo,
|
|
38
|
+
ExpansionCacheRepo: () => ExpansionCacheRepo,
|
|
36
39
|
FhirDefinitionBridge: () => FhirDefinitionBridge,
|
|
37
40
|
FhirPersistence: () => FhirPersistence,
|
|
38
41
|
FhirRuntimeProvider: () => FhirRuntimeProvider,
|
|
39
42
|
FhirStore: () => FhirStore,
|
|
40
43
|
FhirSystem: () => FhirSystem,
|
|
44
|
+
IGImportOrchestrator: () => IGImportOrchestrator,
|
|
41
45
|
IGPersistenceManager: () => IGPersistenceManager,
|
|
46
|
+
IGResourceMapRepo: () => IGResourceMapRepo,
|
|
42
47
|
IndexingPipeline: () => IndexingPipeline,
|
|
43
48
|
LookupTableWriter: () => LookupTableWriter,
|
|
44
49
|
MAX_SEARCH_COUNT: () => MAX_SEARCH_COUNT,
|
|
@@ -60,9 +65,11 @@ __export(index_exports, {
|
|
|
60
65
|
ResourceNotFoundError: () => ResourceNotFoundError,
|
|
61
66
|
ResourceVersionConflictError: () => ResourceVersionConflictError,
|
|
62
67
|
SCHEMA_VERSION: () => SCHEMA_VERSION,
|
|
68
|
+
SDIndexRepo: () => SDIndexRepo,
|
|
63
69
|
SEARCH_PREFIXES: () => SEARCH_PREFIXES,
|
|
64
70
|
SQLiteDialect: () => SQLiteDialect,
|
|
65
71
|
SearchLogger: () => SearchLogger,
|
|
72
|
+
SearchParamIndexRepo: () => SearchParamIndexRepo,
|
|
66
73
|
SearchParameterRegistry: () => SearchParameterRegistry,
|
|
67
74
|
StructureDefinitionRegistry: () => StructureDefinitionRegistry,
|
|
68
75
|
TerminologyCodeRepo: () => TerminologyCodeRepo,
|
|
@@ -8911,17 +8918,727 @@ var FhirRuntimeProvider = class {
|
|
|
8911
8918
|
function createFhirRuntimeProvider(options) {
|
|
8912
8919
|
return new FhirRuntimeProvider(options);
|
|
8913
8920
|
}
|
|
8921
|
+
|
|
8922
|
+
// src/conformance/ig-resource-map-repo.ts
|
|
8923
|
+
var TABLE = "ig_resource_map";
|
|
8924
|
+
var CREATE_TABLE_DDL = `
|
|
8925
|
+
CREATE TABLE IF NOT EXISTS "${TABLE}" (
|
|
8926
|
+
"ig_id" TEXT NOT NULL,
|
|
8927
|
+
"resource_type" TEXT NOT NULL,
|
|
8928
|
+
"resource_id" TEXT NOT NULL,
|
|
8929
|
+
"resource_url" TEXT,
|
|
8930
|
+
"resource_name" TEXT,
|
|
8931
|
+
"base_type" TEXT,
|
|
8932
|
+
PRIMARY KEY ("ig_id", "resource_type", "resource_id")
|
|
8933
|
+
);
|
|
8934
|
+
`;
|
|
8935
|
+
var CREATE_INDEX_IG = `CREATE INDEX IF NOT EXISTS idx_ig_resource_map_ig ON "${TABLE}"("ig_id")`;
|
|
8936
|
+
var CREATE_INDEX_TYPE = `CREATE INDEX IF NOT EXISTS idx_ig_resource_map_type ON "${TABLE}"("ig_id", "resource_type")`;
|
|
8937
|
+
var IGResourceMapRepo = class {
|
|
8938
|
+
constructor(adapter, dialect = "sqlite") {
|
|
8939
|
+
this.adapter = adapter;
|
|
8940
|
+
this.dialect = dialect;
|
|
8941
|
+
}
|
|
8942
|
+
async ensureTable() {
|
|
8943
|
+
await this.adapter.execute(CREATE_TABLE_DDL);
|
|
8944
|
+
await this.adapter.execute(CREATE_INDEX_IG);
|
|
8945
|
+
await this.adapter.execute(CREATE_INDEX_TYPE);
|
|
8946
|
+
}
|
|
8947
|
+
/** Batch insert resource map entries for an IG. */
|
|
8948
|
+
async batchInsert(igId, entries) {
|
|
8949
|
+
await this.ensureTable();
|
|
8950
|
+
let count = 0;
|
|
8951
|
+
const sql = this.dialect === "postgres" ? `INSERT INTO "${TABLE}" ("ig_id", "resource_type", "resource_id", "resource_url", "resource_name", "base_type") VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT ("ig_id", "resource_type", "resource_id") DO UPDATE SET "resource_url" = EXCLUDED."resource_url", "resource_name" = EXCLUDED."resource_name", "base_type" = EXCLUDED."base_type"` : `INSERT OR REPLACE INTO "${TABLE}" ("ig_id", "resource_type", "resource_id", "resource_url", "resource_name", "base_type") VALUES (?, ?, ?, ?, ?, ?)`;
|
|
8952
|
+
for (const e of entries) {
|
|
8953
|
+
await this.adapter.execute(sql, [
|
|
8954
|
+
igId,
|
|
8955
|
+
e.resourceType,
|
|
8956
|
+
e.resourceId,
|
|
8957
|
+
e.resourceUrl ?? null,
|
|
8958
|
+
e.resourceName ?? null,
|
|
8959
|
+
e.baseType ?? null
|
|
8960
|
+
]);
|
|
8961
|
+
count++;
|
|
8962
|
+
}
|
|
8963
|
+
return count;
|
|
8964
|
+
}
|
|
8965
|
+
/** Get grouped IG index. */
|
|
8966
|
+
async getIGIndex(igId) {
|
|
8967
|
+
await this.ensureTable();
|
|
8968
|
+
const rows = await this.adapter.query(
|
|
8969
|
+
`SELECT "ig_id", "resource_type", "resource_id", "resource_url", "resource_name", "base_type" FROM "${TABLE}" WHERE "ig_id" = ? ORDER BY "resource_type", "resource_id"`,
|
|
8970
|
+
[igId]
|
|
8971
|
+
);
|
|
8972
|
+
const index = {
|
|
8973
|
+
profiles: [],
|
|
8974
|
+
extensions: [],
|
|
8975
|
+
valueSets: [],
|
|
8976
|
+
codeSystems: [],
|
|
8977
|
+
searchParameters: []
|
|
8978
|
+
};
|
|
8979
|
+
for (const r of rows) {
|
|
8980
|
+
const entry = {
|
|
8981
|
+
igId: r.ig_id,
|
|
8982
|
+
resourceType: r.resource_type,
|
|
8983
|
+
resourceId: r.resource_id,
|
|
8984
|
+
resourceUrl: r.resource_url ?? void 0,
|
|
8985
|
+
resourceName: r.resource_name ?? void 0,
|
|
8986
|
+
baseType: r.base_type ?? void 0
|
|
8987
|
+
};
|
|
8988
|
+
switch (r.resource_type) {
|
|
8989
|
+
case "StructureDefinition":
|
|
8990
|
+
if (r.base_type === "Extension") {
|
|
8991
|
+
index.extensions.push(entry);
|
|
8992
|
+
} else {
|
|
8993
|
+
index.profiles.push(entry);
|
|
8994
|
+
}
|
|
8995
|
+
break;
|
|
8996
|
+
case "ValueSet":
|
|
8997
|
+
index.valueSets.push(entry);
|
|
8998
|
+
break;
|
|
8999
|
+
case "CodeSystem":
|
|
9000
|
+
index.codeSystems.push(entry);
|
|
9001
|
+
break;
|
|
9002
|
+
case "SearchParameter":
|
|
9003
|
+
index.searchParameters.push(entry);
|
|
9004
|
+
break;
|
|
9005
|
+
default:
|
|
9006
|
+
break;
|
|
9007
|
+
}
|
|
9008
|
+
}
|
|
9009
|
+
return index;
|
|
9010
|
+
}
|
|
9011
|
+
/** Get resources of a specific type within an IG. */
|
|
9012
|
+
async getByType(igId, resourceType) {
|
|
9013
|
+
await this.ensureTable();
|
|
9014
|
+
const rows = await this.adapter.query(
|
|
9015
|
+
`SELECT "ig_id", "resource_type", "resource_id", "resource_url", "resource_name", "base_type" FROM "${TABLE}" WHERE "ig_id" = ? AND "resource_type" = ? ORDER BY "resource_id"`,
|
|
9016
|
+
[igId, resourceType]
|
|
9017
|
+
);
|
|
9018
|
+
return rows.map((r) => ({
|
|
9019
|
+
igId: r.ig_id,
|
|
9020
|
+
resourceType: r.resource_type,
|
|
9021
|
+
resourceId: r.resource_id,
|
|
9022
|
+
resourceUrl: r.resource_url ?? void 0,
|
|
9023
|
+
resourceName: r.resource_name ?? void 0,
|
|
9024
|
+
baseType: r.base_type ?? void 0
|
|
9025
|
+
}));
|
|
9026
|
+
}
|
|
9027
|
+
/** Remove all resource mappings for an IG. */
|
|
9028
|
+
async removeIG(igId) {
|
|
9029
|
+
await this.ensureTable();
|
|
9030
|
+
await this.adapter.execute(`DELETE FROM "${TABLE}" WHERE "ig_id" = ?`, [igId]);
|
|
9031
|
+
}
|
|
9032
|
+
};
|
|
9033
|
+
|
|
9034
|
+
// src/conformance/sd-index-repo.ts
|
|
9035
|
+
var TABLE2 = "structure_definition_index";
|
|
9036
|
+
var CREATE_TABLE_DDL2 = `
|
|
9037
|
+
CREATE TABLE IF NOT EXISTS "${TABLE2}" (
|
|
9038
|
+
"id" TEXT PRIMARY KEY,
|
|
9039
|
+
"url" TEXT,
|
|
9040
|
+
"version" TEXT,
|
|
9041
|
+
"type" TEXT,
|
|
9042
|
+
"kind" TEXT,
|
|
9043
|
+
"base_definition" TEXT,
|
|
9044
|
+
"derivation" TEXT,
|
|
9045
|
+
"snapshot_hash" TEXT
|
|
9046
|
+
);
|
|
9047
|
+
`;
|
|
9048
|
+
var CREATE_INDEX_TYPE2 = `CREATE INDEX IF NOT EXISTS idx_sdi_type ON "${TABLE2}"("type")`;
|
|
9049
|
+
var CREATE_INDEX_KIND = `CREATE INDEX IF NOT EXISTS idx_sdi_kind ON "${TABLE2}"("kind")`;
|
|
9050
|
+
var CREATE_INDEX_BASE = `CREATE INDEX IF NOT EXISTS idx_sdi_base ON "${TABLE2}"("base_definition")`;
|
|
9051
|
+
var SDIndexRepo = class {
|
|
9052
|
+
constructor(adapter, dialect = "sqlite") {
|
|
9053
|
+
this.adapter = adapter;
|
|
9054
|
+
this.dialect = dialect;
|
|
9055
|
+
}
|
|
9056
|
+
async ensureTable() {
|
|
9057
|
+
await this.adapter.execute(CREATE_TABLE_DDL2);
|
|
9058
|
+
await this.adapter.execute(CREATE_INDEX_TYPE2);
|
|
9059
|
+
await this.adapter.execute(CREATE_INDEX_KIND);
|
|
9060
|
+
await this.adapter.execute(CREATE_INDEX_BASE);
|
|
9061
|
+
}
|
|
9062
|
+
async upsert(entry) {
|
|
9063
|
+
await this.ensureTable();
|
|
9064
|
+
const sql = this.dialect === "postgres" ? `INSERT INTO "${TABLE2}" ("id", "url", "version", "type", "kind", "base_definition", "derivation", "snapshot_hash") VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT ("id") DO UPDATE SET "url" = EXCLUDED."url", "version" = EXCLUDED."version", "type" = EXCLUDED."type", "kind" = EXCLUDED."kind", "base_definition" = EXCLUDED."base_definition", "derivation" = EXCLUDED."derivation", "snapshot_hash" = EXCLUDED."snapshot_hash"` : `INSERT OR REPLACE INTO "${TABLE2}" ("id", "url", "version", "type", "kind", "base_definition", "derivation", "snapshot_hash") VALUES (?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
9065
|
+
await this.adapter.execute(sql, [
|
|
9066
|
+
entry.id,
|
|
9067
|
+
entry.url ?? null,
|
|
9068
|
+
entry.version ?? null,
|
|
9069
|
+
entry.type ?? null,
|
|
9070
|
+
entry.kind ?? null,
|
|
9071
|
+
entry.baseDefinition ?? null,
|
|
9072
|
+
entry.derivation ?? null,
|
|
9073
|
+
entry.snapshotHash ?? null
|
|
9074
|
+
]);
|
|
9075
|
+
}
|
|
9076
|
+
async batchUpsert(entries) {
|
|
9077
|
+
let count = 0;
|
|
9078
|
+
for (const entry of entries) {
|
|
9079
|
+
await this.upsert(entry);
|
|
9080
|
+
count++;
|
|
9081
|
+
}
|
|
9082
|
+
return count;
|
|
9083
|
+
}
|
|
9084
|
+
async getById(id) {
|
|
9085
|
+
await this.ensureTable();
|
|
9086
|
+
const row = await this.adapter.queryOne(
|
|
9087
|
+
`SELECT "id", "url", "version", "type", "kind", "base_definition", "derivation", "snapshot_hash" FROM "${TABLE2}" WHERE "id" = ?`,
|
|
9088
|
+
[id]
|
|
9089
|
+
);
|
|
9090
|
+
return row ? this.mapRow(row) : void 0;
|
|
9091
|
+
}
|
|
9092
|
+
async getByUrl(url) {
|
|
9093
|
+
await this.ensureTable();
|
|
9094
|
+
const rows = await this.adapter.query(
|
|
9095
|
+
`SELECT "id", "url", "version", "type", "kind", "base_definition", "derivation", "snapshot_hash" FROM "${TABLE2}" WHERE "url" = ? ORDER BY "version"`,
|
|
9096
|
+
[url]
|
|
9097
|
+
);
|
|
9098
|
+
return rows.map((r) => this.mapRow(r));
|
|
9099
|
+
}
|
|
9100
|
+
async getByType(type) {
|
|
9101
|
+
await this.ensureTable();
|
|
9102
|
+
const rows = await this.adapter.query(
|
|
9103
|
+
`SELECT "id", "url", "version", "type", "kind", "base_definition", "derivation", "snapshot_hash" FROM "${TABLE2}" WHERE "type" = ? ORDER BY "id"`,
|
|
9104
|
+
[type]
|
|
9105
|
+
);
|
|
9106
|
+
return rows.map((r) => this.mapRow(r));
|
|
9107
|
+
}
|
|
9108
|
+
async getByBaseDefinition(baseUrl) {
|
|
9109
|
+
await this.ensureTable();
|
|
9110
|
+
const rows = await this.adapter.query(
|
|
9111
|
+
`SELECT "id", "url", "version", "type", "kind", "base_definition", "derivation", "snapshot_hash" FROM "${TABLE2}" WHERE "base_definition" = ? ORDER BY "id"`,
|
|
9112
|
+
[baseUrl]
|
|
9113
|
+
);
|
|
9114
|
+
return rows.map((r) => this.mapRow(r));
|
|
9115
|
+
}
|
|
9116
|
+
async remove(id) {
|
|
9117
|
+
await this.ensureTable();
|
|
9118
|
+
await this.adapter.execute(`DELETE FROM "${TABLE2}" WHERE "id" = ?`, [id]);
|
|
9119
|
+
}
|
|
9120
|
+
mapRow(r) {
|
|
9121
|
+
return {
|
|
9122
|
+
id: r.id,
|
|
9123
|
+
url: r.url ?? void 0,
|
|
9124
|
+
version: r.version ?? void 0,
|
|
9125
|
+
type: r.type ?? void 0,
|
|
9126
|
+
kind: r.kind ?? void 0,
|
|
9127
|
+
baseDefinition: r.base_definition ?? void 0,
|
|
9128
|
+
derivation: r.derivation ?? void 0,
|
|
9129
|
+
snapshotHash: r.snapshot_hash ?? void 0
|
|
9130
|
+
};
|
|
9131
|
+
}
|
|
9132
|
+
};
|
|
9133
|
+
|
|
9134
|
+
// src/conformance/element-index-repo.ts
|
|
9135
|
+
var TABLE3 = "structure_element_index";
|
|
9136
|
+
function createTableDDL(dialect) {
|
|
9137
|
+
if (dialect === "postgres") {
|
|
9138
|
+
return `
|
|
9139
|
+
CREATE TABLE IF NOT EXISTS "${TABLE3}" (
|
|
9140
|
+
"id" TEXT PRIMARY KEY,
|
|
9141
|
+
"structure_id" TEXT NOT NULL,
|
|
9142
|
+
"path" TEXT NOT NULL,
|
|
9143
|
+
"min" INTEGER,
|
|
9144
|
+
"max" TEXT,
|
|
9145
|
+
"type_codes" JSONB,
|
|
9146
|
+
"is_slice" BOOLEAN DEFAULT FALSE,
|
|
9147
|
+
"slice_name" TEXT,
|
|
9148
|
+
"is_extension" BOOLEAN DEFAULT FALSE,
|
|
9149
|
+
"binding_value_set" TEXT,
|
|
9150
|
+
"must_support" BOOLEAN DEFAULT FALSE
|
|
9151
|
+
);
|
|
9152
|
+
`;
|
|
9153
|
+
}
|
|
9154
|
+
return `
|
|
9155
|
+
CREATE TABLE IF NOT EXISTS "${TABLE3}" (
|
|
9156
|
+
"id" TEXT PRIMARY KEY,
|
|
9157
|
+
"structure_id" TEXT NOT NULL,
|
|
9158
|
+
"path" TEXT NOT NULL,
|
|
9159
|
+
"min" INTEGER,
|
|
9160
|
+
"max" TEXT,
|
|
9161
|
+
"type_codes" TEXT,
|
|
9162
|
+
"is_slice" INTEGER DEFAULT 0,
|
|
9163
|
+
"slice_name" TEXT,
|
|
9164
|
+
"is_extension" INTEGER DEFAULT 0,
|
|
9165
|
+
"binding_value_set" TEXT,
|
|
9166
|
+
"must_support" INTEGER DEFAULT 0
|
|
9167
|
+
);
|
|
9168
|
+
`;
|
|
9169
|
+
}
|
|
9170
|
+
var CREATE_INDEX_STRUCTURE = `CREATE INDEX IF NOT EXISTS idx_sei_structure ON "${TABLE3}"("structure_id")`;
|
|
9171
|
+
var CREATE_INDEX_PATH = `CREATE INDEX IF NOT EXISTS idx_sei_path ON "${TABLE3}"("path")`;
|
|
9172
|
+
var CREATE_INDEX_SLICE = `CREATE INDEX IF NOT EXISTS idx_sei_slice ON "${TABLE3}"("structure_id", "is_slice")`;
|
|
9173
|
+
var ElementIndexRepo = class {
|
|
9174
|
+
constructor(adapter, dialect = "sqlite") {
|
|
9175
|
+
this.adapter = adapter;
|
|
9176
|
+
this.dialect = dialect;
|
|
9177
|
+
}
|
|
9178
|
+
async ensureTable() {
|
|
9179
|
+
await this.adapter.execute(createTableDDL(this.dialect));
|
|
9180
|
+
await this.adapter.execute(CREATE_INDEX_STRUCTURE);
|
|
9181
|
+
await this.adapter.execute(CREATE_INDEX_PATH);
|
|
9182
|
+
await this.adapter.execute(CREATE_INDEX_SLICE);
|
|
9183
|
+
}
|
|
9184
|
+
/** Batch insert element index entries for a StructureDefinition. */
|
|
9185
|
+
async batchInsert(structureId, elements) {
|
|
9186
|
+
await this.ensureTable();
|
|
9187
|
+
let count = 0;
|
|
9188
|
+
const sql = this.dialect === "postgres" ? `INSERT INTO "${TABLE3}" ("id", "structure_id", "path", "min", "max", "type_codes", "is_slice", "slice_name", "is_extension", "binding_value_set", "must_support") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT ("id") DO UPDATE SET "path" = EXCLUDED."path", "min" = EXCLUDED."min", "max" = EXCLUDED."max", "type_codes" = EXCLUDED."type_codes", "is_slice" = EXCLUDED."is_slice", "slice_name" = EXCLUDED."slice_name", "is_extension" = EXCLUDED."is_extension", "binding_value_set" = EXCLUDED."binding_value_set", "must_support" = EXCLUDED."must_support"` : `INSERT OR REPLACE INTO "${TABLE3}" ("id", "structure_id", "path", "min", "max", "type_codes", "is_slice", "slice_name", "is_extension", "binding_value_set", "must_support") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
9189
|
+
for (const e of elements) {
|
|
9190
|
+
const typeCodes = e.typeCodes ? this.dialect === "postgres" ? JSON.stringify(e.typeCodes) : JSON.stringify(e.typeCodes) : null;
|
|
9191
|
+
const isSlice = this.dialect === "postgres" ? e.isSlice ?? false : e.isSlice ? 1 : 0;
|
|
9192
|
+
const isExtension = this.dialect === "postgres" ? e.isExtension ?? false : e.isExtension ? 1 : 0;
|
|
9193
|
+
const mustSupport = this.dialect === "postgres" ? e.mustSupport ?? false : e.mustSupport ? 1 : 0;
|
|
9194
|
+
await this.adapter.execute(sql, [
|
|
9195
|
+
e.id,
|
|
9196
|
+
structureId,
|
|
9197
|
+
e.path,
|
|
9198
|
+
e.min ?? null,
|
|
9199
|
+
e.max ?? null,
|
|
9200
|
+
typeCodes,
|
|
9201
|
+
isSlice,
|
|
9202
|
+
e.sliceName ?? null,
|
|
9203
|
+
isExtension,
|
|
9204
|
+
e.bindingValueSet ?? null,
|
|
9205
|
+
mustSupport
|
|
9206
|
+
]);
|
|
9207
|
+
count++;
|
|
9208
|
+
}
|
|
9209
|
+
return count;
|
|
9210
|
+
}
|
|
9211
|
+
/** Get all elements for a StructureDefinition. */
|
|
9212
|
+
async getByStructureId(structureId) {
|
|
9213
|
+
await this.ensureTable();
|
|
9214
|
+
const rows = await this.adapter.query(
|
|
9215
|
+
`SELECT "id", "structure_id", "path", "min", "max", "type_codes", "is_slice", "slice_name", "is_extension", "binding_value_set", "must_support" FROM "${TABLE3}" WHERE "structure_id" = ? ORDER BY "id"`,
|
|
9216
|
+
[structureId]
|
|
9217
|
+
);
|
|
9218
|
+
return rows.map((r) => this.mapRow(r));
|
|
9219
|
+
}
|
|
9220
|
+
/** Search elements by path pattern (LIKE). */
|
|
9221
|
+
async searchByPath(pathPattern) {
|
|
9222
|
+
await this.ensureTable();
|
|
9223
|
+
const rows = await this.adapter.query(
|
|
9224
|
+
`SELECT "id", "structure_id", "path", "min", "max", "type_codes", "is_slice", "slice_name", "is_extension", "binding_value_set", "must_support" FROM "${TABLE3}" WHERE "path" LIKE ? ORDER BY "structure_id", "path"`,
|
|
9225
|
+
[pathPattern]
|
|
9226
|
+
);
|
|
9227
|
+
return rows.map((r) => this.mapRow(r));
|
|
9228
|
+
}
|
|
9229
|
+
/** Remove all element indexes for a StructureDefinition. */
|
|
9230
|
+
async removeByStructureId(structureId) {
|
|
9231
|
+
await this.ensureTable();
|
|
9232
|
+
await this.adapter.execute(`DELETE FROM "${TABLE3}" WHERE "structure_id" = ?`, [structureId]);
|
|
9233
|
+
}
|
|
9234
|
+
mapRow(r) {
|
|
9235
|
+
const typeCodes = r.type_codes ? typeof r.type_codes === "string" ? JSON.parse(r.type_codes) : r.type_codes : void 0;
|
|
9236
|
+
return {
|
|
9237
|
+
id: r.id,
|
|
9238
|
+
structureId: r.structure_id,
|
|
9239
|
+
path: r.path,
|
|
9240
|
+
min: r.min != null ? Number(r.min) : void 0,
|
|
9241
|
+
max: r.max ?? void 0,
|
|
9242
|
+
typeCodes,
|
|
9243
|
+
isSlice: Boolean(r.is_slice),
|
|
9244
|
+
sliceName: r.slice_name ?? void 0,
|
|
9245
|
+
isExtension: Boolean(r.is_extension),
|
|
9246
|
+
bindingValueSet: r.binding_value_set ?? void 0,
|
|
9247
|
+
mustSupport: Boolean(r.must_support)
|
|
9248
|
+
};
|
|
9249
|
+
}
|
|
9250
|
+
};
|
|
9251
|
+
|
|
9252
|
+
// src/conformance/expansion-cache-repo.ts
|
|
9253
|
+
var TABLE4 = "value_set_expansion";
|
|
9254
|
+
function createTableDDL2(dialect) {
|
|
9255
|
+
const ts = dialect === "postgres" ? "TIMESTAMPTZ DEFAULT NOW()" : "TEXT DEFAULT (datetime('now'))";
|
|
9256
|
+
const jsonType = dialect === "postgres" ? "JSONB NOT NULL" : "TEXT NOT NULL";
|
|
9257
|
+
return `
|
|
9258
|
+
CREATE TABLE IF NOT EXISTS "${TABLE4}" (
|
|
9259
|
+
"valueset_url" TEXT NOT NULL,
|
|
9260
|
+
"version" TEXT NOT NULL DEFAULT '',
|
|
9261
|
+
"expanded_at" ${ts},
|
|
9262
|
+
"code_count" INTEGER,
|
|
9263
|
+
"expansion_json" ${jsonType},
|
|
9264
|
+
PRIMARY KEY ("valueset_url", "version")
|
|
9265
|
+
);
|
|
9266
|
+
`;
|
|
9267
|
+
}
|
|
9268
|
+
var ExpansionCacheRepo = class {
|
|
9269
|
+
constructor(adapter, dialect = "sqlite") {
|
|
9270
|
+
this.adapter = adapter;
|
|
9271
|
+
this.dialect = dialect;
|
|
9272
|
+
}
|
|
9273
|
+
async ensureTable() {
|
|
9274
|
+
await this.adapter.execute(createTableDDL2(this.dialect));
|
|
9275
|
+
}
|
|
9276
|
+
/** Write or update an expansion cache entry. */
|
|
9277
|
+
async upsert(url, version, expansionJson, codeCount) {
|
|
9278
|
+
await this.ensureTable();
|
|
9279
|
+
const sql = this.dialect === "postgres" ? `INSERT INTO "${TABLE4}" ("valueset_url", "version", "expansion_json", "code_count") VALUES (?, ?, ?, ?) ON CONFLICT ("valueset_url", "version") DO UPDATE SET "expansion_json" = EXCLUDED."expansion_json", "code_count" = EXCLUDED."code_count", "expanded_at" = NOW()` : `INSERT OR REPLACE INTO "${TABLE4}" ("valueset_url", "version", "expansion_json", "code_count") VALUES (?, ?, ?, ?)`;
|
|
9280
|
+
await this.adapter.execute(sql, [url, version, expansionJson, codeCount]);
|
|
9281
|
+
}
|
|
9282
|
+
/** Get a cached expansion by URL and version. */
|
|
9283
|
+
async get(url, version) {
|
|
9284
|
+
await this.ensureTable();
|
|
9285
|
+
const row = await this.adapter.queryOne(
|
|
9286
|
+
`SELECT "valueset_url", "version", "expanded_at", "code_count", "expansion_json" FROM "${TABLE4}" WHERE "valueset_url" = ? AND "version" = ?`,
|
|
9287
|
+
[url, version]
|
|
9288
|
+
);
|
|
9289
|
+
if (!row) return void 0;
|
|
9290
|
+
return {
|
|
9291
|
+
valuesetUrl: row.valueset_url,
|
|
9292
|
+
version: row.version,
|
|
9293
|
+
expandedAt: row.expanded_at,
|
|
9294
|
+
codeCount: row.code_count,
|
|
9295
|
+
expansionJson: row.expansion_json
|
|
9296
|
+
};
|
|
9297
|
+
}
|
|
9298
|
+
/** Invalidate a specific expansion cache entry. */
|
|
9299
|
+
async invalidate(url, version) {
|
|
9300
|
+
await this.ensureTable();
|
|
9301
|
+
await this.adapter.execute(
|
|
9302
|
+
`DELETE FROM "${TABLE4}" WHERE "valueset_url" = ? AND "version" = ?`,
|
|
9303
|
+
[url, version]
|
|
9304
|
+
);
|
|
9305
|
+
}
|
|
9306
|
+
/** Clear all expansion caches. */
|
|
9307
|
+
async clear() {
|
|
9308
|
+
await this.ensureTable();
|
|
9309
|
+
await this.adapter.execute(`DELETE FROM "${TABLE4}"`);
|
|
9310
|
+
}
|
|
9311
|
+
};
|
|
9312
|
+
|
|
9313
|
+
// src/conformance/concept-hierarchy-repo.ts
|
|
9314
|
+
var TABLE5 = "code_system_concept";
|
|
9315
|
+
var CREATE_TABLE_DDL3 = `
|
|
9316
|
+
CREATE TABLE IF NOT EXISTS "${TABLE5}" (
|
|
9317
|
+
"id" TEXT PRIMARY KEY,
|
|
9318
|
+
"code_system_url" TEXT NOT NULL,
|
|
9319
|
+
"code_system_version" TEXT,
|
|
9320
|
+
"code" TEXT NOT NULL,
|
|
9321
|
+
"display" TEXT,
|
|
9322
|
+
"parent_code" TEXT,
|
|
9323
|
+
"level" INTEGER DEFAULT 0
|
|
9324
|
+
);
|
|
9325
|
+
`;
|
|
9326
|
+
var CREATE_INDEX_URL = `CREATE INDEX IF NOT EXISTS idx_csc_url ON "${TABLE5}"("code_system_url")`;
|
|
9327
|
+
var CREATE_INDEX_CODE = `CREATE INDEX IF NOT EXISTS idx_csc_code ON "${TABLE5}"("code_system_url", "code")`;
|
|
9328
|
+
var CREATE_INDEX_PARENT = `CREATE INDEX IF NOT EXISTS idx_csc_parent ON "${TABLE5}"("code_system_url", "parent_code")`;
|
|
9329
|
+
var ConceptHierarchyRepo = class {
|
|
9330
|
+
constructor(adapter, dialect = "sqlite") {
|
|
9331
|
+
this.adapter = adapter;
|
|
9332
|
+
this.dialect = dialect;
|
|
9333
|
+
}
|
|
9334
|
+
async ensureTable() {
|
|
9335
|
+
await this.adapter.execute(CREATE_TABLE_DDL3);
|
|
9336
|
+
await this.adapter.execute(CREATE_INDEX_URL);
|
|
9337
|
+
await this.adapter.execute(CREATE_INDEX_CODE);
|
|
9338
|
+
await this.adapter.execute(CREATE_INDEX_PARENT);
|
|
9339
|
+
}
|
|
9340
|
+
/** Batch insert hierarchical concept entries. */
|
|
9341
|
+
async batchInsert(entries) {
|
|
9342
|
+
await this.ensureTable();
|
|
9343
|
+
let count = 0;
|
|
9344
|
+
const sql = this.dialect === "postgres" ? `INSERT INTO "${TABLE5}" ("id", "code_system_url", "code_system_version", "code", "display", "parent_code", "level") VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT ("id") DO UPDATE SET "display" = EXCLUDED."display", "parent_code" = EXCLUDED."parent_code", "level" = EXCLUDED."level"` : `INSERT OR REPLACE INTO "${TABLE5}" ("id", "code_system_url", "code_system_version", "code", "display", "parent_code", "level") VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
|
9345
|
+
for (const e of entries) {
|
|
9346
|
+
await this.adapter.execute(sql, [
|
|
9347
|
+
e.id,
|
|
9348
|
+
e.codeSystemUrl,
|
|
9349
|
+
e.codeSystemVersion ?? null,
|
|
9350
|
+
e.code,
|
|
9351
|
+
e.display ?? null,
|
|
9352
|
+
e.parentCode ?? null,
|
|
9353
|
+
e.level
|
|
9354
|
+
]);
|
|
9355
|
+
count++;
|
|
9356
|
+
}
|
|
9357
|
+
return count;
|
|
9358
|
+
}
|
|
9359
|
+
/** Get all concepts for a CodeSystem (tree order by level). */
|
|
9360
|
+
async getTree(codeSystemUrl) {
|
|
9361
|
+
await this.ensureTable();
|
|
9362
|
+
const rows = await this.adapter.query(
|
|
9363
|
+
`SELECT "id", "code_system_url", "code_system_version", "code", "display", "parent_code", "level" FROM "${TABLE5}" WHERE "code_system_url" = ? ORDER BY "level", "code"`,
|
|
9364
|
+
[codeSystemUrl]
|
|
9365
|
+
);
|
|
9366
|
+
return rows.map((r) => this.mapRow(r));
|
|
9367
|
+
}
|
|
9368
|
+
/** Get direct children of a concept. */
|
|
9369
|
+
async getChildren(codeSystemUrl, parentCode) {
|
|
9370
|
+
await this.ensureTable();
|
|
9371
|
+
const rows = await this.adapter.query(
|
|
9372
|
+
`SELECT "id", "code_system_url", "code_system_version", "code", "display", "parent_code", "level" FROM "${TABLE5}" WHERE "code_system_url" = ? AND "parent_code" = ? ORDER BY "code"`,
|
|
9373
|
+
[codeSystemUrl, parentCode]
|
|
9374
|
+
);
|
|
9375
|
+
return rows.map((r) => this.mapRow(r));
|
|
9376
|
+
}
|
|
9377
|
+
/** Lookup a single concept by code. */
|
|
9378
|
+
async lookup(codeSystemUrl, code) {
|
|
9379
|
+
await this.ensureTable();
|
|
9380
|
+
const row = await this.adapter.queryOne(
|
|
9381
|
+
`SELECT "id", "code_system_url", "code_system_version", "code", "display", "parent_code", "level" FROM "${TABLE5}" WHERE "code_system_url" = ? AND "code" = ?`,
|
|
9382
|
+
[codeSystemUrl, code]
|
|
9383
|
+
);
|
|
9384
|
+
return row ? this.mapRow(row) : void 0;
|
|
9385
|
+
}
|
|
9386
|
+
/** Remove all concepts for a CodeSystem. */
|
|
9387
|
+
async removeByCodeSystem(codeSystemUrl) {
|
|
9388
|
+
await this.ensureTable();
|
|
9389
|
+
await this.adapter.execute(`DELETE FROM "${TABLE5}" WHERE "code_system_url" = ?`, [codeSystemUrl]);
|
|
9390
|
+
}
|
|
9391
|
+
mapRow(r) {
|
|
9392
|
+
return {
|
|
9393
|
+
id: r.id,
|
|
9394
|
+
codeSystemUrl: r.code_system_url,
|
|
9395
|
+
codeSystemVersion: r.code_system_version ?? void 0,
|
|
9396
|
+
code: r.code,
|
|
9397
|
+
display: r.display ?? void 0,
|
|
9398
|
+
parentCode: r.parent_code ?? void 0,
|
|
9399
|
+
level: Number(r.level)
|
|
9400
|
+
};
|
|
9401
|
+
}
|
|
9402
|
+
};
|
|
9403
|
+
|
|
9404
|
+
// src/conformance/search-param-index-repo.ts
|
|
9405
|
+
var TABLE6 = "search_parameter_index";
|
|
9406
|
+
function createTableDDL3(dialect) {
|
|
9407
|
+
const baseType = dialect === "postgres" ? "JSONB" : "TEXT";
|
|
9408
|
+
return `
|
|
9409
|
+
CREATE TABLE IF NOT EXISTS "${TABLE6}" (
|
|
9410
|
+
"id" TEXT PRIMARY KEY,
|
|
9411
|
+
"ig_id" TEXT NOT NULL,
|
|
9412
|
+
"url" TEXT,
|
|
9413
|
+
"code" TEXT NOT NULL,
|
|
9414
|
+
"type" TEXT NOT NULL,
|
|
9415
|
+
"base" ${baseType},
|
|
9416
|
+
"expression" TEXT
|
|
9417
|
+
);
|
|
9418
|
+
`;
|
|
9419
|
+
}
|
|
9420
|
+
var CREATE_INDEX_IG2 = `CREATE INDEX IF NOT EXISTS idx_spi_ig ON "${TABLE6}"("ig_id")`;
|
|
9421
|
+
var CREATE_INDEX_CODE2 = `CREATE INDEX IF NOT EXISTS idx_spi_code ON "${TABLE6}"("code")`;
|
|
9422
|
+
var SearchParamIndexRepo = class {
|
|
9423
|
+
constructor(adapter, dialect = "sqlite") {
|
|
9424
|
+
this.adapter = adapter;
|
|
9425
|
+
this.dialect = dialect;
|
|
9426
|
+
}
|
|
9427
|
+
async ensureTable() {
|
|
9428
|
+
await this.adapter.execute(createTableDDL3(this.dialect));
|
|
9429
|
+
await this.adapter.execute(CREATE_INDEX_IG2);
|
|
9430
|
+
await this.adapter.execute(CREATE_INDEX_CODE2);
|
|
9431
|
+
}
|
|
9432
|
+
async upsert(entry) {
|
|
9433
|
+
await this.ensureTable();
|
|
9434
|
+
const baseJson = JSON.stringify(entry.base);
|
|
9435
|
+
const sql = this.dialect === "postgres" ? `INSERT INTO "${TABLE6}" ("id", "ig_id", "url", "code", "type", "base", "expression") VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT ("id") DO UPDATE SET "url" = EXCLUDED."url", "code" = EXCLUDED."code", "type" = EXCLUDED."type", "base" = EXCLUDED."base", "expression" = EXCLUDED."expression"` : `INSERT OR REPLACE INTO "${TABLE6}" ("id", "ig_id", "url", "code", "type", "base", "expression") VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
|
9436
|
+
await this.adapter.execute(sql, [
|
|
9437
|
+
entry.id,
|
|
9438
|
+
entry.igId,
|
|
9439
|
+
entry.url ?? null,
|
|
9440
|
+
entry.code,
|
|
9441
|
+
entry.type,
|
|
9442
|
+
baseJson,
|
|
9443
|
+
entry.expression ?? null
|
|
9444
|
+
]);
|
|
9445
|
+
}
|
|
9446
|
+
async batchUpsert(entries) {
|
|
9447
|
+
let count = 0;
|
|
9448
|
+
for (const entry of entries) {
|
|
9449
|
+
await this.upsert(entry);
|
|
9450
|
+
count++;
|
|
9451
|
+
}
|
|
9452
|
+
return count;
|
|
9453
|
+
}
|
|
9454
|
+
async getByIG(igId) {
|
|
9455
|
+
await this.ensureTable();
|
|
9456
|
+
const rows = await this.adapter.query(
|
|
9457
|
+
`SELECT "id", "ig_id", "url", "code", "type", "base", "expression" FROM "${TABLE6}" WHERE "ig_id" = ? ORDER BY "code"`,
|
|
9458
|
+
[igId]
|
|
9459
|
+
);
|
|
9460
|
+
return rows.map((r) => this.mapRow(r));
|
|
9461
|
+
}
|
|
9462
|
+
async getByCode(code) {
|
|
9463
|
+
await this.ensureTable();
|
|
9464
|
+
const rows = await this.adapter.query(
|
|
9465
|
+
`SELECT "id", "ig_id", "url", "code", "type", "base", "expression" FROM "${TABLE6}" WHERE "code" = ? ORDER BY "ig_id"`,
|
|
9466
|
+
[code]
|
|
9467
|
+
);
|
|
9468
|
+
return rows.map((r) => this.mapRow(r));
|
|
9469
|
+
}
|
|
9470
|
+
async remove(id) {
|
|
9471
|
+
await this.ensureTable();
|
|
9472
|
+
await this.adapter.execute(`DELETE FROM "${TABLE6}" WHERE "id" = ?`, [id]);
|
|
9473
|
+
}
|
|
9474
|
+
async removeByIG(igId) {
|
|
9475
|
+
await this.ensureTable();
|
|
9476
|
+
await this.adapter.execute(`DELETE FROM "${TABLE6}" WHERE "ig_id" = ?`, [igId]);
|
|
9477
|
+
}
|
|
9478
|
+
mapRow(r) {
|
|
9479
|
+
const base = r.base ? typeof r.base === "string" ? JSON.parse(r.base) : r.base : [];
|
|
9480
|
+
return {
|
|
9481
|
+
id: r.id,
|
|
9482
|
+
igId: r.ig_id,
|
|
9483
|
+
url: r.url ?? void 0,
|
|
9484
|
+
code: r.code,
|
|
9485
|
+
type: r.type,
|
|
9486
|
+
base,
|
|
9487
|
+
expression: r.expression ?? void 0
|
|
9488
|
+
};
|
|
9489
|
+
}
|
|
9490
|
+
};
|
|
9491
|
+
|
|
9492
|
+
// src/conformance/ig-import-orchestrator.ts
|
|
9493
|
+
var IGImportOrchestrator = class {
|
|
9494
|
+
resourceMapRepo;
|
|
9495
|
+
sdIndexRepo;
|
|
9496
|
+
elementIndexRepo;
|
|
9497
|
+
expansionCacheRepo;
|
|
9498
|
+
conceptRepo;
|
|
9499
|
+
spIndexRepo;
|
|
9500
|
+
opts;
|
|
9501
|
+
constructor(adapter, dialect = "sqlite", options) {
|
|
9502
|
+
this.resourceMapRepo = new IGResourceMapRepo(adapter, dialect);
|
|
9503
|
+
this.sdIndexRepo = new SDIndexRepo(adapter, dialect);
|
|
9504
|
+
this.elementIndexRepo = new ElementIndexRepo(adapter, dialect);
|
|
9505
|
+
this.expansionCacheRepo = new ExpansionCacheRepo(adapter, dialect);
|
|
9506
|
+
this.conceptRepo = new ConceptHierarchyRepo(adapter, dialect);
|
|
9507
|
+
this.spIndexRepo = new SearchParamIndexRepo(adapter, dialect);
|
|
9508
|
+
this.opts = options ?? {};
|
|
9509
|
+
}
|
|
9510
|
+
/** Ensure all conformance tables exist. */
|
|
9511
|
+
async ensureAllTables() {
|
|
9512
|
+
await this.resourceMapRepo.ensureTable();
|
|
9513
|
+
await this.sdIndexRepo.ensureTable();
|
|
9514
|
+
await this.elementIndexRepo.ensureTable();
|
|
9515
|
+
await this.expansionCacheRepo.ensureTable();
|
|
9516
|
+
await this.conceptRepo.ensureTable();
|
|
9517
|
+
await this.spIndexRepo.ensureTable();
|
|
9518
|
+
}
|
|
9519
|
+
/** Execute a complete IG import from a FHIR Bundle. */
|
|
9520
|
+
async importIG(igId, bundle) {
|
|
9521
|
+
await this.ensureAllTables();
|
|
9522
|
+
const result = {
|
|
9523
|
+
igId,
|
|
9524
|
+
resourceCount: 0,
|
|
9525
|
+
sdIndexCount: 0,
|
|
9526
|
+
elementIndexCount: 0,
|
|
9527
|
+
conceptCount: 0,
|
|
9528
|
+
spIndexCount: 0,
|
|
9529
|
+
errors: []
|
|
9530
|
+
};
|
|
9531
|
+
const entries = bundle.entry ?? [];
|
|
9532
|
+
const resourceMapEntries = [];
|
|
9533
|
+
const structureDefs = [];
|
|
9534
|
+
const codeSystems = [];
|
|
9535
|
+
const searchParams = [];
|
|
9536
|
+
for (const entry of entries) {
|
|
9537
|
+
const resource = entry.resource;
|
|
9538
|
+
if (!resource || !resource.resourceType || !resource.id) continue;
|
|
9539
|
+
const resourceType = resource.resourceType;
|
|
9540
|
+
const resourceId = resource.id;
|
|
9541
|
+
const mapEntry = {
|
|
9542
|
+
resourceType,
|
|
9543
|
+
resourceId,
|
|
9544
|
+
resourceUrl: resource.url ?? void 0,
|
|
9545
|
+
resourceName: resource.name ?? void 0
|
|
9546
|
+
};
|
|
9547
|
+
if (resourceType === "StructureDefinition") {
|
|
9548
|
+
mapEntry.baseType = resource.type ?? void 0;
|
|
9549
|
+
structureDefs.push(resource);
|
|
9550
|
+
} else if (resourceType === "CodeSystem") {
|
|
9551
|
+
codeSystems.push(resource);
|
|
9552
|
+
} else if (resourceType === "SearchParameter") {
|
|
9553
|
+
searchParams.push(resource);
|
|
9554
|
+
}
|
|
9555
|
+
resourceMapEntries.push(mapEntry);
|
|
9556
|
+
}
|
|
9557
|
+
try {
|
|
9558
|
+
result.resourceCount = await this.resourceMapRepo.batchInsert(igId, resourceMapEntries);
|
|
9559
|
+
} catch (err) {
|
|
9560
|
+
result.errors.push(`Resource map insert failed: ${String(err)}`);
|
|
9561
|
+
}
|
|
9562
|
+
for (const sd of structureDefs) {
|
|
9563
|
+
try {
|
|
9564
|
+
const sdEntry = {
|
|
9565
|
+
id: sd.id,
|
|
9566
|
+
url: sd.url ?? void 0,
|
|
9567
|
+
version: sd.version ?? void 0,
|
|
9568
|
+
type: sd.type ?? void 0,
|
|
9569
|
+
kind: sd.kind ?? void 0,
|
|
9570
|
+
baseDefinition: sd.baseDefinition ?? void 0,
|
|
9571
|
+
derivation: sd.derivation ?? void 0
|
|
9572
|
+
};
|
|
9573
|
+
await this.sdIndexRepo.upsert(sdEntry);
|
|
9574
|
+
result.sdIndexCount++;
|
|
9575
|
+
if (this.opts.extractElementIndex) {
|
|
9576
|
+
const elements = this.opts.extractElementIndex(sd);
|
|
9577
|
+
const count = await this.elementIndexRepo.batchInsert(sd.id, elements);
|
|
9578
|
+
result.elementIndexCount += count;
|
|
9579
|
+
}
|
|
9580
|
+
} catch (err) {
|
|
9581
|
+
result.errors.push(`SD processing failed for ${sd.id}: ${String(err)}`);
|
|
9582
|
+
}
|
|
9583
|
+
}
|
|
9584
|
+
for (const cs of codeSystems) {
|
|
9585
|
+
try {
|
|
9586
|
+
if (this.opts.flattenConcepts) {
|
|
9587
|
+
const concepts = this.opts.flattenConcepts(cs);
|
|
9588
|
+
const count = await this.conceptRepo.batchInsert(concepts);
|
|
9589
|
+
result.conceptCount += count;
|
|
9590
|
+
}
|
|
9591
|
+
} catch (err) {
|
|
9592
|
+
result.errors.push(`CodeSystem processing failed for ${cs.id}: ${String(err)}`);
|
|
9593
|
+
}
|
|
9594
|
+
}
|
|
9595
|
+
for (const sp of searchParams) {
|
|
9596
|
+
try {
|
|
9597
|
+
const spEntry = {
|
|
9598
|
+
id: sp.id,
|
|
9599
|
+
igId,
|
|
9600
|
+
url: sp.url ?? void 0,
|
|
9601
|
+
code: sp.code ?? "",
|
|
9602
|
+
type: sp.type ?? "",
|
|
9603
|
+
base: Array.isArray(sp.base) ? sp.base : [],
|
|
9604
|
+
expression: sp.expression ?? void 0
|
|
9605
|
+
};
|
|
9606
|
+
await this.spIndexRepo.upsert(spEntry);
|
|
9607
|
+
result.spIndexCount++;
|
|
9608
|
+
} catch (err) {
|
|
9609
|
+
result.errors.push(`SearchParameter processing failed for ${sp.id}: ${String(err)}`);
|
|
9610
|
+
}
|
|
9611
|
+
}
|
|
9612
|
+
return result;
|
|
9613
|
+
}
|
|
9614
|
+
/** Get individual repos for direct access. */
|
|
9615
|
+
get repos() {
|
|
9616
|
+
return {
|
|
9617
|
+
resourceMap: this.resourceMapRepo,
|
|
9618
|
+
sdIndex: this.sdIndexRepo,
|
|
9619
|
+
elementIndex: this.elementIndexRepo,
|
|
9620
|
+
expansionCache: this.expansionCacheRepo,
|
|
9621
|
+
conceptHierarchy: this.conceptRepo,
|
|
9622
|
+
searchParamIndex: this.spIndexRepo
|
|
9623
|
+
};
|
|
9624
|
+
}
|
|
9625
|
+
};
|
|
8914
9626
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8915
9627
|
0 && (module.exports = {
|
|
8916
9628
|
BetterSqlite3Adapter,
|
|
9629
|
+
ConceptHierarchyRepo,
|
|
8917
9630
|
DEFAULT_SEARCH_COUNT,
|
|
8918
9631
|
DELETED_SCHEMA_VERSION,
|
|
9632
|
+
ElementIndexRepo,
|
|
9633
|
+
ExpansionCacheRepo,
|
|
8919
9634
|
FhirDefinitionBridge,
|
|
8920
9635
|
FhirPersistence,
|
|
8921
9636
|
FhirRuntimeProvider,
|
|
8922
9637
|
FhirStore,
|
|
8923
9638
|
FhirSystem,
|
|
9639
|
+
IGImportOrchestrator,
|
|
8924
9640
|
IGPersistenceManager,
|
|
9641
|
+
IGResourceMapRepo,
|
|
8925
9642
|
IndexingPipeline,
|
|
8926
9643
|
LookupTableWriter,
|
|
8927
9644
|
MAX_SEARCH_COUNT,
|
|
@@ -8943,9 +9660,11 @@ function createFhirRuntimeProvider(options) {
|
|
|
8943
9660
|
ResourceNotFoundError,
|
|
8944
9661
|
ResourceVersionConflictError,
|
|
8945
9662
|
SCHEMA_VERSION,
|
|
9663
|
+
SDIndexRepo,
|
|
8946
9664
|
SEARCH_PREFIXES,
|
|
8947
9665
|
SQLiteDialect,
|
|
8948
9666
|
SearchLogger,
|
|
9667
|
+
SearchParamIndexRepo,
|
|
8949
9668
|
SearchParameterRegistry,
|
|
8950
9669
|
StructureDefinitionRegistry,
|
|
8951
9670
|
TerminologyCodeRepo,
|