fhir-persistence 0.1.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 +77 -0
- package/LICENSE +21 -0
- package/README.md +225 -0
- package/dist/cjs/index.cjs +8869 -0
- package/dist/cjs/index.cjs.map +7 -0
- package/dist/cjs/index.d.ts +3114 -0
- package/dist/cjs/package.json +5 -0
- package/dist/esm/index.d.ts +3114 -0
- package/dist/esm/index.mjs +8745 -0
- package/dist/esm/index.mjs.map +7 -0
- package/dist/esm/package.json +5 -0
- package/dist/index.d.ts +3114 -0
- package/dist/lib/cache/resource-cache.d.ts +137 -0
- package/dist/lib/cache/resource-cache.d.ts.map +1 -0
- package/dist/lib/cli/reindex.d.ts +55 -0
- package/dist/lib/cli/reindex.d.ts.map +1 -0
- package/dist/lib/db/adapter.d.ts +79 -0
- package/dist/lib/db/adapter.d.ts.map +1 -0
- package/dist/lib/db/better-sqlite3-adapter.d.ts +65 -0
- package/dist/lib/db/better-sqlite3-adapter.d.ts.map +1 -0
- package/dist/lib/db/dialect.d.ts +87 -0
- package/dist/lib/db/dialect.d.ts.map +1 -0
- package/dist/lib/db/index.d.ts +18 -0
- package/dist/lib/db/index.d.ts.map +1 -0
- package/dist/lib/db/postgres-adapter.d.ts +84 -0
- package/dist/lib/db/postgres-adapter.d.ts.map +1 -0
- package/dist/lib/db/postgres-dialect.d.ts +36 -0
- package/dist/lib/db/postgres-dialect.d.ts.map +1 -0
- package/dist/lib/db/sqlite-adapter.d.ts +41 -0
- package/dist/lib/db/sqlite-adapter.d.ts.map +1 -0
- package/dist/lib/db/sqlite-dialect.d.ts +34 -0
- package/dist/lib/db/sqlite-dialect.d.ts.map +1 -0
- package/dist/lib/index.d.ts +65 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/migration/ig-persistence-manager.d.ts +56 -0
- package/dist/lib/migration/ig-persistence-manager.d.ts.map +1 -0
- package/dist/lib/migration/migration-generator.d.ts +38 -0
- package/dist/lib/migration/migration-generator.d.ts.map +1 -0
- package/dist/lib/migration/reindex-scheduler.d.ts +82 -0
- package/dist/lib/migration/reindex-scheduler.d.ts.map +1 -0
- package/dist/lib/migration/schema-diff.d.ts +44 -0
- package/dist/lib/migration/schema-diff.d.ts.map +1 -0
- package/dist/lib/migrations/index.d.ts +8 -0
- package/dist/lib/migrations/index.d.ts.map +1 -0
- package/dist/lib/migrations/migration-runner.d.ts +102 -0
- package/dist/lib/migrations/migration-runner.d.ts.map +1 -0
- package/dist/lib/observability/search-logger.d.ts +74 -0
- package/dist/lib/observability/search-logger.d.ts.map +1 -0
- package/dist/lib/platform/platform-ig-definitions.d.ts +51 -0
- package/dist/lib/platform/platform-ig-definitions.d.ts.map +1 -0
- package/dist/lib/platform/platform-ig-loader.d.ts +30 -0
- package/dist/lib/platform/platform-ig-loader.d.ts.map +1 -0
- package/dist/lib/providers/definition-provider.d.ts +124 -0
- package/dist/lib/providers/definition-provider.d.ts.map +1 -0
- package/dist/lib/providers/fhir-definition-provider.d.ts +58 -0
- package/dist/lib/providers/fhir-definition-provider.d.ts.map +1 -0
- package/dist/lib/providers/fhir-runtime-provider.d.ts +75 -0
- package/dist/lib/providers/fhir-runtime-provider.d.ts.map +1 -0
- package/dist/lib/providers/in-memory-definition-provider.d.ts +72 -0
- package/dist/lib/providers/in-memory-definition-provider.d.ts.map +1 -0
- package/dist/lib/providers/index.d.ts +13 -0
- package/dist/lib/providers/index.d.ts.map +1 -0
- package/dist/lib/providers/property-path-runtime-provider.d.ts +34 -0
- package/dist/lib/providers/property-path-runtime-provider.d.ts.map +1 -0
- package/dist/lib/providers/runtime-provider.d.ts +84 -0
- package/dist/lib/providers/runtime-provider.d.ts.map +1 -0
- package/dist/lib/registry/element-cardinality.d.ts +15 -0
- package/dist/lib/registry/element-cardinality.d.ts.map +1 -0
- package/dist/lib/registry/index.d.ts +10 -0
- package/dist/lib/registry/index.d.ts.map +1 -0
- package/dist/lib/registry/package-registry-repo.d.ts +106 -0
- package/dist/lib/registry/package-registry-repo.d.ts.map +1 -0
- package/dist/lib/registry/search-parameter-registry.d.ts +175 -0
- package/dist/lib/registry/search-parameter-registry.d.ts.map +1 -0
- package/dist/lib/registry/structure-definition-registry.d.ts +93 -0
- package/dist/lib/registry/structure-definition-registry.d.ts.map +1 -0
- package/dist/lib/repo/errors.d.ts +61 -0
- package/dist/lib/repo/errors.d.ts.map +1 -0
- package/dist/lib/repo/history-bundle.d.ts +78 -0
- package/dist/lib/repo/history-bundle.d.ts.map +1 -0
- package/dist/lib/repo/index.d.ts +17 -0
- package/dist/lib/repo/index.d.ts.map +1 -0
- package/dist/lib/repo/indexing-pipeline.d.ts +108 -0
- package/dist/lib/repo/indexing-pipeline.d.ts.map +1 -0
- package/dist/lib/repo/lookup-table-writer.d.ts +46 -0
- package/dist/lib/repo/lookup-table-writer.d.ts.map +1 -0
- package/dist/lib/repo/reference-indexer.d.ts +56 -0
- package/dist/lib/repo/reference-indexer.d.ts.map +1 -0
- package/dist/lib/repo/row-builder.d.ts +78 -0
- package/dist/lib/repo/row-builder.d.ts.map +1 -0
- package/dist/lib/repo/row-indexer.d.ts +111 -0
- package/dist/lib/repo/row-indexer.d.ts.map +1 -0
- package/dist/lib/repo/sql-builder.d.ts +166 -0
- package/dist/lib/repo/sql-builder.d.ts.map +1 -0
- package/dist/lib/repo/types.d.ts +321 -0
- package/dist/lib/repo/types.d.ts.map +1 -0
- package/dist/lib/schema/ddl-generator.d.ts +81 -0
- package/dist/lib/schema/ddl-generator.d.ts.map +1 -0
- package/dist/lib/schema/index.d.ts +8 -0
- package/dist/lib/schema/index.d.ts.map +1 -0
- package/dist/lib/schema/table-schema-builder.d.ts +66 -0
- package/dist/lib/schema/table-schema-builder.d.ts.map +1 -0
- package/dist/lib/schema/table-schema.d.ts +236 -0
- package/dist/lib/schema/table-schema.d.ts.map +1 -0
- package/dist/lib/search/index.d.ts +22 -0
- package/dist/lib/search/index.d.ts.map +1 -0
- package/dist/lib/search/pagination.d.ts +53 -0
- package/dist/lib/search/pagination.d.ts.map +1 -0
- package/dist/lib/search/param-parser.d.ts +85 -0
- package/dist/lib/search/param-parser.d.ts.map +1 -0
- package/dist/lib/search/search-bundle.d.ts +61 -0
- package/dist/lib/search/search-bundle.d.ts.map +1 -0
- package/dist/lib/search/search-executor.d.ts +58 -0
- package/dist/lib/search/search-executor.d.ts.map +1 -0
- package/dist/lib/search/search-planner.d.ts +57 -0
- package/dist/lib/search/search-planner.d.ts.map +1 -0
- package/dist/lib/search/search-sql-builder.d.ts +86 -0
- package/dist/lib/search/search-sql-builder.d.ts.map +1 -0
- package/dist/lib/search/types.d.ts +219 -0
- package/dist/lib/search/types.d.ts.map +1 -0
- package/dist/lib/search/where-builder.d.ts +64 -0
- package/dist/lib/search/where-builder.d.ts.map +1 -0
- package/dist/lib/startup/fhir-system.d.ts +82 -0
- package/dist/lib/startup/fhir-system.d.ts.map +1 -0
- package/dist/lib/store/conditional-service.d.ts +76 -0
- package/dist/lib/store/conditional-service.d.ts.map +1 -0
- package/dist/lib/store/fhir-persistence.d.ts +81 -0
- package/dist/lib/store/fhir-persistence.d.ts.map +1 -0
- package/dist/lib/store/fhir-store.d.ts +44 -0
- package/dist/lib/store/fhir-store.d.ts.map +1 -0
- package/dist/lib/terminology/terminology-code-repo.d.ts +61 -0
- package/dist/lib/terminology/terminology-code-repo.d.ts.map +1 -0
- package/dist/lib/terminology/valueset-repo.d.ts +76 -0
- package/dist/lib/terminology/valueset-repo.d.ts.map +1 -0
- package/dist/lib/transaction/bundle-processor.d.ts +84 -0
- package/dist/lib/transaction/bundle-processor.d.ts.map +1 -0
- package/dist/lib/transaction/urn-resolver.d.ts +62 -0
- package/dist/lib/transaction/urn-resolver.d.ts.map +1 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/package.json +87 -0
|
@@ -0,0 +1,3114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fhir-persistence` — Embedded FHIR R4 Persistence Layer
|
|
3
|
+
*
|
|
4
|
+
* Provides CRUD, search, indexing, schema migration, and terminology
|
|
5
|
+
* for FHIR R4 resources over SQLite (sql.js / better-sqlite3) and PostgreSQL.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Database } from 'better-sqlite3';
|
|
11
|
+
|
|
12
|
+
export declare class BetterSqlite3Adapter implements StorageAdapter {
|
|
13
|
+
private db;
|
|
14
|
+
private closed;
|
|
15
|
+
constructor(options?: BetterSqlite3Options);
|
|
16
|
+
private ensureOpen;
|
|
17
|
+
execute(sql: string, params?: unknown[]): Promise<{
|
|
18
|
+
changes: number;
|
|
19
|
+
}>;
|
|
20
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
21
|
+
queryOne<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T | undefined>;
|
|
22
|
+
queryStream<T = Record<string, unknown>>(sql: string, params?: unknown[]): AsyncIterable<T>;
|
|
23
|
+
prepare<T = Record<string, unknown>>(sql: string): PreparedStatement<T>;
|
|
24
|
+
transaction<R>(fn: (tx: TransactionContext) => R | Promise<R>): Promise<R>;
|
|
25
|
+
close(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Get the underlying better-sqlite3 Database instance.
|
|
28
|
+
* Use with caution — bypasses the adapter abstraction.
|
|
29
|
+
*/
|
|
30
|
+
getRawDatabase(): Database;
|
|
31
|
+
/**
|
|
32
|
+
* Execute a PRAGMA and return the result.
|
|
33
|
+
*/
|
|
34
|
+
pragma(statement: string): unknown;
|
|
35
|
+
/**
|
|
36
|
+
* Checkpoint WAL file to main database file.
|
|
37
|
+
* Useful before backup or when shutting down.
|
|
38
|
+
*/
|
|
39
|
+
checkpoint(mode?: 'PASSIVE' | 'FULL' | 'RESTART' | 'TRUNCATE'): void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export declare interface BetterSqlite3Options {
|
|
43
|
+
/** Database file path, or ':memory:' for in-memory database. */
|
|
44
|
+
path?: string;
|
|
45
|
+
/** Enable WAL journal mode (default: true). */
|
|
46
|
+
wal?: boolean;
|
|
47
|
+
/** Enable foreign key constraints (default: true). */
|
|
48
|
+
foreignKeys?: boolean;
|
|
49
|
+
/** Busy timeout in milliseconds (default: 5000). */
|
|
50
|
+
busyTimeout?: number;
|
|
51
|
+
/** Additional PRAGMA statements to execute on init. */
|
|
52
|
+
pragmas?: Record<string, string | number | boolean>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Build table schemas for ALL non-abstract resource types.
|
|
57
|
+
*
|
|
58
|
+
* @returns Array of `ResourceTableSet`, one per concrete resource type, sorted alphabetically.
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildAllResourceTableSets(sdRegistry: StructureDefinitionRegistry, spRegistry: SearchParameterRegistry): ResourceTableSet[];
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* v2: Build a COUNT query using ? placeholders.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildCountSQLv2(request: SearchRequest, registry: SearchParameterRegistry): CountSQL;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* v2: DELETE all reference rows for a resource (before re-inserting on update).
|
|
69
|
+
*/
|
|
70
|
+
export declare function buildDeleteReferencesSQLv2(tableName: string): string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build a FHIR R4 history Bundle from HistoryEntry[].
|
|
74
|
+
*
|
|
75
|
+
* @param entries - History entries (newest first).
|
|
76
|
+
* @param options - Optional bundle metadata.
|
|
77
|
+
* @returns A FHIR R4 Bundle of type `history`.
|
|
78
|
+
*/
|
|
79
|
+
export declare function buildHistoryBundle(entries: HistoryEntry[], options?: BuildHistoryBundleOptions): HistoryBundle;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Options for building a history bundle.
|
|
83
|
+
*/
|
|
84
|
+
export declare interface BuildHistoryBundleOptions {
|
|
85
|
+
/** Base URL for fullUrl construction (e.g., `"http://localhost:3000/fhir/R4"`). */
|
|
86
|
+
baseUrl?: string;
|
|
87
|
+
/** Total count of matching entries (may differ from entries.length if paginated). */
|
|
88
|
+
total?: number;
|
|
89
|
+
/** Self link URL. */
|
|
90
|
+
selfUrl?: string;
|
|
91
|
+
/** Next page link URL. */
|
|
92
|
+
nextUrl?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* v2: Build an INSERT statement for the history table.
|
|
97
|
+
* Uses `?` placeholders. Does NOT include versionSeq (AUTOINCREMENT).
|
|
98
|
+
*/
|
|
99
|
+
export declare function buildInsertHistorySQLv2(tableName: string, columns: Record<string, unknown>): {
|
|
100
|
+
sql: string;
|
|
101
|
+
values: unknown[];
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* v2: Build an INSERT statement for the main resource table.
|
|
106
|
+
* Uses `?` placeholders (SQLite-compatible).
|
|
107
|
+
*/
|
|
108
|
+
export declare function buildInsertMainSQLv2(tableName: string, columns: Record<string, unknown>): {
|
|
109
|
+
sql: string;
|
|
110
|
+
values: unknown[];
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* v2: Build a multi-row INSERT for the references table.
|
|
115
|
+
* Each row has 5 columns: resourceId, targetType, targetId, code, referenceRaw.
|
|
116
|
+
*/
|
|
117
|
+
export declare function buildInsertReferencesSQLv2(tableName: string, rowCount: number): string;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* v2: Instance history SELECT with optional _since, _count, cursor.
|
|
121
|
+
* Uses `?` placeholders and ORDER BY versionSeq DESC.
|
|
122
|
+
*/
|
|
123
|
+
export declare function buildInstanceHistorySQLv2(tableName: string, resourceId: string, options?: {
|
|
124
|
+
since?: string;
|
|
125
|
+
count?: number;
|
|
126
|
+
cursor?: string;
|
|
127
|
+
}): {
|
|
128
|
+
sql: string;
|
|
129
|
+
values: unknown[];
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Extract rows for global lookup tables from a FHIR resource.
|
|
134
|
+
*
|
|
135
|
+
* Scans the resource for HumanName, Address, ContactPoint, and Identifier
|
|
136
|
+
* values and decomposes them into individual rows matching Medplum's schema:
|
|
137
|
+
*
|
|
138
|
+
* - `HumanName` → { resourceId, name, given, family }
|
|
139
|
+
* - `Address` → { resourceId, address, city, country, postalCode, state, use }
|
|
140
|
+
* - `ContactPoint` → { resourceId, system, value, use }
|
|
141
|
+
* - `Identifier` → { resourceId, system, value }
|
|
142
|
+
*
|
|
143
|
+
* @param resource - The FHIR resource (must have `id`).
|
|
144
|
+
* @param impls - SearchParameterImpl list for this resource type.
|
|
145
|
+
* @returns Array of LookupTableRow to insert into global tables.
|
|
146
|
+
*/
|
|
147
|
+
export declare function buildLookupTableRows(resource: FhirResource & {
|
|
148
|
+
id: string;
|
|
149
|
+
}, impls: SearchParameterImpl[]): LookupTableRow[];
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Build the `next` link URL, or `undefined` if there is no next page.
|
|
153
|
+
*
|
|
154
|
+
* A next page exists when the current page returned exactly `count` results,
|
|
155
|
+
* indicating there may be more.
|
|
156
|
+
*/
|
|
157
|
+
export declare function buildNextLink(ctx: PaginationContext): string | undefined;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Build a pagination context from search request parameters.
|
|
161
|
+
*/
|
|
162
|
+
export declare function buildPaginationContext(baseUrl: string, resourceType: string, queryParams: Record<string, string | string[]>, count: number | undefined, offset: number | undefined, resultCount: number): PaginationContext;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Build ResourceTableSets for all platform resource types.
|
|
166
|
+
*
|
|
167
|
+
* Uses StructureDefinitionRegistry + SearchParameterRegistry
|
|
168
|
+
* populated with platform definitions to generate the table schemas.
|
|
169
|
+
*/
|
|
170
|
+
export declare function buildPlatformTableSets(): ResourceTableSet[];
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Build a main table row with search column values populated.
|
|
174
|
+
*
|
|
175
|
+
* Extends `buildResourceRow()` by extracting search parameter values
|
|
176
|
+
* from the resource JSON and merging them into the row.
|
|
177
|
+
*
|
|
178
|
+
* @param resource - The persisted resource.
|
|
179
|
+
* @param searchImpls - SearchParameterImpl list for this resource type.
|
|
180
|
+
* @returns A `ResourceRow` with both fixed and search columns.
|
|
181
|
+
*/
|
|
182
|
+
export declare function buildResourceRowWithSearch(resource: PersistedResource, searchImpls: SearchParameterImpl[], context?: OperationContext): ResourceRow;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Build the complete 3-table schema for a single resource type.
|
|
186
|
+
*
|
|
187
|
+
* @param resourceType - The FHIR resource type (e.g., `'Patient'`).
|
|
188
|
+
* @param sdRegistry - StructureDefinitionRegistry (used to verify the type exists).
|
|
189
|
+
* @param spRegistry - SearchParameterRegistry (provides search column definitions).
|
|
190
|
+
* @returns The complete `ResourceTableSet` for the resource type.
|
|
191
|
+
* @throws Error if the resource type is not found or is abstract.
|
|
192
|
+
*/
|
|
193
|
+
export declare function buildResourceTableSet(resourceType: string, sdRegistry: StructureDefinitionRegistry, spRegistry: SearchParameterRegistry): ResourceTableSet;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Build a complete `SchemaDefinition` for all resource types.
|
|
197
|
+
*
|
|
198
|
+
* @param sdRegistry - StructureDefinitionRegistry with indexed profiles.
|
|
199
|
+
* @param spRegistry - SearchParameterRegistry with indexed search params.
|
|
200
|
+
* @param version - Schema version string (default: `'fhir-r4-v4.0.1'`).
|
|
201
|
+
* @returns The complete `SchemaDefinition`.
|
|
202
|
+
*/
|
|
203
|
+
export declare function buildSchemaDefinition(sdRegistry: StructureDefinitionRegistry, spRegistry: SearchParameterRegistry, version?: string): SchemaDefinition;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Build a FHIR R4 searchset Bundle from PersistedResource[].
|
|
207
|
+
*
|
|
208
|
+
* @param resources - Matched resources.
|
|
209
|
+
* @param options - Optional bundle metadata.
|
|
210
|
+
* @returns A FHIR R4 Bundle of type `searchset`.
|
|
211
|
+
*/
|
|
212
|
+
export declare function buildSearchBundle(resources: PersistedResource[], options?: BuildSearchBundleOptions): SearchBundle;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Options for building a searchset Bundle.
|
|
216
|
+
*/
|
|
217
|
+
export declare interface BuildSearchBundleOptions {
|
|
218
|
+
/** Base URL for fullUrl construction (e.g., `"http://localhost:3000/fhir/R4"`). */
|
|
219
|
+
baseUrl?: string;
|
|
220
|
+
/** Total count of matching resources (only included when `_total=accurate`). */
|
|
221
|
+
total?: number;
|
|
222
|
+
/** Self link URL. */
|
|
223
|
+
selfUrl?: string;
|
|
224
|
+
/** Next page link URL. */
|
|
225
|
+
nextUrl?: string;
|
|
226
|
+
/** Included resources from _include/_revinclude. */
|
|
227
|
+
included?: PersistedResource[];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Build search column values for a FHIR resource.
|
|
232
|
+
*
|
|
233
|
+
* Given a resource and its applicable SearchParameterImpl list,
|
|
234
|
+
* extracts values from the resource JSON and returns a map of
|
|
235
|
+
* column name → value pairs ready for SQL insertion.
|
|
236
|
+
*
|
|
237
|
+
* @param resource - The FHIR resource to index.
|
|
238
|
+
* @param impls - SearchParameterImpl list for this resource type.
|
|
239
|
+
* @returns Column name → value map for search columns.
|
|
240
|
+
*/
|
|
241
|
+
export declare function buildSearchColumns(resource: FhirResource, impls: SearchParameterImpl[]): SearchColumnValues;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* v2: Build a complete search SQL query using ? placeholders.
|
|
245
|
+
* No projectId filter. deleted = 0 (INTEGER).
|
|
246
|
+
*/
|
|
247
|
+
export declare function buildSearchSQLv2(request: SearchRequest, registry: SearchParameterRegistry): SearchSQL;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* v2: SELECT by ID — no projectId, returns versionId + deleted.
|
|
251
|
+
*/
|
|
252
|
+
export declare function buildSelectByIdSQLv2(tableName: string): string;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* v2: SELECT a specific version from the history table.
|
|
256
|
+
*/
|
|
257
|
+
export declare function buildSelectVersionSQLv2(tableName: string): string;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Build the `self` link URL for the current search page.
|
|
261
|
+
*/
|
|
262
|
+
export declare function buildSelfLink(ctx: PaginationContext): string;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* v2: Build two-phase search SQL for improved performance on large tables.
|
|
266
|
+
*
|
|
267
|
+
* ## Strategy
|
|
268
|
+
*
|
|
269
|
+
* **Phase 1** — Lightweight id-only query with all filters, sorting, and pagination.
|
|
270
|
+
* Only reads the indexed columns, avoiding expensive content deserialization.
|
|
271
|
+
*
|
|
272
|
+
* ```sql
|
|
273
|
+
* SELECT "id" FROM "Patient"
|
|
274
|
+
* WHERE "deleted" = 0 AND "birthdate" >= ?
|
|
275
|
+
* ORDER BY "lastUpdated" DESC
|
|
276
|
+
* LIMIT ?
|
|
277
|
+
* ```
|
|
278
|
+
*
|
|
279
|
+
* **Phase 2** — Fetch full content for matched ids (executed by caller).
|
|
280
|
+
*
|
|
281
|
+
* ```sql
|
|
282
|
+
* SELECT "id", "versionId", "content", "lastUpdated", "deleted"
|
|
283
|
+
* FROM "Patient"
|
|
284
|
+
* WHERE "id" IN (?, ?, ?)
|
|
285
|
+
* ```
|
|
286
|
+
*
|
|
287
|
+
* @param request - The parsed search request.
|
|
288
|
+
* @param registry - The SearchParameterRegistry.
|
|
289
|
+
* @returns TwoPhaseSearchSQL with phase1 query and phase2 template.
|
|
290
|
+
*/
|
|
291
|
+
export declare function buildTwoPhaseSearchSQLv2(request: SearchRequest, registry: SearchParameterRegistry): TwoPhaseSearchSQL;
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* v2: Type-level history SELECT.
|
|
295
|
+
* Uses `?` placeholders and ORDER BY versionSeq DESC.
|
|
296
|
+
*/
|
|
297
|
+
export declare function buildTypeHistorySQLv2(tableName: string, options?: {
|
|
298
|
+
since?: string;
|
|
299
|
+
count?: number;
|
|
300
|
+
cursor?: string;
|
|
301
|
+
}): {
|
|
302
|
+
sql: string;
|
|
303
|
+
values: unknown[];
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* v2: Build an UPDATE statement for the main resource table.
|
|
308
|
+
* Uses `?` placeholders. Updates all columns except `id`.
|
|
309
|
+
*/
|
|
310
|
+
export declare function buildUpdateMainSQLv2(tableName: string, columns: Record<string, unknown>): {
|
|
311
|
+
sql: string;
|
|
312
|
+
values: unknown[];
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* v2: Build a complete WHERE clause from parsed search params using ? placeholders.
|
|
317
|
+
*/
|
|
318
|
+
export declare function buildWhereClauseV2(params: ParsedSearchParam[], registry: SearchParameterRegistry, resourceType: string): WhereFragment | null;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* v2: Build a WHERE clause fragment using ? placeholders (SQLite).
|
|
322
|
+
*
|
|
323
|
+
* Dispatches to type-specific v2 builders. Key differences from v1:
|
|
324
|
+
* - Uses `?` instead of `$N`
|
|
325
|
+
* - Token search uses `json_each()` instead of `ARRAY[]::text[]`
|
|
326
|
+
* - Array columns use `json_each()` instead of PG array operators
|
|
327
|
+
*/
|
|
328
|
+
export declare function buildWhereFragmentV2(impl: SearchParameterImpl, param: ParsedSearchParam): WhereFragment | null;
|
|
329
|
+
|
|
330
|
+
declare interface BundleLink {
|
|
331
|
+
relation: string;
|
|
332
|
+
url: string;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* StructureDefinition Registry
|
|
337
|
+
*
|
|
338
|
+
* Indexes `CanonicalProfile[]` by resource type for fast lookup.
|
|
339
|
+
* MedXAI equivalent of Medplum's `indexStructureDefinitionBundle()` →
|
|
340
|
+
* `DATA_TYPES`, but as an injectable instance (no global state).
|
|
341
|
+
*
|
|
342
|
+
* Used by `TableSchemaBuilder` to determine which resource types
|
|
343
|
+
* need tables and to access element definitions for search column
|
|
344
|
+
* generation.
|
|
345
|
+
*
|
|
346
|
+
* @module fhir-persistence/registry
|
|
347
|
+
*/
|
|
348
|
+
/**
|
|
349
|
+
* Minimal CanonicalProfile shape (replaces @medxai/fhir-core dependency).
|
|
350
|
+
*/
|
|
351
|
+
export declare interface CanonicalProfile {
|
|
352
|
+
url: string;
|
|
353
|
+
name: string;
|
|
354
|
+
kind: 'resource' | 'complex-type' | 'primitive-type' | 'logical';
|
|
355
|
+
type: string;
|
|
356
|
+
abstract: boolean;
|
|
357
|
+
elements: Map<string, unknown>;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Target information for a chained search parameter.
|
|
362
|
+
*
|
|
363
|
+
* Example: `subject:Patient.name=Smith`
|
|
364
|
+
* - `targetType` = `"Patient"`
|
|
365
|
+
* - `targetParam` = `"name"`
|
|
366
|
+
*/
|
|
367
|
+
declare interface ChainedSearchTarget {
|
|
368
|
+
/** The target resource type (e.g., `"Patient"`). */
|
|
369
|
+
targetType: string;
|
|
370
|
+
/** The search parameter on the target resource (e.g., `"name"`). */
|
|
371
|
+
targetParam: string;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Minimal CodeSystem shape used by fhir-persistence.
|
|
376
|
+
*/
|
|
377
|
+
declare interface CodeSystemDef {
|
|
378
|
+
resourceType: 'CodeSystem';
|
|
379
|
+
url: string;
|
|
380
|
+
name?: string;
|
|
381
|
+
status?: string;
|
|
382
|
+
content?: string;
|
|
383
|
+
concept?: Array<{
|
|
384
|
+
code: string;
|
|
385
|
+
display?: string;
|
|
386
|
+
definition?: string;
|
|
387
|
+
concept?: unknown[];
|
|
388
|
+
}>;
|
|
389
|
+
[key: string]: unknown;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Definition of a single database column.
|
|
394
|
+
*
|
|
395
|
+
* v2: Dialect-neutral. DDLGenerator maps types to dialect-specific
|
|
396
|
+
* equivalents (e.g., BOOLEAN → INTEGER for SQLite).
|
|
397
|
+
*/
|
|
398
|
+
export declare interface ColumnSchema {
|
|
399
|
+
/** Column name (e.g., `id`, `content`, `birthdate`). */
|
|
400
|
+
name: string;
|
|
401
|
+
/** Logical SQL data type (mapped to dialect-specific type in DDL). */
|
|
402
|
+
type: SqlColumnType;
|
|
403
|
+
/** Whether the column has a NOT NULL constraint. */
|
|
404
|
+
notNull: boolean;
|
|
405
|
+
/** Whether this column is the primary key. */
|
|
406
|
+
primaryKey: boolean;
|
|
407
|
+
/** SQL default value expression (e.g., `'false'`, `'0'`). */
|
|
408
|
+
defaultValue?: string;
|
|
409
|
+
/** Source FHIRPath expression (documentation only). */
|
|
410
|
+
fhirPath?: string;
|
|
411
|
+
/** Source SearchParameter.code (documentation only). */
|
|
412
|
+
searchParamCode?: string;
|
|
413
|
+
/**
|
|
414
|
+
* v2: Search parameter storage strategy.
|
|
415
|
+
* Enables SchemaDiff to understand column purpose.
|
|
416
|
+
*/
|
|
417
|
+
strategy?: 'column' | 'token-column' | 'lookup-table' | 'skip';
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Compare two sets of ResourceTableSets and produce a list of deltas.
|
|
422
|
+
*
|
|
423
|
+
* @param oldSets - The previously installed schema (from PackageRegistry).
|
|
424
|
+
* @param newSets - The newly generated schema (from current IG).
|
|
425
|
+
* @returns Array of SchemaDelta describing all changes.
|
|
426
|
+
*/
|
|
427
|
+
export declare function compareSchemas(oldSets: ResourceTableSet[], newSets: ResourceTableSet[]): SchemaDelta[];
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Definition of a PostgreSQL table constraint.
|
|
431
|
+
*/
|
|
432
|
+
export declare interface ConstraintSchema {
|
|
433
|
+
/** Constraint name (e.g., `Patient_pk`). */
|
|
434
|
+
name: string;
|
|
435
|
+
/** Constraint type. */
|
|
436
|
+
type: 'primary_key' | 'unique' | 'check';
|
|
437
|
+
/** Columns involved (for primary_key and unique). */
|
|
438
|
+
columns?: string[];
|
|
439
|
+
/** SQL expression (for check constraints). */
|
|
440
|
+
expression?: string;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Result of a count query.
|
|
445
|
+
*/
|
|
446
|
+
export declare interface CountSQL {
|
|
447
|
+
/** The SQL COUNT query string. */
|
|
448
|
+
sql: string;
|
|
449
|
+
/** The parameter values for the query. */
|
|
450
|
+
values: unknown[];
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Create a FhirRuntimeProvider from the fhir-runtime package.
|
|
455
|
+
*
|
|
456
|
+
* Usage:
|
|
457
|
+
* ```typescript
|
|
458
|
+
* import { extractSearchValues, extractAllSearchValues, extractReferences } from 'fhir-runtime';
|
|
459
|
+
*
|
|
460
|
+
* const provider = createFhirRuntimeProvider({
|
|
461
|
+
* extractSearchValues,
|
|
462
|
+
* extractAllSearchValues,
|
|
463
|
+
* extractReferences,
|
|
464
|
+
* });
|
|
465
|
+
* ```
|
|
466
|
+
*/
|
|
467
|
+
export declare function createFhirRuntimeProvider(options: FhirRuntimeProviderOptions): FhirRuntimeProvider;
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Options for `createResource()`.
|
|
471
|
+
*/
|
|
472
|
+
export declare interface CreateResourceOptions {
|
|
473
|
+
/**
|
|
474
|
+
* Pre-assigned UUID for the resource.
|
|
475
|
+
* Used in batch/transaction operations where the ID is determined
|
|
476
|
+
* before the create call.
|
|
477
|
+
*/
|
|
478
|
+
assignedId?: string;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
declare interface CreateResourceOptions_2 {
|
|
482
|
+
/** Pre-assigned ID (used in batch/transaction). */
|
|
483
|
+
assignedId?: string;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
declare interface CreateResourceOptions_3 {
|
|
487
|
+
/** Pre-assigned ID (used in batch/transaction). */
|
|
488
|
+
assignedId?: string;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
declare type DDLDialect = 'sqlite' | 'postgres';
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Default page size for search results.
|
|
495
|
+
*/
|
|
496
|
+
export declare const DEFAULT_SEARCH_COUNT = 20;
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Bridge interface for fhir-definition registry.
|
|
500
|
+
*
|
|
501
|
+
* fhir-persistence depends only on this interface, never on
|
|
502
|
+
* fhir-definition internal types. Implementations may wrap
|
|
503
|
+
* `InMemoryDefinitionRegistry` or provide test-only mocks.
|
|
504
|
+
*
|
|
505
|
+
* ADR-01 §2.3 — structural typing, no `implements` required.
|
|
506
|
+
*/
|
|
507
|
+
declare interface DefinitionProvider {
|
|
508
|
+
/**
|
|
509
|
+
* Get a StructureDefinition by canonical URL.
|
|
510
|
+
*/
|
|
511
|
+
getStructureDefinition(url: string): StructureDefinitionDef | undefined;
|
|
512
|
+
/**
|
|
513
|
+
* Get a ValueSet by canonical URL.
|
|
514
|
+
*/
|
|
515
|
+
getValueSet(url: string): ValueSetDef | undefined;
|
|
516
|
+
/**
|
|
517
|
+
* Get a CodeSystem by canonical URL.
|
|
518
|
+
*/
|
|
519
|
+
getCodeSystem(url: string): CodeSystemDef | undefined;
|
|
520
|
+
/**
|
|
521
|
+
* Get all SearchParameters for a specific resource type.
|
|
522
|
+
*/
|
|
523
|
+
getSearchParameters(resourceType: string): SearchParameterDef[];
|
|
524
|
+
/**
|
|
525
|
+
* Enumerate all known resource types.
|
|
526
|
+
* Used by SchemaEngine and ReindexCLI to iterate over all tables.
|
|
527
|
+
*/
|
|
528
|
+
getAllResourceTypes(): string[];
|
|
529
|
+
/**
|
|
530
|
+
* Get metadata about loaded packages (optional).
|
|
531
|
+
*/
|
|
532
|
+
getLoadedPackages?(): LoadedPackageDef[];
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Schema version for deleted resources.
|
|
537
|
+
*/
|
|
538
|
+
export declare const DELETED_SCHEMA_VERSION = -1;
|
|
539
|
+
|
|
540
|
+
export declare type DeltaKind = 'ADD_TABLE' | 'DROP_TABLE' | 'ADD_COLUMN' | 'DROP_COLUMN' | 'ALTER_COLUMN' | 'ADD_INDEX' | 'DROP_INDEX' | 'REINDEX';
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Eviction policy for the cache.
|
|
544
|
+
*
|
|
545
|
+
* - `lru` — Least Recently Used: evict the entry that was accessed longest ago.
|
|
546
|
+
* - `fifo` — First In First Out: evict the entry that was inserted first.
|
|
547
|
+
* - `ttl-only` — No size-based eviction; entries only expire via TTL.
|
|
548
|
+
*/
|
|
549
|
+
declare type EvictionPolicy = 'lru' | 'fifo' | 'ttl-only';
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* v2: Execute a FHIR search query using StorageAdapter.
|
|
553
|
+
*
|
|
554
|
+
* Key differences from v1:
|
|
555
|
+
* - Uses `StorageAdapter` instead of `DatabaseClient`
|
|
556
|
+
* - Uses `?` placeholders (SQLite)
|
|
557
|
+
* - `deleted` is number (0/1), not boolean
|
|
558
|
+
* - No `_include` / `_revinclude` in this MVP (can be added)
|
|
559
|
+
*/
|
|
560
|
+
export declare function executeSearch(adapter: StorageAdapter, request: SearchRequest, registry: SearchParameterRegistry, options?: SearchOptions_2): Promise<SearchResult_2>;
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* A reference extracted from a FHIR resource.
|
|
564
|
+
*/
|
|
565
|
+
declare interface ExtractedReference {
|
|
566
|
+
/** The SearchParameter code (e.g., 'subject', 'performer'). */
|
|
567
|
+
code: string;
|
|
568
|
+
/** The full reference string (e.g., 'Patient/123'). */
|
|
569
|
+
reference: string;
|
|
570
|
+
/** The target resource type (e.g., 'Patient'). */
|
|
571
|
+
targetType: string;
|
|
572
|
+
/** The target resource ID (e.g., '123'). */
|
|
573
|
+
targetId: string;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Extract a search prefix from values if the parameter type supports it.
|
|
578
|
+
*
|
|
579
|
+
* Prefixes are two-letter codes at the start of the first value:
|
|
580
|
+
* - `"ge1990-01-01"` → prefix `"ge"`, value `"1990-01-01"`
|
|
581
|
+
* - `"male"` → no prefix, value `"male"`
|
|
582
|
+
*
|
|
583
|
+
* Only number, date, and quantity types support prefixes.
|
|
584
|
+
*/
|
|
585
|
+
export declare function extractPrefix(values: string[], paramType?: string): {
|
|
586
|
+
prefix?: SearchPrefix;
|
|
587
|
+
cleanValues: string[];
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Extract the property path for a given resource type from a FHIRPath expression.
|
|
592
|
+
*
|
|
593
|
+
* Handles:
|
|
594
|
+
* - Simple: `"Patient.birthDate"` → `["birthDate"]`
|
|
595
|
+
* - Union: `"Patient.name | Practitioner.name"` → `["name"]` (for Patient)
|
|
596
|
+
* - .where(): `"Account.subject.where(resolve() is Patient)"` → `["subject"]`
|
|
597
|
+
* - Nested: `"Observation.value.as(Quantity)"` → `["valueQuantity"]` (special)
|
|
598
|
+
* - Deep: `"Patient.contact.name"` → `["contact", "name"]`
|
|
599
|
+
*
|
|
600
|
+
* @returns Array of path segments, or null if no matching path found.
|
|
601
|
+
*/
|
|
602
|
+
export declare function extractPropertyPath(expression: string, resourceType: string): string[] | null;
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* v2: Extract all outgoing reference rows with targetType + referenceRaw.
|
|
606
|
+
*/
|
|
607
|
+
export declare function extractReferencesV2(resource: FhirResource, impls: SearchParameterImpl[]): ReferenceRowV2[];
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Bridges a fhir-definition DefinitionRegistry into our DefinitionProvider.
|
|
611
|
+
*
|
|
612
|
+
* Usage:
|
|
613
|
+
* ```typescript
|
|
614
|
+
* import { loadDefinitionPackages } from 'fhir-definition';
|
|
615
|
+
*
|
|
616
|
+
* const { registry } = await loadDefinitionPackages({ ... });
|
|
617
|
+
* const provider = new FhirDefinitionBridge(registry);
|
|
618
|
+
*
|
|
619
|
+
* // Use with FhirSystem
|
|
620
|
+
* const system = new FhirSystem(adapter);
|
|
621
|
+
* await system.initialize(provider);
|
|
622
|
+
* ```
|
|
623
|
+
*/
|
|
624
|
+
export declare class FhirDefinitionBridge implements DefinitionProvider {
|
|
625
|
+
private readonly registry;
|
|
626
|
+
private cachedResourceTypes;
|
|
627
|
+
constructor(registry: FhirDefinitionRegistry);
|
|
628
|
+
getStructureDefinition(url: string): StructureDefinitionDef | undefined;
|
|
629
|
+
getValueSet(url: string): ValueSetDef | undefined;
|
|
630
|
+
getCodeSystem(url: string): CodeSystemDef | undefined;
|
|
631
|
+
getSearchParameters(resourceType: string): SearchParameterDef[];
|
|
632
|
+
getAllResourceTypes(): string[];
|
|
633
|
+
getLoadedPackages(): LoadedPackageDef[];
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Structural type matching fhir-definition's DefinitionRegistry.
|
|
638
|
+
* Uses `any` for return types to bridge between fhir-definition's
|
|
639
|
+
* concrete types and our minimal structural types.
|
|
640
|
+
*/
|
|
641
|
+
declare interface FhirDefinitionRegistry {
|
|
642
|
+
getStructureDefinition(url: string): any | undefined;
|
|
643
|
+
getValueSet(url: string): any | undefined;
|
|
644
|
+
getCodeSystem(url: string): any | undefined;
|
|
645
|
+
getSearchParameters(resourceType: string): any[];
|
|
646
|
+
listStructureDefinitions(): string[];
|
|
647
|
+
getLoadedPackages?(): any[];
|
|
648
|
+
getStatistics?(): any;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* FHIR Meta element (subset used by the repository).
|
|
653
|
+
*/
|
|
654
|
+
export declare interface FhirMeta {
|
|
655
|
+
versionId?: string;
|
|
656
|
+
lastUpdated?: string;
|
|
657
|
+
source?: string;
|
|
658
|
+
profile?: string[];
|
|
659
|
+
[key: string]: unknown;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
export declare class FhirPersistence {
|
|
663
|
+
private readonly adapter;
|
|
664
|
+
private readonly registry;
|
|
665
|
+
private readonly pipeline;
|
|
666
|
+
constructor(adapter: StorageAdapter, registry: SearchParameterRegistry, options?: FhirPersistenceOptions);
|
|
667
|
+
/** Get the underlying StorageAdapter. */
|
|
668
|
+
getAdapter(): StorageAdapter;
|
|
669
|
+
/** Get the SearchParameterRegistry. */
|
|
670
|
+
getRegistry(): SearchParameterRegistry;
|
|
671
|
+
/** Get the IndexingPipeline. */
|
|
672
|
+
getPipeline(): IndexingPipeline;
|
|
673
|
+
createResource<T extends FhirResource>(resourceType: string, resource: T, options?: CreateResourceOptions_3): Promise<T & PersistedResource>;
|
|
674
|
+
readResource(resourceType: string, id: string): Promise<PersistedResource>;
|
|
675
|
+
updateResource<T extends FhirResource>(resourceType: string, resource: T, options?: UpdateResourceOptions_3): Promise<T & PersistedResource>;
|
|
676
|
+
deleteResource(resourceType: string, id: string): Promise<void>;
|
|
677
|
+
readVersion(resourceType: string, id: string, versionId: string): Promise<PersistedResource>;
|
|
678
|
+
readHistory(resourceType: string, id: string, options?: HistoryOptions_3): Promise<HistoryEntry[]>;
|
|
679
|
+
/**
|
|
680
|
+
* Stream search results row-by-row for large result sets.
|
|
681
|
+
*
|
|
682
|
+
* Uses `StorageAdapter.queryStream` for true row-by-row iteration
|
|
683
|
+
* without loading all results into memory. Useful for:
|
|
684
|
+
* - Export operations ($export)
|
|
685
|
+
* - Reindex-all workflows
|
|
686
|
+
* - Large batch processing
|
|
687
|
+
*
|
|
688
|
+
* NOTE: Does NOT include _include/_revinclude resources.
|
|
689
|
+
* Use `searchResources` for full FHIR search with includes.
|
|
690
|
+
*/
|
|
691
|
+
searchStream(resourceType: string, sql: string, params?: unknown[]): AsyncGenerator<PersistedResource>;
|
|
692
|
+
/**
|
|
693
|
+
* Re-index an existing resource (update search columns + references + lookup).
|
|
694
|
+
* Does NOT create a new version.
|
|
695
|
+
*/
|
|
696
|
+
reindexResource(resourceType: string, id: string): Promise<void>;
|
|
697
|
+
private getImpls;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
export declare interface FhirPersistenceOptions {
|
|
701
|
+
/** Indexing pipeline options. */
|
|
702
|
+
indexing?: IndexingPipelineOptions;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Minimal FHIR resource shape for persistence operations.
|
|
707
|
+
*
|
|
708
|
+
* This is intentionally loose — the repository does not validate
|
|
709
|
+
* resource structure (that's the validator's job). It only requires
|
|
710
|
+
* `resourceType` and optionally `id` / `meta`.
|
|
711
|
+
*/
|
|
712
|
+
export declare interface FhirResource {
|
|
713
|
+
resourceType: string;
|
|
714
|
+
id?: string;
|
|
715
|
+
meta?: FhirMeta;
|
|
716
|
+
[key: string]: unknown;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
export declare class FhirRuntimeProvider implements RuntimeProvider {
|
|
720
|
+
private readonly opts;
|
|
721
|
+
constructor(options: FhirRuntimeProviderOptions);
|
|
722
|
+
extractSearchValues(resource: Record<string, unknown>, params: SearchParameterDef[]): Record<string, unknown[]>;
|
|
723
|
+
extractReferences(resource: Record<string, unknown>, params: SearchParameterDef[]): ExtractedReference[];
|
|
724
|
+
/**
|
|
725
|
+
* Convert our minimal SearchParameterDef to fhir-runtime's SearchParameter shape.
|
|
726
|
+
*/
|
|
727
|
+
private toRuntimeSearchParameter;
|
|
728
|
+
/**
|
|
729
|
+
* Normalize fhir-runtime SearchIndexValue[] to persistence-friendly unknown[].
|
|
730
|
+
*/
|
|
731
|
+
private normalizeSearchValues;
|
|
732
|
+
/**
|
|
733
|
+
* Normalize token values to "system|code" strings.
|
|
734
|
+
*/
|
|
735
|
+
private normalizeTokenValues;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Options for creating a FhirRuntimeProvider.
|
|
740
|
+
*
|
|
741
|
+
* Uses `any` for function signatures to bridge between fhir-runtime's
|
|
742
|
+
* narrow union types (e.g., SearchParamType) and our structural types.
|
|
743
|
+
* The conversion is handled internally by FhirRuntimeProvider.
|
|
744
|
+
*/
|
|
745
|
+
export declare interface FhirRuntimeProviderOptions {
|
|
746
|
+
/**
|
|
747
|
+
* The `extractSearchValues` function from fhir-runtime.
|
|
748
|
+
* Signature: (resource: Resource, searchParam: SearchParameter) => SearchIndexEntry
|
|
749
|
+
*/
|
|
750
|
+
extractSearchValues: (resource: any, searchParam: any) => any;
|
|
751
|
+
/**
|
|
752
|
+
* The `extractAllSearchValues` function from fhir-runtime.
|
|
753
|
+
* Signature: (resource: Resource, searchParams: SearchParameter[]) => SearchIndexEntry[]
|
|
754
|
+
*/
|
|
755
|
+
extractAllSearchValues: (resource: any, searchParams: any[]) => any[];
|
|
756
|
+
/**
|
|
757
|
+
* The `extractReferences` function from fhir-runtime.
|
|
758
|
+
* Signature: (resource: Resource) => ReferenceInfo[]
|
|
759
|
+
*/
|
|
760
|
+
extractReferences: (resource: any) => any[];
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
export declare class FhirStore {
|
|
764
|
+
private readonly adapter;
|
|
765
|
+
constructor(adapter: StorageAdapter);
|
|
766
|
+
createResource<T extends FhirResource>(resourceType: string, resource: T, options?: CreateResourceOptions_2): Promise<T & PersistedResource>;
|
|
767
|
+
readResource(resourceType: string, id: string): Promise<PersistedResource>;
|
|
768
|
+
updateResource<T extends FhirResource>(resourceType: string, resource: T, options?: UpdateResourceOptions_2): Promise<T & PersistedResource>;
|
|
769
|
+
deleteResource(resourceType: string, id: string): Promise<void>;
|
|
770
|
+
readVersion(resourceType: string, id: string, versionId: string): Promise<PersistedResource>;
|
|
771
|
+
readHistory(resourceType: string, id: string, options?: HistoryOptions_2): Promise<HistoryEntry[]>;
|
|
772
|
+
writeReferences(resourceType: string, resourceId: string, refs: ReferenceRowV2[]): Promise<void>;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
export declare class FhirSystem {
|
|
776
|
+
private readonly adapter;
|
|
777
|
+
private readonly dialect;
|
|
778
|
+
private readonly options;
|
|
779
|
+
constructor(adapter: StorageAdapter, options?: FhirSystemOptions);
|
|
780
|
+
/**
|
|
781
|
+
* Initialize the full FHIR persistence system.
|
|
782
|
+
*
|
|
783
|
+
* Flow (ADR-01 §4.1):
|
|
784
|
+
* ```
|
|
785
|
+
* DefinitionProvider
|
|
786
|
+
* → populate SD/SP registries
|
|
787
|
+
* → buildResourceTableSets
|
|
788
|
+
* → IGPersistenceManager.initialize (DDL + migration)
|
|
789
|
+
* → FhirPersistence(adapter, spRegistry, { runtimeProvider })
|
|
790
|
+
* ```
|
|
791
|
+
*/
|
|
792
|
+
initialize(definitionProvider: DefinitionProvider): Promise<FhirSystemReady>;
|
|
793
|
+
/**
|
|
794
|
+
* Bridge DefinitionProvider → StructureDefinitionRegistry + SearchParameterRegistry.
|
|
795
|
+
*
|
|
796
|
+
* Converts DefinitionProvider's minimal types to the existing registry
|
|
797
|
+
* types expected by the schema builder and indexing pipeline.
|
|
798
|
+
*/
|
|
799
|
+
private populateRegistries;
|
|
800
|
+
private buildTableSets;
|
|
801
|
+
/**
|
|
802
|
+
* Simple checksum from table set structure for change detection.
|
|
803
|
+
* Uses JSON serialization of table schemas (column names + types).
|
|
804
|
+
*/
|
|
805
|
+
private computeChecksum;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
export declare interface FhirSystemOptions {
|
|
809
|
+
/** SQL dialect (default: 'sqlite'). */
|
|
810
|
+
dialect?: DDLDialect;
|
|
811
|
+
/** Optional RuntimeProvider for FHIRPath-driven extraction. */
|
|
812
|
+
runtimeProvider?: RuntimeProvider;
|
|
813
|
+
/** Enable lookup tables in the indexing pipeline (default: true). */
|
|
814
|
+
enableLookupTables?: boolean;
|
|
815
|
+
/** Enable reference indexing (default: true). */
|
|
816
|
+
enableReferences?: boolean;
|
|
817
|
+
/** Package name for IG persistence tracking (default: 'fhir-persistence.default'). */
|
|
818
|
+
packageName?: string;
|
|
819
|
+
/** Package version (default: '1.0.0'). */
|
|
820
|
+
packageVersion?: string;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
export declare interface FhirSystemReady {
|
|
824
|
+
/** The initialized FhirPersistence facade. */
|
|
825
|
+
persistence: FhirPersistence;
|
|
826
|
+
/** StructureDefinition registry (populated from DefinitionProvider). */
|
|
827
|
+
sdRegistry: StructureDefinitionRegistry;
|
|
828
|
+
/** SearchParameter registry (populated from DefinitionProvider). */
|
|
829
|
+
spRegistry: SearchParameterRegistry;
|
|
830
|
+
/** IG initialization result (new/upgrade/consistent). */
|
|
831
|
+
igResult: IGInitResult;
|
|
832
|
+
/** Resource types with tables. */
|
|
833
|
+
resourceTypes: string[];
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Generate a `CREATE TABLE IF NOT EXISTS` statement for a history table.
|
|
838
|
+
*
|
|
839
|
+
* v2: Handles versionSeq AUTOINCREMENT for SQLite and GENERATED ALWAYS for PG.
|
|
840
|
+
*/
|
|
841
|
+
export declare function generateCreateHistoryTable(table: HistoryTableSchema, dialect?: DDLDialect): string;
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Generate a `CREATE INDEX IF NOT EXISTS` statement.
|
|
845
|
+
*
|
|
846
|
+
* Supports:
|
|
847
|
+
* - `opClass` — operator class appended to each column key (e.g., `gin_trgm_ops`)
|
|
848
|
+
* - `expression` — functional expression to index instead of plain columns
|
|
849
|
+
* (e.g., `to_tsvector('simple'::regconfig, family)`)
|
|
850
|
+
*/
|
|
851
|
+
export declare function generateCreateIndex(index: IndexSchema, tableName: string, dialect?: DDLDialect): string | null;
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Generate a `CREATE TABLE IF NOT EXISTS` statement for a main table.
|
|
855
|
+
*/
|
|
856
|
+
export declare function generateCreateMainTable(table: MainTableSchema, dialect?: DDLDialect): string;
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Generate a `CREATE TABLE IF NOT EXISTS` statement for a references table.
|
|
860
|
+
*/
|
|
861
|
+
export declare function generateCreateReferencesTable(table: ReferencesTableSchema, dialect?: DDLDialect): string;
|
|
862
|
+
|
|
863
|
+
export declare interface GeneratedMigration {
|
|
864
|
+
/** SQL statements to apply (up). */
|
|
865
|
+
up: string[];
|
|
866
|
+
/** SQL statements to revert (down). Best-effort; some are irreversible. */
|
|
867
|
+
down: string[];
|
|
868
|
+
/** Deltas that require reindex (no DDL, just scheduling). */
|
|
869
|
+
reindexDeltas: SchemaDelta[];
|
|
870
|
+
/** Human-readable description of changes. */
|
|
871
|
+
description: string;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Generate SQL DDL from a list of schema deltas.
|
|
876
|
+
*
|
|
877
|
+
* @param deltas - Schema changes to apply.
|
|
878
|
+
* @param dialect - Target SQL dialect.
|
|
879
|
+
* @returns Generated migration with up/down SQL and reindex info.
|
|
880
|
+
*/
|
|
881
|
+
export declare function generateMigration(deltas: SchemaDelta[], dialect: DDLDialect): GeneratedMigration;
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Generate all DDL statements for a single resource type (3 tables + indexes).
|
|
885
|
+
*
|
|
886
|
+
* Returns an array of SQL statements in order:
|
|
887
|
+
* 1. CREATE TABLE for main table
|
|
888
|
+
* 2. CREATE TABLE for history table
|
|
889
|
+
* 3. CREATE TABLE for references table
|
|
890
|
+
* 4. All CREATE INDEX statements
|
|
891
|
+
*/
|
|
892
|
+
export declare function generateResourceDDL(tableSet: ResourceTableSet, dialect?: DDLDialect): string[];
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Generate all DDL statements for a complete schema definition.
|
|
896
|
+
*
|
|
897
|
+
* Order:
|
|
898
|
+
* 1. Global lookup tables (HumanName, Address, ContactPoint, Identifier)
|
|
899
|
+
* 2. Resource tables (main, history, references)
|
|
900
|
+
* 3. All indexes (global lookup + resource tables)
|
|
901
|
+
*
|
|
902
|
+
* @param schema - The complete schema definition.
|
|
903
|
+
* @returns Array of SQL DDL statements.
|
|
904
|
+
*/
|
|
905
|
+
export declare function generateSchemaDDL(schema: SchemaDefinition, dialect?: DDLDialect): string[];
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Generate the complete DDL as a single string, with statements
|
|
909
|
+
* separated by double newlines.
|
|
910
|
+
*
|
|
911
|
+
* Includes a header comment with version and generation timestamp.
|
|
912
|
+
*/
|
|
913
|
+
export declare function generateSchemaDDLString(schema: SchemaDefinition, dialect?: DDLDialect): string;
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* Navigate a resource object using a property path and return the value(s).
|
|
917
|
+
*
|
|
918
|
+
* Handles arrays at any level — if a path segment hits an array,
|
|
919
|
+
* the remaining path is applied to each element.
|
|
920
|
+
*
|
|
921
|
+
* @returns Array of extracted values (may be empty).
|
|
922
|
+
*/
|
|
923
|
+
export declare function getNestedValues(obj: unknown, pathSegments: string[]): unknown[];
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Schema for a global shared lookup table (e.g., `HumanName`, `Address`).
|
|
927
|
+
*
|
|
928
|
+
* Matches Medplum's production-verified design where a single table
|
|
929
|
+
* stores data from ALL resource types that use that complex type.
|
|
930
|
+
*
|
|
931
|
+
* - `HumanName` — stores name/given/family from Patient.name, Practitioner.name, etc.
|
|
932
|
+
* - `Address` — stores address/city/country/postalCode/state/use
|
|
933
|
+
* - `ContactPoint` — stores system/value/use from telecom fields
|
|
934
|
+
* - `Identifier` — stores system/value from identifier fields
|
|
935
|
+
*/
|
|
936
|
+
declare interface GlobalLookupTableSchema {
|
|
937
|
+
/** Table name (e.g., `'HumanName'`, `'Address'`). */
|
|
938
|
+
tableName: LookupTableType;
|
|
939
|
+
/** All columns. */
|
|
940
|
+
columns: ColumnSchema[];
|
|
941
|
+
/** All indexes. */
|
|
942
|
+
indexes: IndexSchema[];
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Generate a deterministic UUID-like hash for a token value.
|
|
947
|
+
*
|
|
948
|
+
* Produces a v4-format UUID string from the SHA-256 hash of `system|code`.
|
|
949
|
+
* This matches Medplum's approach of using a deterministic hash for token
|
|
950
|
+
* search columns (UUID[] type).
|
|
951
|
+
*/
|
|
952
|
+
export declare function hashToken(system: string, code: string): string;
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Determine whether there is a next page of results.
|
|
956
|
+
*
|
|
957
|
+
* Returns `true` when the current page is full (resultCount === count),
|
|
958
|
+
* indicating there may be more results.
|
|
959
|
+
*/
|
|
960
|
+
export declare function hasNextPage(ctx: PaginationContext): boolean;
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* A FHIR R4 Bundle (minimal shape for history).
|
|
964
|
+
*/
|
|
965
|
+
export declare interface HistoryBundle {
|
|
966
|
+
resourceType: 'Bundle';
|
|
967
|
+
id: string;
|
|
968
|
+
type: 'history';
|
|
969
|
+
total: number;
|
|
970
|
+
link?: BundleLink[];
|
|
971
|
+
entry?: HistoryBundleEntry[];
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
export declare interface HistoryBundleEntry {
|
|
975
|
+
fullUrl?: string;
|
|
976
|
+
resource?: Record<string, unknown>;
|
|
977
|
+
request: {
|
|
978
|
+
method: string;
|
|
979
|
+
url: string;
|
|
980
|
+
};
|
|
981
|
+
response: {
|
|
982
|
+
status: string;
|
|
983
|
+
etag?: string;
|
|
984
|
+
lastModified?: string;
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* A single entry in a history result, including delete markers.
|
|
990
|
+
*/
|
|
991
|
+
export declare interface HistoryEntry {
|
|
992
|
+
/** The resource (null for delete entries). */
|
|
993
|
+
resource: PersistedResource | null;
|
|
994
|
+
/** The versionId for this entry. */
|
|
995
|
+
versionId: string;
|
|
996
|
+
/** The timestamp of this version. */
|
|
997
|
+
lastUpdated: string;
|
|
998
|
+
/** Whether this entry represents a deletion. */
|
|
999
|
+
deleted: boolean;
|
|
1000
|
+
/** The resource type (needed for delete entries where resource is null). */
|
|
1001
|
+
resourceType: string;
|
|
1002
|
+
/** The resource id. */
|
|
1003
|
+
id: string;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Options for history queries.
|
|
1008
|
+
*/
|
|
1009
|
+
export declare interface HistoryOptions {
|
|
1010
|
+
/**
|
|
1011
|
+
* Only include versions updated after this instant.
|
|
1012
|
+
* Corresponds to the `_since` parameter.
|
|
1013
|
+
*/
|
|
1014
|
+
since?: string;
|
|
1015
|
+
/**
|
|
1016
|
+
* Maximum number of entries to return.
|
|
1017
|
+
* Corresponds to the `_count` parameter.
|
|
1018
|
+
*/
|
|
1019
|
+
count?: number;
|
|
1020
|
+
/**
|
|
1021
|
+
* Cursor for pagination — the `lastUpdated` value of the last
|
|
1022
|
+
* entry from the previous page. Only entries with `lastUpdated`
|
|
1023
|
+
* strictly before this value are returned.
|
|
1024
|
+
*/
|
|
1025
|
+
cursor?: string;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
declare interface HistoryOptions_2 {
|
|
1029
|
+
since?: string;
|
|
1030
|
+
count?: number;
|
|
1031
|
+
cursor?: string;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
declare interface HistoryOptions_3 {
|
|
1035
|
+
since?: string;
|
|
1036
|
+
count?: number;
|
|
1037
|
+
cursor?: string;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* Schema for a FHIR resource history table.
|
|
1042
|
+
*
|
|
1043
|
+
* Stores all historical versions of a resource.
|
|
1044
|
+
* Fixed structure — no search columns.
|
|
1045
|
+
*/
|
|
1046
|
+
export declare interface HistoryTableSchema {
|
|
1047
|
+
/** Table name (e.g., `'Patient_History'`). */
|
|
1048
|
+
tableName: string;
|
|
1049
|
+
/** FHIR resource type name. */
|
|
1050
|
+
resourceType: string;
|
|
1051
|
+
/** All columns (fixed). */
|
|
1052
|
+
columns: ColumnSchema[];
|
|
1053
|
+
/** All indexes (fixed). */
|
|
1054
|
+
indexes: IndexSchema[];
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
declare type IGInitAction = 'new' | 'upgrade' | 'consistent';
|
|
1058
|
+
|
|
1059
|
+
declare interface IGInitResult {
|
|
1060
|
+
/** What action was taken. */
|
|
1061
|
+
action: IGInitAction;
|
|
1062
|
+
/** Package name. */
|
|
1063
|
+
packageName: string;
|
|
1064
|
+
/** Package version. */
|
|
1065
|
+
packageVersion: string;
|
|
1066
|
+
/** Number of DDL statements applied (0 for 'consistent'). */
|
|
1067
|
+
ddlCount: number;
|
|
1068
|
+
/** Number of reindex jobs scheduled. */
|
|
1069
|
+
reindexCount: number;
|
|
1070
|
+
/** Error message if any step failed. */
|
|
1071
|
+
error?: string;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
declare interface IGPackageInput {
|
|
1075
|
+
/** Package name (e.g., "hl7.fhir.r4.core"). */
|
|
1076
|
+
name: string;
|
|
1077
|
+
/** Package version (e.g., "4.0.1"). */
|
|
1078
|
+
version: string;
|
|
1079
|
+
/** Content checksum for change detection. */
|
|
1080
|
+
checksum: string;
|
|
1081
|
+
/** The new schema table sets generated from this package. */
|
|
1082
|
+
tableSets: ResourceTableSet[];
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
export declare class IGPersistenceManager {
|
|
1086
|
+
private readonly dialect;
|
|
1087
|
+
private readonly packageRepo;
|
|
1088
|
+
private readonly migrationRunner;
|
|
1089
|
+
private readonly reindexScheduler;
|
|
1090
|
+
constructor(adapter: StorageAdapter, dialect?: DDLDialect);
|
|
1091
|
+
/**
|
|
1092
|
+
* Initialize an IG package — the main entry point.
|
|
1093
|
+
*
|
|
1094
|
+
* Three-way branch based on checksum comparison:
|
|
1095
|
+
* - **new**: Fresh install → apply full schema DDL
|
|
1096
|
+
* - **upgrade**: Checksum changed → diff + apply migration
|
|
1097
|
+
* - **consistent**: Checksum matches → no-op
|
|
1098
|
+
*/
|
|
1099
|
+
initialize(input: IGPackageInput): Promise<IGInitResult>;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* A parsed `_include` or `_revinclude` target.
|
|
1104
|
+
*
|
|
1105
|
+
* Syntax: `{sourceType}:{searchParam}` or `{sourceType}:{searchParam}:{targetType}`
|
|
1106
|
+
*
|
|
1107
|
+
* Examples:
|
|
1108
|
+
* - `_include=MedicationRequest:patient` → `{ resourceType: "MedicationRequest", searchParam: "patient" }`
|
|
1109
|
+
* - `_include=Observation:subject:Patient` → `{ resourceType: "Observation", searchParam: "subject", targetType: "Patient" }`
|
|
1110
|
+
*/
|
|
1111
|
+
declare interface IncludeTarget {
|
|
1112
|
+
/** Source resource type (e.g., "MedicationRequest"). */
|
|
1113
|
+
resourceType: string;
|
|
1114
|
+
/** Search parameter code (e.g., "patient", "subject"). */
|
|
1115
|
+
searchParam: string;
|
|
1116
|
+
/** Optional target type filter (e.g., "Patient"). */
|
|
1117
|
+
targetType?: string;
|
|
1118
|
+
/**
|
|
1119
|
+
* If true, this is an `_include:iterate` — recursively include
|
|
1120
|
+
* resources referenced by included resources (max depth 3, with cycle detection).
|
|
1121
|
+
*/
|
|
1122
|
+
iterate?: boolean;
|
|
1123
|
+
/**
|
|
1124
|
+
* If true, this is a wildcard `_include=*` — include ALL referenced resources.
|
|
1125
|
+
*/
|
|
1126
|
+
wildcard?: boolean;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
export declare class IndexingPipeline {
|
|
1130
|
+
private readonly adapter;
|
|
1131
|
+
private readonly lookupWriter;
|
|
1132
|
+
private readonly options;
|
|
1133
|
+
private readonly runtimeProvider;
|
|
1134
|
+
constructor(adapter: StorageAdapter, options?: IndexingPipelineOptions);
|
|
1135
|
+
/**
|
|
1136
|
+
* Index a resource: extract search columns, write references, write lookup rows.
|
|
1137
|
+
*
|
|
1138
|
+
* @param resourceType - The FHIR resource type (e.g., "Patient").
|
|
1139
|
+
* @param resource - The FHIR resource (must have `id`).
|
|
1140
|
+
* @param impls - SearchParameterImpl list for this resource type.
|
|
1141
|
+
* @returns IndexResult with search columns and write counts.
|
|
1142
|
+
*/
|
|
1143
|
+
indexResource(resourceType: string, resource: FhirResource, impls: SearchParameterImpl[]): Promise<IndexResult>;
|
|
1144
|
+
/**
|
|
1145
|
+
* Remove all index data for a deleted resource.
|
|
1146
|
+
*
|
|
1147
|
+
* @param resourceType - The FHIR resource type.
|
|
1148
|
+
* @param resourceId - The resource ID.
|
|
1149
|
+
*/
|
|
1150
|
+
deleteIndex(resourceType: string, resourceId: string): Promise<void>;
|
|
1151
|
+
/**
|
|
1152
|
+
* Extract search column values without writing references or lookup rows.
|
|
1153
|
+
* Useful for re-indexing or testing.
|
|
1154
|
+
*/
|
|
1155
|
+
extractSearchColumns(resource: FhirResource, impls: SearchParameterImpl[]): SearchColumnValues;
|
|
1156
|
+
/**
|
|
1157
|
+
* Extract reference rows without writing them.
|
|
1158
|
+
* Useful for re-indexing or testing.
|
|
1159
|
+
*/
|
|
1160
|
+
extractReferences(resource: FhirResource, impls: SearchParameterImpl[]): ReferenceRowV2[];
|
|
1161
|
+
/**
|
|
1162
|
+
* Extract lookup table rows without writing them.
|
|
1163
|
+
* Useful for re-indexing or testing.
|
|
1164
|
+
*/
|
|
1165
|
+
extractLookupRows(resource: FhirResource, impls: SearchParameterImpl[]): LookupTableRow[];
|
|
1166
|
+
/**
|
|
1167
|
+
* Get the underlying LookupTableWriter for direct access.
|
|
1168
|
+
*/
|
|
1169
|
+
getLookupWriter(): LookupTableWriter;
|
|
1170
|
+
private writeReferences;
|
|
1171
|
+
private writeLookupRows;
|
|
1172
|
+
/**
|
|
1173
|
+
* Convert SearchParameterImpl[] to SearchParameterDef[] for RuntimeProvider.
|
|
1174
|
+
*/
|
|
1175
|
+
private implsToDefs;
|
|
1176
|
+
/**
|
|
1177
|
+
* Extract search column values via RuntimeProvider.
|
|
1178
|
+
*/
|
|
1179
|
+
private extractViaRuntime;
|
|
1180
|
+
/**
|
|
1181
|
+
* Extract references via RuntimeProvider → ReferenceRowV2[].
|
|
1182
|
+
*/
|
|
1183
|
+
private extractRefsViaRuntime;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* Options for the indexing pipeline.
|
|
1188
|
+
*/
|
|
1189
|
+
export declare interface IndexingPipelineOptions {
|
|
1190
|
+
/** Enable lookup table writes (default: true). */
|
|
1191
|
+
enableLookupTables?: boolean;
|
|
1192
|
+
/** Enable reference indexing (default: true). */
|
|
1193
|
+
enableReferences?: boolean;
|
|
1194
|
+
/** Optional RuntimeProvider for FHIRPath-driven extraction (B3). */
|
|
1195
|
+
runtimeProvider?: RuntimeProvider;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Result of indexing a single resource.
|
|
1200
|
+
*/
|
|
1201
|
+
export declare interface IndexResult {
|
|
1202
|
+
/** Search column values to merge into the main table row. */
|
|
1203
|
+
searchColumns: SearchColumnValues;
|
|
1204
|
+
/** Reference rows written to {RT}_References table. */
|
|
1205
|
+
referenceCount: number;
|
|
1206
|
+
/** Lookup table rows written to global lookup tables. */
|
|
1207
|
+
lookupRowCount: number;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
* Definition of a PostgreSQL index.
|
|
1212
|
+
*/
|
|
1213
|
+
export declare interface IndexSchema {
|
|
1214
|
+
/** Index name (e.g., `Patient_lastUpdated_idx`). */
|
|
1215
|
+
name: string;
|
|
1216
|
+
/** Columns included in the index key. */
|
|
1217
|
+
columns: string[];
|
|
1218
|
+
/** Index type. */
|
|
1219
|
+
indexType: 'btree' | 'gin' | 'gist';
|
|
1220
|
+
/** Whether this is a unique index. */
|
|
1221
|
+
unique: boolean;
|
|
1222
|
+
/** Partial index WHERE clause (e.g., `'deleted = false'`). */
|
|
1223
|
+
where?: string;
|
|
1224
|
+
/** INCLUDE columns for covering indexes. */
|
|
1225
|
+
include?: string[];
|
|
1226
|
+
/**
|
|
1227
|
+
* Operator class for the index (e.g., `'gin_trgm_ops'` for trigram GIN).
|
|
1228
|
+
* Applied to all columns in the index.
|
|
1229
|
+
*/
|
|
1230
|
+
opClass?: string;
|
|
1231
|
+
/**
|
|
1232
|
+
* Functional expression to index instead of a plain column.
|
|
1233
|
+
* When set, `columns` is ignored and this SQL expression is used directly.
|
|
1234
|
+
* Example: `"to_tsvector('simple'::regconfig, family)"`
|
|
1235
|
+
*/
|
|
1236
|
+
expression?: string;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
/**
|
|
1240
|
+
* Initialize the platform IG — create or upgrade platform resource tables.
|
|
1241
|
+
*
|
|
1242
|
+
* This is the main entry point for bootstrapping platform tables on startup.
|
|
1243
|
+
* Uses IGPersistenceManager for checksum-based change detection.
|
|
1244
|
+
*
|
|
1245
|
+
* @param adapter - StorageAdapter (SQLite or PostgreSQL).
|
|
1246
|
+
* @returns IGInitResult with action taken (new/upgrade/consistent).
|
|
1247
|
+
*/
|
|
1248
|
+
export declare function initializePlatformIG(adapter: StorageAdapter): Promise<IGInitResult>;
|
|
1249
|
+
|
|
1250
|
+
declare interface InstalledPackage {
|
|
1251
|
+
/** Package name (e.g., "hl7.fhir.r4.core"). */
|
|
1252
|
+
name: string;
|
|
1253
|
+
/** Package version (e.g., "4.0.1"). */
|
|
1254
|
+
version: string;
|
|
1255
|
+
/** Content checksum for change detection. */
|
|
1256
|
+
checksum: string;
|
|
1257
|
+
/** Serialized ResourceTableSet[] JSON for SchemaDiff. */
|
|
1258
|
+
schemaSnapshot: string | null;
|
|
1259
|
+
/** When this package was installed/updated. */
|
|
1260
|
+
installedAt: string;
|
|
1261
|
+
/** Package status: active or superseded. */
|
|
1262
|
+
status: PackageStatus;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/**
|
|
1266
|
+
* Loaded package metadata.
|
|
1267
|
+
*/
|
|
1268
|
+
declare interface LoadedPackageDef {
|
|
1269
|
+
name: string;
|
|
1270
|
+
version: string;
|
|
1271
|
+
loadedAt?: string;
|
|
1272
|
+
resourceCount?: number;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* A row to be inserted into one of the 4 global lookup tables.
|
|
1277
|
+
*/
|
|
1278
|
+
export declare interface LookupTableRow {
|
|
1279
|
+
/** Which global table: HumanName, Address, ContactPoint, or Identifier. */
|
|
1280
|
+
table: LookupTableType;
|
|
1281
|
+
/** Column name → value map for the lookup table row. */
|
|
1282
|
+
values: Record<string, unknown>;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
/**
|
|
1286
|
+
* @deprecated Use GlobalLookupTableSchema instead. Kept for backward compatibility.
|
|
1287
|
+
*/
|
|
1288
|
+
declare interface LookupTableSchema {
|
|
1289
|
+
tableName: string;
|
|
1290
|
+
resourceType: string;
|
|
1291
|
+
searchParamCode: string;
|
|
1292
|
+
columns: ColumnSchema[];
|
|
1293
|
+
indexes: IndexSchema[];
|
|
1294
|
+
compositePrimaryKey: string[];
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
/**
|
|
1298
|
+
* The 4 global lookup table types, matching Medplum's production design.
|
|
1299
|
+
*
|
|
1300
|
+
* Each is a shared table across ALL resource types, storing decomposed
|
|
1301
|
+
* complex FHIR types for precise search via JOINs.
|
|
1302
|
+
*/
|
|
1303
|
+
declare type LookupTableType = 'HumanName' | 'Address' | 'ContactPoint' | 'Identifier';
|
|
1304
|
+
|
|
1305
|
+
export declare class LookupTableWriter {
|
|
1306
|
+
private readonly adapter;
|
|
1307
|
+
private initialized;
|
|
1308
|
+
constructor(adapter: StorageAdapter);
|
|
1309
|
+
/**
|
|
1310
|
+
* Create all 4 lookup tables + indexes if they don't exist.
|
|
1311
|
+
*/
|
|
1312
|
+
ensureTables(): Promise<void>;
|
|
1313
|
+
/**
|
|
1314
|
+
* Write lookup table rows for a resource (replace strategy).
|
|
1315
|
+
*
|
|
1316
|
+
* 1. Deletes all existing rows for the resourceId across all 4 tables
|
|
1317
|
+
* 2. Inserts new rows grouped by table type
|
|
1318
|
+
*
|
|
1319
|
+
* @param resourceId - The resource ID to index.
|
|
1320
|
+
* @param rows - LookupTableRow[] from `buildLookupTableRows()`.
|
|
1321
|
+
*/
|
|
1322
|
+
writeRows(resourceId: string, rows: LookupTableRow[]): Promise<void>;
|
|
1323
|
+
/**
|
|
1324
|
+
* Delete all lookup table rows for a given resourceId.
|
|
1325
|
+
*/
|
|
1326
|
+
deleteRows(resourceId: string): Promise<void>;
|
|
1327
|
+
/**
|
|
1328
|
+
* Get all lookup rows for a given resourceId and table type.
|
|
1329
|
+
*/
|
|
1330
|
+
getRows<T = Record<string, unknown>>(table: string, resourceId: string): Promise<T[]>;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
/**
|
|
1334
|
+
* Schema for a FHIR resource main table (current version).
|
|
1335
|
+
*
|
|
1336
|
+
* Contains fixed columns (id, content, lastUpdated, etc.) plus
|
|
1337
|
+
* dynamic search columns derived from SearchParameters.
|
|
1338
|
+
*/
|
|
1339
|
+
export declare interface MainTableSchema {
|
|
1340
|
+
/** Table name (e.g., `'Patient'`). */
|
|
1341
|
+
tableName: string;
|
|
1342
|
+
/** FHIR resource type name. */
|
|
1343
|
+
resourceType: string;
|
|
1344
|
+
/** All columns (fixed + search). */
|
|
1345
|
+
columns: ColumnSchema[];
|
|
1346
|
+
/** All indexes (fixed + search). */
|
|
1347
|
+
indexes: IndexSchema[];
|
|
1348
|
+
/** Table constraints (PK, unique, check). */
|
|
1349
|
+
constraints: ConstraintSchema[];
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
/**
|
|
1353
|
+
* v2: Map rows with deleted:number to PersistedResource[].
|
|
1354
|
+
*/
|
|
1355
|
+
export declare function mapRowsToResources(rows: SearchRowV2[]): PersistedResource[];
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Maximum allowed page size.
|
|
1359
|
+
*/
|
|
1360
|
+
export declare const MAX_SEARCH_COUNT = 1000;
|
|
1361
|
+
|
|
1362
|
+
declare interface MigrationRecordV2 {
|
|
1363
|
+
version: number;
|
|
1364
|
+
description: string;
|
|
1365
|
+
type: string;
|
|
1366
|
+
applied_at: string;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
export declare interface MigrationResultV2 {
|
|
1370
|
+
action: 'up' | 'down' | 'none';
|
|
1371
|
+
applied: number[];
|
|
1372
|
+
currentVersion: number;
|
|
1373
|
+
errors: Array<{
|
|
1374
|
+
version: number;
|
|
1375
|
+
error: string;
|
|
1376
|
+
}>;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* v2: Manages schema migrations using StorageAdapter (SQLite / PG).
|
|
1381
|
+
*
|
|
1382
|
+
* Key differences from v1:
|
|
1383
|
+
* - Uses `StorageAdapter` instead of `DatabaseClient`
|
|
1384
|
+
* - `?` placeholders instead of `$1`
|
|
1385
|
+
* - Supports `type` field: 'ig' | 'file'
|
|
1386
|
+
* - IG migrations are forward-only (no down/revert)
|
|
1387
|
+
* - Tracking table uses `datetime('now')` for SQLite
|
|
1388
|
+
*/
|
|
1389
|
+
export declare class MigrationRunnerV2 {
|
|
1390
|
+
private readonly adapter;
|
|
1391
|
+
private readonly migrations;
|
|
1392
|
+
constructor(adapter: StorageAdapter, migrations?: MigrationV2[]);
|
|
1393
|
+
/**
|
|
1394
|
+
* Ensure the tracking table exists.
|
|
1395
|
+
*/
|
|
1396
|
+
ensureTrackingTable(): Promise<void>;
|
|
1397
|
+
/**
|
|
1398
|
+
* Apply all pending migrations (or up to a target version).
|
|
1399
|
+
*/
|
|
1400
|
+
up(targetVersion?: number): Promise<MigrationResultV2>;
|
|
1401
|
+
/**
|
|
1402
|
+
* Revert migrations down to a target version.
|
|
1403
|
+
* IG migrations (type='ig') cannot be reverted — they are skipped.
|
|
1404
|
+
*/
|
|
1405
|
+
down(targetVersion?: number): Promise<MigrationResultV2>;
|
|
1406
|
+
/**
|
|
1407
|
+
* Get the current migration status.
|
|
1408
|
+
*/
|
|
1409
|
+
status(): Promise<MigrationStatusV2>;
|
|
1410
|
+
/**
|
|
1411
|
+
* Get all applied migration records.
|
|
1412
|
+
*/
|
|
1413
|
+
getRecords(): Promise<MigrationRecordV2[]>;
|
|
1414
|
+
/**
|
|
1415
|
+
* Apply an IG-generated migration directly.
|
|
1416
|
+
*
|
|
1417
|
+
* Assigns the next available version number automatically.
|
|
1418
|
+
* This is the primary entry point for IGPersistenceManager.
|
|
1419
|
+
*/
|
|
1420
|
+
applyIGMigration(generated: GeneratedMigration): Promise<MigrationResultV2>;
|
|
1421
|
+
private getAppliedVersions;
|
|
1422
|
+
private applyMigration;
|
|
1423
|
+
private revertMigration;
|
|
1424
|
+
private maxApplied;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
declare interface MigrationStatusV2 {
|
|
1428
|
+
currentVersion: number;
|
|
1429
|
+
appliedVersions: number[];
|
|
1430
|
+
availableVersions: number[];
|
|
1431
|
+
pendingVersions: number[];
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* v2 migration types — adds `type` field for IG vs file distinction.
|
|
1436
|
+
*/
|
|
1437
|
+
export declare interface MigrationV2 {
|
|
1438
|
+
/** Unique version number. Must be positive integer. */
|
|
1439
|
+
version: number;
|
|
1440
|
+
/** Human-readable description. */
|
|
1441
|
+
description: string;
|
|
1442
|
+
/** SQL statements to apply this migration. */
|
|
1443
|
+
up: string[];
|
|
1444
|
+
/** SQL statements to revert this migration. Empty for IG migrations (forward-only). */
|
|
1445
|
+
down: string[];
|
|
1446
|
+
/** Migration source type: 'ig' for IG-driven, 'file' for manual file-based. */
|
|
1447
|
+
type: 'ig' | 'file';
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
/**
|
|
1451
|
+
* Repository Types & Interfaces
|
|
1452
|
+
*
|
|
1453
|
+
* Defines the contract for FHIR resource persistence operations.
|
|
1454
|
+
* All implementations must support transactional CRUD with versioning.
|
|
1455
|
+
*
|
|
1456
|
+
* Design decisions (from WF-E2E-001 Medplum analysis):
|
|
1457
|
+
* - `id` and `versionId` are UUIDs, generated app-side
|
|
1458
|
+
* - Every write produces a new history entry (new version snapshot)
|
|
1459
|
+
* - Soft delete: `deleted=true`, `content=''`, `__version=-1`
|
|
1460
|
+
* - Optimistic locking via `ifMatch` (versionId comparison)
|
|
1461
|
+
*
|
|
1462
|
+
* @module fhir-persistence/repo
|
|
1463
|
+
*/
|
|
1464
|
+
/**
|
|
1465
|
+
* Operation context — flows through all CRUD/Search operations.
|
|
1466
|
+
*
|
|
1467
|
+
* S1 (Phase B): Only `project` is used — multi-tenant isolation.
|
|
1468
|
+
* S5 (Phase C): Will extend to use `author`, `accessPolicy`, `superAdmin`.
|
|
1469
|
+
*/
|
|
1470
|
+
export declare interface OperationContext {
|
|
1471
|
+
/** Current project ID for multi-tenant scoping. */
|
|
1472
|
+
project?: string;
|
|
1473
|
+
/** The actor performing the operation (User/Bot/ClientApplication reference). */
|
|
1474
|
+
author?: string;
|
|
1475
|
+
/** The AccessPolicy ID bound to this operation. */
|
|
1476
|
+
accessPolicy?: string;
|
|
1477
|
+
/** Whether this is a super-admin operation (bypasses project scoping). */
|
|
1478
|
+
superAdmin?: boolean;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
export declare class PackageRegistryRepo {
|
|
1482
|
+
private readonly adapter;
|
|
1483
|
+
constructor(adapter: StorageAdapter);
|
|
1484
|
+
/**
|
|
1485
|
+
* Ensure the packages tracking table exists.
|
|
1486
|
+
*/
|
|
1487
|
+
ensureTable(): Promise<void>;
|
|
1488
|
+
/**
|
|
1489
|
+
* Get the active version of a package by name.
|
|
1490
|
+
*/
|
|
1491
|
+
getPackage(name: string): Promise<InstalledPackage | undefined>;
|
|
1492
|
+
/**
|
|
1493
|
+
* Get all installed packages (all statuses).
|
|
1494
|
+
*/
|
|
1495
|
+
getInstalledPackages(): Promise<InstalledPackage[]>;
|
|
1496
|
+
/**
|
|
1497
|
+
* Get only active packages.
|
|
1498
|
+
*/
|
|
1499
|
+
getActivePackages(): Promise<InstalledPackage[]>;
|
|
1500
|
+
/**
|
|
1501
|
+
* Register a package version.
|
|
1502
|
+
*
|
|
1503
|
+
* When a new version is registered for the same package name:
|
|
1504
|
+
* 1. Previous active versions are marked as 'superseded'
|
|
1505
|
+
* 2. The new version is inserted as 'active'
|
|
1506
|
+
* 3. A schema_version record is created with the package_list snapshot
|
|
1507
|
+
*/
|
|
1508
|
+
registerPackage(pkg: Omit<InstalledPackage, 'installedAt' | 'status'>, description?: string): Promise<void>;
|
|
1509
|
+
/**
|
|
1510
|
+
* Insert or update a package record (backward-compatible).
|
|
1511
|
+
*
|
|
1512
|
+
* Uses INSERT OR REPLACE (SQLite UPSERT) to handle both new and upgraded packages.
|
|
1513
|
+
*/
|
|
1514
|
+
upsertPackage(pkg: Omit<InstalledPackage, 'installedAt' | 'status'>): Promise<void>;
|
|
1515
|
+
/**
|
|
1516
|
+
* Remove all versions of a package.
|
|
1517
|
+
*/
|
|
1518
|
+
removePackage(name: string): Promise<void>;
|
|
1519
|
+
/**
|
|
1520
|
+
* Check if a package needs update by comparing checksums.
|
|
1521
|
+
*
|
|
1522
|
+
* Returns:
|
|
1523
|
+
* - 'new' if the package is not installed (no active version)
|
|
1524
|
+
* - 'upgrade' if the checksum differs
|
|
1525
|
+
* - 'consistent' if the checksum matches
|
|
1526
|
+
*/
|
|
1527
|
+
checkStatus(name: string, checksum: string): Promise<'new' | 'upgrade' | 'consistent'>;
|
|
1528
|
+
/**
|
|
1529
|
+
* Ensure the schema version table exists.
|
|
1530
|
+
*/
|
|
1531
|
+
ensureSchemaVersionTable(): Promise<void>;
|
|
1532
|
+
/**
|
|
1533
|
+
* Record a schema version with the current active package list.
|
|
1534
|
+
*/
|
|
1535
|
+
recordSchemaVersion(description: string): Promise<void>;
|
|
1536
|
+
/**
|
|
1537
|
+
* Get all schema version records.
|
|
1538
|
+
*/
|
|
1539
|
+
getSchemaVersions(): Promise<SchemaVersionRecord[]>;
|
|
1540
|
+
/**
|
|
1541
|
+
* Get the latest schema version record.
|
|
1542
|
+
*/
|
|
1543
|
+
getLatestSchemaVersion(): Promise<SchemaVersionRecord | undefined>;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
declare type PackageStatus = 'active' | 'superseded';
|
|
1547
|
+
|
|
1548
|
+
/**
|
|
1549
|
+
* Pagination Helpers
|
|
1550
|
+
*
|
|
1551
|
+
* Build pagination URLs for FHIR search Bundle links.
|
|
1552
|
+
* Pure functions — no database dependency.
|
|
1553
|
+
*
|
|
1554
|
+
* FHIR R4 Pagination spec:
|
|
1555
|
+
* - `Bundle.link` with `relation: "self"` — current page URL
|
|
1556
|
+
* - `Bundle.link` with `relation: "next"` — next page URL (if more results)
|
|
1557
|
+
* - Offset-based pagination using `_offset` and `_count`
|
|
1558
|
+
*
|
|
1559
|
+
* @module fhir-persistence/search
|
|
1560
|
+
*/
|
|
1561
|
+
/**
|
|
1562
|
+
* Context for building pagination links.
|
|
1563
|
+
*/
|
|
1564
|
+
export declare interface PaginationContext {
|
|
1565
|
+
/** Base URL of the FHIR server (e.g., `"http://localhost:3000/fhir/R4"`). */
|
|
1566
|
+
baseUrl: string;
|
|
1567
|
+
/** The FHIR resource type being searched. */
|
|
1568
|
+
resourceType: string;
|
|
1569
|
+
/** Original query parameters (excluding `_offset`). */
|
|
1570
|
+
queryParams: Record<string, string | string[]>;
|
|
1571
|
+
/** Page size (`_count`). */
|
|
1572
|
+
count: number;
|
|
1573
|
+
/** Current offset (`_offset`). */
|
|
1574
|
+
offset: number;
|
|
1575
|
+
/** Number of results returned on the current page. */
|
|
1576
|
+
resultCount: number;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* A single parsed search parameter from a FHIR search URL.
|
|
1581
|
+
*
|
|
1582
|
+
* Examples:
|
|
1583
|
+
* - `?gender=male` → `{ code: "gender", values: ["male"] }`
|
|
1584
|
+
* - `?gender=male,female` → `{ code: "gender", values: ["male", "female"] }`
|
|
1585
|
+
* - `?birthdate=ge1990-01-01`→ `{ code: "birthdate", prefix: "ge", values: ["1990-01-01"] }`
|
|
1586
|
+
* - `?name:exact=Smith` → `{ code: "name", modifier: "exact", values: ["Smith"] }`
|
|
1587
|
+
*/
|
|
1588
|
+
export declare interface ParsedSearchParam {
|
|
1589
|
+
/** The search parameter code (e.g., `"gender"`, `"birthdate"`). */
|
|
1590
|
+
code: string;
|
|
1591
|
+
/** Optional modifier (e.g., `"exact"`, `"contains"`, `"missing"`). */
|
|
1592
|
+
modifier?: SearchModifier;
|
|
1593
|
+
/** Optional prefix for number/date/quantity (e.g., `"ge"`, `"lt"`). */
|
|
1594
|
+
prefix?: SearchPrefix;
|
|
1595
|
+
/**
|
|
1596
|
+
* The search values (OR semantics within a single parameter).
|
|
1597
|
+
* Comma-separated values in the URL are split into this array.
|
|
1598
|
+
*/
|
|
1599
|
+
values: string[];
|
|
1600
|
+
/**
|
|
1601
|
+
* Chained search info (single-level).
|
|
1602
|
+
*
|
|
1603
|
+
* Present when the param uses chained syntax:
|
|
1604
|
+
* `subject:Patient.name=Smith` →
|
|
1605
|
+
* code = "subject", chain = { targetType: "Patient", targetParam: "name" }
|
|
1606
|
+
*/
|
|
1607
|
+
chain?: ChainedSearchTarget;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
/**
|
|
1611
|
+
* Parse a query parameter key into code, optional modifier, and optional chain.
|
|
1612
|
+
*
|
|
1613
|
+
* Examples:
|
|
1614
|
+
* - `"gender"` → `{ code: "gender" }`
|
|
1615
|
+
* - `"name:exact"` → `{ code: "name", modifier: "exact" }`
|
|
1616
|
+
* - `"code:not"` → `{ code: "code", modifier: "not" }`
|
|
1617
|
+
* - `"subject:Patient.name"` → `{ code: "subject", chain: { targetType: "Patient", targetParam: "name" } }`
|
|
1618
|
+
*/
|
|
1619
|
+
export declare function parseParamKey(key: string): {
|
|
1620
|
+
code: string;
|
|
1621
|
+
modifier?: SearchModifier;
|
|
1622
|
+
chain?: ChainedSearchTarget;
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
/**
|
|
1626
|
+
* Parse a FHIR search URL query string into a `SearchRequest`.
|
|
1627
|
+
*
|
|
1628
|
+
* @param resourceType - The FHIR resource type being searched.
|
|
1629
|
+
* @param queryParams - The URL query parameters as a key-value record.
|
|
1630
|
+
* For repeated keys, values should be joined with `&` or passed as arrays.
|
|
1631
|
+
* @param registry - Optional SearchParameterRegistry for parameter validation.
|
|
1632
|
+
* If provided, unknown parameter codes will be rejected.
|
|
1633
|
+
* @returns A fully parsed SearchRequest.
|
|
1634
|
+
* @throws Error if a parameter code is unknown and registry is provided.
|
|
1635
|
+
*/
|
|
1636
|
+
export declare function parseSearchRequest(resourceType: string, queryParams: Record<string, string | string[] | undefined>, registry?: SearchParameterRegistry): SearchRequest;
|
|
1637
|
+
|
|
1638
|
+
/**
|
|
1639
|
+
* Parse the `_sort` parameter value into `SortRule[]`.
|
|
1640
|
+
*
|
|
1641
|
+
* Examples:
|
|
1642
|
+
* - `"birthdate"` → `[{ code: "birthdate", descending: false }]`
|
|
1643
|
+
* - `"-birthdate"` → `[{ code: "birthdate", descending: true }]`
|
|
1644
|
+
* - `"family,-birthdate"` → two rules
|
|
1645
|
+
*/
|
|
1646
|
+
export declare function parseSortParam(value: string): SortRule[];
|
|
1647
|
+
|
|
1648
|
+
/**
|
|
1649
|
+
* A FHIR resource that has been persisted (id and meta are guaranteed).
|
|
1650
|
+
*/
|
|
1651
|
+
export declare interface PersistedResource extends FhirResource {
|
|
1652
|
+
id: string;
|
|
1653
|
+
meta: FhirMeta & {
|
|
1654
|
+
versionId: string;
|
|
1655
|
+
lastUpdated: string;
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
/**
|
|
1660
|
+
* Plan and optimize a search request.
|
|
1661
|
+
*
|
|
1662
|
+
* @param request - The parsed search request.
|
|
1663
|
+
* @param registry - The SearchParameterRegistry for resolving implementations.
|
|
1664
|
+
* @param options - Optional planner configuration.
|
|
1665
|
+
* @returns A SearchPlan with the optimized request and metadata.
|
|
1666
|
+
*/
|
|
1667
|
+
export declare function planSearch(request: SearchRequest, registry: SearchParameterRegistry, options?: SearchPlannerOptions): SearchPlan;
|
|
1668
|
+
|
|
1669
|
+
export declare const PLATFORM_PACKAGE_NAME = "medxai.core";
|
|
1670
|
+
|
|
1671
|
+
export declare const PLATFORM_PACKAGE_VERSION = "1.0.0";
|
|
1672
|
+
|
|
1673
|
+
/**
|
|
1674
|
+
* Platform resource types that require special handling.
|
|
1675
|
+
*
|
|
1676
|
+
* These are MedXAI-defined resources (not part of FHIR R4 base spec).
|
|
1677
|
+
* They participate in multi-tenant isolation via `projectId`.
|
|
1678
|
+
*/
|
|
1679
|
+
export declare const PLATFORM_RESOURCE_TYPES: ReadonlySet<string>;
|
|
1680
|
+
|
|
1681
|
+
export declare const PLATFORM_SEARCH_PARAMETERS: SearchParameterResource[];
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* FHIR search parameter types that support prefixes.
|
|
1685
|
+
*/
|
|
1686
|
+
export declare const PREFIX_TYPES: ReadonlySet<string>;
|
|
1687
|
+
|
|
1688
|
+
/**
|
|
1689
|
+
* Map a FHIR search prefix to a SQL comparison operator.
|
|
1690
|
+
*/
|
|
1691
|
+
export declare function prefixToOperator(prefix?: SearchPrefix): string;
|
|
1692
|
+
|
|
1693
|
+
/**
|
|
1694
|
+
* StorageAdapter — Database Abstraction Interface
|
|
1695
|
+
*
|
|
1696
|
+
* Provides a unified interface for database operations across
|
|
1697
|
+
* SQLite and PostgreSQL. All business logic interacts with
|
|
1698
|
+
* the database exclusively through this interface.
|
|
1699
|
+
*
|
|
1700
|
+
* v2 upgrade: Replaces direct `pg.Pool` usage in v1's `DatabaseClient`.
|
|
1701
|
+
* The existing `DatabaseClient` is preserved for backward compatibility.
|
|
1702
|
+
*
|
|
1703
|
+
* @module fhir-persistence/db
|
|
1704
|
+
*/
|
|
1705
|
+
/**
|
|
1706
|
+
* A prepared (precompiled) SQL statement for high-frequency operations.
|
|
1707
|
+
*
|
|
1708
|
+
* Prepared statements avoid repeated SQL parsing overhead.
|
|
1709
|
+
* The caller is responsible for calling `finalize()` when done.
|
|
1710
|
+
*/
|
|
1711
|
+
declare interface PreparedStatement<T = Record<string, unknown>> {
|
|
1712
|
+
/** Execute as a read query, returning all matching rows. */
|
|
1713
|
+
query(params?: unknown[]): T[];
|
|
1714
|
+
/** Execute as a write operation, returning change count. */
|
|
1715
|
+
execute(params?: unknown[]): {
|
|
1716
|
+
changes: number;
|
|
1717
|
+
lastInsertRowid?: number | bigint;
|
|
1718
|
+
};
|
|
1719
|
+
/** Release the prepared statement resources. */
|
|
1720
|
+
finalize(): void;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/**
|
|
1724
|
+
* Resource types that can be managed by project admins (not just super-admins).
|
|
1725
|
+
*
|
|
1726
|
+
* Phase B: informational only — enforcement deferred to Phase C (Auth).
|
|
1727
|
+
*/
|
|
1728
|
+
export declare const PROJECT_ADMIN_RESOURCE_TYPES: ReadonlySet<string>;
|
|
1729
|
+
|
|
1730
|
+
/**
|
|
1731
|
+
* Protected resource types that can only be managed by super-admins or
|
|
1732
|
+
* the system itself. Normal project-scoped operations cannot create/update/delete these.
|
|
1733
|
+
*
|
|
1734
|
+
* Phase B: informational only — enforcement deferred to Phase C (Auth).
|
|
1735
|
+
*/
|
|
1736
|
+
export declare const PROTECTED_RESOURCE_TYPES: ReadonlySet<string>;
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* v2: A row for the `{ResourceType}_References` table.
|
|
1740
|
+
* Adds targetType and referenceRaw for more precise reference queries.
|
|
1741
|
+
*/
|
|
1742
|
+
export declare interface ReferenceRowV2 {
|
|
1743
|
+
/** The source resource ID. */
|
|
1744
|
+
resourceId: string;
|
|
1745
|
+
/** The target resource type (e.g., "Patient"). */
|
|
1746
|
+
targetType: string;
|
|
1747
|
+
/** The target resource ID. */
|
|
1748
|
+
targetId: string;
|
|
1749
|
+
/** The search parameter code (e.g., "subject"). */
|
|
1750
|
+
code: string;
|
|
1751
|
+
/** The original reference string, or null. */
|
|
1752
|
+
referenceRaw: string | null;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
/**
|
|
1756
|
+
* Schema for a FHIR resource references table.
|
|
1757
|
+
*
|
|
1758
|
+
* Stores outgoing reference relationships for `_revinclude` support.
|
|
1759
|
+
* Uses a composite primary key.
|
|
1760
|
+
*/
|
|
1761
|
+
export declare interface ReferencesTableSchema {
|
|
1762
|
+
/** Table name (e.g., `'Patient_References'`). */
|
|
1763
|
+
tableName: string;
|
|
1764
|
+
/** FHIR resource type name. */
|
|
1765
|
+
resourceType: string;
|
|
1766
|
+
/** All columns (fixed). */
|
|
1767
|
+
columns: ColumnSchema[];
|
|
1768
|
+
/** All indexes. */
|
|
1769
|
+
indexes: IndexSchema[];
|
|
1770
|
+
/** Composite primary key column names. */
|
|
1771
|
+
compositePrimaryKey: string[];
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
/**
|
|
1775
|
+
* Re-index all resource types using StorageAdapter.
|
|
1776
|
+
*
|
|
1777
|
+
* @param adapter - StorageAdapter.
|
|
1778
|
+
* @param resourceTypes - List of resource types to re-index.
|
|
1779
|
+
* @param onProgress - Optional progress callback.
|
|
1780
|
+
* @returns Complete re-index result.
|
|
1781
|
+
*/
|
|
1782
|
+
export declare function reindexAllV2(adapter: StorageAdapter, resourceTypes: string[], onProgress?: ReindexProgressCallbackV2): Promise<ReindexResultV2>;
|
|
1783
|
+
|
|
1784
|
+
declare interface ReindexJob {
|
|
1785
|
+
/** Auto-assigned job ID. */
|
|
1786
|
+
id: number;
|
|
1787
|
+
/** Resource type to reindex (e.g., "Patient"). */
|
|
1788
|
+
resourceType: string;
|
|
1789
|
+
/** Search parameter code that changed (e.g., "birthdate"). */
|
|
1790
|
+
searchParamCode: string;
|
|
1791
|
+
/** New FHIRPath expression. */
|
|
1792
|
+
expression: string;
|
|
1793
|
+
/** Current job status. */
|
|
1794
|
+
status: ReindexJobStatus;
|
|
1795
|
+
/** Cursor for keyset pagination (lastUpdated of last processed resource). */
|
|
1796
|
+
cursor: string | null;
|
|
1797
|
+
/** Number of resources processed so far. */
|
|
1798
|
+
processedCount: number;
|
|
1799
|
+
/** When the job was created. */
|
|
1800
|
+
createdAt: string;
|
|
1801
|
+
/** When the job was last updated. */
|
|
1802
|
+
updatedAt: string;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
declare type ReindexJobStatus = 'pending' | 'running' | 'completed' | 'failed';
|
|
1806
|
+
|
|
1807
|
+
declare type ReindexProgressCallbackV2 = (info: {
|
|
1808
|
+
resourceType: string;
|
|
1809
|
+
processed: number;
|
|
1810
|
+
total: number;
|
|
1811
|
+
}) => void;
|
|
1812
|
+
|
|
1813
|
+
/**
|
|
1814
|
+
* Re-index all resources of a given type using StorageAdapter.
|
|
1815
|
+
*
|
|
1816
|
+
* Reads all non-deleted resources in batches via keyset pagination,
|
|
1817
|
+
* parses content JSON, and can be extended with custom row-update logic.
|
|
1818
|
+
*
|
|
1819
|
+
* @param adapter - StorageAdapter (SQLite or PostgreSQL).
|
|
1820
|
+
* @param resourceType - The FHIR resource type to re-index.
|
|
1821
|
+
* @param onProgress - Optional progress callback.
|
|
1822
|
+
* @returns Per-type reindex result.
|
|
1823
|
+
*/
|
|
1824
|
+
export declare function reindexResourceTypeV2(adapter: StorageAdapter, resourceType: string, onProgress?: ReindexProgressCallbackV2): Promise<{
|
|
1825
|
+
processed: number;
|
|
1826
|
+
updated: number;
|
|
1827
|
+
errors: number;
|
|
1828
|
+
}>;
|
|
1829
|
+
|
|
1830
|
+
declare interface ReindexResultV2 {
|
|
1831
|
+
totalProcessed: number;
|
|
1832
|
+
totalUpdated: number;
|
|
1833
|
+
totalErrors: number;
|
|
1834
|
+
byType: Record<string, {
|
|
1835
|
+
processed: number;
|
|
1836
|
+
updated: number;
|
|
1837
|
+
errors: number;
|
|
1838
|
+
}>;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
export declare class ReindexScheduler {
|
|
1842
|
+
private readonly adapter;
|
|
1843
|
+
constructor(adapter: StorageAdapter);
|
|
1844
|
+
/**
|
|
1845
|
+
* Ensure the reindex jobs table exists.
|
|
1846
|
+
*/
|
|
1847
|
+
ensureTable(): Promise<void>;
|
|
1848
|
+
/**
|
|
1849
|
+
* Schedule reindex jobs from REINDEX deltas.
|
|
1850
|
+
*
|
|
1851
|
+
* @param deltas - REINDEX deltas from SchemaDiff (filtered by caller).
|
|
1852
|
+
* @returns Number of jobs scheduled.
|
|
1853
|
+
*/
|
|
1854
|
+
schedule(deltas: SchemaDelta[]): Promise<number>;
|
|
1855
|
+
/**
|
|
1856
|
+
* Get all pending reindex jobs.
|
|
1857
|
+
*/
|
|
1858
|
+
getPendingJobs(): Promise<ReindexJob[]>;
|
|
1859
|
+
/**
|
|
1860
|
+
* Get a specific job by ID.
|
|
1861
|
+
*/
|
|
1862
|
+
getJob(id: number): Promise<ReindexJob | undefined>;
|
|
1863
|
+
/**
|
|
1864
|
+
* Get all jobs (any status).
|
|
1865
|
+
*/
|
|
1866
|
+
getAllJobs(): Promise<ReindexJob[]>;
|
|
1867
|
+
/**
|
|
1868
|
+
* Update job status and cursor.
|
|
1869
|
+
*/
|
|
1870
|
+
updateJob(id: number, update: {
|
|
1871
|
+
status?: ReindexJobStatus;
|
|
1872
|
+
cursor?: string;
|
|
1873
|
+
processedCount?: number;
|
|
1874
|
+
}): Promise<void>;
|
|
1875
|
+
/**
|
|
1876
|
+
* Get status summary of all jobs.
|
|
1877
|
+
*/
|
|
1878
|
+
getStatus(): Promise<{
|
|
1879
|
+
pending: number;
|
|
1880
|
+
running: number;
|
|
1881
|
+
completed: number;
|
|
1882
|
+
failed: number;
|
|
1883
|
+
}>;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
/**
|
|
1887
|
+
* Repository Error Hierarchy
|
|
1888
|
+
*
|
|
1889
|
+
* Maps to standard FHIR/HTTP error semantics:
|
|
1890
|
+
* - 404 Not Found → ResourceNotFoundError
|
|
1891
|
+
* - 410 Gone → ResourceGoneError
|
|
1892
|
+
* - 412 Precondition Failed → ResourceVersionConflictError
|
|
1893
|
+
*
|
|
1894
|
+
* @module fhir-persistence/repo
|
|
1895
|
+
*/
|
|
1896
|
+
/**
|
|
1897
|
+
* Base class for all repository errors.
|
|
1898
|
+
*/
|
|
1899
|
+
export declare class RepositoryError extends Error {
|
|
1900
|
+
readonly name: string;
|
|
1901
|
+
constructor(message: string);
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
/**
|
|
1905
|
+
* v2 Resource Cache with configurable eviction policy.
|
|
1906
|
+
*
|
|
1907
|
+
* Upgrades v1 with:
|
|
1908
|
+
* - Eviction policy: lru / fifo / ttl-only
|
|
1909
|
+
* - stats.reset() to zero counters
|
|
1910
|
+
* - sweep() to proactively remove expired entries
|
|
1911
|
+
*/
|
|
1912
|
+
export declare class ResourceCacheV2 {
|
|
1913
|
+
private readonly cache;
|
|
1914
|
+
private readonly maxSize;
|
|
1915
|
+
private readonly ttlMs;
|
|
1916
|
+
private readonly enabled;
|
|
1917
|
+
private readonly evictionPolicy;
|
|
1918
|
+
private _hits;
|
|
1919
|
+
private _misses;
|
|
1920
|
+
private _evictions;
|
|
1921
|
+
constructor(config?: ResourceCacheV2Config);
|
|
1922
|
+
private key;
|
|
1923
|
+
get(resourceType: string, id: string): PersistedResource | undefined;
|
|
1924
|
+
set(resourceType: string, id: string, resource: PersistedResource): void;
|
|
1925
|
+
invalidate(resourceType: string, id: string): void;
|
|
1926
|
+
clear(): void;
|
|
1927
|
+
/**
|
|
1928
|
+
* Proactively remove all expired entries.
|
|
1929
|
+
* @returns Number of entries swept.
|
|
1930
|
+
*/
|
|
1931
|
+
sweep(): number;
|
|
1932
|
+
get size(): number;
|
|
1933
|
+
get stats(): {
|
|
1934
|
+
hits: number;
|
|
1935
|
+
misses: number;
|
|
1936
|
+
size: number;
|
|
1937
|
+
hitRate: number;
|
|
1938
|
+
evictions: number;
|
|
1939
|
+
};
|
|
1940
|
+
/**
|
|
1941
|
+
* Reset stats counters without clearing cache entries.
|
|
1942
|
+
*/
|
|
1943
|
+
resetStats(): void;
|
|
1944
|
+
get isEnabled(): boolean;
|
|
1945
|
+
get policy(): EvictionPolicy;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
/**
|
|
1949
|
+
* v2 configuration for the resource cache.
|
|
1950
|
+
*/
|
|
1951
|
+
declare interface ResourceCacheV2Config {
|
|
1952
|
+
/** Maximum number of entries. Default: 1000. Ignored for ttl-only policy. */
|
|
1953
|
+
maxSize?: number;
|
|
1954
|
+
/** Time-to-live in milliseconds. Default: 60000 (60s). */
|
|
1955
|
+
ttlMs?: number;
|
|
1956
|
+
/** Whether the cache is enabled. Default: false. */
|
|
1957
|
+
enabled?: boolean;
|
|
1958
|
+
/** Eviction policy. Default: 'lru'. */
|
|
1959
|
+
evictionPolicy?: EvictionPolicy;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
/**
|
|
1963
|
+
* Resource has been deleted (HTTP 410 Gone).
|
|
1964
|
+
*/
|
|
1965
|
+
export declare class ResourceGoneError extends RepositoryError {
|
|
1966
|
+
readonly name = "ResourceGoneError";
|
|
1967
|
+
readonly resourceType: string;
|
|
1968
|
+
readonly resourceId: string;
|
|
1969
|
+
constructor(resourceType: string, id: string);
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
/**
|
|
1973
|
+
* Resource not found (HTTP 404).
|
|
1974
|
+
*/
|
|
1975
|
+
export declare class ResourceNotFoundError extends RepositoryError {
|
|
1976
|
+
readonly name = "ResourceNotFoundError";
|
|
1977
|
+
readonly resourceType: string;
|
|
1978
|
+
readonly resourceId: string;
|
|
1979
|
+
constructor(resourceType: string, id: string);
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
/**
|
|
1983
|
+
* FHIR Resource Repository — persistence contract.
|
|
1984
|
+
*
|
|
1985
|
+
* All write operations are transactional (ACID).
|
|
1986
|
+
* All write operations produce a history entry.
|
|
1987
|
+
*/
|
|
1988
|
+
export declare interface ResourceRepository {
|
|
1989
|
+
/**
|
|
1990
|
+
* Create a new FHIR resource.
|
|
1991
|
+
*
|
|
1992
|
+
* - Generates `id` (UUID) if not provided via `options.assignedId`
|
|
1993
|
+
* - Generates `meta.versionId` (UUID)
|
|
1994
|
+
* - Sets `meta.lastUpdated` to current time
|
|
1995
|
+
* - Writes to main table + history table in a transaction
|
|
1996
|
+
* - If `context.project` is set, injects projectId into the row
|
|
1997
|
+
*
|
|
1998
|
+
* @returns The persisted resource with populated `id` and `meta`.
|
|
1999
|
+
*/
|
|
2000
|
+
createResource<T extends FhirResource>(resource: T, options?: CreateResourceOptions, context?: OperationContext): Promise<T & PersistedResource>;
|
|
2001
|
+
/**
|
|
2002
|
+
* Read a resource by type and ID.
|
|
2003
|
+
*
|
|
2004
|
+
* When `context.project` is set, verifies the resource belongs to that project.
|
|
2005
|
+
*
|
|
2006
|
+
* @throws ResourceNotFoundError if the resource does not exist.
|
|
2007
|
+
* @throws ResourceGoneError if the resource has been deleted.
|
|
2008
|
+
*/
|
|
2009
|
+
readResource(resourceType: string, id: string, context?: OperationContext): Promise<PersistedResource>;
|
|
2010
|
+
/**
|
|
2011
|
+
* Update an existing resource.
|
|
2012
|
+
*
|
|
2013
|
+
* - The resource must have `id` set.
|
|
2014
|
+
* - Generates new `meta.versionId` (UUID)
|
|
2015
|
+
* - Sets `meta.lastUpdated` to current time
|
|
2016
|
+
* - Writes to main table (UPSERT) + history table in a transaction
|
|
2017
|
+
* - If `options.ifMatch` is set, performs optimistic locking check
|
|
2018
|
+
* - If `context.project` is set, injects projectId into the row
|
|
2019
|
+
*
|
|
2020
|
+
* @throws ResourceNotFoundError if the resource does not exist.
|
|
2021
|
+
* @throws ResourceGoneError if the resource has been deleted.
|
|
2022
|
+
* @throws ResourceVersionConflictError if `ifMatch` does not match.
|
|
2023
|
+
*/
|
|
2024
|
+
updateResource<T extends FhirResource>(resource: T, options?: UpdateResourceOptions, context?: OperationContext): Promise<T & PersistedResource>;
|
|
2025
|
+
/**
|
|
2026
|
+
* Soft-delete a resource.
|
|
2027
|
+
*
|
|
2028
|
+
* - Sets `deleted=true`, `content=''`, `__version=-1`
|
|
2029
|
+
* - Writes a delete history entry
|
|
2030
|
+
*
|
|
2031
|
+
* @throws ResourceNotFoundError if the resource does not exist.
|
|
2032
|
+
* @throws ResourceGoneError if already deleted.
|
|
2033
|
+
*/
|
|
2034
|
+
deleteResource(resourceType: string, id: string, context?: OperationContext): Promise<void>;
|
|
2035
|
+
/**
|
|
2036
|
+
* Read the version history of a resource (newest first).
|
|
2037
|
+
*/
|
|
2038
|
+
readHistory(resourceType: string, id: string, options?: HistoryOptions): Promise<HistoryEntry[]>;
|
|
2039
|
+
/**
|
|
2040
|
+
* Read type-level history (all changes to a resource type, newest first).
|
|
2041
|
+
*/
|
|
2042
|
+
readTypeHistory(resourceType: string, options?: HistoryOptions): Promise<HistoryEntry[]>;
|
|
2043
|
+
/**
|
|
2044
|
+
* Read a specific version of a resource.
|
|
2045
|
+
*
|
|
2046
|
+
* @throws ResourceNotFoundError if the version does not exist.
|
|
2047
|
+
*/
|
|
2048
|
+
readVersion(resourceType: string, id: string, versionId: string): Promise<PersistedResource>;
|
|
2049
|
+
/**
|
|
2050
|
+
* Search for resources matching the given search request.
|
|
2051
|
+
*
|
|
2052
|
+
* - Executes parameterized SQL built from the search request
|
|
2053
|
+
* - Optionally returns total count when `options.total === 'accurate'`
|
|
2054
|
+
* - If `context.project` is set, adds projectId filter to the query
|
|
2055
|
+
*
|
|
2056
|
+
* @param request - Parsed FHIR search request.
|
|
2057
|
+
* @param options - Search options (e.g., total mode).
|
|
2058
|
+
* @param context - Operation context for project scoping.
|
|
2059
|
+
* @returns Search result with matched resources and optional total.
|
|
2060
|
+
*/
|
|
2061
|
+
searchResources(request: SearchRequest, options?: SearchOptions, context?: OperationContext): Promise<SearchResult>;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
/**
|
|
2065
|
+
* v1 ResourceRow — preserved for backward compatibility with FhirRepository (PG).
|
|
2066
|
+
* @deprecated Use ResourceRowV2 for new code.
|
|
2067
|
+
*/
|
|
2068
|
+
declare interface ResourceRow {
|
|
2069
|
+
[key: string]: unknown;
|
|
2070
|
+
id: string;
|
|
2071
|
+
content: string;
|
|
2072
|
+
lastUpdated: string;
|
|
2073
|
+
deleted: boolean;
|
|
2074
|
+
projectId: string;
|
|
2075
|
+
__version: number;
|
|
2076
|
+
_source?: string;
|
|
2077
|
+
_profile?: string[];
|
|
2078
|
+
compartments?: string[];
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
/**
|
|
2082
|
+
* Complete table set for a single FHIR resource type.
|
|
2083
|
+
*
|
|
2084
|
+
* Contains 3 core tables (main, history, references).
|
|
2085
|
+
* Lookup tables are now global (shared across all resource types)
|
|
2086
|
+
* and stored at the SchemaDefinition level.
|
|
2087
|
+
*/
|
|
2088
|
+
export declare interface ResourceTableSet {
|
|
2089
|
+
/** FHIR resource type (e.g., `'Patient'`). */
|
|
2090
|
+
resourceType: string;
|
|
2091
|
+
/** Main table (current version + search columns). */
|
|
2092
|
+
main: MainTableSchema;
|
|
2093
|
+
/** History table (all versions). */
|
|
2094
|
+
history: HistoryTableSchema;
|
|
2095
|
+
/** References table (outgoing references). */
|
|
2096
|
+
references: ReferencesTableSchema;
|
|
2097
|
+
/**
|
|
2098
|
+
* v2: Raw SP metadata for SchemaDiff to compare old vs new search params.
|
|
2099
|
+
*/
|
|
2100
|
+
searchParams?: SearchParamMeta[];
|
|
2101
|
+
/**
|
|
2102
|
+
* @deprecated Per-resource lookup tables removed. Use SchemaDefinition.globalLookupTables.
|
|
2103
|
+
*/
|
|
2104
|
+
lookupTables?: LookupTableSchema[];
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
/**
|
|
2108
|
+
* Optimistic locking conflict (HTTP 412 Precondition Failed).
|
|
2109
|
+
*
|
|
2110
|
+
* Thrown when `ifMatch` (expected versionId) does not match
|
|
2111
|
+
* the current versionId of the resource.
|
|
2112
|
+
*/
|
|
2113
|
+
export declare class ResourceVersionConflictError extends RepositoryError {
|
|
2114
|
+
readonly name = "ResourceVersionConflictError";
|
|
2115
|
+
readonly resourceType: string;
|
|
2116
|
+
readonly resourceId: string;
|
|
2117
|
+
readonly expectedVersion: string;
|
|
2118
|
+
readonly actualVersion: string;
|
|
2119
|
+
constructor(resourceType: string, id: string, expectedVersion: string, actualVersion: string);
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
/**
|
|
2123
|
+
* Bridge interface for fhir-runtime.
|
|
2124
|
+
*
|
|
2125
|
+
* fhir-persistence depends only on this interface, never on
|
|
2126
|
+
* fhir-runtime internal types. Implementations may wrap
|
|
2127
|
+
* a real `FhirRuntimeInstance` or provide test-only approximations.
|
|
2128
|
+
*
|
|
2129
|
+
* ADR-01 §4.1b — structural typing, no `implements` required.
|
|
2130
|
+
*/
|
|
2131
|
+
declare interface RuntimeProvider {
|
|
2132
|
+
/**
|
|
2133
|
+
* Extract search parameter values from a resource.
|
|
2134
|
+
*
|
|
2135
|
+
* Real implementation uses FHIRPath evaluation via fhir-runtime.
|
|
2136
|
+
* Test implementation uses extractPropertyPath approximation.
|
|
2137
|
+
*
|
|
2138
|
+
* @param resource - The FHIR resource to extract values from.
|
|
2139
|
+
* @param params - SearchParameter definitions to extract.
|
|
2140
|
+
* @returns Map of param code → extracted values.
|
|
2141
|
+
*/
|
|
2142
|
+
extractSearchValues(resource: Record<string, unknown>, params: SearchParameterDef[]): Record<string, unknown[]>;
|
|
2143
|
+
/**
|
|
2144
|
+
* Extract all outgoing references from a resource.
|
|
2145
|
+
*
|
|
2146
|
+
* Real implementation uses fhir-runtime's reference extractor
|
|
2147
|
+
* based on StructureDefinition knowledge.
|
|
2148
|
+
* Test implementation scans JSON for `.reference` fields.
|
|
2149
|
+
*
|
|
2150
|
+
* @param resource - The FHIR resource to scan.
|
|
2151
|
+
* @param params - Reference-type SearchParameters (used for code mapping).
|
|
2152
|
+
* @returns Array of extracted references with targetType/targetId.
|
|
2153
|
+
*/
|
|
2154
|
+
extractReferences(resource: Record<string, unknown>, params: SearchParameterDef[]): ExtractedReference[];
|
|
2155
|
+
/**
|
|
2156
|
+
* Validate a resource against a profile (optional capability).
|
|
2157
|
+
*
|
|
2158
|
+
* Not all implementations support validation. Check existence before calling.
|
|
2159
|
+
*/
|
|
2160
|
+
validate?(resource: Record<string, unknown>, profileUrl?: string): Promise<ValidationResult>;
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
/**
|
|
2164
|
+
* Schema version constant.
|
|
2165
|
+
*
|
|
2166
|
+
* Tracks the schema migration version (not the resource version).
|
|
2167
|
+
* Incremented when the schema structure changes.
|
|
2168
|
+
* Set to -1 for deleted resources.
|
|
2169
|
+
*/
|
|
2170
|
+
export declare const SCHEMA_VERSION = 1;
|
|
2171
|
+
|
|
2172
|
+
/**
|
|
2173
|
+
* Complete schema definition for all resource types.
|
|
2174
|
+
*
|
|
2175
|
+
* This is the top-level output of the schema generation pipeline.
|
|
2176
|
+
*/
|
|
2177
|
+
export declare interface SchemaDefinition {
|
|
2178
|
+
/** Schema version identifier (e.g., `'fhir-r4-v4.0.1'`). */
|
|
2179
|
+
version: string;
|
|
2180
|
+
/** ISO timestamp of when the schema was generated. */
|
|
2181
|
+
generatedAt: string;
|
|
2182
|
+
/** Table sets for all resource types. */
|
|
2183
|
+
tableSets: ResourceTableSet[];
|
|
2184
|
+
/**
|
|
2185
|
+
* Global lookup tables shared across all resource types.
|
|
2186
|
+
* Matches Medplum's production design: HumanName, Address, ContactPoint, Identifier.
|
|
2187
|
+
*/
|
|
2188
|
+
globalLookupTables: GlobalLookupTableSchema[];
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
export declare interface SchemaDelta {
|
|
2192
|
+
/** The type of schema change. */
|
|
2193
|
+
kind: DeltaKind;
|
|
2194
|
+
/** The resource type affected (e.g., "Patient"). */
|
|
2195
|
+
resourceType: string;
|
|
2196
|
+
/** The table name affected (e.g., "Patient", "Patient_History"). */
|
|
2197
|
+
tableName: string;
|
|
2198
|
+
/** Column details (for ADD_COLUMN, DROP_COLUMN, ALTER_COLUMN). */
|
|
2199
|
+
column?: ColumnSchema;
|
|
2200
|
+
/** Previous column details (for ALTER_COLUMN). */
|
|
2201
|
+
oldColumn?: ColumnSchema;
|
|
2202
|
+
/** Index details (for ADD_INDEX, DROP_INDEX). */
|
|
2203
|
+
index?: IndexSchema;
|
|
2204
|
+
/** Search parameter details (for REINDEX). */
|
|
2205
|
+
searchParam?: SearchParamMeta;
|
|
2206
|
+
/** The full ResourceTableSet (for ADD_TABLE). */
|
|
2207
|
+
tableSet?: ResourceTableSet;
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
declare interface SchemaVersionRecord {
|
|
2211
|
+
/** Auto-incrementing version number. */
|
|
2212
|
+
version: number;
|
|
2213
|
+
/** JSON snapshot of active package names+versions at this schema version. */
|
|
2214
|
+
packageList: string;
|
|
2215
|
+
/** Description of the schema change. */
|
|
2216
|
+
description: string;
|
|
2217
|
+
/** When this schema version was applied. */
|
|
2218
|
+
appliedAt: string;
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
/**
|
|
2222
|
+
* All valid search prefixes.
|
|
2223
|
+
*/
|
|
2224
|
+
export declare const SEARCH_PREFIXES: ReadonlySet<string>;
|
|
2225
|
+
|
|
2226
|
+
/**
|
|
2227
|
+
* A FHIR R4 Bundle of type `searchset`.
|
|
2228
|
+
*/
|
|
2229
|
+
export declare interface SearchBundle {
|
|
2230
|
+
resourceType: 'Bundle';
|
|
2231
|
+
id: string;
|
|
2232
|
+
type: 'searchset';
|
|
2233
|
+
total?: number;
|
|
2234
|
+
link?: BundleLink[];
|
|
2235
|
+
entry?: SearchBundleEntry[];
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
/**
|
|
2239
|
+
* A single entry in a searchset Bundle.
|
|
2240
|
+
*/
|
|
2241
|
+
export declare interface SearchBundleEntry {
|
|
2242
|
+
fullUrl?: string;
|
|
2243
|
+
resource: Record<string, unknown>;
|
|
2244
|
+
search: {
|
|
2245
|
+
mode: 'match' | 'include' | 'outcome';
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
/**
|
|
2250
|
+
* Column type for search parameter columns.
|
|
2251
|
+
*/
|
|
2252
|
+
export declare type SearchColumnType = SqlColumnType;
|
|
2253
|
+
|
|
2254
|
+
/**
|
|
2255
|
+
* Search column values to merge into the main table row.
|
|
2256
|
+
*/
|
|
2257
|
+
export declare interface SearchColumnValues {
|
|
2258
|
+
[columnName: string]: unknown;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
/**
|
|
2262
|
+
* Search Logger — Execution Time Observability
|
|
2263
|
+
*
|
|
2264
|
+
* Wraps search operations with timing and result counting.
|
|
2265
|
+
* Provides slow query detection, recent log buffer, and stats.
|
|
2266
|
+
*
|
|
2267
|
+
* @module fhir-persistence/observability
|
|
2268
|
+
*/
|
|
2269
|
+
declare interface SearchLogEntry {
|
|
2270
|
+
/** Resource type being searched. */
|
|
2271
|
+
resourceType: string;
|
|
2272
|
+
/** Number of search parameters used. */
|
|
2273
|
+
paramCount: number;
|
|
2274
|
+
/** Number of results returned. */
|
|
2275
|
+
resultCount: number;
|
|
2276
|
+
/** Execution duration in milliseconds. */
|
|
2277
|
+
durationMs: number;
|
|
2278
|
+
/** ISO 8601 timestamp. */
|
|
2279
|
+
timestamp: string;
|
|
2280
|
+
/** Whether this was flagged as slow. */
|
|
2281
|
+
slow: boolean;
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
export declare class SearchLogger {
|
|
2285
|
+
private readonly entries;
|
|
2286
|
+
private readonly enabled;
|
|
2287
|
+
private readonly slowThresholdMs;
|
|
2288
|
+
private readonly maxEntries;
|
|
2289
|
+
private readonly onLog?;
|
|
2290
|
+
constructor(config?: SearchLoggerConfig);
|
|
2291
|
+
/**
|
|
2292
|
+
* Log a completed search operation.
|
|
2293
|
+
*/
|
|
2294
|
+
log(resourceType: string, paramCount: number, resultCount: number, durationMs: number): void;
|
|
2295
|
+
/**
|
|
2296
|
+
* Get the most recent N log entries.
|
|
2297
|
+
*/
|
|
2298
|
+
getRecentLogs(count?: number): SearchLogEntry[];
|
|
2299
|
+
/**
|
|
2300
|
+
* Get entries flagged as slow queries.
|
|
2301
|
+
*/
|
|
2302
|
+
getSlowQueries(): SearchLogEntry[];
|
|
2303
|
+
/**
|
|
2304
|
+
* Get aggregate statistics.
|
|
2305
|
+
*/
|
|
2306
|
+
getStats(): SearchStats;
|
|
2307
|
+
/**
|
|
2308
|
+
* Clear all log entries.
|
|
2309
|
+
*/
|
|
2310
|
+
clearLogs(): void;
|
|
2311
|
+
get isEnabled(): boolean;
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
declare interface SearchLoggerConfig {
|
|
2315
|
+
/** Whether logging is enabled. Default: true. */
|
|
2316
|
+
enabled?: boolean;
|
|
2317
|
+
/** Slow query threshold in milliseconds. Default: 1000. */
|
|
2318
|
+
slowThresholdMs?: number;
|
|
2319
|
+
/** Maximum number of log entries to retain. Default: 100. */
|
|
2320
|
+
maxEntries?: number;
|
|
2321
|
+
/** Custom log handler. Called for every search log entry. */
|
|
2322
|
+
onLog?: (entry: SearchLogEntry) => void;
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
/**
|
|
2326
|
+
* FHIR search modifier.
|
|
2327
|
+
*
|
|
2328
|
+
* See: https://hl7.org/fhir/R4/search.html#modifiers
|
|
2329
|
+
*/
|
|
2330
|
+
export declare type SearchModifier = 'exact' | 'contains' | 'missing' | 'not' | 'text' | 'above' | 'below' | 'in' | 'not-in' | 'of-type';
|
|
2331
|
+
|
|
2332
|
+
/**
|
|
2333
|
+
* Options for search execution.
|
|
2334
|
+
*/
|
|
2335
|
+
export declare interface SearchOptions {
|
|
2336
|
+
/** Whether to include total count. */
|
|
2337
|
+
total?: 'none' | 'estimate' | 'accurate';
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
/**
|
|
2341
|
+
* Options for search execution.
|
|
2342
|
+
*/
|
|
2343
|
+
declare interface SearchOptions_2 {
|
|
2344
|
+
/** Whether to include total count. */
|
|
2345
|
+
total?: 'none' | 'estimate' | 'accurate';
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
/**
|
|
2349
|
+
* Shape of a FHIR Bundle containing SearchParameter entries.
|
|
2350
|
+
*/
|
|
2351
|
+
export declare interface SearchParameterBundle {
|
|
2352
|
+
resourceType: 'Bundle';
|
|
2353
|
+
entry?: Array<{
|
|
2354
|
+
resource?: SearchParameterResource;
|
|
2355
|
+
}>;
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
/**
|
|
2359
|
+
* Minimal SearchParameter shape used by fhir-persistence.
|
|
2360
|
+
*/
|
|
2361
|
+
declare interface SearchParameterDef {
|
|
2362
|
+
resourceType: 'SearchParameter';
|
|
2363
|
+
url?: string;
|
|
2364
|
+
name?: string;
|
|
2365
|
+
code: string;
|
|
2366
|
+
type: 'number' | 'date' | 'string' | 'token' | 'reference' | 'composite' | 'quantity' | 'uri' | 'special';
|
|
2367
|
+
base: string[];
|
|
2368
|
+
expression?: string;
|
|
2369
|
+
target?: string[];
|
|
2370
|
+
[key: string]: unknown;
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
/**
|
|
2374
|
+
* Resolved implementation details for a single search parameter
|
|
2375
|
+
* on a specific resource type.
|
|
2376
|
+
*/
|
|
2377
|
+
export declare interface SearchParameterImpl {
|
|
2378
|
+
/** SearchParameter.code (e.g., `'birthdate'`). */
|
|
2379
|
+
code: string;
|
|
2380
|
+
/** FHIR search parameter type. */
|
|
2381
|
+
type: SearchParamType;
|
|
2382
|
+
/** Resource types this parameter applies to. */
|
|
2383
|
+
resourceTypes: string[];
|
|
2384
|
+
/** FHIRPath expression for value extraction. */
|
|
2385
|
+
expression: string;
|
|
2386
|
+
/** Physical storage strategy. */
|
|
2387
|
+
strategy: SearchStrategy;
|
|
2388
|
+
/** Column name in the main table (for `column` strategy). */
|
|
2389
|
+
columnName: string;
|
|
2390
|
+
/** PostgreSQL column type (for `column` strategy). */
|
|
2391
|
+
columnType: SearchColumnType;
|
|
2392
|
+
/** Whether the column stores an array of values. */
|
|
2393
|
+
array: boolean;
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
/**
|
|
2397
|
+
* Indexes SearchParameter definitions by resource type.
|
|
2398
|
+
*
|
|
2399
|
+
* ## Usage
|
|
2400
|
+
*
|
|
2401
|
+
* ```typescript
|
|
2402
|
+
* const registry = new SearchParameterRegistry();
|
|
2403
|
+
* const bundle = JSON.parse(fs.readFileSync('search-parameters.json', 'utf8'));
|
|
2404
|
+
* registry.indexBundle(bundle);
|
|
2405
|
+
*
|
|
2406
|
+
* const patientParams = registry.getForResource('Patient');
|
|
2407
|
+
* ```
|
|
2408
|
+
*/
|
|
2409
|
+
export declare class SearchParameterRegistry {
|
|
2410
|
+
/**
|
|
2411
|
+
* Map from resource type → Map from param code → SearchParameterImpl.
|
|
2412
|
+
*/
|
|
2413
|
+
private readonly byResource;
|
|
2414
|
+
/**
|
|
2415
|
+
* Total number of indexed implementations (across all resource types).
|
|
2416
|
+
*/
|
|
2417
|
+
private _totalCount;
|
|
2418
|
+
/**
|
|
2419
|
+
* Number of skipped parameters (composite, special, ignored).
|
|
2420
|
+
*/
|
|
2421
|
+
private _skippedCount;
|
|
2422
|
+
/**
|
|
2423
|
+
* Index all SearchParameter entries from a FHIR Bundle.
|
|
2424
|
+
*
|
|
2425
|
+
* Skips entries that are:
|
|
2426
|
+
* - Not a SearchParameter resource
|
|
2427
|
+
* - Of type `composite` or `special`
|
|
2428
|
+
* - In the ignored list (`_id`, `_lastUpdated`, etc.)
|
|
2429
|
+
*
|
|
2430
|
+
* @returns Stats about the indexing operation.
|
|
2431
|
+
*/
|
|
2432
|
+
indexBundle(bundle: SearchParameterBundle): {
|
|
2433
|
+
indexed: number;
|
|
2434
|
+
skipped: number;
|
|
2435
|
+
};
|
|
2436
|
+
/**
|
|
2437
|
+
* Index a single SearchParameterImpl directly.
|
|
2438
|
+
*
|
|
2439
|
+
* Useful for adding platform-specific or custom search parameters.
|
|
2440
|
+
*/
|
|
2441
|
+
indexImpl(resourceType: string, impl: SearchParameterImpl): void;
|
|
2442
|
+
/**
|
|
2443
|
+
* Get all search parameter implementations for a resource type.
|
|
2444
|
+
*
|
|
2445
|
+
* @returns Array of SearchParameterImpl, sorted by code for deterministic output.
|
|
2446
|
+
*/
|
|
2447
|
+
getForResource(resourceType: string): SearchParameterImpl[];
|
|
2448
|
+
/**
|
|
2449
|
+
* Get a specific search parameter implementation for a resource type.
|
|
2450
|
+
*/
|
|
2451
|
+
getImpl(resourceType: string, code: string): SearchParameterImpl | undefined;
|
|
2452
|
+
/**
|
|
2453
|
+
* Check if a resource type has any indexed search parameters.
|
|
2454
|
+
*/
|
|
2455
|
+
hasResource(resourceType: string): boolean;
|
|
2456
|
+
/**
|
|
2457
|
+
* Get all resource types that have indexed search parameters.
|
|
2458
|
+
*/
|
|
2459
|
+
getResourceTypes(): string[];
|
|
2460
|
+
/**
|
|
2461
|
+
* Get the total number of indexed implementations.
|
|
2462
|
+
*/
|
|
2463
|
+
get totalCount(): number;
|
|
2464
|
+
/**
|
|
2465
|
+
* Get the number of skipped parameters.
|
|
2466
|
+
*/
|
|
2467
|
+
get skippedCount(): number;
|
|
2468
|
+
/**
|
|
2469
|
+
* Get the number of resource types with indexed parameters.
|
|
2470
|
+
*/
|
|
2471
|
+
get resourceTypeCount(): number;
|
|
2472
|
+
/**
|
|
2473
|
+
* Remove all indexed parameters.
|
|
2474
|
+
*/
|
|
2475
|
+
clear(): void;
|
|
2476
|
+
/**
|
|
2477
|
+
* Build a SearchParameterImpl from a raw SearchParameter resource.
|
|
2478
|
+
*/
|
|
2479
|
+
private buildImpl;
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
/**
|
|
2483
|
+
* Raw FHIR SearchParameter shape (subset of fields we need).
|
|
2484
|
+
*/
|
|
2485
|
+
export declare interface SearchParameterResource {
|
|
2486
|
+
resourceType: 'SearchParameter';
|
|
2487
|
+
code: string;
|
|
2488
|
+
type: SearchParamType;
|
|
2489
|
+
base: string[];
|
|
2490
|
+
expression?: string;
|
|
2491
|
+
url?: string;
|
|
2492
|
+
name?: string;
|
|
2493
|
+
target?: string[];
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
/**
|
|
2497
|
+
* Metadata for a search parameter, preserved for SchemaDiff.
|
|
2498
|
+
*/
|
|
2499
|
+
declare interface SearchParamMeta {
|
|
2500
|
+
code: string;
|
|
2501
|
+
type: string;
|
|
2502
|
+
expression: string;
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
/**
|
|
2506
|
+
* FHIR SearchParameter type codes.
|
|
2507
|
+
*/
|
|
2508
|
+
export declare type SearchParamType = 'number' | 'date' | 'string' | 'token' | 'reference' | 'composite' | 'quantity' | 'uri' | 'special';
|
|
2509
|
+
|
|
2510
|
+
/**
|
|
2511
|
+
* Search plan produced by the planner.
|
|
2512
|
+
*/
|
|
2513
|
+
export declare interface SearchPlan {
|
|
2514
|
+
/** The optimized search request (params reordered). */
|
|
2515
|
+
request: SearchRequest;
|
|
2516
|
+
/** Whether two-phase SQL is recommended for this query. */
|
|
2517
|
+
useTwoPhase: boolean;
|
|
2518
|
+
/** Whether any chained search params are present. */
|
|
2519
|
+
hasChainedSearch: boolean;
|
|
2520
|
+
/** Estimated selectivity: 'high' (few results), 'medium', 'low' (many results). */
|
|
2521
|
+
estimatedSelectivity: 'high' | 'medium' | 'low';
|
|
2522
|
+
/** Warnings produced during planning (e.g., deep chain rejected). */
|
|
2523
|
+
warnings: string[];
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
/**
|
|
2527
|
+
* Options for the search planner.
|
|
2528
|
+
*/
|
|
2529
|
+
export declare interface SearchPlannerOptions {
|
|
2530
|
+
/** Maximum allowed chain depth (default: 1, i.e., single-level chain). */
|
|
2531
|
+
maxChainDepth?: number;
|
|
2532
|
+
/** Row count threshold above which two-phase SQL is recommended. Default: 10000. */
|
|
2533
|
+
twoPhaseThreshold?: number;
|
|
2534
|
+
/** Estimated table row count (from stats or hint). Default: 0 (unknown). */
|
|
2535
|
+
estimatedRowCount?: number;
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
/**
|
|
2539
|
+
* Search Types
|
|
2540
|
+
*
|
|
2541
|
+
* Defines the data structures for FHIR search request parsing
|
|
2542
|
+
* and SQL WHERE clause generation.
|
|
2543
|
+
*
|
|
2544
|
+
* ## FHIR Search Semantics
|
|
2545
|
+
*
|
|
2546
|
+
* - Multiple values for the same parameter → OR (comma-separated)
|
|
2547
|
+
* - Multiple different parameters → AND (separate query params)
|
|
2548
|
+
* - Prefixes (eq, ne, lt, gt, le, ge) → comparison operators
|
|
2549
|
+
* - Modifiers (:exact, :contains, :missing, :not) → behavior modifiers
|
|
2550
|
+
*
|
|
2551
|
+
* Reference: https://hl7.org/fhir/R4/search.html
|
|
2552
|
+
*
|
|
2553
|
+
* @module fhir-persistence/search
|
|
2554
|
+
*/
|
|
2555
|
+
/**
|
|
2556
|
+
* FHIR search prefix for number, date, and quantity parameters.
|
|
2557
|
+
*
|
|
2558
|
+
* See: https://hl7.org/fhir/R4/search.html#prefix
|
|
2559
|
+
*/
|
|
2560
|
+
export declare type SearchPrefix = 'eq' | 'ne' | 'lt' | 'gt' | 'le' | 'ge' | 'sa' | 'eb' | 'ap';
|
|
2561
|
+
|
|
2562
|
+
/**
|
|
2563
|
+
* A fully parsed FHIR search request.
|
|
2564
|
+
*
|
|
2565
|
+
* Produced by `parseSearchRequest()` from a URL query string.
|
|
2566
|
+
* Consumed by `buildSearchSQL()` to generate a SQL query.
|
|
2567
|
+
*/
|
|
2568
|
+
export declare interface SearchRequest {
|
|
2569
|
+
/** The FHIR resource type to search. */
|
|
2570
|
+
resourceType: string;
|
|
2571
|
+
/** Parsed search parameters (AND semantics between parameters). */
|
|
2572
|
+
params: ParsedSearchParam[];
|
|
2573
|
+
/**
|
|
2574
|
+
* Maximum number of results to return.
|
|
2575
|
+
* Corresponds to `_count`. Default: 20.
|
|
2576
|
+
*/
|
|
2577
|
+
count?: number;
|
|
2578
|
+
/**
|
|
2579
|
+
* Offset for pagination.
|
|
2580
|
+
* Corresponds to `_offset`.
|
|
2581
|
+
*/
|
|
2582
|
+
offset?: number;
|
|
2583
|
+
/**
|
|
2584
|
+
* Sort rules.
|
|
2585
|
+
* Corresponds to `_sort`.
|
|
2586
|
+
*/
|
|
2587
|
+
sort?: SortRule[];
|
|
2588
|
+
/**
|
|
2589
|
+
* Total count mode.
|
|
2590
|
+
* Corresponds to `_total`.
|
|
2591
|
+
*/
|
|
2592
|
+
total?: 'none' | 'estimate' | 'accurate';
|
|
2593
|
+
/**
|
|
2594
|
+
* Resources to include (forward references).
|
|
2595
|
+
* Corresponds to `_include`.
|
|
2596
|
+
*/
|
|
2597
|
+
include?: IncludeTarget[];
|
|
2598
|
+
/**
|
|
2599
|
+
* Resources to reverse-include (reverse references).
|
|
2600
|
+
* Corresponds to `_revinclude`.
|
|
2601
|
+
*/
|
|
2602
|
+
revinclude?: IncludeTarget[];
|
|
2603
|
+
/**
|
|
2604
|
+
* Compartment filter for compartment search.
|
|
2605
|
+
* Set when the URL is `/:compartmentType/:compartmentId/:resourceType`.
|
|
2606
|
+
*
|
|
2607
|
+
* Example: `GET /Patient/123/Observation` →
|
|
2608
|
+
* `{ resourceType: "Patient", id: "123" }`
|
|
2609
|
+
*/
|
|
2610
|
+
compartment?: {
|
|
2611
|
+
resourceType: string;
|
|
2612
|
+
id: string;
|
|
2613
|
+
};
|
|
2614
|
+
/**
|
|
2615
|
+
* Project ID for multi-tenant scoping.
|
|
2616
|
+
* When set, search results are restricted to resources with matching `projectId`.
|
|
2617
|
+
*
|
|
2618
|
+
* Injected by the server layer from OperationContext.project.
|
|
2619
|
+
*/
|
|
2620
|
+
project?: string;
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
/**
|
|
2624
|
+
* Result of a search execution.
|
|
2625
|
+
*/
|
|
2626
|
+
export declare interface SearchResult {
|
|
2627
|
+
/** Matched resources. */
|
|
2628
|
+
resources: PersistedResource[];
|
|
2629
|
+
/** Included resources from _include/_revinclude (search.mode = 'include'). */
|
|
2630
|
+
included?: PersistedResource[];
|
|
2631
|
+
/** Total count (only when `total=accurate`). */
|
|
2632
|
+
total?: number;
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
/**
|
|
2636
|
+
* Result of a search execution.
|
|
2637
|
+
*/
|
|
2638
|
+
declare interface SearchResult_2 {
|
|
2639
|
+
/** Matched resources. */
|
|
2640
|
+
resources: PersistedResource[];
|
|
2641
|
+
/** Included resources from _include/_revinclude (search.mode = 'include'). */
|
|
2642
|
+
included?: PersistedResource[];
|
|
2643
|
+
/** Total count (only when `total=accurate`). */
|
|
2644
|
+
total?: number;
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
/**
|
|
2648
|
+
* v2: Raw row shape returned by search SQL.
|
|
2649
|
+
* Uses deleted: number (0/1) instead of boolean.
|
|
2650
|
+
*/
|
|
2651
|
+
declare interface SearchRowV2 {
|
|
2652
|
+
id: string;
|
|
2653
|
+
versionId: string;
|
|
2654
|
+
content: string;
|
|
2655
|
+
deleted: number;
|
|
2656
|
+
lastUpdated: string;
|
|
2657
|
+
[key: string]: unknown;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
/**
|
|
2661
|
+
* A complete search SQL query with parameterized values.
|
|
2662
|
+
*
|
|
2663
|
+
* Produced by `buildSearchSQL()`.
|
|
2664
|
+
*/
|
|
2665
|
+
export declare interface SearchSQL {
|
|
2666
|
+
/** The full SQL query string. */
|
|
2667
|
+
sql: string;
|
|
2668
|
+
/** The parameter values for the query. */
|
|
2669
|
+
values: unknown[];
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
declare interface SearchStats {
|
|
2673
|
+
/** Total number of logged searches. */
|
|
2674
|
+
totalSearches: number;
|
|
2675
|
+
/** Average duration in ms. */
|
|
2676
|
+
avgDurationMs: number;
|
|
2677
|
+
/** Maximum duration in ms. */
|
|
2678
|
+
maxDurationMs: number;
|
|
2679
|
+
/** Minimum duration in ms. */
|
|
2680
|
+
minDurationMs: number;
|
|
2681
|
+
/** Number of slow queries. */
|
|
2682
|
+
slowCount: number;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
/**
|
|
2686
|
+
* Physical storage strategy for a search parameter.
|
|
2687
|
+
*
|
|
2688
|
+
* - `column` — single column in the main table
|
|
2689
|
+
* - `token-column` — three columns (UUID[], TEXT[], TEXT) for token search
|
|
2690
|
+
* - `lookup-table` — separate lookup table; only a sort column in main table
|
|
2691
|
+
*/
|
|
2692
|
+
export declare type SearchStrategy = 'column' | 'token-column' | 'lookup-table';
|
|
2693
|
+
|
|
2694
|
+
/**
|
|
2695
|
+
* A single sort rule from the `_sort` parameter.
|
|
2696
|
+
*
|
|
2697
|
+
* Examples:
|
|
2698
|
+
* - `_sort=birthdate` → `{ code: "birthdate", descending: false }`
|
|
2699
|
+
* - `_sort=-birthdate` → `{ code: "birthdate", descending: true }`
|
|
2700
|
+
*/
|
|
2701
|
+
export declare interface SortRule {
|
|
2702
|
+
/** The search parameter code to sort by. */
|
|
2703
|
+
code: string;
|
|
2704
|
+
/** Whether to sort in descending order. */
|
|
2705
|
+
descending: boolean;
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
/**
|
|
2709
|
+
* Split a search value string on commas (OR semantics).
|
|
2710
|
+
*
|
|
2711
|
+
* Escaped commas (`\,`) are preserved as literal commas.
|
|
2712
|
+
*
|
|
2713
|
+
* Examples:
|
|
2714
|
+
* - `"male"` → `["male"]`
|
|
2715
|
+
* - `"male,female"` → `["male", "female"]`
|
|
2716
|
+
* - `"a\\,b"` → `["a,b"]`
|
|
2717
|
+
*/
|
|
2718
|
+
export declare function splitSearchValues(value: string): string[];
|
|
2719
|
+
|
|
2720
|
+
/**
|
|
2721
|
+
* Table Schema — Type Definitions
|
|
2722
|
+
*
|
|
2723
|
+
* Intermediate data model representing PostgreSQL table structure.
|
|
2724
|
+
* These types are the output of `TableSchemaBuilder` and the input
|
|
2725
|
+
* to `DDLGenerator`. They are pure data — no behavior, no DB dependency.
|
|
2726
|
+
*
|
|
2727
|
+
* ## Design
|
|
2728
|
+
*
|
|
2729
|
+
* Each FHIR resource type maps to a `ResourceTableSet` containing
|
|
2730
|
+
* exactly 3 tables:
|
|
2731
|
+
* - **Main table** (`Patient`) — current version + search columns
|
|
2732
|
+
* - **History table** (`Patient_History`) — all versions
|
|
2733
|
+
* - **References table** (`Patient_References`) — outgoing references
|
|
2734
|
+
*
|
|
2735
|
+
* This mirrors Medplum's 3-table-per-resource strategy (WF-MIG-002).
|
|
2736
|
+
*
|
|
2737
|
+
* @module fhir-persistence/schema
|
|
2738
|
+
*/
|
|
2739
|
+
/**
|
|
2740
|
+
* SQL column types used in FHIR resource tables.
|
|
2741
|
+
*
|
|
2742
|
+
* v2: Removed UUID / UUID[]. Token columns now use TEXT / TEXT[].
|
|
2743
|
+
* PostgreSQL-specific types (TIMESTAMPTZ, TEXT[]) are still here
|
|
2744
|
+
* for PG DDL generation. SQLite adapter maps them to TEXT.
|
|
2745
|
+
*/
|
|
2746
|
+
export declare type SqlColumnType = 'TEXT' | 'TEXT[]' | 'BOOLEAN' | 'INTEGER' | 'BIGINT' | 'TIMESTAMPTZ' | 'TIMESTAMPTZ[]' | 'DATE' | 'DATE[]' | 'NUMERIC' | 'DOUBLE PRECISION' | 'DOUBLE PRECISION[]' | 'REAL';
|
|
2747
|
+
|
|
2748
|
+
export declare class SQLiteAdapter implements StorageAdapter {
|
|
2749
|
+
private readonly data?;
|
|
2750
|
+
private db;
|
|
2751
|
+
private initPromise;
|
|
2752
|
+
/**
|
|
2753
|
+
* @param path - Database file path, or ':memory:' for in-memory database.
|
|
2754
|
+
* @param data - Optional Uint8Array of an existing database file to load.
|
|
2755
|
+
*/
|
|
2756
|
+
constructor(_path?: string, data?: Uint8Array | undefined);
|
|
2757
|
+
private initialize;
|
|
2758
|
+
private getDb;
|
|
2759
|
+
execute(sql: string, params?: unknown[]): Promise<{
|
|
2760
|
+
changes: number;
|
|
2761
|
+
}>;
|
|
2762
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
2763
|
+
queryOne<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T | undefined>;
|
|
2764
|
+
queryStream<T = Record<string, unknown>>(sql: string, params?: unknown[]): AsyncIterable<T>;
|
|
2765
|
+
prepare<T = Record<string, unknown>>(sql: string): PreparedStatement<T>;
|
|
2766
|
+
transaction<R>(fn: (tx: TransactionContext) => R | Promise<R>): Promise<R>;
|
|
2767
|
+
close(): Promise<void>;
|
|
2768
|
+
/**
|
|
2769
|
+
* Export the database as a Uint8Array (for file persistence).
|
|
2770
|
+
*/
|
|
2771
|
+
export(): Promise<Uint8Array>;
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
/**
|
|
2775
|
+
* Unified database access interface for SQLite and PostgreSQL.
|
|
2776
|
+
*
|
|
2777
|
+
* All methods are async to support both synchronous (SQLite via sql.js)
|
|
2778
|
+
* and asynchronous (PostgreSQL via pg) database drivers.
|
|
2779
|
+
*
|
|
2780
|
+
* ## Transaction Semantics
|
|
2781
|
+
* - SQLite: `BEGIN IMMEDIATE ... COMMIT / ROLLBACK`
|
|
2782
|
+
* - PostgreSQL: `BEGIN ... COMMIT / ROLLBACK` with `SELECT FOR UPDATE`
|
|
2783
|
+
*/
|
|
2784
|
+
export declare interface StorageAdapter {
|
|
2785
|
+
/** Execute a write operation (INSERT / UPDATE / DELETE / DDL). */
|
|
2786
|
+
execute(sql: string, params?: unknown[]): Promise<{
|
|
2787
|
+
changes: number;
|
|
2788
|
+
}>;
|
|
2789
|
+
/** Execute a read query, returning all matching rows. */
|
|
2790
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
2791
|
+
/** Execute a read query, returning the first row or undefined. */
|
|
2792
|
+
queryOne<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T | undefined>;
|
|
2793
|
+
/** Stream rows for large result sets (avoids full memory load). */
|
|
2794
|
+
queryStream<T = Record<string, unknown>>(sql: string, params?: unknown[]): AsyncIterable<T>;
|
|
2795
|
+
/** Prepare a SQL statement for repeated execution. */
|
|
2796
|
+
prepare<T = Record<string, unknown>>(sql: string): PreparedStatement<T>;
|
|
2797
|
+
/**
|
|
2798
|
+
* Execute a function within a single database transaction.
|
|
2799
|
+
*
|
|
2800
|
+
* - On success (fn returns normally): COMMIT
|
|
2801
|
+
* - On failure (fn throws): ROLLBACK and re-throw
|
|
2802
|
+
*/
|
|
2803
|
+
transaction<R>(fn: (tx: TransactionContext) => R | Promise<R>): Promise<R>;
|
|
2804
|
+
/** Close the database connection and release resources. */
|
|
2805
|
+
close(): Promise<void>;
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2808
|
+
declare interface StoredValueSet {
|
|
2809
|
+
/** ValueSet canonical URL (e.g., "http://hl7.org/fhir/ValueSet/observation-codes"). */
|
|
2810
|
+
url: string;
|
|
2811
|
+
/** ValueSet version (e.g., "4.0.1"). */
|
|
2812
|
+
version: string;
|
|
2813
|
+
/** ValueSet name (human-readable). */
|
|
2814
|
+
name: string | null;
|
|
2815
|
+
/** Full ValueSet content as JSON string. */
|
|
2816
|
+
content: string;
|
|
2817
|
+
/** When this record was stored. */
|
|
2818
|
+
storedAt: string;
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
/**
|
|
2822
|
+
* DefinitionProvider — Bridge Interface for fhir-definition
|
|
2823
|
+
*
|
|
2824
|
+
* Abstracts the `fhir-definition` registry so that `fhir-persistence`
|
|
2825
|
+
* never imports `fhir-definition` types directly. This enables:
|
|
2826
|
+
*
|
|
2827
|
+
* - Testing with in-memory mocks (no IG package loading)
|
|
2828
|
+
* - Swapping fhir-definition versions without touching persistence code
|
|
2829
|
+
* - Structural typing compatibility (duck typing)
|
|
2830
|
+
*
|
|
2831
|
+
* ADR-01 §2.3: DefinitionProvider interface contract.
|
|
2832
|
+
*
|
|
2833
|
+
* @module fhir-persistence/providers
|
|
2834
|
+
*/
|
|
2835
|
+
/**
|
|
2836
|
+
* Minimal StructureDefinition shape used by fhir-persistence.
|
|
2837
|
+
* Only the fields that fhir-persistence reads are declared.
|
|
2838
|
+
*/
|
|
2839
|
+
declare interface StructureDefinitionDef {
|
|
2840
|
+
resourceType: 'StructureDefinition';
|
|
2841
|
+
url: string;
|
|
2842
|
+
name?: string;
|
|
2843
|
+
type?: string;
|
|
2844
|
+
kind?: string;
|
|
2845
|
+
snapshot?: {
|
|
2846
|
+
element?: Array<{
|
|
2847
|
+
path?: string;
|
|
2848
|
+
type?: Array<{
|
|
2849
|
+
code?: string;
|
|
2850
|
+
}>;
|
|
2851
|
+
[key: string]: unknown;
|
|
2852
|
+
}>;
|
|
2853
|
+
};
|
|
2854
|
+
[key: string]: unknown;
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
/**
|
|
2858
|
+
* Indexes CanonicalProfile instances by their `type` field for O(1) lookup.
|
|
2859
|
+
*
|
|
2860
|
+
* ## Usage
|
|
2861
|
+
*
|
|
2862
|
+
* ```typescript
|
|
2863
|
+
* const registry = new StructureDefinitionRegistry();
|
|
2864
|
+
* const profiles = loadBundleFromFile('profiles-resources.json').profiles;
|
|
2865
|
+
* registry.indexAll(profiles);
|
|
2866
|
+
*
|
|
2867
|
+
* const patient = registry.get('Patient');
|
|
2868
|
+
* const tableTypes = registry.getTableResourceTypes(); // ~140+ types
|
|
2869
|
+
* ```
|
|
2870
|
+
*/
|
|
2871
|
+
export declare class StructureDefinitionRegistry {
|
|
2872
|
+
private readonly profiles;
|
|
2873
|
+
/**
|
|
2874
|
+
* Index a single CanonicalProfile by its `type` field.
|
|
2875
|
+
*
|
|
2876
|
+
* If a profile with the same type already exists, it is overwritten
|
|
2877
|
+
* (later definitions override earlier ones, matching BundleLoader
|
|
2878
|
+
* merge semantics).
|
|
2879
|
+
*/
|
|
2880
|
+
index(profile: CanonicalProfile): void;
|
|
2881
|
+
/**
|
|
2882
|
+
* Index multiple CanonicalProfiles.
|
|
2883
|
+
*
|
|
2884
|
+
* Profiles are indexed in order; later entries override earlier
|
|
2885
|
+
* ones with the same type.
|
|
2886
|
+
*/
|
|
2887
|
+
indexAll(profiles: readonly CanonicalProfile[]): void;
|
|
2888
|
+
/**
|
|
2889
|
+
* Get a profile by resource type name.
|
|
2890
|
+
*
|
|
2891
|
+
* @param resourceType - The FHIR resource type (e.g., `'Patient'`).
|
|
2892
|
+
* @returns The CanonicalProfile, or `undefined` if not indexed.
|
|
2893
|
+
*/
|
|
2894
|
+
get(resourceType: string): CanonicalProfile | undefined;
|
|
2895
|
+
/**
|
|
2896
|
+
* Check if a resource type is indexed.
|
|
2897
|
+
*/
|
|
2898
|
+
has(resourceType: string): boolean;
|
|
2899
|
+
/**
|
|
2900
|
+
* Get all resource types that should have database tables.
|
|
2901
|
+
*
|
|
2902
|
+
* Returns types where `kind === 'resource'` AND `abstract === false`.
|
|
2903
|
+
* This excludes:
|
|
2904
|
+
* - Abstract types (Resource, DomainResource)
|
|
2905
|
+
* - Complex types (HumanName, Address)
|
|
2906
|
+
* - Primitive types (string, boolean)
|
|
2907
|
+
* - Logical models
|
|
2908
|
+
*
|
|
2909
|
+
* Results are sorted alphabetically for deterministic output.
|
|
2910
|
+
*/
|
|
2911
|
+
getTableResourceTypes(): string[];
|
|
2912
|
+
/**
|
|
2913
|
+
* Get all indexed type names (regardless of kind or abstract).
|
|
2914
|
+
*/
|
|
2915
|
+
getAllTypes(): string[];
|
|
2916
|
+
/**
|
|
2917
|
+
* Get the number of indexed profiles.
|
|
2918
|
+
*/
|
|
2919
|
+
get size(): number;
|
|
2920
|
+
/**
|
|
2921
|
+
* Remove all indexed profiles.
|
|
2922
|
+
*/
|
|
2923
|
+
clear(): void;
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
declare interface TerminologyCode {
|
|
2927
|
+
/** Code system URI (e.g., "http://loinc.org"). */
|
|
2928
|
+
system: string;
|
|
2929
|
+
/** Code value (e.g., "8480-6"). */
|
|
2930
|
+
code: string;
|
|
2931
|
+
/** Human-readable display text. */
|
|
2932
|
+
display: string;
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
export declare class TerminologyCodeRepo {
|
|
2936
|
+
private readonly adapter;
|
|
2937
|
+
constructor(adapter: StorageAdapter);
|
|
2938
|
+
/**
|
|
2939
|
+
* Ensure the terminology_codes table and indexes exist.
|
|
2940
|
+
*/
|
|
2941
|
+
ensureTable(): Promise<void>;
|
|
2942
|
+
/**
|
|
2943
|
+
* Batch insert codes. Duplicates are silently ignored (INSERT OR IGNORE).
|
|
2944
|
+
*
|
|
2945
|
+
* @param codes - Array of codes to insert.
|
|
2946
|
+
* @returns Number of codes actually inserted (excluding duplicates).
|
|
2947
|
+
*/
|
|
2948
|
+
batchInsert(codes: TerminologyCode[]): Promise<number>;
|
|
2949
|
+
/**
|
|
2950
|
+
* Lookup display text for a specific (system, code) pair.
|
|
2951
|
+
*
|
|
2952
|
+
* @returns Display text, or undefined if not found.
|
|
2953
|
+
*/
|
|
2954
|
+
lookup(system: string, code: string): Promise<string | undefined>;
|
|
2955
|
+
/**
|
|
2956
|
+
* Lookup all codes matching a code value (any system).
|
|
2957
|
+
* Useful for code-only search without specifying system.
|
|
2958
|
+
*
|
|
2959
|
+
* @returns Array of matching TerminologyCode entries.
|
|
2960
|
+
*/
|
|
2961
|
+
lookupByCode(code: string): Promise<TerminologyCode[]>;
|
|
2962
|
+
/**
|
|
2963
|
+
* Get the total number of codes in the table.
|
|
2964
|
+
*/
|
|
2965
|
+
getCodeCount(): Promise<number>;
|
|
2966
|
+
/**
|
|
2967
|
+
* Remove all codes from the table.
|
|
2968
|
+
*/
|
|
2969
|
+
clear(): Promise<void>;
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
/**
|
|
2973
|
+
* A restricted adapter interface available inside a transaction callback.
|
|
2974
|
+
*
|
|
2975
|
+
* All operations within a transaction use this context to ensure
|
|
2976
|
+
* they execute on the same database connection/transaction.
|
|
2977
|
+
*/
|
|
2978
|
+
export declare interface TransactionContext {
|
|
2979
|
+
/** Execute a write operation within the transaction. */
|
|
2980
|
+
execute(sql: string, params?: unknown[]): {
|
|
2981
|
+
changes: number;
|
|
2982
|
+
};
|
|
2983
|
+
/** Execute a read query within the transaction. */
|
|
2984
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): T[];
|
|
2985
|
+
/** Execute a read query returning the first row or undefined. */
|
|
2986
|
+
queryOne<T = Record<string, unknown>>(sql: string, params?: unknown[]): T | undefined;
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
/**
|
|
2990
|
+
* Result of a two-phase search SQL build.
|
|
2991
|
+
*/
|
|
2992
|
+
export declare interface TwoPhaseSearchSQL {
|
|
2993
|
+
/** Phase 1: SELECT id with full WHERE + ORDER BY + LIMIT/OFFSET. */
|
|
2994
|
+
phase1: SearchSQL;
|
|
2995
|
+
/** Phase 2: SELECT content WHERE id IN (?,...). Values are id strings from Phase 1 results. */
|
|
2996
|
+
phase2Template: string;
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
/**
|
|
3000
|
+
* Options for `updateResource()`.
|
|
3001
|
+
*/
|
|
3002
|
+
export declare interface UpdateResourceOptions {
|
|
3003
|
+
/**
|
|
3004
|
+
* Expected versionId for optimistic locking.
|
|
3005
|
+
* If provided and does not match the current versionId,
|
|
3006
|
+
* the update is rejected with `ResourceVersionConflictError`.
|
|
3007
|
+
*
|
|
3008
|
+
* Corresponds to the HTTP `If-Match` header.
|
|
3009
|
+
*/
|
|
3010
|
+
ifMatch?: string;
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
declare interface UpdateResourceOptions_2 {
|
|
3014
|
+
/** Expected versionId for optimistic locking (If-Match header). */
|
|
3015
|
+
ifMatch?: string;
|
|
3016
|
+
}
|
|
3017
|
+
|
|
3018
|
+
declare interface UpdateResourceOptions_3 {
|
|
3019
|
+
/** Expected versionId for optimistic locking (If-Match header). */
|
|
3020
|
+
ifMatch?: string;
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
/**
|
|
3024
|
+
* A single validation issue.
|
|
3025
|
+
*/
|
|
3026
|
+
declare interface ValidationIssue {
|
|
3027
|
+
severity: 'error' | 'warning' | 'information';
|
|
3028
|
+
message: string;
|
|
3029
|
+
path?: string;
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
/**
|
|
3033
|
+
* Result of resource validation.
|
|
3034
|
+
*/
|
|
3035
|
+
declare interface ValidationResult {
|
|
3036
|
+
valid: boolean;
|
|
3037
|
+
issues: ValidationIssue[];
|
|
3038
|
+
}
|
|
3039
|
+
|
|
3040
|
+
/**
|
|
3041
|
+
* Minimal ValueSet shape used by fhir-persistence.
|
|
3042
|
+
*/
|
|
3043
|
+
declare interface ValueSetDef {
|
|
3044
|
+
resourceType: 'ValueSet';
|
|
3045
|
+
url: string;
|
|
3046
|
+
name?: string;
|
|
3047
|
+
status?: string;
|
|
3048
|
+
compose?: unknown;
|
|
3049
|
+
expansion?: unknown;
|
|
3050
|
+
[key: string]: unknown;
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
declare interface ValueSetInput {
|
|
3054
|
+
url: string;
|
|
3055
|
+
version: string;
|
|
3056
|
+
name?: string;
|
|
3057
|
+
content: string;
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
export declare class ValueSetRepo {
|
|
3061
|
+
private readonly adapter;
|
|
3062
|
+
constructor(adapter: StorageAdapter);
|
|
3063
|
+
/**
|
|
3064
|
+
* Ensure the terminology_valuesets table exists.
|
|
3065
|
+
*/
|
|
3066
|
+
ensureTable(): Promise<void>;
|
|
3067
|
+
/**
|
|
3068
|
+
* Insert or update a ValueSet.
|
|
3069
|
+
* If a ValueSet with the same (url, version) exists, it is replaced.
|
|
3070
|
+
*/
|
|
3071
|
+
upsert(input: ValueSetInput): Promise<void>;
|
|
3072
|
+
/**
|
|
3073
|
+
* Get a specific ValueSet by url and version.
|
|
3074
|
+
*
|
|
3075
|
+
* @returns The stored ValueSet, or undefined if not found.
|
|
3076
|
+
*/
|
|
3077
|
+
getValueSet(url: string, version: string): Promise<StoredValueSet | undefined>;
|
|
3078
|
+
/**
|
|
3079
|
+
* Get all versions of a ValueSet by URL.
|
|
3080
|
+
*
|
|
3081
|
+
* @returns Array of stored ValueSets, ordered by version.
|
|
3082
|
+
*/
|
|
3083
|
+
getByUrl(url: string): Promise<StoredValueSet[]>;
|
|
3084
|
+
/**
|
|
3085
|
+
* Get all stored ValueSets.
|
|
3086
|
+
*/
|
|
3087
|
+
getAll(): Promise<StoredValueSet[]>;
|
|
3088
|
+
/**
|
|
3089
|
+
* Remove a specific ValueSet by url and version.
|
|
3090
|
+
*/
|
|
3091
|
+
remove(url: string, version: string): Promise<void>;
|
|
3092
|
+
/**
|
|
3093
|
+
* Get the total number of stored ValueSets.
|
|
3094
|
+
*/
|
|
3095
|
+
getValueSetCount(): Promise<number>;
|
|
3096
|
+
/**
|
|
3097
|
+
* Remove all stored ValueSets.
|
|
3098
|
+
*/
|
|
3099
|
+
clear(): Promise<void>;
|
|
3100
|
+
}
|
|
3101
|
+
|
|
3102
|
+
/**
|
|
3103
|
+
* A SQL WHERE clause fragment with parameterized values.
|
|
3104
|
+
*
|
|
3105
|
+
* Used by `buildWhereFragment()` to produce composable SQL pieces.
|
|
3106
|
+
*/
|
|
3107
|
+
export declare interface WhereFragment {
|
|
3108
|
+
/** The SQL expression (e.g., `'"gender" = $1'`). */
|
|
3109
|
+
sql: string;
|
|
3110
|
+
/** The parameter values (e.g., `['male']`). */
|
|
3111
|
+
values: unknown[];
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
export { }
|