fhirsmith 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +2 -0
- package/configurations/projector.json +21 -0
- package/configurations/readme.md +5 -0
- package/library/package-manager.js +0 -2
- package/library/version-utilities.js +85 -0
- package/package.json +1 -1
- package/packages/package-crawler.js +44 -9
- package/packages/packages.js +1 -0
- package/registry/crawler.js +35 -14
- package/registry/registry.js +3 -0
- package/server.js +4 -0
- package/tx/README.md +4 -4
- package/tx/cs/cs-loinc.js +5 -2
- package/tx/cs/cs-provider-api.js +25 -1
- package/tx/cs/cs-provider-list.js +2 -2
- package/tx/library/canonical-resource.js +6 -1
- package/tx/library.js +127 -10
- package/tx/ocl/README.md +236 -0
- package/tx/ocl/cache/cache-paths.cjs +32 -0
- package/tx/ocl/cache/cache-paths.js +2 -0
- package/tx/ocl/cache/cache-utils.cjs +43 -0
- package/tx/ocl/cache/cache-utils.js +2 -0
- package/tx/ocl/cm-ocl.cjs +531 -0
- package/tx/ocl/cm-ocl.js +1 -105
- package/tx/ocl/cs-ocl.cjs +1779 -0
- package/tx/ocl/cs-ocl.js +1 -38
- package/tx/ocl/fingerprint/fingerprint.cjs +67 -0
- package/tx/ocl/fingerprint/fingerprint.js +2 -0
- package/tx/ocl/http/client.cjs +31 -0
- package/tx/ocl/http/client.js +2 -0
- package/tx/ocl/http/pagination.cjs +98 -0
- package/tx/ocl/http/pagination.js +2 -0
- package/tx/ocl/jobs/background-queue.cjs +200 -0
- package/tx/ocl/jobs/background-queue.js +2 -0
- package/tx/ocl/mappers/concept-mapper.cjs +66 -0
- package/tx/ocl/mappers/concept-mapper.js +2 -0
- package/tx/ocl/model/concept-filter-context.cjs +51 -0
- package/tx/ocl/model/concept-filter-context.js +2 -0
- package/tx/ocl/shared/constants.cjs +15 -0
- package/tx/ocl/shared/constants.js +2 -0
- package/tx/ocl/shared/patches.cjs +224 -0
- package/tx/ocl/shared/patches.js +2 -0
- package/tx/ocl/vs-ocl.cjs +1848 -0
- package/tx/ocl/vs-ocl.js +1 -104
- package/tx/operation-context.js +8 -1
- package/tx/params.js +24 -3
- package/tx/provider.js +47 -0
- package/tx/tx-html.js +1 -1
- package/tx/tx.js +8 -0
- package/tx/vs/vs-vsac.js +4 -3
- package/tx/workers/batch-validate.js +3 -2
- package/tx/workers/batch.js +3 -2
- package/tx/workers/expand.js +64 -9
- package/tx/workers/lookup.js +5 -4
- package/tx/workers/read.js +2 -1
- package/tx/workers/related.js +3 -2
- package/tx/workers/search.js +4 -9
- package/tx/workers/subsumes.js +3 -2
- package/tx/workers/translate.js +4 -3
- package/tx/workers/validate.js +132 -40
- package/tx/workers/worker.js +1 -7
package/tx/ocl/vs-ocl.js
CHANGED
|
@@ -1,105 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Abstract base class for value set providers
|
|
3
|
-
* Defines the interface that all value set providers must implement
|
|
4
|
-
*/
|
|
5
|
-
// eslint-disable-next-line no-unused-vars
|
|
6
|
-
class OCLValueSetProvider {
|
|
7
|
-
/**
|
|
8
|
-
* {int} Unique number assigned to this provider
|
|
9
|
-
*/
|
|
10
|
-
spaceId;
|
|
1
|
+
module.exports = require('./vs-ocl.cjs');
|
|
11
2
|
|
|
12
|
-
/**
|
|
13
|
-
* ensure that the ids on the value sets are unique, if they are
|
|
14
|
-
* in the global namespace
|
|
15
|
-
*
|
|
16
|
-
* @param {Set<String>} ids
|
|
17
|
-
*/
|
|
18
|
-
// eslint-disable-next-line no-unused-vars
|
|
19
|
-
assignIds(ids) {
|
|
20
|
-
throw new Error('assignIds must be implemented by AbstractValueSetProvider subclass');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Fetches a specific value set by URL and version
|
|
25
|
-
* @param {string} url - The URL/identifier of the value set
|
|
26
|
-
* @param {string} version - The version of the value set
|
|
27
|
-
* @returns {Promise<ValueSet>} The requested value set
|
|
28
|
-
* @throws {Error} Must be implemented by subclasses
|
|
29
|
-
*/
|
|
30
|
-
// eslint-disable-next-line no-unused-vars
|
|
31
|
-
async fetchValueSet(url, version) {
|
|
32
|
-
throw new Error('fetchValueSet must be implemented by subclass');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Fetches a specific value set by id. ValueSet providers must enforce that value set ids are unique
|
|
37
|
-
* either globally (as enforced by assignIds) or in their space
|
|
38
|
-
*
|
|
39
|
-
* @param {string} id - The id of the value set
|
|
40
|
-
* @returns {Promise<ValueSet>} The requested value set
|
|
41
|
-
* @throws {Error} Must be implemented by subclasses
|
|
42
|
-
*/
|
|
43
|
-
// eslint-disable-next-line no-unused-vars
|
|
44
|
-
async fetchValueSetById(id) {
|
|
45
|
-
throw new Error('fetchValueSetById must be implemented by subclass');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Searches for value sets based on provided criteria
|
|
50
|
-
* @param {Array<{name: string, value: string}>} searchParams - List of name/value pairs for search criteria
|
|
51
|
-
* @returns {Promise<Array<ValueSet>>} List of matching value sets
|
|
52
|
-
* @throws {Error} Must be implemented by subclasses
|
|
53
|
-
*/
|
|
54
|
-
// eslint-disable-next-line no-unused-vars
|
|
55
|
-
async searchValueSets(searchParams, elements = null) {
|
|
56
|
-
throw new Error('searchValueSets must be implemented by subclass');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
*
|
|
61
|
-
* @returns {number} total number of value sets
|
|
62
|
-
*/
|
|
63
|
-
vsCount() {
|
|
64
|
-
return 0;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Validates search parameters
|
|
69
|
-
* @param {Array<{name: string, value: string}>} searchParams - Search parameters to validate
|
|
70
|
-
* @protected
|
|
71
|
-
*/
|
|
72
|
-
_validateSearchParams(searchParams) {
|
|
73
|
-
if (!Array.isArray(searchParams)) {
|
|
74
|
-
throw new Error('Search parameters must be an array');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
for (const param of searchParams) {
|
|
78
|
-
if (!param || typeof param !== 'object') {
|
|
79
|
-
throw new Error('Each search parameter must be an object');
|
|
80
|
-
}
|
|
81
|
-
if (typeof param.name !== 'string' || typeof param.value !== 'string') {
|
|
82
|
-
throw new Error('Search parameter must have string name and value properties');
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Validates URL and version parameters
|
|
89
|
-
* @param {string} url - URL to validate
|
|
90
|
-
* @param {string} version - Version to validate
|
|
91
|
-
* @protected
|
|
92
|
-
*/
|
|
93
|
-
_validateFetchParams(url, version) {
|
|
94
|
-
if (typeof url !== 'string' || !url.trim()) {
|
|
95
|
-
throw new Error('URL must be a non-empty string');
|
|
96
|
-
}
|
|
97
|
-
if (version != null && typeof version !== 'string') {
|
|
98
|
-
throw new Error('Version must be a string');
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
module.exports = {
|
|
104
|
-
AbstractValueSetProvider
|
|
105
|
-
};
|
package/tx/operation-context.js
CHANGED
|
@@ -19,6 +19,12 @@ function isDebugging() {
|
|
|
19
19
|
);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function debugLog(error, message) {
|
|
23
|
+
if (isDebugging()) {
|
|
24
|
+
console.log(error, message);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
|
|
23
29
|
class TimeTracker {
|
|
24
30
|
constructor() {
|
|
@@ -584,5 +590,6 @@ module.exports = {
|
|
|
584
590
|
TimeTracker,
|
|
585
591
|
ResourceCache,
|
|
586
592
|
ExpansionCache,
|
|
587
|
-
isDebugging
|
|
593
|
+
isDebugging,
|
|
594
|
+
debugLog
|
|
588
595
|
};
|
package/tx/params.js
CHANGED
|
@@ -66,6 +66,7 @@ class TxParameters {
|
|
|
66
66
|
this.FDisplayWarning = false;
|
|
67
67
|
this.FMembershipOnly = false;
|
|
68
68
|
this.FDiagnostics = false;
|
|
69
|
+
this.FVersionsMatch = false;
|
|
69
70
|
|
|
70
71
|
this.hasActiveOnly = false;
|
|
71
72
|
this.hasExcludeNested = false;
|
|
@@ -77,6 +78,7 @@ class TxParameters {
|
|
|
77
78
|
this.hasDefaultToLatestVersion = false;
|
|
78
79
|
this.hasDisplayWarning = false;
|
|
79
80
|
this.hasMembershipOnly = false;
|
|
81
|
+
this.hasVersionsMatch = false;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
readParams(params) {
|
|
@@ -199,6 +201,10 @@ class TxParameters {
|
|
|
199
201
|
if (getValuePrimitive(p) == true) this.membershipOnly = true;
|
|
200
202
|
break;
|
|
201
203
|
}
|
|
204
|
+
case 'versionsMatch' : {
|
|
205
|
+
if (getValuePrimitive(p) == true) this.FVersionsMatch = true;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
202
208
|
case 'profile' : {
|
|
203
209
|
let value = p.resource;
|
|
204
210
|
if (value && (value.resourceType === 'Parameters' || value.resourceType === 'ExpansionProfile')) {
|
|
@@ -387,6 +393,15 @@ class TxParameters {
|
|
|
387
393
|
this.hasMembershipOnly = true;
|
|
388
394
|
}
|
|
389
395
|
|
|
396
|
+
get versionsMatch() {
|
|
397
|
+
return this.FVersionsMatch;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
set versionsMatch(value) {
|
|
401
|
+
this.FVersionsMatch = value;
|
|
402
|
+
this.hasVersionsMatch = true;
|
|
403
|
+
}
|
|
404
|
+
e
|
|
390
405
|
get versionRules() {
|
|
391
406
|
return this.FVersionRules;
|
|
392
407
|
}
|
|
@@ -412,6 +427,10 @@ class TxParameters {
|
|
|
412
427
|
if (name === 'designation') {
|
|
413
428
|
this.designations.push(getValuePrimitive(value));
|
|
414
429
|
}
|
|
430
|
+
|
|
431
|
+
if (name === 'versionsMatch') {
|
|
432
|
+
this.versionsMatch = getValuePrimitive(value) === 'true';
|
|
433
|
+
}
|
|
415
434
|
}
|
|
416
435
|
}
|
|
417
436
|
|
|
@@ -502,6 +521,7 @@ class TxParameters {
|
|
|
502
521
|
b('include-designations', this.FIncludeDesignations);
|
|
503
522
|
b('include-definition', this.FIncludeDefinition);
|
|
504
523
|
b('membership-only', this.FMembershipOnly);
|
|
524
|
+
b('versions-match', this.FVersionsMatch);
|
|
505
525
|
b('default-to-latest', this.FDefaultToLatestVersion);
|
|
506
526
|
b('display-warning', this.FDisplayWarning);
|
|
507
527
|
|
|
@@ -526,11 +546,11 @@ class TxParameters {
|
|
|
526
546
|
};
|
|
527
547
|
|
|
528
548
|
let s = '|'+this.count+'|'+this.limit+'|'+this.offset+
|
|
529
|
-
this.FUid + '|' + b(this.FMembershipOnly) + '|' + this.FProperties.join(',') + '|' +
|
|
549
|
+
this.FUid + '|' + b(this.FMembershipOnly) + '|' + b(this.FVersionsMatch)+'|' + this.FProperties.join(',') + '|' +
|
|
530
550
|
b(this.FActiveOnly) + b(this.FDisplayWarning) + b(this.FExcludeNested) + b(this.FGenerateNarrative) + b(this.FExcludeNotForUI) + b(this.FExcludePostCoordinated) +
|
|
531
551
|
b(this.FIncludeDesignations) + b(this.FIncludeDefinition) + b(this.hasActiveOnly) + b(this.hasExcludeNested) + b(this.hasGenerateNarrative) +
|
|
532
552
|
b(this.hasExcludeNotForUI) + b(this.hasExcludePostCoordinated) + b(this.hasIncludeDesignations) + this.sort+'|'+
|
|
533
|
-
b(this.hasIncludeDefinition) + b(this.hasDefaultToLatestVersion) + b(this.hasDisplayWarning) + b(this.hasExcludeNotForUI) + b(this.hasMembershipOnly) + b(this.FDefaultToLatestVersion);
|
|
553
|
+
b(this.hasIncludeDefinition) + b(this.hasDefaultToLatestVersion) + b(this.hasDisplayWarning) + b(this.hasExcludeNotForUI) + b(this.hasMembershipOnly) + b(this.hasVersionsMatch) + b(this.FDefaultToLatestVersion);
|
|
534
554
|
|
|
535
555
|
if (this.hasHTTPLanguages) {
|
|
536
556
|
s = s + this.FHTTPLanguages.asString(true) + '|';
|
|
@@ -577,6 +597,7 @@ class TxParameters {
|
|
|
577
597
|
this.FIncludeDefinition = other.FIncludeDefinition;
|
|
578
598
|
this.FUid = other.FUid;
|
|
579
599
|
this.FMembershipOnly = other.FMembershipOnly;
|
|
600
|
+
this.FVersionsMatch = other.FVersionsMatch;
|
|
580
601
|
this.FDefaultToLatestVersion = other.FDefaultToLatestVersion;
|
|
581
602
|
this.FDisplayWarning = other.FDisplayWarning;
|
|
582
603
|
this.FDiagnostics = other.FDiagnostics;
|
|
@@ -588,7 +609,7 @@ class TxParameters {
|
|
|
588
609
|
this.hasIncludeDesignations = other.hasIncludeDesignations;
|
|
589
610
|
this.hasIncludeDefinition = other.hasIncludeDefinition;
|
|
590
611
|
this.hasDefaultToLatestVersion = other.hasDefaultToLatestVersion;
|
|
591
|
-
this.
|
|
612
|
+
this.hasVersionsMatch = other.hasVersionsMatch;
|
|
592
613
|
this.hasDisplayWarning = other.hasDisplayWarning;
|
|
593
614
|
this.sort = other.sort;
|
|
594
615
|
|
package/tx/provider.js
CHANGED
|
@@ -23,6 +23,7 @@ const {PackageConceptMapProvider} = require("./cm/cm-package");
|
|
|
23
23
|
class Provider {
|
|
24
24
|
i18n;
|
|
25
25
|
fhirVersion;
|
|
26
|
+
context;
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* {Map<String, CodeSystemFactoryProvider>} A list of code system factories that contains all the preloaded native code systems
|
|
@@ -34,6 +35,11 @@ class Provider {
|
|
|
34
35
|
*/
|
|
35
36
|
codeSystems;
|
|
36
37
|
|
|
38
|
+
/**
|
|
39
|
+
* {List<AbstractCodeSystemProvider>} code system providers, for maintaing the code system list
|
|
40
|
+
*/
|
|
41
|
+
codeSystemProviders
|
|
42
|
+
|
|
37
43
|
/**
|
|
38
44
|
* {List<AbstractValueSetProvider>} A list of value set providers that know how to provide value sets by request
|
|
39
45
|
*/
|
|
@@ -425,6 +431,47 @@ class Provider {
|
|
|
425
431
|
}
|
|
426
432
|
}
|
|
427
433
|
return false;
|
|
434
|
+
}x
|
|
435
|
+
|
|
436
|
+
async updateCodeSystemList() {
|
|
437
|
+
for (let csp of this.codeSystemProviders) {
|
|
438
|
+
let changes = await csp.getCodeSystemChanges(this.fhirVersion, this.context);
|
|
439
|
+
if (changes) {
|
|
440
|
+
for (let cs of changes.added || []) {
|
|
441
|
+
this.addCodeSystem(cs);
|
|
442
|
+
}
|
|
443
|
+
for (let cs of changes.changed || []) {
|
|
444
|
+
this.addCodeSystem(cs);
|
|
445
|
+
}
|
|
446
|
+
for (let cs of changes.deleted || []) {
|
|
447
|
+
this.deleteCodeSystem(cs);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
addCodeSystem(cs) {
|
|
454
|
+
const existing = this.codeSystems.get(cs.url);
|
|
455
|
+
if (!existing || cs.isMoreRecent(existing)) {
|
|
456
|
+
this.codeSystems.set(cs.url, cs);
|
|
457
|
+
}
|
|
458
|
+
if (cs.version) {
|
|
459
|
+
this.codeSystems.set(cs.vurl, cs);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
deleteCodeSystem(cs) {
|
|
464
|
+
this.codeSystems.delete(cs.vurl);
|
|
465
|
+
this.codeSystems.delete(cs.url);
|
|
466
|
+
let existing = null;
|
|
467
|
+
for (let t of this.codeSystems.values()) {
|
|
468
|
+
if (!existing || t.isMoreRecent(existing)) {
|
|
469
|
+
existing = t;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (existing) {
|
|
473
|
+
this.codeSystems.set(cs.url, cs);
|
|
474
|
+
}
|
|
428
475
|
}
|
|
429
476
|
|
|
430
477
|
}
|
package/tx/tx-html.js
CHANGED
|
@@ -1246,7 +1246,7 @@ class TxHtmlRenderer {
|
|
|
1246
1246
|
}
|
|
1247
1247
|
|
|
1248
1248
|
buildSourceOptions(provider) {
|
|
1249
|
-
let result = '';
|
|
1249
|
+
let result = '<option value=""></option>';
|
|
1250
1250
|
result += `<option value="internal">internal</option>`;
|
|
1251
1251
|
for (let sp of provider.listValueSetSourceCodes()) {
|
|
1252
1252
|
result += `<option value="${sp}">${sp}</option>`;
|
package/tx/tx.js
CHANGED
|
@@ -247,6 +247,14 @@ class TXModule {
|
|
|
247
247
|
if (this.stats) {
|
|
248
248
|
this.stats.addTask("Client Cache", "5 min");
|
|
249
249
|
}
|
|
250
|
+
this.timers.push(setInterval(async () => {
|
|
251
|
+
try {
|
|
252
|
+
await endpointInfo.provider.updateCodeSystemList();
|
|
253
|
+
} catch (error) {
|
|
254
|
+
this.log.error(`Error updating CodeSystem list for ${endpointPath}: ${error.message}`);
|
|
255
|
+
}
|
|
256
|
+
}, 60 * 1000));
|
|
257
|
+
this.log.info(`CodeSystem list update scheduled for ${endpointPath}`);
|
|
250
258
|
this.timers.push(setInterval(() => {
|
|
251
259
|
endpointInfo.resourceCache.prune(cacheTimeoutMs);
|
|
252
260
|
}, pruneIntervalMs));
|
package/tx/vs/vs-vsac.js
CHANGED
|
@@ -4,6 +4,7 @@ const { AbstractValueSetProvider } = require('./vs-api');
|
|
|
4
4
|
const { ValueSetDatabase } = require('./vs-database');
|
|
5
5
|
const { VersionUtilities } = require('../../library/version-utilities');
|
|
6
6
|
const folders = require('../../library/folder-setup');
|
|
7
|
+
const {debugLog} = require("../operation-context");
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* VSAC (Value Set Authority Center) ValueSet provider
|
|
@@ -178,7 +179,7 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
178
179
|
await this.processContentAndHistory(q, tracking, this.queue.length);
|
|
179
180
|
} catch (error) {
|
|
180
181
|
this.requeue.push(q)
|
|
181
|
-
|
|
182
|
+
debugLog(error);
|
|
182
183
|
this.stats.task('VSAC Sync', error.message);
|
|
183
184
|
}
|
|
184
185
|
// `running (${totalFetched} fetched, ${totalNew} new)`)
|
|
@@ -190,7 +191,7 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
190
191
|
try {
|
|
191
192
|
await this.processContentAndHistory(q, tracking, this.requeue.length);
|
|
192
193
|
} catch (error) {
|
|
193
|
-
|
|
194
|
+
debugLog(error);
|
|
194
195
|
this.stats.task('VSAC Sync', error.message);
|
|
195
196
|
}
|
|
196
197
|
// `running (${totalFetched} fetched, ${totalNew} new)`)
|
|
@@ -201,7 +202,7 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
201
202
|
await this._reloadMap();
|
|
202
203
|
console.log(`VSAC refresh completed. Total: ${tracking.totalFetched} ValueSets, Deleted: ${tracking.deletedCount}`);
|
|
203
204
|
} catch (error) {
|
|
204
|
-
|
|
205
|
+
debugLog(error, 'Error during VSAC refresh:');
|
|
205
206
|
this.stats.task('VSAC Sync', `Error (${error.message})`);
|
|
206
207
|
throw error;
|
|
207
208
|
} finally {
|
|
@@ -15,6 +15,7 @@ const { TerminologyWorker } = require('./worker');
|
|
|
15
15
|
const {OperationOutcome, Issue} = require("../library/operation-outcome");
|
|
16
16
|
const {Parameters} = require("../library/parameters");
|
|
17
17
|
const {ValidateWorker} = require("./validate");
|
|
18
|
+
const {debugLog} = require("../operation-context");
|
|
18
19
|
|
|
19
20
|
class BatchValidateWorker extends TerminologyWorker {
|
|
20
21
|
|
|
@@ -82,7 +83,7 @@ class BatchValidateWorker extends TerminologyWorker {
|
|
|
82
83
|
output.push({name: "validation", resource : p});
|
|
83
84
|
} catch (error) {
|
|
84
85
|
this.log.error(error);
|
|
85
|
-
|
|
86
|
+
debugLog(error);
|
|
86
87
|
if (error instanceof Issue) {
|
|
87
88
|
let op = new OperationOutcome();
|
|
88
89
|
op.addIssue(error);
|
|
@@ -98,7 +99,7 @@ class BatchValidateWorker extends TerminologyWorker {
|
|
|
98
99
|
return res.json(result);
|
|
99
100
|
} catch (error) {
|
|
100
101
|
this.log.error(error);
|
|
101
|
-
|
|
102
|
+
debugLog(error);
|
|
102
103
|
return res.status(error.statusCode || 500).json(this.operationOutcome(
|
|
103
104
|
'error', error.issueCode || 'exception', error.message));
|
|
104
105
|
}
|
package/tx/workers/batch.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const { TerminologyWorker } = require('./worker');
|
|
8
8
|
const { Issue, OperationOutcome } = require('../library/operation-outcome');
|
|
9
|
+
const {debugLog} = require("../operation-context");
|
|
9
10
|
|
|
10
11
|
class BatchWorker extends TerminologyWorker {
|
|
11
12
|
/**
|
|
@@ -40,7 +41,7 @@ class BatchWorker extends TerminologyWorker {
|
|
|
40
41
|
await this.handleBatch(req, res);
|
|
41
42
|
} catch (error) {
|
|
42
43
|
this.log.error(error);
|
|
43
|
-
|
|
44
|
+
debugLog(error);
|
|
44
45
|
if (error instanceof Issue) {
|
|
45
46
|
const oo = new OperationOutcome();
|
|
46
47
|
oo.addIssue(error);
|
|
@@ -160,7 +161,7 @@ class BatchWorker extends TerminologyWorker {
|
|
|
160
161
|
|
|
161
162
|
} catch (error) {
|
|
162
163
|
this.log.error(error);
|
|
163
|
-
|
|
164
|
+
debugLog(error);
|
|
164
165
|
const statusCode = error.statusCode || 500;
|
|
165
166
|
const issueCode = error.issueCode || 'exception';
|
|
166
167
|
|
package/tx/workers/expand.js
CHANGED
|
@@ -18,6 +18,7 @@ const {Issue, OperationOutcome} = require("../library/operation-outcome");
|
|
|
18
18
|
const crypto = require('crypto');
|
|
19
19
|
const ValueSet = require("../library/valueset");
|
|
20
20
|
const {VersionUtilities} = require("../../library/version-utilities");
|
|
21
|
+
const {debugLog} = require("../operation-context");
|
|
21
22
|
|
|
22
23
|
// Expansion limits (from Pascal constants)
|
|
23
24
|
const EXTERNAL_DEFAULT_LIMIT = 1000;
|
|
@@ -197,6 +198,7 @@ class ValueSetCounter {
|
|
|
197
198
|
class ValueSetExpander {
|
|
198
199
|
worker;
|
|
199
200
|
params;
|
|
201
|
+
doingVersion = true;
|
|
200
202
|
excludedSystems = new Set();
|
|
201
203
|
excluded = new Set();
|
|
202
204
|
hasExclusions = false;
|
|
@@ -495,7 +497,8 @@ class ValueSetExpander {
|
|
|
495
497
|
}
|
|
496
498
|
}
|
|
497
499
|
|
|
498
|
-
this.
|
|
500
|
+
let key = (this.doingVersion && !this.params.versionsMatch ? system + '|' + version : system) + '#' + code
|
|
501
|
+
this.excluded.add(key);
|
|
499
502
|
}
|
|
500
503
|
|
|
501
504
|
async checkCanExpandValueSet(uri, version) {
|
|
@@ -922,8 +925,20 @@ class ValueSetExpander {
|
|
|
922
925
|
if (!cset.concept && !cset.filter) {
|
|
923
926
|
this.worker.opContext.log('handle system');
|
|
924
927
|
if (!cset.valueSet) {
|
|
925
|
-
|
|
926
|
-
|
|
928
|
+
if (!this.excludeSpecialCase) {
|
|
929
|
+
// excluding a whole system - we don't list the codes in this case
|
|
930
|
+
this.excludedSystems.add(cset.system + (this.doingVersion && cset.version ? '|' + cset.version : ''));
|
|
931
|
+
} else {
|
|
932
|
+
const iter = await cs.iteratorAll();
|
|
933
|
+
if (iter) {
|
|
934
|
+
let c = await cs.nextContext(iter);
|
|
935
|
+
while (c) {
|
|
936
|
+
this.worker.deadCheck('processCodes#3aa');
|
|
937
|
+
this.excludeCode(cs, cs.system(), cs.version(), await cs.code(c), expansion, valueSets, vsSrc.url);
|
|
938
|
+
c = await cs.nextContext(iter);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
}
|
|
927
942
|
} else {
|
|
928
943
|
if (cs.isNotClosed(filter)) {
|
|
929
944
|
if (cs.specialEnumeration()) {
|
|
@@ -1081,6 +1096,7 @@ class ValueSetExpander {
|
|
|
1081
1096
|
async handleCompose(source, filter, expansion, notClosed, vsInfo) {
|
|
1082
1097
|
this.worker.opContext.log('compose #1');
|
|
1083
1098
|
|
|
1099
|
+
this.doingVersion = false;
|
|
1084
1100
|
const ts = new Map();
|
|
1085
1101
|
for (const c of source.jsonObj.compose.include || []) {
|
|
1086
1102
|
this.worker.deadCheck('handleCompose#2');
|
|
@@ -1097,6 +1113,8 @@ class ValueSetExpander {
|
|
|
1097
1113
|
if (vsInfo.handleByCS) {
|
|
1098
1114
|
await this.processCodes("ValueSet.compose", source, source.jsonObj.compose, filter, expansion, this.excludeInactives(source), notClosed, vsInfo);
|
|
1099
1115
|
} else {
|
|
1116
|
+
this.checkForExclusionVersionSpecialCase(source, expansion);
|
|
1117
|
+
|
|
1100
1118
|
let i = 0;
|
|
1101
1119
|
for (const c of source.jsonObj.compose.exclude || []) {
|
|
1102
1120
|
this.worker.deadCheck('handleCompose#4');
|
|
@@ -1104,7 +1122,14 @@ class ValueSetExpander {
|
|
|
1104
1122
|
}
|
|
1105
1123
|
|
|
1106
1124
|
i = 0;
|
|
1107
|
-
|
|
1125
|
+
const includes = [...(source.jsonObj.compose.include || [])];
|
|
1126
|
+
includes.sort((a, b) => {
|
|
1127
|
+
if (a.system === b.system && a.version && b.version) {
|
|
1128
|
+
return -VersionUtilities.compareVersionsGeneral(a.version, b.version);
|
|
1129
|
+
}
|
|
1130
|
+
return 0;
|
|
1131
|
+
});
|
|
1132
|
+
for (const c of includes) {
|
|
1108
1133
|
this.worker.deadCheck('handleCompose#5');
|
|
1109
1134
|
await this.includeCodes(c, "ValueSet.compose.include[" + i + "]", source, source.jsonObj.compose, filter, expansion, this.excludeInactives(source), notClosed);
|
|
1110
1135
|
i++;
|
|
@@ -1197,6 +1222,9 @@ class ValueSetExpander {
|
|
|
1197
1222
|
if (this.params.hasExcludeNested) {
|
|
1198
1223
|
this.addParamBool(exp, 'excludeNested', this.params.excludeNested);
|
|
1199
1224
|
}
|
|
1225
|
+
if (this.params.versionsMatch) {
|
|
1226
|
+
this.addParamBool(exp, 'versionsMatch', this.params.versionsMatch);
|
|
1227
|
+
}
|
|
1200
1228
|
if (this.params.hasActiveOnly) {
|
|
1201
1229
|
this.addParamBool(exp, 'activeOnly', this.params.activeOnly);
|
|
1202
1230
|
}
|
|
@@ -1481,14 +1509,16 @@ class ValueSetExpander {
|
|
|
1481
1509
|
if (this.excludedSystems.has(system)) {
|
|
1482
1510
|
return true;
|
|
1483
1511
|
}
|
|
1484
|
-
|
|
1512
|
+
let key = this.doingVersion && !this.params.versionsMatch? system+'|'+version : system;
|
|
1513
|
+
if (this.excludedSystems.has(key)) {
|
|
1485
1514
|
return true;
|
|
1486
1515
|
}
|
|
1487
|
-
|
|
1516
|
+
key = (this.doingVersion && !this.params.versionsMatch ? system+'|'+version : system)+'#'+code;
|
|
1517
|
+
return this.excluded.has(key);
|
|
1488
1518
|
}
|
|
1489
1519
|
|
|
1490
1520
|
keyS(system, version, code) {
|
|
1491
|
-
return system+"~"+(this.doingVersion ? version+"~" : "")+code;
|
|
1521
|
+
return system+"~"+(this.doingVersion && !this.params.versionsMatch ? version+"~" : "")+code;
|
|
1492
1522
|
}
|
|
1493
1523
|
|
|
1494
1524
|
keyC(contains) {
|
|
@@ -1636,6 +1666,31 @@ class ValueSetExpander {
|
|
|
1636
1666
|
}
|
|
1637
1667
|
return null;
|
|
1638
1668
|
}
|
|
1669
|
+
|
|
1670
|
+
|
|
1671
|
+
// special case: excluding a different version from the include
|
|
1672
|
+
checkForExclusionVersionSpecialCase(source, exp) {
|
|
1673
|
+
if (!this.params.hasVersionsMatch) {
|
|
1674
|
+
|
|
1675
|
+
|
|
1676
|
+
const includes = source.jsonObj.compose.include || [];
|
|
1677
|
+
const excludes = source.jsonObj.compose.exclude || [];
|
|
1678
|
+
|
|
1679
|
+
if (includes.length > 0 && excludes.length > 0) {
|
|
1680
|
+
const system = includes[0].system;
|
|
1681
|
+
const allSameSystem = includes.every(i => i.system === system && i.version)
|
|
1682
|
+
&& excludes.every(e => e.system === system && e.version);
|
|
1683
|
+
const noOverlap = !includes.some(i => excludes.some(e => e.version === i.version));
|
|
1684
|
+
|
|
1685
|
+
if (allSameSystem && noOverlap) {
|
|
1686
|
+
this.params.versionsMatch = true;
|
|
1687
|
+
this.excludeSpecialCase = true;
|
|
1688
|
+
this.addParamBool(exp, 'versionsMatch', this.params.versionsMatch);
|
|
1689
|
+
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1639
1694
|
}
|
|
1640
1695
|
|
|
1641
1696
|
class ExpandWorker extends TerminologyWorker {
|
|
@@ -1676,7 +1731,7 @@ class ExpandWorker extends TerminologyWorker {
|
|
|
1676
1731
|
await this.handleTypeLevelExpand(req, res);
|
|
1677
1732
|
} catch (error) {
|
|
1678
1733
|
this.log.error(error);
|
|
1679
|
-
|
|
1734
|
+
debugLog(error);
|
|
1680
1735
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
1681
1736
|
const statusCode = error.statusCode || 500;
|
|
1682
1737
|
if (error instanceof Issue) {
|
|
@@ -1711,7 +1766,7 @@ class ExpandWorker extends TerminologyWorker {
|
|
|
1711
1766
|
await this.handleInstanceLevelExpand(req, res);
|
|
1712
1767
|
} catch (error) {
|
|
1713
1768
|
this.log.error(error);
|
|
1714
|
-
|
|
1769
|
+
debugLog(error);
|
|
1715
1770
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
1716
1771
|
const statusCode = error.statusCode || 500;
|
|
1717
1772
|
const issueCode = error.issueCode || 'exception';
|
package/tx/workers/lookup.js
CHANGED
|
@@ -13,6 +13,7 @@ const { Designations} = require("../library/designations");
|
|
|
13
13
|
const {TxParameters} = require("../params");
|
|
14
14
|
const {Parameters} = require("../library/parameters");
|
|
15
15
|
const {Issue, OperationOutcome} = require("../library/operation-outcome");
|
|
16
|
+
const {debugLog} = require("../operation-context");
|
|
16
17
|
|
|
17
18
|
class LookupWorker extends TerminologyWorker {
|
|
18
19
|
/**
|
|
@@ -45,7 +46,7 @@ class LookupWorker extends TerminologyWorker {
|
|
|
45
46
|
await this.handleTypeLevelLookup(req, res);
|
|
46
47
|
} catch (error) {
|
|
47
48
|
this.log.error(error);
|
|
48
|
-
|
|
49
|
+
debugLog(error);
|
|
49
50
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
50
51
|
const statusCode = error.statusCode || 500;
|
|
51
52
|
const issueCode = error.issueCode || 'exception';
|
|
@@ -72,7 +73,7 @@ class LookupWorker extends TerminologyWorker {
|
|
|
72
73
|
await this.handleInstanceLevelLookup(req, res);
|
|
73
74
|
} catch (error) {
|
|
74
75
|
this.log.error(error);
|
|
75
|
-
|
|
76
|
+
debugLog(error);
|
|
76
77
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
77
78
|
const issueCode = error.issueCode || 'exception';
|
|
78
79
|
return res.status(400).json({
|
|
@@ -159,7 +160,7 @@ class LookupWorker extends TerminologyWorker {
|
|
|
159
160
|
return res.status(200).json(result);
|
|
160
161
|
} catch (error) {
|
|
161
162
|
this.log.error(error);
|
|
162
|
-
|
|
163
|
+
debugLog(error);
|
|
163
164
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
164
165
|
if (error instanceof Issue) {
|
|
165
166
|
let oo = new OperationOutcome();
|
|
@@ -223,7 +224,7 @@ class LookupWorker extends TerminologyWorker {
|
|
|
223
224
|
return res.status(200).json(result);
|
|
224
225
|
} catch (error) {
|
|
225
226
|
this.log.error(error);
|
|
226
|
-
|
|
227
|
+
debugLog(error);
|
|
227
228
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
228
229
|
if (error instanceof Issue) {
|
|
229
230
|
let oo = new OperationOutcome();
|
package/tx/workers/read.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
//
|
|
6
6
|
|
|
7
7
|
const { TerminologyWorker } = require('./worker');
|
|
8
|
+
const {debugLog} = require("../operation-context");
|
|
8
9
|
|
|
9
10
|
class ReadWorker extends TerminologyWorker {
|
|
10
11
|
/**
|
|
@@ -67,7 +68,7 @@ class ReadWorker extends TerminologyWorker {
|
|
|
67
68
|
}
|
|
68
69
|
} catch (error) {
|
|
69
70
|
this.log.error(error);
|
|
70
|
-
|
|
71
|
+
debugLog(error);
|
|
71
72
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
72
73
|
return res.status(500).json({
|
|
73
74
|
resourceType: 'OperationOutcome',
|
package/tx/workers/related.js
CHANGED
|
@@ -16,6 +16,7 @@ const ValueSet = require("../library/valueset");
|
|
|
16
16
|
const {ValueSetExpander} = require("./expand");
|
|
17
17
|
const {SearchFilterText} = require("../library/designations");
|
|
18
18
|
const {ArrayMatcher} = require("../../library/utilities");
|
|
19
|
+
const {debugLog} = require("../operation-context");
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
class RelatedWorker extends TerminologyWorker {
|
|
@@ -49,7 +50,7 @@ class RelatedWorker extends TerminologyWorker {
|
|
|
49
50
|
await this.handleTypeLevelRelated(req, res);
|
|
50
51
|
} catch (error) {
|
|
51
52
|
this.log.error(error);
|
|
52
|
-
|
|
53
|
+
debugLog(error);
|
|
53
54
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
54
55
|
const statusCode = error.statusCode || 500;
|
|
55
56
|
if (error instanceof Issue) {
|
|
@@ -84,7 +85,7 @@ class RelatedWorker extends TerminologyWorker {
|
|
|
84
85
|
await this.handleInstanceLevelRelated(req, res);
|
|
85
86
|
} catch (error) {
|
|
86
87
|
this.log.error(error);
|
|
87
|
-
|
|
88
|
+
debugLog(error);
|
|
88
89
|
req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
|
|
89
90
|
const statusCode = error.statusCode || 500;
|
|
90
91
|
const issueCode = error.issueCode || 'exception';
|