3
3
4
4
let engine = { } ;
5
5
6
+ /**
7
+ * Maximum number of codes to load when loading a paginated value set.
8
+ * @type {number }
9
+ */
10
+ const MAX_VS_CODES = 500 ;
11
+
6
12
/**
7
13
* Returns numeric values from the score extension associated with the input
8
14
* collection of Questionnaire items. See the description of the ordinal()
@@ -211,77 +217,28 @@ function addWeightFromCorrespondingResourcesToResult(res, ctx, questionnaire,
211
217
212
218
if ( containedVS ) {
213
219
if ( ! containedVS . expansion ) {
214
- const parameters = [ {
215
- "name" : "valueSet" ,
216
- "resource" : containedVS
217
- } ] ;
218
- if ( ctx . model ?. version === 'r5' ) {
219
- parameters . push ( {
220
- "name" : "property" ,
221
- "valueString" : "itemWeight"
222
- } ) ;
223
- }
224
- score = fetchWithCache ( `${ getTerminologyUrl ( ctx ) } /ValueSet/$expand` , {
225
- method : 'POST' ,
226
- headers : {
227
- 'Accept' : 'application/fhir+json' ,
228
- 'Content-Type' : 'application/fhir+json'
229
- } ,
230
- body : JSON . stringify ( {
231
- "resourceType" : "Parameters" ,
232
- "parameter" : parameters
233
- } )
234
- } )
235
- . then ( r => r . ok ? r . json ( ) : Promise . reject ( r . json ( ) ) )
236
- . then ( ( terminologyVS ) => {
237
- return getScoreFromVS ( ctx . model ?. version , terminologyVS ,
238
- checkExtUrl , code , system ) ;
239
- } ) ;
220
+ score = getWeightFromContainedVS ( ctx , containedVS , checkExtUrl , code , system ) ;
240
221
} else {
241
- score = getScoreFromVS ( ctx . model ?. version , containedVS , checkExtUrl ,
222
+ score = getWeightFromVS ( ctx . model ?. version , containedVS , checkExtUrl ,
242
223
code , system ) ;
243
224
}
225
+ } else if ( vsId ) {
226
+ throw new Error (
227
+ `Cannot find a contained value set with id: ` + vsId + '.' ) ;
244
228
} else {
245
- const parameters = ctx . model ?. version === 'dstu2' ?
246
- { identifier : vsURL } : { url : vsURL } ;
247
- if ( ctx . model ?. version === 'r5' ) {
248
- parameters . property = 'itemWeight' ;
249
- }
250
- score = fetchWithCache ( `${ getTerminologyUrl ( ctx ) } /ValueSet/$expand?` +
251
- new URLSearchParams ( parameters ) . toString ( ) , {
252
- headers : {
253
- 'Accept' : 'application/fhir+json'
254
- }
255
- } )
256
- . then ( r => r . ok ? r . json ( ) : Promise . reject ( r . json ( ) ) )
257
- . then ( ( terminologyVS ) => {
258
- return getScoreFromVS ( ctx . model ?. version , terminologyVS ,
259
- checkExtUrl , code , system ) ;
260
- } ) ;
229
+ score = getWeightFromTerminologyVS ( ctx , vsURL , checkExtUrl , code , system ) ;
261
230
}
262
231
} // end if (vsURL)
263
232
264
233
if ( system && ctx . model ?. version !== 'dstu2' ) {
265
- if ( score === undefined ) {
266
- const isCodeSystem = ( r ) => r . url === system && r . resourceType === 'CodeSystem' ;
267
- const containedCS = getContainedResources ( elem ) ?. find ( isCodeSystem )
268
- || questionnaire ?. contained ?. find ( isCodeSystem ) ;
269
-
270
- if ( containedCS ) {
271
- if ( checkIfItemWeightExists ( containedCS ?. property ) ) {
272
- score = getItemWeightFromProperty (
273
- getCodeSystemItem ( containedCS ?. concept , code )
274
- ) ;
275
- }
276
- } else {
277
- score = getWeightFromTerminologyCodeSet ( ctx , code , system ) ;
278
- }
234
+ if ( score === undefined || score === null ) {
235
+ score = getWeightFromCS ( ctx , questionnaire , elem , checkExtUrl , code , system ) ;
279
236
} else if ( score instanceof Promise ) {
280
237
score = score . then ( weightFromVS => {
281
238
if ( weightFromVS !== undefined ) {
282
239
return weightFromVS ;
283
240
}
284
- return getWeightFromTerminologyCodeSet ( ctx , code , system ) ;
241
+ return getWeightFromCS ( ctx , questionnaire , elem , checkExtUrl , code , system ) ;
285
242
} ) ;
286
243
}
287
244
}
@@ -297,6 +254,153 @@ function addWeightFromCorrespondingResourcesToResult(res, ctx, questionnaire,
297
254
return score instanceof Promise ;
298
255
}
299
256
257
+ /**
258
+ * Returns the promised score value from the expanded contained value set
259
+ * obtained from the terminology server.
260
+ * @param {Object } ctx - object describing the context of expression
261
+ * evaluation (see the "applyParsedPath" function).
262
+ * @param {string } containedVS - contained value set.
263
+ * @param {Function } checkExtUrl - function to check if the extension passed as
264
+ * a parameter has a score URL.
265
+ * @param {string } code - symbol in syntax defined by the system.
266
+ * @param {string } system - code system.
267
+ * @param {number } offset - Paging support - where to start if a subset is
268
+ * desired (default = 0). Offset is number of records (not number of pages).
269
+ * Paging only applies to flat expansions - servers ignore paging if the
270
+ * expansion is not flat (I think if the server doesn't return the
271
+ * "ValueSet.expansion.offset" field, it means there is no paging for the
272
+ * ValueSet).
273
+ * @returns {Promise<number|undefined> }
274
+ */
275
+ function getWeightFromContainedVS ( ctx , containedVS , checkExtUrl , code , system , offset = 0 ) {
276
+ const parameters = [ {
277
+ "name" : "valueSet" ,
278
+ "resource" : containedVS
279
+ } ] ;
280
+ if ( offset ) {
281
+ parameters . push ( {
282
+ "name" : "offset" ,
283
+ "valueInteger" : offset
284
+ } ) ;
285
+ }
286
+ if ( ctx . model ?. version === 'r5' ) {
287
+ parameters . push ( {
288
+ "name" : "property" ,
289
+ "valueString" : "itemWeight"
290
+ } ) ;
291
+ }
292
+ return fetchWithCache ( `${ getTerminologyUrl ( ctx ) } /ValueSet/$expand` , {
293
+ method : 'POST' ,
294
+ headers : {
295
+ 'Accept' : 'application/fhir+json' ,
296
+ 'Content-Type' : 'application/fhir+json'
297
+ } ,
298
+ body : JSON . stringify ( {
299
+ "resourceType" : "Parameters" ,
300
+ "parameter" : parameters
301
+ } )
302
+ } )
303
+ . then ( r => r . ok ? r . json ( ) : Promise . reject ( r . json ( ) ) )
304
+ . then ( ( terminologyVS ) => {
305
+ let score = getWeightFromVS ( ctx . model ?. version , terminologyVS ,
306
+ checkExtUrl , code , system ) ;
307
+ if ( score === null ) {
308
+ if ( terminologyVS ?. expansion ?. offset === offset ) {
309
+ const newOffset = terminologyVS ?. expansion ?. offset +
310
+ terminologyVS ?. expansion ?. contains ?. length ;
311
+ if ( newOffset < MAX_VS_CODES ) {
312
+ return getWeightFromContainedVS ( ctx , containedVS , checkExtUrl , code , system , newOffset ) ;
313
+ }
314
+ }
315
+ score = undefined ;
316
+ }
317
+ return score ;
318
+ } ) ;
319
+ }
320
+
321
+ /**
322
+ * Returns the promised score value from the expanded value set obtained from the
323
+ * terminology server.
324
+ * @param {Object } ctx - object describing the context of expression
325
+ * evaluation (see the "applyParsedPath" function).
326
+ * @param {string } vsURL - value set URL specified in the Questionnaire item.
327
+ * @param {Function } checkExtUrl - function to check if the extension passed as
328
+ * a parameter has a score URL.
329
+ * @param {string } code - symbol in syntax defined by the system.
330
+ * @param {string } system - code system.
331
+ * @param {number } offset - Paging support - where to start if a subset is
332
+ * desired (default = 0). Offset is number of records (not number of pages).
333
+ * Paging only applies to flat expansions - servers ignore paging if the
334
+ * expansion is not flat (I think if the server doesn't return the
335
+ * "ValueSet.expansion.offset" field, it means there is no paging for the
336
+ * ValueSet).
337
+ * @returns {Promise<number|undefined> }
338
+ */
339
+ function getWeightFromTerminologyVS ( ctx , vsURL , checkExtUrl , code , system , offset = 0 ) {
340
+ const parameters = ctx . model ?. version === 'dstu2' ?
341
+ { identifier : vsURL } : { url : vsURL } ;
342
+ if ( offset ) {
343
+ parameters . offset = offset ;
344
+ }
345
+ if ( ctx . model ?. version === 'r5' ) {
346
+ parameters . property = 'itemWeight' ;
347
+ }
348
+ return fetchWithCache ( `${ getTerminologyUrl ( ctx ) } /ValueSet/$expand?` +
349
+ new URLSearchParams ( parameters ) . toString ( ) , {
350
+ headers : {
351
+ 'Accept' : 'application/fhir+json'
352
+ }
353
+ } )
354
+ . then ( r => r . ok ? r . json ( ) : Promise . reject ( r . json ( ) ) )
355
+ . then ( ( terminologyVS ) => {
356
+ const score = getWeightFromVS ( ctx . model ?. version , terminologyVS ,
357
+ checkExtUrl , code , system ) ;
358
+ if ( score === null ) {
359
+ if ( terminologyVS ?. expansion ?. offset === offset ) {
360
+ const newOffset = terminologyVS ?. expansion ?. offset +
361
+ terminologyVS ?. expansion ?. contains ?. length ;
362
+ if ( newOffset < MAX_VS_CODES ) {
363
+ return getWeightFromTerminologyVS ( ctx , vsURL , checkExtUrl , code , system , newOffset ) ;
364
+ }
365
+ }
366
+ return undefined ;
367
+ }
368
+ return score ;
369
+ } ) ;
370
+ }
371
+
372
+ /**
373
+ * Returns the value (or its promise) of the itemWeight property or score
374
+ * extension for the specified system and code from a CodeSystem.
375
+ * @param {Object } ctx - object describing the context of expression
376
+ * evaluation (see the "applyParsedPath" function). * @param ctx
377
+ * @param {Object } questionnaire - object containing questionnaire resource data
378
+ * @param {ResourceNode|any } elem - source collection item for which we obtain
379
+ * the score value.
380
+ * @param {Function } checkExtUrl - function to check if the extension passed as
381
+ * a parameter has a score URL.
382
+ * @param {string } code - symbol in syntax defined by the system.
383
+ * @param {string } system - code system.
384
+ * @return {number|undefined|Promise<number|undefined> }
385
+ */
386
+ function getWeightFromCS ( ctx , questionnaire , elem , checkExtUrl , code , system ) {
387
+ const isCodeSystem = ( r ) => r . url === system && r . resourceType === 'CodeSystem' ;
388
+ const containedCS = getContainedResources ( elem ) ?. find ( isCodeSystem )
389
+ || questionnaire ?. contained ?. find ( isCodeSystem ) ;
390
+ let score ;
391
+
392
+ if ( containedCS ) {
393
+ const item = getCodeSystemItem ( containedCS ?. concept , code ) ;
394
+ score = ctx . model ?. version === 'r5' &&
395
+ checkIfItemWeightExists ( containedCS ?. property ) &&
396
+ getItemWeightFromProperty ( item ) ||
397
+ item ?. extension ?. find ( checkExtUrl ) ?. valueDecimal ;
398
+ } else {
399
+ score = getWeightFromTerminologyCodeSet ( ctx , code , system ) ;
400
+ }
401
+
402
+ return score ;
403
+ }
300
404
301
405
/**
302
406
* Returns the promised score value from the code system obtained from the
@@ -415,7 +519,7 @@ function getCodeSystemItem(concept, code) {
415
519
*/
416
520
function checkIfItemWeightExists ( properties ) {
417
521
return properties ?. find ( p => p . code === 'itemWeight' ) ?. uri ===
418
- 'http://hl7.org/fhir/concept-properties' ;
522
+ 'http://hl7.org/fhir/concept-properties#itemWeight ' ;
419
523
}
420
524
421
525
/**
@@ -430,23 +534,27 @@ function getItemWeightFromProperty(item) {
430
534
431
535
/**
432
536
* Returns the value of the itemWeight property or score extension for the
433
- * specified system and code from a value set.
537
+ * specified system and code from a value set. If the item in the value set has
538
+ * no score, undefined is returned. If the item does not exist, null is returned.
539
+ * The difference between null and undefined values used in paging.
434
540
* @param {string } modelVersion - model version, e.g. 'r5', 'r4', 'stu3', or 'dstu2'.
435
541
* @param {Object } vs - ValueSet.
436
542
* @param {Function } checkExtUrl - function to check if the extension passed as
437
543
* a parameter has a score URL.
438
544
* @param {string } code - symbol in syntax defined by the system.
439
545
* @param {string } system - code system.
440
- * @return {number|undefined }
546
+ * @return {number|undefined|null }
441
547
*/
442
- function getScoreFromVS ( modelVersion , vs , checkExtUrl , code , system ) {
548
+ function getWeightFromVS ( modelVersion , vs , checkExtUrl , code , system ) {
443
549
const item = getValueSetItem ( vs . expansion ?. contains , code , system ) ;
444
550
445
- return item && (
551
+ const score = item ? (
446
552
modelVersion === 'r5' && checkIfItemWeightExists ( vs . expansion ?. property ) &&
447
553
getItemWeightFromProperty ( item ) ||
448
554
item ?. extension ?. find ( checkExtUrl ) ?. valueDecimal
449
- ) ;
555
+ ) : null ;
556
+
557
+ return score ;
450
558
}
451
559
452
560
@@ -567,7 +675,7 @@ function getQItemByLinkIds(questionnaire, linkIds) {
567
675
}
568
676
}
569
677
570
- questionnaire2linkIds . get ( questionnaire ) [ linkIdsKey ] = currentNode ;
678
+ linkIds2items [ linkIdsKey ] = currentNode ;
571
679
}
572
680
573
681
return currentNode ;
0 commit comments