fhirsmith 0.14.2 → 0.15.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 +23 -0
- package/library/changelog.js +57 -0
- package/package.json +1 -1
- package/registry/crawler.js +17 -0
- package/registry/fhirsmith-releases.js +3 -6
- package/registry/model.js +3 -0
- package/registry/registry.js +21 -3
- package/tx/README.md +20 -4
- package/tx/cm/cm-api.js +25 -10
- package/tx/cm/cm-database.js +0 -4
- package/tx/cm/cm-package.js +53 -14
- package/tx/cs/cs-provider-api.js +22 -7
- package/tx/cs/cs-provider-list.js +10 -9
- package/tx/library/resource-ids.js +107 -0
- package/tx/library.js +96 -24
- package/tx/ocl/cm-ocl.cjs +23 -15
- package/tx/ocl/cs-ocl.cjs +9 -10
- package/tx/ocl/vs-ocl.cjs +17 -17
- package/tx/provider.js +80 -13
- package/tx/tx.fhir.org.yml +16 -8
- package/tx/tx.js +7 -1
- package/tx/vs/vs-api.js +25 -10
- package/tx/vs/vs-database.js +0 -4
- package/tx/vs/vs-package.js +48 -31
- package/tx/vs/vs-vsac.js +20 -5
- package/tx/workers/metadata.js +2 -1
- package/tx/workers/read.js +3 -18
package/tx/vs/vs-package.js
CHANGED
|
@@ -6,6 +6,7 @@ const { ValueSetDatabase } = require('./vs-database');
|
|
|
6
6
|
const { checkContained } = require('../library/canonical-resource');
|
|
7
7
|
const { VersionUtilities } = require('../../library/version-utilities');
|
|
8
8
|
const {validateParameter} = require("../../library/utilities");
|
|
9
|
+
const { applyIdPrefix, stripIdPrefix } = require('../library/resource-ids');
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Package-based ValueSet provider using shared database layer
|
|
@@ -78,6 +79,8 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
|
|
|
78
79
|
Object.defineProperty(vs, 'isCached', { value: true, enumerable: false, configurable: true, writable: true });
|
|
79
80
|
}
|
|
80
81
|
}
|
|
82
|
+
// nothing, unless the spaceId was assigned before the provider was initialized
|
|
83
|
+
this.#applyIdPrefix();
|
|
81
84
|
this.initialized = true;
|
|
82
85
|
}
|
|
83
86
|
|
|
@@ -212,7 +215,9 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
|
|
|
212
215
|
this._validateSearchParams(searchParams);
|
|
213
216
|
|
|
214
217
|
if (this.USE_DATABASE_SEARCH) {
|
|
215
|
-
|
|
218
|
+
const results = await this.database.search(this.spaceId, this.valueSetMap, searchParams, elements);
|
|
219
|
+
return this.#excludedIds.size === 0 ? results
|
|
220
|
+
: results.filter(r => !this.#excludedIds.has(stripIdPrefix((r.jsonObj || r).id, this.spaceId)));
|
|
216
221
|
} else {
|
|
217
222
|
const matches = [];
|
|
218
223
|
const seen = new Set(); // Track by URL to avoid duplicates from versioned keys
|
|
@@ -398,38 +403,19 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
|
|
|
398
403
|
}
|
|
399
404
|
|
|
400
405
|
async fetchValueSetById(id) {
|
|
401
|
-
|
|
406
|
+
// the map is keyed by the value set's own id (and its url); the value set itself
|
|
407
|
+
// carries the prefixed id, which is how a url key that happens to match is excluded
|
|
408
|
+
const vs = this.valueSetMap.get(stripIdPrefix(id, this.spaceId));
|
|
409
|
+
return vs && vs.id === id ? vs : null;
|
|
402
410
|
}
|
|
403
411
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const prefix = this.spaceId + '-';
|
|
411
|
-
const alreadyPrefixed = new Set();
|
|
412
|
-
|
|
413
|
-
// Get all current entries - we'll iterate and modify
|
|
414
|
-
const entries = Array.from(this.valueSetMap.entries());
|
|
415
|
-
|
|
416
|
-
// eslint-disable-next-line no-unused-vars
|
|
417
|
-
for (const [key, vs] of entries) {
|
|
418
|
-
// Skip if we've already processed this ValueSet instance
|
|
419
|
-
if (alreadyPrefixed.has(vs)) {
|
|
420
|
-
continue;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Update the id on the ValueSet itself
|
|
424
|
-
if (vs.id && !vs.id.startsWith(prefix)) {
|
|
425
|
-
const oldId = vs.id;
|
|
426
|
-
vs.id = prefix + oldId;
|
|
427
|
-
|
|
428
|
-
// Add to map under the new id as well
|
|
429
|
-
this.valueSetMap.set(vs.id, vs);
|
|
430
|
-
}
|
|
412
|
+
prefixIds() {
|
|
413
|
+
this.#applyIdPrefix();
|
|
414
|
+
}
|
|
431
415
|
|
|
432
|
-
|
|
416
|
+
#applyIdPrefix() {
|
|
417
|
+
for (const vs of new Set(this.valueSetMap.values())) {
|
|
418
|
+
applyIdPrefix(vs, this.spaceId);
|
|
433
419
|
}
|
|
434
420
|
}
|
|
435
421
|
|
|
@@ -438,7 +424,38 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
|
|
|
438
424
|
}
|
|
439
425
|
|
|
440
426
|
async listAllValueSets() {
|
|
441
|
-
|
|
427
|
+
const urls = await this.database.listAllValueSets();
|
|
428
|
+
return this.#excludedUrls.size === 0 ? urls : urls.filter(url => !this.#excludedUrls.has(url));
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// the value sets left out by excludeUrls - by url, and by their own (unprefixed) id
|
|
432
|
+
#excludedUrls = new Set();
|
|
433
|
+
#excludedIds = new Set();
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Leave out the value sets with any of these urls: they can't be fetched, and they aren't
|
|
437
|
+
* found by search. The FHIR core package's value sets are left out where hl7.terminology
|
|
438
|
+
* provides the same url (see Provider.applyTHOPrecedence). Must be called once the
|
|
439
|
+
* provider is initialized - the database is shared, so it isn't changed.
|
|
440
|
+
*
|
|
441
|
+
* @param {Set<string>} urls
|
|
442
|
+
*/
|
|
443
|
+
excludeUrls(urls) {
|
|
444
|
+
const excluded = new Set();
|
|
445
|
+
for (const vs of this.valueSetMap.values()) {
|
|
446
|
+
if (vs && urls.has(vs.url)) {
|
|
447
|
+
excluded.add(vs);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
for (const [key, vs] of [...this.valueSetMap]) {
|
|
451
|
+
if (excluded.has(vs)) {
|
|
452
|
+
this.valueSetMap.delete(key);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
for (const vs of excluded) {
|
|
456
|
+
this.#excludedUrls.add(vs.url);
|
|
457
|
+
this.#excludedIds.add(stripIdPrefix(vs.id, this.spaceId) ?? vs.id);
|
|
458
|
+
}
|
|
442
459
|
}
|
|
443
460
|
}
|
|
444
461
|
|
package/tx/vs/vs-vsac.js
CHANGED
|
@@ -6,6 +6,7 @@ const { ValueSetDatabase } = require('./vs-database');
|
|
|
6
6
|
const { VersionUtilities } = require('../../library/version-utilities');
|
|
7
7
|
const folders = require('../../library/folder-setup');
|
|
8
8
|
const {debugLog} = require("../operation-context");
|
|
9
|
+
const { applyIdPrefix, stripIdPrefix } = require("../library/resource-ids");
|
|
9
10
|
|
|
10
11
|
// Persisted watermark for the phase-1b _lastUpdated scan.
|
|
11
12
|
const VSAC_LAST_UPDATED_KEY = 'vsac_last_updated_date';
|
|
@@ -422,6 +423,10 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
422
423
|
}
|
|
423
424
|
}
|
|
424
425
|
}
|
|
426
|
+
// the value sets are served in this provider's id space
|
|
427
|
+
for (const vs of new Set(newMap.values())) {
|
|
428
|
+
applyIdPrefix(vs, this.spaceId);
|
|
429
|
+
}
|
|
425
430
|
// Atomic replacement of the map
|
|
426
431
|
this.valueSetMap = newMap;
|
|
427
432
|
}
|
|
@@ -466,7 +471,10 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
466
471
|
}
|
|
467
472
|
|
|
468
473
|
async fetchValueSetById(id) {
|
|
469
|
-
|
|
474
|
+
// the map is keyed by the value set's own id (and its url); the value set itself
|
|
475
|
+
// carries the prefixed id, which is how a url key that happens to match is excluded
|
|
476
|
+
const vs = this.valueSetMap.get(stripIdPrefix(id, this.spaceId));
|
|
477
|
+
return vs && vs.id === id ? await this.checkFullVS(vs) : null;
|
|
470
478
|
}
|
|
471
479
|
/**
|
|
472
480
|
* Searches for value sets based on criteria
|
|
@@ -556,9 +564,16 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
556
564
|
await this.database.close();
|
|
557
565
|
}
|
|
558
566
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
567
|
+
prefixIds() {
|
|
568
|
+
this.#applyIdPrefix();
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// the map is replaced every time it's reloaded from the database (see _reloadMap), and that
|
|
572
|
+
// can happen before or after the spaceId is assigned - so both prefix whatever is there
|
|
573
|
+
#applyIdPrefix() {
|
|
574
|
+
for (const vs of new Set(this.valueSetMap.values())) {
|
|
575
|
+
applyIdPrefix(vs, this.spaceId);
|
|
576
|
+
}
|
|
562
577
|
}
|
|
563
578
|
|
|
564
579
|
// when we get a valueset from vsac via search, the compose is not
|
|
@@ -898,7 +913,7 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
898
913
|
html += `<tr>`;
|
|
899
914
|
html += `<td>${escape(timeOnly(row.ts))}</td>`;
|
|
900
915
|
html += `<td><span style="color:${colour}">${label}</span></td>`;
|
|
901
|
-
html += `<td>${escape(this.urlTail(row.url) || '')} v <a href="../ValueSet/${escape(this.urlTail(row.url) || '')}-${escape(row.version || '')}">${escape(row.version || '')}</a></td>`;
|
|
916
|
+
html += `<td>${escape(this.urlTail(row.url) || '')} v <a href="../ValueSet/${escape(this.spaceId ? this.spaceId + '-' : '')}${escape(this.urlTail(row.url) || '')}-${escape(row.version || '')}">${escape(row.version || '')}</a></td>`;
|
|
902
917
|
html += `</tr>`;
|
|
903
918
|
}
|
|
904
919
|
}
|
package/tx/workers/metadata.js
CHANGED
|
@@ -202,7 +202,8 @@ class MetadataHandler {
|
|
|
202
202
|
software: {
|
|
203
203
|
name: this.config.softwareName || 'FHIR Terminology Server',
|
|
204
204
|
version: serverVersion,
|
|
205
|
-
|
|
205
|
+
// only when it's known - this used to fall back to the time of the request
|
|
206
|
+
...(this.config.releaseDate ? { releaseDate: this.config.releaseDate } : {})
|
|
206
207
|
},
|
|
207
208
|
implementation: {
|
|
208
209
|
description: `FHIR Server running at ${baseUrl}`,
|
package/tx/workers/read.js
CHANGED
|
@@ -61,21 +61,6 @@ class ReadWorker extends TerminologyWorker {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/**
|
|
65
|
-
* The resource as served at [type]/[id] must carry that id. Providers that
|
|
66
|
-
* share the server with others prefix their ids with a space id ("1-foo") but
|
|
67
|
-
* may keep the resource itself under its original id ("foo") - package
|
|
68
|
-
* ConceptMaps do - and then the HTML tabs, which link to [type]/[resource.id],
|
|
69
|
-
* point at a resource that doesn't exist (issue #256). Copy rather than
|
|
70
|
-
* mutate: the provider's object is shared and keyed on its original id.
|
|
71
|
-
*/
|
|
72
|
-
withId(json, id) {
|
|
73
|
-
if (!json || json.id === id) {
|
|
74
|
-
return json;
|
|
75
|
-
}
|
|
76
|
-
return { ...json, id: id };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
64
|
/**
|
|
80
65
|
* Handle CodeSystem read
|
|
81
66
|
*/
|
|
@@ -83,7 +68,7 @@ class ReadWorker extends TerminologyWorker {
|
|
|
83
68
|
let cs = this.provider.getCodeSystemById(this.opContext, id);
|
|
84
69
|
if (cs != null) {
|
|
85
70
|
req.sourcePackage = cs.sourcePackage;
|
|
86
|
-
return res.json(
|
|
71
|
+
return res.json(cs.jsonObj);
|
|
87
72
|
}
|
|
88
73
|
|
|
89
74
|
if (id.startsWith("x-")) {
|
|
@@ -142,7 +127,7 @@ class ReadWorker extends TerminologyWorker {
|
|
|
142
127
|
const vs = await vsp.fetchValueSetById(id);
|
|
143
128
|
if (vs) {
|
|
144
129
|
req.sourcePackage = vs.sourcePackage;
|
|
145
|
-
return res.json(
|
|
130
|
+
return res.json(vs.jsonObj);
|
|
146
131
|
}
|
|
147
132
|
}
|
|
148
133
|
|
|
@@ -158,7 +143,7 @@ class ReadWorker extends TerminologyWorker {
|
|
|
158
143
|
const cm = await cmsp.fetchConceptMapById(id);
|
|
159
144
|
if (cm) {
|
|
160
145
|
req.sourcePackage = cm.sourcePackage;
|
|
161
|
-
return res.json(
|
|
146
|
+
return res.json(cm.jsonObj);
|
|
162
147
|
}
|
|
163
148
|
}
|
|
164
149
|
|