@medplum/fhir-router 2.0.16 → 2.0.17
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/dist/cjs/index.cjs +129 -10
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/cjs/index.min.cjs.map +1 -1
- package/dist/esm/index.min.mjs +1 -1
- package/dist/esm/index.min.mjs.map +1 -1
- package/dist/esm/index.mjs +130 -11
- package/dist/esm/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -55,6 +55,11 @@
|
|
|
55
55
|
const resultEntries = [];
|
|
56
56
|
for (const entry of entries) {
|
|
57
57
|
const rewritten = this.rewriteIdsInObject(entry);
|
|
58
|
+
// If the resource 'id' element is specified, we want to replace teh `urn:uuid:*` string and
|
|
59
|
+
// remove the `resourceType` prefix
|
|
60
|
+
if (entry?.resource?.id) {
|
|
61
|
+
rewritten.resource.id = this.rewriteIdsInString(entry.resource.id, true);
|
|
62
|
+
}
|
|
58
63
|
try {
|
|
59
64
|
resultEntries.push(await this.processBatchEntry(rewritten));
|
|
60
65
|
}
|
|
@@ -158,13 +163,17 @@
|
|
|
158
163
|
rewriteIdsInObject(input) {
|
|
159
164
|
return Object.fromEntries(Object.entries(input).map(([k, v]) => [k, this.rewriteIds(v)]));
|
|
160
165
|
}
|
|
161
|
-
rewriteIdsInString(input) {
|
|
166
|
+
rewriteIdsInString(input, removeResourceType = false) {
|
|
162
167
|
const matches = input.match(/urn:uuid:\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/);
|
|
163
168
|
if (matches) {
|
|
164
169
|
const fullUrl = matches[0];
|
|
165
170
|
const resource = this.ids[fullUrl];
|
|
166
171
|
if (resource) {
|
|
167
|
-
|
|
172
|
+
let referenceString = core.getReferenceString(resource);
|
|
173
|
+
if (removeResourceType) {
|
|
174
|
+
referenceString = core.resolveId({ reference: referenceString });
|
|
175
|
+
}
|
|
176
|
+
return referenceString ? input.replaceAll(fullUrl, referenceString) : input;
|
|
168
177
|
}
|
|
169
178
|
}
|
|
170
179
|
return input;
|
|
@@ -13524,17 +13533,95 @@ spurious results.`);
|
|
|
13524
13533
|
for (const key of Object.keys(properties)) {
|
|
13525
13534
|
const elementDefinition = core.getElementDefinition(resourceType, key);
|
|
13526
13535
|
for (const type of elementDefinition.type) {
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
|
|
13536
|
+
buildPropertyField(fields, key, elementDefinition, type);
|
|
13537
|
+
}
|
|
13538
|
+
}
|
|
13539
|
+
}
|
|
13540
|
+
function buildPropertyField(fields, key, elementDefinition, elementDefinitionType) {
|
|
13541
|
+
let typeName = elementDefinitionType.code;
|
|
13542
|
+
if (typeName === 'Element' || typeName === 'BackboneElement') {
|
|
13543
|
+
typeName = core.buildTypeName(elementDefinition.path?.split('.'));
|
|
13544
|
+
}
|
|
13545
|
+
const fieldConfig = {
|
|
13546
|
+
description: elementDefinition.short,
|
|
13547
|
+
type: getPropertyType(elementDefinition, typeName),
|
|
13548
|
+
resolve: resolveField,
|
|
13549
|
+
};
|
|
13550
|
+
if (elementDefinition.max === '*') {
|
|
13551
|
+
fieldConfig.args = buildListPropertyFieldArgs(typeName);
|
|
13552
|
+
}
|
|
13553
|
+
const propertyName = key.replace('[x]', core.capitalize(elementDefinitionType.code));
|
|
13554
|
+
fields[propertyName] = fieldConfig;
|
|
13555
|
+
}
|
|
13556
|
+
/**
|
|
13557
|
+
* Builds field arguments for a list property.
|
|
13558
|
+
*
|
|
13559
|
+
* The FHIR GraphQL specification defines the following arguments for list properties:
|
|
13560
|
+
* 1. _count: Specify how many elements to return from a repeating list.
|
|
13561
|
+
* 2. _offset: Specify the offset to start at for a repeating element.
|
|
13562
|
+
* 3. fhirpath: A FHIRPath statement selecting which of the subnodes is to be included.
|
|
13563
|
+
* 4. All properties of the list element type.
|
|
13564
|
+
*
|
|
13565
|
+
* See: https://hl7.org/fhir/R4/graphql.html#list
|
|
13566
|
+
*
|
|
13567
|
+
* @param fieldTypeName The type name of the field.
|
|
13568
|
+
* @returns The arguments for the field.
|
|
13569
|
+
*/
|
|
13570
|
+
function buildListPropertyFieldArgs(fieldTypeName) {
|
|
13571
|
+
const fieldArgs = {
|
|
13572
|
+
_count: {
|
|
13573
|
+
type: GraphQLInt,
|
|
13574
|
+
description: 'Specify how many elements to return from a repeating list.',
|
|
13575
|
+
},
|
|
13576
|
+
_offset: {
|
|
13577
|
+
type: GraphQLInt,
|
|
13578
|
+
description: 'Specify the offset to start at for a repeating element.',
|
|
13579
|
+
},
|
|
13580
|
+
};
|
|
13581
|
+
if (!core.isLowerCase(fieldTypeName.charAt(0))) {
|
|
13582
|
+
// If this is a backbone element, add "fhirpath" and all properties as arguments
|
|
13583
|
+
fieldArgs.fhirpath = {
|
|
13584
|
+
type: GraphQLString,
|
|
13585
|
+
description: 'A FHIRPath statement selecting which of the subnodes is to be included',
|
|
13586
|
+
};
|
|
13587
|
+
// Add all "string" and "code" properties as arguments
|
|
13588
|
+
const fieldTypeSchema = core.globalSchema.types[fieldTypeName];
|
|
13589
|
+
if (fieldTypeSchema.properties) {
|
|
13590
|
+
for (const fieldKey of Object.keys(fieldTypeSchema.properties)) {
|
|
13591
|
+
const fieldElementDefinition = core.getElementDefinition(fieldTypeName, fieldKey);
|
|
13592
|
+
for (const type of fieldElementDefinition.type) {
|
|
13593
|
+
buildListPropertyFieldArg(fieldArgs, fieldKey, fieldElementDefinition, type);
|
|
13594
|
+
}
|
|
13530
13595
|
}
|
|
13531
|
-
|
|
13596
|
+
}
|
|
13597
|
+
}
|
|
13598
|
+
return fieldArgs;
|
|
13599
|
+
}
|
|
13600
|
+
/**
|
|
13601
|
+
* Builds a field argument for a list property.
|
|
13602
|
+
* @param fieldArgs The output argument map.
|
|
13603
|
+
* @param fieldKey The key of the field.
|
|
13604
|
+
* @param elementDefinition The FHIR element definition of the field.
|
|
13605
|
+
* @param elementDefinitionType The FHIR element definition type of the field.
|
|
13606
|
+
*/
|
|
13607
|
+
function buildListPropertyFieldArg(fieldArgs, fieldKey, elementDefinition, elementDefinitionType) {
|
|
13608
|
+
const baseType = elementDefinitionType.code;
|
|
13609
|
+
const fieldName = fieldKey.replace('[x]', core.capitalize(baseType));
|
|
13610
|
+
switch (baseType) {
|
|
13611
|
+
case 'canonical':
|
|
13612
|
+
case 'code':
|
|
13613
|
+
case 'id':
|
|
13614
|
+
case 'oid':
|
|
13615
|
+
case 'string':
|
|
13616
|
+
case 'uri':
|
|
13617
|
+
case 'url':
|
|
13618
|
+
case 'uuid':
|
|
13619
|
+
case 'http://hl7.org/fhirpath/System.String':
|
|
13620
|
+
fieldArgs[fieldName] = {
|
|
13621
|
+
type: GraphQLString,
|
|
13532
13622
|
description: elementDefinition.short,
|
|
13533
|
-
type: getPropertyType(elementDefinition, typeName),
|
|
13534
13623
|
};
|
|
13535
|
-
|
|
13536
|
-
fields[propertyName] = fieldConfig;
|
|
13537
|
-
}
|
|
13624
|
+
break;
|
|
13538
13625
|
}
|
|
13539
13626
|
}
|
|
13540
13627
|
/**
|
|
@@ -13708,6 +13795,38 @@ spurious results.`);
|
|
|
13708
13795
|
}
|
|
13709
13796
|
return getGraphQLType(resourceType).name;
|
|
13710
13797
|
}
|
|
13798
|
+
/**
|
|
13799
|
+
* GraphQL resolver for fields.
|
|
13800
|
+
* In the common case, this is just a matter of returning the field value from the source object.
|
|
13801
|
+
* If the field is a list and the user specifies list arguments, then we can apply those arguments here.
|
|
13802
|
+
* @param source The source. This is the object that contains the field.
|
|
13803
|
+
* @param args The GraphQL search arguments.
|
|
13804
|
+
* @param _ctx The GraphQL context.
|
|
13805
|
+
* @param info The GraphQL resolve info. This includes the field name.
|
|
13806
|
+
* @returns Promise to read the resoure for the query.
|
|
13807
|
+
* @implements {GraphQLFieldResolver}
|
|
13808
|
+
*/
|
|
13809
|
+
async function resolveField(source, args, _ctx, info) {
|
|
13810
|
+
const fieldValue = source?.[info.fieldName];
|
|
13811
|
+
if (!args || !fieldValue) {
|
|
13812
|
+
return fieldValue;
|
|
13813
|
+
}
|
|
13814
|
+
const { _offset, _count, fhirpath, ...rest } = args;
|
|
13815
|
+
let array = fieldValue;
|
|
13816
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
13817
|
+
array = array.filter((item) => item[key] === value);
|
|
13818
|
+
}
|
|
13819
|
+
if (fhirpath) {
|
|
13820
|
+
array = array.filter((item) => core.toJsBoolean(core.evalFhirPathTyped(fhirpath, [core.toTypedValue(item)])));
|
|
13821
|
+
}
|
|
13822
|
+
if (_offset) {
|
|
13823
|
+
array = array.slice(_offset);
|
|
13824
|
+
}
|
|
13825
|
+
if (_count) {
|
|
13826
|
+
array = array.slice(0, _count);
|
|
13827
|
+
}
|
|
13828
|
+
return array;
|
|
13829
|
+
}
|
|
13711
13830
|
function parseSearchArgs(resourceType, source, args) {
|
|
13712
13831
|
let referenceFilter = undefined;
|
|
13713
13832
|
if (source) {
|