fhirsmith 0.7.1 → 0.7.3
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 +42 -2
- package/config-template.json +16 -0
- package/extension-tracker/extension-tracker-template.html +124 -0
- package/extension-tracker/extension-tracker.js +697 -0
- package/extension-tracker/readme.md +63 -0
- package/folder/folder.js +305 -0
- package/folder/readme.md +57 -0
- package/library/html-server.js +8 -2
- package/package.json +4 -2
- package/packages/packages.js +8 -8
- package/publisher/publisher.js +104 -13
- package/server.js +58 -4
- package/tx/cs/cs-snomed.js +13 -7
- package/tx/library/extensions.js +6 -2
- package/tx/library/renderer.js +1 -1
- package/tx/ocl/cache/cache-paths.cjs +4 -5
- package/tx/ocl/cm-ocl.cjs +4 -1
- package/tx/ocl/cs-ocl.cjs +9 -9
- package/tx/ocl/jobs/background-queue.cjs +11 -5
- package/tx/ocl/shared/patches.cjs +37 -0
- package/tx/ocl/vs-ocl.cjs +92 -44
- package/tx/workers/expand.js +23 -12
- package/tx/workers/search.js +26 -15
- package/xig/xig.js +59 -8
package/xig/xig.js
CHANGED
|
@@ -99,14 +99,15 @@ function validateExternalUrl(url) {
|
|
|
99
99
|
|
|
100
100
|
// Secure SQL query building with parameterized queries
|
|
101
101
|
function buildSecureResourceQuery(queryParams, offset = 0, limit = 50) {
|
|
102
|
-
const { realm, auth, ver, type, rt, text } = queryParams;
|
|
102
|
+
const { realm, auth, ver, type, rt, text, pkg, onlyUsed } = queryParams;
|
|
103
103
|
|
|
104
104
|
let baseQuery = `
|
|
105
105
|
SELECT
|
|
106
106
|
ResourceKey, ResourceType, Type, Kind, Description, PackageKey,
|
|
107
107
|
Realm, Authority, R2, R2B, R3, R4, R4B, R5, R6,
|
|
108
108
|
Id, Url, Version, Status, Date, Name, Title, Content,
|
|
109
|
-
Supplements, Details, FMM, WG, StandardsStatus, Web
|
|
109
|
+
Supplements, Details, FMM, WG, StandardsStatus, Web,
|
|
110
|
+
(SELECT COUNT(*) FROM DependencyList WHERE TargetKey = Resources.ResourceKey) AS UsageCount
|
|
110
111
|
FROM Resources
|
|
111
112
|
WHERE 1=1
|
|
112
113
|
`;
|
|
@@ -225,6 +226,17 @@ function buildSecureResourceQuery(queryParams, offset = 0, limit = 50) {
|
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
228
|
|
|
229
|
+
// Package filter - matches packageId#version containing the search string
|
|
230
|
+
if (pkg && pkg !== '') {
|
|
231
|
+
conditions.push('AND PackageKey IN (SELECT PackageKey FROM Packages WHERE (Id || \'#\' || Version) LIKE ?)');
|
|
232
|
+
params.push(`%${pkg}%`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Only used filter
|
|
236
|
+
if (onlyUsed === 'true') {
|
|
237
|
+
conditions.push('AND EXISTS (SELECT 1 FROM DependencyList WHERE TargetKey = Resources.ResourceKey)');
|
|
238
|
+
}
|
|
239
|
+
|
|
228
240
|
// Build final query
|
|
229
241
|
const fullQuery = baseQuery + ' ' + conditions.join(' ') + ' ORDER BY ResourceType, Type, Description LIMIT ? OFFSET ?';
|
|
230
242
|
params.push(limit, offset);
|
|
@@ -233,7 +245,7 @@ function buildSecureResourceQuery(queryParams, offset = 0, limit = 50) {
|
|
|
233
245
|
}
|
|
234
246
|
|
|
235
247
|
function buildSecureResourceCountQuery(queryParams) {
|
|
236
|
-
const { realm, auth, ver, type, rt, text } = queryParams;
|
|
248
|
+
const { realm, auth, ver, type, rt, text, pkg, onlyUsed } = queryParams;
|
|
237
249
|
|
|
238
250
|
let baseQuery = 'SELECT COUNT(*) as total FROM Resources WHERE 1=1';
|
|
239
251
|
const conditions = [];
|
|
@@ -324,6 +336,17 @@ function buildSecureResourceCountQuery(queryParams) {
|
|
|
324
336
|
}
|
|
325
337
|
}
|
|
326
338
|
|
|
339
|
+
// Package filter - matches packageId#version containing the search string
|
|
340
|
+
if (pkg && pkg !== '') {
|
|
341
|
+
conditions.push('AND PackageKey IN (SELECT PackageKey FROM Packages WHERE (Id || \'#\' || Version) LIKE ?)');
|
|
342
|
+
params.push(`%${pkg}%`);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Only used filter
|
|
346
|
+
if (onlyUsed === 'true') {
|
|
347
|
+
conditions.push('AND EXISTS (SELECT 1 FROM DependencyList WHERE TargetKey = Resources.ResourceKey)');
|
|
348
|
+
}
|
|
349
|
+
|
|
327
350
|
const fullQuery = baseQuery + ' ' + conditions.join(' ');
|
|
328
351
|
return { query: fullQuery, params };
|
|
329
352
|
}
|
|
@@ -449,7 +472,7 @@ function sqlEscapeString(str) {
|
|
|
449
472
|
}
|
|
450
473
|
|
|
451
474
|
function buildSqlFilter(queryParams) {
|
|
452
|
-
const { realm, auth, ver, type, rt, text } = queryParams;
|
|
475
|
+
const { realm, auth, ver, type, rt, text, pkg, onlyUsed } = queryParams;
|
|
453
476
|
let filter = '';
|
|
454
477
|
|
|
455
478
|
// Realm filter
|
|
@@ -555,6 +578,17 @@ function buildSqlFilter(queryParams) {
|
|
|
555
578
|
}
|
|
556
579
|
}
|
|
557
580
|
|
|
581
|
+
// Package filter - matches packageId#version containing the search string
|
|
582
|
+
if (pkg && pkg !== '') {
|
|
583
|
+
const escapedPkg = sqlEscapeString(pkg);
|
|
584
|
+
filter += ` and PackageKey in (select PackageKey from Packages where (Id || '#' || Version) like '%${escapedPkg}%')`;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Only used filter
|
|
588
|
+
if (onlyUsed === 'true') {
|
|
589
|
+
filter += ` and exists (select 1 from DependencyList where TargetKey = Resources.ResourceKey)`;
|
|
590
|
+
}
|
|
591
|
+
|
|
558
592
|
// Convert to proper WHERE clause
|
|
559
593
|
if (filter !== '') {
|
|
560
594
|
// Remove the first " and " and prepend "WHERE "
|
|
@@ -600,7 +634,8 @@ function buildResourceListQuery(queryParams, offset = 0, limit = 50) {
|
|
|
600
634
|
FMM,
|
|
601
635
|
WG,
|
|
602
636
|
StandardsStatus,
|
|
603
|
-
Web
|
|
637
|
+
Web,
|
|
638
|
+
(SELECT COUNT(*) FROM DependencyList WHERE TargetKey = Resources.ResourceKey) AS UsageCount
|
|
604
639
|
FROM Resources
|
|
605
640
|
${whereClause}
|
|
606
641
|
ORDER BY ResourceType, Type, Description
|
|
@@ -784,6 +819,7 @@ async function buildResourceTable(queryParams, resourceCount, offset = 0) {
|
|
|
784
819
|
break;
|
|
785
820
|
}
|
|
786
821
|
|
|
822
|
+
parts.push('<th>Usage #</th>');
|
|
787
823
|
parts.push('</tr>');
|
|
788
824
|
|
|
789
825
|
const resourceRows = await new Promise((resolve, reject) => {
|
|
@@ -912,6 +948,10 @@ async function buildResourceTable(queryParams, resourceCount, offset = 0) {
|
|
|
912
948
|
}
|
|
913
949
|
}
|
|
914
950
|
|
|
951
|
+
// Usage count column
|
|
952
|
+
const usageCount = row.UsageCount || 0;
|
|
953
|
+
parts.push(`<td>${usageCount > 0 ? usageCount.toLocaleString() : ''}</td>`);
|
|
954
|
+
|
|
915
955
|
parts.push('</tr>');
|
|
916
956
|
}
|
|
917
957
|
|
|
@@ -1116,7 +1156,7 @@ function makeSelect(selectedValue, optionsList, name = 'rt') {
|
|
|
1116
1156
|
}
|
|
1117
1157
|
|
|
1118
1158
|
function buildAdditionalForm(queryParams) {
|
|
1119
|
-
const { ver, realm, auth, type, rt, text } = queryParams;
|
|
1159
|
+
const { ver, realm, auth, type, rt, text, pkg, onlyUsed } = queryParams;
|
|
1120
1160
|
|
|
1121
1161
|
let html = '<form method="GET" action="" style="background-color: #eeeeee; border: 1px black solid; padding: 6px; font-size: 12px; font-family: verdana;">';
|
|
1122
1162
|
|
|
@@ -1142,6 +1182,7 @@ function buildAdditionalForm(queryParams) {
|
|
|
1142
1182
|
const profileResources = getCachedSet('profileResources');
|
|
1143
1183
|
if (profileResources.length > 0) {
|
|
1144
1184
|
html += 'Type: ' + makeSelect(rt, profileResources) + ' ';
|
|
1185
|
+
html += '<br/>';
|
|
1145
1186
|
}
|
|
1146
1187
|
break;
|
|
1147
1188
|
}
|
|
@@ -1150,6 +1191,7 @@ function buildAdditionalForm(queryParams) {
|
|
|
1150
1191
|
const profileTypes = getCachedSet('profileTypes');
|
|
1151
1192
|
if (profileTypes.length > 0) {
|
|
1152
1193
|
html += 'Type: ' + makeSelect(rt, profileTypes) + ' ';
|
|
1194
|
+
html += '<br/>';
|
|
1153
1195
|
}
|
|
1154
1196
|
break;
|
|
1155
1197
|
}
|
|
@@ -1162,6 +1204,7 @@ function buildAdditionalForm(queryParams) {
|
|
|
1162
1204
|
const extensionContexts = getCachedSet('extensionContexts');
|
|
1163
1205
|
if (extensionContexts.length > 0) {
|
|
1164
1206
|
html += 'Context: ' + makeSelect(rt, extensionContexts) + ' ';
|
|
1207
|
+
html += '<br/>';
|
|
1165
1208
|
}
|
|
1166
1209
|
break;
|
|
1167
1210
|
}
|
|
@@ -1172,6 +1215,7 @@ function buildAdditionalForm(queryParams) {
|
|
|
1172
1215
|
// Convert txSources map to "code=display" format
|
|
1173
1216
|
const sourceOptions = Object.keys(txSources).map(code => `${code}=${txSources[code]}`);
|
|
1174
1217
|
html += 'Source: ' + makeSelect(rt, sourceOptions) + ' ';
|
|
1218
|
+
html += '<br/>';
|
|
1175
1219
|
}
|
|
1176
1220
|
break;
|
|
1177
1221
|
}
|
|
@@ -1182,6 +1226,7 @@ function buildAdditionalForm(queryParams) {
|
|
|
1182
1226
|
// Convert txSources map to "code=display" format
|
|
1183
1227
|
const sourceOptionsCM = Object.keys(txSourcesCM).map(code => `${code}=${txSourcesCM[code]}`);
|
|
1184
1228
|
html += 'Source: ' + makeSelect(rt, sourceOptionsCM) + ' ';
|
|
1229
|
+
html += '<br/>';
|
|
1185
1230
|
}
|
|
1186
1231
|
break;
|
|
1187
1232
|
}
|
|
@@ -1190,15 +1235,19 @@ function buildAdditionalForm(queryParams) {
|
|
|
1190
1235
|
const resourceTypes = getCachedSet('resourceTypes');
|
|
1191
1236
|
if (resourceTypes.length > 0) {
|
|
1192
1237
|
html += 'Type: ' + makeSelect(rt, resourceTypes);
|
|
1238
|
+
html += '<br/>';
|
|
1193
1239
|
}
|
|
1194
1240
|
break;
|
|
1195
1241
|
}
|
|
1196
1242
|
}
|
|
1197
1243
|
|
|
1198
|
-
// Add text search field
|
|
1244
|
+
// Add text search field and package filter field
|
|
1199
1245
|
html += `Text: <input type="text" name="text" value="${escape(text || '')}" class="" style="width: 200px;"/> `;
|
|
1246
|
+
html += `Package: <input type="text" name="pkg" value="${escape(pkg || '')}" placeholder="e.g. hl7.fhir.us" class="" style="width: 200px;"/> `;
|
|
1200
1247
|
|
|
1201
|
-
// Add submit button
|
|
1248
|
+
// Add submit button with 'only used' checkbox immediately before it
|
|
1249
|
+
const onlyUsedChecked = onlyUsed === 'true' ? ' checked' : '';
|
|
1250
|
+
html += `<input type="checkbox" name="onlyUsed" value="true"${onlyUsedChecked}/> Only Used `;
|
|
1202
1251
|
html += '<input type="submit" value="Search" style="color:rgb(89, 137, 241)"/>';
|
|
1203
1252
|
|
|
1204
1253
|
html += '</form>';
|
|
@@ -2252,6 +2301,8 @@ router.get('/', async (req, res) => {
|
|
|
2252
2301
|
type: req.query.type || '',
|
|
2253
2302
|
rt: req.query.rt || '',
|
|
2254
2303
|
text: req.query.text || '',
|
|
2304
|
+
pkg: req.query.pkg || '',
|
|
2305
|
+
onlyUsed: req.query.onlyUsed || '',
|
|
2255
2306
|
offset: req.query.offset || '0'
|
|
2256
2307
|
};
|
|
2257
2308
|
|