@medplum/fhir-router 2.0.21 → 2.0.22
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 +201 -40
- 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 +202 -41
- package/dist/esm/index.mjs.map +1 -1
- package/dist/types/batch.d.ts +0 -1
- package/dist/types/fhirrouter.d.ts +6 -1
- package/dist/types/graphql.d.ts +6 -2
- package/dist/types/repo.d.ts +0 -15
- package/package.json +1 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OperationOutcomeError, badRequest, normalizeOperationOutcome, parseSearchUrl, getReferenceString, resolveId, getStatus, isOk, allOk, LRUCache, forbidden, getResourceTypes, getResourceTypeSchema, isResourceTypeSchema, getElementDefinition, buildTypeName, capitalize, isLowerCase, globalSchema, getSearchParameters, DEFAULT_SEARCH_COUNT, toJsBoolean, evalFhirPathTyped, toTypedValue, Operator, parseSearchRequest, notFound, created, deepClone, matchesSearchRequest, evalFhirPath } from '@medplum/core';
|
|
1
|
+
import { OperationOutcomeError, badRequest, normalizeOperationOutcome, parseSearchUrl, getReferenceString, resolveId, getStatus, isOk, allOk, LRUCache, forbidden, getResourceTypes, getResourceTypeSchema, isResourceTypeSchema, getElementDefinition, buildTypeName, capitalize, isLowerCase, globalSchema, getSearchParameters, DEFAULT_SEARCH_COUNT, toJsBoolean, evalFhirPathTyped, toTypedValue, Operator, parseSearchRequest, isResourceType, notFound, created, deepClone, matchesSearchRequest, evalFhirPath } from '@medplum/core';
|
|
2
2
|
import DataLoader from 'dataloader';
|
|
3
3
|
import { applyPatch } from 'rfc6902';
|
|
4
4
|
|
|
@@ -6,7 +6,6 @@ import { applyPatch } from 'rfc6902';
|
|
|
6
6
|
* Processes a FHIR batch request.
|
|
7
7
|
*
|
|
8
8
|
* See: https://www.hl7.org/fhir/http.html#transaction
|
|
9
|
-
*
|
|
10
9
|
* @param router The FHIR router.
|
|
11
10
|
* @param repo The FHIR repository.
|
|
12
11
|
* @param bundle The input bundle.
|
|
@@ -34,8 +33,6 @@ class BatchProcessor {
|
|
|
34
33
|
}
|
|
35
34
|
/**
|
|
36
35
|
* Processes a FHIR batch request.
|
|
37
|
-
* @param repo The FHIR repository.
|
|
38
|
-
* @param bundle The input bundle.
|
|
39
36
|
* @returns The bundle response.
|
|
40
37
|
*/
|
|
41
38
|
async processBatch() {
|
|
@@ -13376,6 +13373,12 @@ const typeCache = {
|
|
|
13376
13373
|
'http://hl7.org/fhirpath/System.String': GraphQLString,
|
|
13377
13374
|
'http://hl7.org/fhirpath/System.Time': GraphQLString,
|
|
13378
13375
|
};
|
|
13376
|
+
const outputTypeCache = {
|
|
13377
|
+
...typeCache,
|
|
13378
|
+
};
|
|
13379
|
+
const inputTypeCache = {
|
|
13380
|
+
...typeCache,
|
|
13381
|
+
};
|
|
13379
13382
|
/**
|
|
13380
13383
|
* Cache of "introspection" query results.
|
|
13381
13384
|
* Common case is the standard schema query from GraphiQL and Insomnia.
|
|
@@ -13391,8 +13394,12 @@ let rootSchema;
|
|
|
13391
13394
|
* Handles FHIR GraphQL requests.
|
|
13392
13395
|
*
|
|
13393
13396
|
* See: https://www.hl7.org/fhir/graphql.html
|
|
13397
|
+
* @param req The request details.
|
|
13398
|
+
* @param repo The current user FHIR repository.
|
|
13399
|
+
* @param router The router for router options.
|
|
13400
|
+
* @returns The response.
|
|
13394
13401
|
*/
|
|
13395
|
-
async function graphqlHandler(req, repo) {
|
|
13402
|
+
async function graphqlHandler(req, repo, router) {
|
|
13396
13403
|
const { query, operationName, variables } = req.body;
|
|
13397
13404
|
if (!query) {
|
|
13398
13405
|
return [badRequest('Must provide query.')];
|
|
@@ -13411,7 +13418,7 @@ async function graphqlHandler(req, repo) {
|
|
|
13411
13418
|
return [invalidRequest(validationErrors)];
|
|
13412
13419
|
}
|
|
13413
13420
|
const introspection = isIntrospectionQuery(query);
|
|
13414
|
-
if (introspection) {
|
|
13421
|
+
if (introspection && !router.options?.introspectionEnabled) {
|
|
13415
13422
|
return [forbidden];
|
|
13416
13423
|
}
|
|
13417
13424
|
const dataLoader = new DataLoader((keys) => repo.readReferences(keys));
|
|
@@ -13433,7 +13440,6 @@ async function graphqlHandler(req, repo) {
|
|
|
13433
13440
|
* Introspection queries ask for the schema, which is expensive.
|
|
13434
13441
|
*
|
|
13435
13442
|
* See: https://graphql.org/learn/introspection/
|
|
13436
|
-
*
|
|
13437
13443
|
* @param query The GraphQL query.
|
|
13438
13444
|
* @returns True if the query is an introspection query.
|
|
13439
13445
|
*/
|
|
@@ -13450,15 +13456,16 @@ function buildRootSchema() {
|
|
|
13450
13456
|
// First, create placeholder types
|
|
13451
13457
|
// We need this first for circular dependencies
|
|
13452
13458
|
for (const resourceType of getResourceTypes()) {
|
|
13453
|
-
|
|
13459
|
+
outputTypeCache[resourceType] = buildGraphQLOutputType(resourceType);
|
|
13454
13460
|
}
|
|
13455
13461
|
// Next, fill in all of the type properties
|
|
13456
13462
|
const fields = {};
|
|
13463
|
+
const mutationFields = {};
|
|
13457
13464
|
for (const resourceType of getResourceTypes()) {
|
|
13458
|
-
const
|
|
13465
|
+
const graphQLOutputType = getGraphQLOutputType(resourceType);
|
|
13459
13466
|
// Get resource by ID
|
|
13460
13467
|
fields[resourceType] = {
|
|
13461
|
-
type:
|
|
13468
|
+
type: graphQLOutputType,
|
|
13462
13469
|
args: {
|
|
13463
13470
|
id: {
|
|
13464
13471
|
type: new GraphQLNonNull(GraphQLID),
|
|
@@ -13469,38 +13476,71 @@ function buildRootSchema() {
|
|
|
13469
13476
|
};
|
|
13470
13477
|
// Search resource by search parameters
|
|
13471
13478
|
fields[resourceType + 'List'] = {
|
|
13472
|
-
type: new GraphQLList(
|
|
13479
|
+
type: new GraphQLList(graphQLOutputType),
|
|
13473
13480
|
args: buildSearchArgs(resourceType),
|
|
13474
13481
|
resolve: resolveBySearch,
|
|
13475
13482
|
};
|
|
13476
13483
|
// FHIR GraphQL Connection API
|
|
13477
13484
|
fields[resourceType + 'Connection'] = {
|
|
13478
|
-
type: buildConnectionType(resourceType,
|
|
13485
|
+
type: buildConnectionType(resourceType, graphQLOutputType),
|
|
13479
13486
|
args: buildSearchArgs(resourceType),
|
|
13480
13487
|
resolve: resolveByConnectionApi,
|
|
13481
13488
|
};
|
|
13489
|
+
// Mutation API
|
|
13490
|
+
mutationFields[resourceType + 'Create'] = {
|
|
13491
|
+
type: graphQLOutputType,
|
|
13492
|
+
args: buildCreateArgs(resourceType),
|
|
13493
|
+
resolve: resolveByCreate,
|
|
13494
|
+
};
|
|
13495
|
+
mutationFields[resourceType + 'Update'] = {
|
|
13496
|
+
type: graphQLOutputType,
|
|
13497
|
+
args: buildUpdateArgs(resourceType),
|
|
13498
|
+
resolve: resolveByUpdate,
|
|
13499
|
+
};
|
|
13500
|
+
mutationFields[resourceType + 'Delete'] = {
|
|
13501
|
+
type: graphQLOutputType,
|
|
13502
|
+
args: {
|
|
13503
|
+
id: {
|
|
13504
|
+
type: new GraphQLNonNull(GraphQLID),
|
|
13505
|
+
description: resourceType + ' ID',
|
|
13506
|
+
},
|
|
13507
|
+
},
|
|
13508
|
+
resolve: resolveByDelete,
|
|
13509
|
+
};
|
|
13482
13510
|
}
|
|
13483
13511
|
return new GraphQLSchema({
|
|
13484
13512
|
query: new GraphQLObjectType({
|
|
13485
13513
|
name: 'QueryType',
|
|
13486
13514
|
fields,
|
|
13487
13515
|
}),
|
|
13516
|
+
mutation: new GraphQLObjectType({
|
|
13517
|
+
name: 'MutationType',
|
|
13518
|
+
fields: mutationFields,
|
|
13519
|
+
}),
|
|
13488
13520
|
});
|
|
13489
13521
|
}
|
|
13490
|
-
function
|
|
13491
|
-
let result =
|
|
13522
|
+
function getGraphQLOutputType(inputType) {
|
|
13523
|
+
let result = outputTypeCache[inputType];
|
|
13524
|
+
if (!result) {
|
|
13525
|
+
result = buildGraphQLOutputType(inputType);
|
|
13526
|
+
outputTypeCache[inputType] = result;
|
|
13527
|
+
}
|
|
13528
|
+
return result;
|
|
13529
|
+
}
|
|
13530
|
+
function getGraphQLInputType(inputType, nameSuffix) {
|
|
13531
|
+
let result = inputTypeCache[inputType];
|
|
13492
13532
|
if (!result) {
|
|
13493
|
-
result =
|
|
13494
|
-
|
|
13533
|
+
result = buildGraphQLInputType(inputType, nameSuffix);
|
|
13534
|
+
inputTypeCache[inputType] = result;
|
|
13495
13535
|
}
|
|
13496
13536
|
return result;
|
|
13497
13537
|
}
|
|
13498
|
-
function
|
|
13538
|
+
function buildGraphQLOutputType(resourceType) {
|
|
13499
13539
|
if (resourceType === 'ResourceList') {
|
|
13500
13540
|
return new GraphQLUnionType({
|
|
13501
13541
|
name: 'ResourceList',
|
|
13502
13542
|
types: () => getResourceTypes()
|
|
13503
|
-
.map(
|
|
13543
|
+
.map(getGraphQLOutputType)
|
|
13504
13544
|
.filter((t) => !!t),
|
|
13505
13545
|
resolveType: resolveTypeByReference,
|
|
13506
13546
|
});
|
|
@@ -13509,16 +13549,37 @@ function buildGraphQLType(resourceType) {
|
|
|
13509
13549
|
return new GraphQLObjectType({
|
|
13510
13550
|
name: resourceType,
|
|
13511
13551
|
description: schema.description,
|
|
13512
|
-
fields: () =>
|
|
13552
|
+
fields: () => buildGraphQLOutputFields(resourceType),
|
|
13513
13553
|
});
|
|
13514
13554
|
}
|
|
13515
|
-
function
|
|
13555
|
+
function buildGraphQLInputType(resourceType, nameSuffix) {
|
|
13556
|
+
const schema = getResourceTypeSchema(resourceType);
|
|
13557
|
+
return new GraphQLInputObjectType({
|
|
13558
|
+
name: resourceType + nameSuffix,
|
|
13559
|
+
description: schema.description,
|
|
13560
|
+
fields: () => buildGraphQLInputFields(resourceType, nameSuffix),
|
|
13561
|
+
});
|
|
13562
|
+
}
|
|
13563
|
+
function buildGraphQLOutputFields(resourceType) {
|
|
13516
13564
|
const fields = {};
|
|
13517
|
-
|
|
13565
|
+
buildOutputPropertyFields(resourceType, fields);
|
|
13518
13566
|
buildReverseLookupFields(resourceType, fields);
|
|
13519
13567
|
return fields;
|
|
13520
13568
|
}
|
|
13521
|
-
function
|
|
13569
|
+
function buildGraphQLInputFields(resourceType, nameSuffix) {
|
|
13570
|
+
const fields = {};
|
|
13571
|
+
// Add resourceType field for root resource
|
|
13572
|
+
if (isResourceType(resourceType)) {
|
|
13573
|
+
const propertyFieldConfig = {
|
|
13574
|
+
description: 'The type of resource',
|
|
13575
|
+
type: GraphQLString,
|
|
13576
|
+
};
|
|
13577
|
+
fields['resourceType'] = propertyFieldConfig;
|
|
13578
|
+
}
|
|
13579
|
+
buildInputPropertyFields(resourceType, fields, nameSuffix);
|
|
13580
|
+
return fields;
|
|
13581
|
+
}
|
|
13582
|
+
function buildOutputPropertyFields(resourceType, fields) {
|
|
13522
13583
|
const schema = getResourceTypeSchema(resourceType);
|
|
13523
13584
|
const properties = schema.properties;
|
|
13524
13585
|
if (isResourceTypeSchema(schema)) {
|
|
@@ -13530,25 +13591,35 @@ function buildPropertyFields(resourceType, fields) {
|
|
|
13530
13591
|
if (resourceType === 'Reference') {
|
|
13531
13592
|
fields.resource = {
|
|
13532
13593
|
description: 'Reference',
|
|
13533
|
-
type:
|
|
13594
|
+
type: getGraphQLOutputType('ResourceList'),
|
|
13534
13595
|
resolve: resolveByReference,
|
|
13535
13596
|
};
|
|
13536
13597
|
}
|
|
13537
13598
|
for (const key of Object.keys(properties)) {
|
|
13538
13599
|
const elementDefinition = getElementDefinition(resourceType, key);
|
|
13539
13600
|
for (const type of elementDefinition.type) {
|
|
13540
|
-
|
|
13601
|
+
buildOutputPropertyField(fields, key, elementDefinition, type);
|
|
13541
13602
|
}
|
|
13542
13603
|
}
|
|
13543
13604
|
}
|
|
13544
|
-
function
|
|
13605
|
+
function buildInputPropertyFields(resourceType, fields, nameSuffix) {
|
|
13606
|
+
const schema = getResourceTypeSchema(resourceType);
|
|
13607
|
+
const properties = schema.properties;
|
|
13608
|
+
for (const key of Object.keys(properties)) {
|
|
13609
|
+
const elementDefinition = getElementDefinition(resourceType, key);
|
|
13610
|
+
for (const type of elementDefinition.type) {
|
|
13611
|
+
buildInputPropertyField(fields, key, elementDefinition, type, nameSuffix);
|
|
13612
|
+
}
|
|
13613
|
+
}
|
|
13614
|
+
}
|
|
13615
|
+
function buildOutputPropertyField(fields, key, elementDefinition, elementDefinitionType) {
|
|
13545
13616
|
let typeName = elementDefinitionType.code;
|
|
13546
13617
|
if (typeName === 'Element' || typeName === 'BackboneElement') {
|
|
13547
13618
|
typeName = buildTypeName(elementDefinition.path?.split('.'));
|
|
13548
13619
|
}
|
|
13549
13620
|
const fieldConfig = {
|
|
13550
13621
|
description: elementDefinition.short,
|
|
13551
|
-
type:
|
|
13622
|
+
type: getOutputPropertyType(elementDefinition, typeName),
|
|
13552
13623
|
resolve: resolveField,
|
|
13553
13624
|
};
|
|
13554
13625
|
if (elementDefinition.max === '*') {
|
|
@@ -13557,6 +13628,21 @@ function buildPropertyField(fields, key, elementDefinition, elementDefinitionTyp
|
|
|
13557
13628
|
const propertyName = key.replace('[x]', capitalize(elementDefinitionType.code));
|
|
13558
13629
|
fields[propertyName] = fieldConfig;
|
|
13559
13630
|
}
|
|
13631
|
+
function buildInputPropertyField(fields, key, elementDefinition, elementDefinitionType, nameSuffix) {
|
|
13632
|
+
let typeName = elementDefinitionType.code;
|
|
13633
|
+
if (typeName === 'Element' || typeName === 'BackboneElement') {
|
|
13634
|
+
typeName = buildTypeName(elementDefinition.path?.split('.'));
|
|
13635
|
+
}
|
|
13636
|
+
const fieldConfig = {
|
|
13637
|
+
description: elementDefinition.short,
|
|
13638
|
+
type: getGraphQLInputType(typeName, nameSuffix),
|
|
13639
|
+
};
|
|
13640
|
+
if (elementDefinition.max === '*') {
|
|
13641
|
+
fieldConfig.type = new GraphQLList(getGraphQLInputType(typeName, nameSuffix));
|
|
13642
|
+
}
|
|
13643
|
+
const propertyName = key.replace('[x]', capitalize(elementDefinitionType.code));
|
|
13644
|
+
fields[propertyName] = fieldConfig;
|
|
13645
|
+
}
|
|
13560
13646
|
/**
|
|
13561
13647
|
* Builds field arguments for a list property.
|
|
13562
13648
|
*
|
|
@@ -13567,7 +13653,6 @@ function buildPropertyField(fields, key, elementDefinition, elementDefinitionTyp
|
|
|
13567
13653
|
* 4. All properties of the list element type.
|
|
13568
13654
|
*
|
|
13569
13655
|
* See: https://hl7.org/fhir/R4/graphql.html#list
|
|
13570
|
-
*
|
|
13571
13656
|
* @param fieldTypeName The type name of the field.
|
|
13572
13657
|
* @returns The arguments for the field.
|
|
13573
13658
|
*/
|
|
@@ -13652,13 +13737,12 @@ function buildListPropertyFieldArg(fieldArgs, fieldKey, elementDefinition, eleme
|
|
|
13652
13737
|
* (except that the "id" argument is prohibited here as nonsensical).
|
|
13653
13738
|
*
|
|
13654
13739
|
* See: https://www.hl7.org/fhir/graphql.html#reverse
|
|
13655
|
-
*
|
|
13656
13740
|
* @param resourceType The resource type to build fields for.
|
|
13657
13741
|
* @param fields The fields object to add fields to.
|
|
13658
13742
|
*/
|
|
13659
13743
|
function buildReverseLookupFields(resourceType, fields) {
|
|
13660
13744
|
for (const childResourceType of getResourceTypes()) {
|
|
13661
|
-
const childGraphQLType =
|
|
13745
|
+
const childGraphQLType = getGraphQLOutputType(childResourceType);
|
|
13662
13746
|
const childSearchParams = getSearchParameters(childResourceType);
|
|
13663
13747
|
const enumValues = {};
|
|
13664
13748
|
let count = 0;
|
|
@@ -13724,8 +13808,30 @@ function buildSearchArgs(resourceType) {
|
|
|
13724
13808
|
}
|
|
13725
13809
|
return args;
|
|
13726
13810
|
}
|
|
13727
|
-
function
|
|
13728
|
-
const
|
|
13811
|
+
function buildCreateArgs(resourceType) {
|
|
13812
|
+
const args = {
|
|
13813
|
+
res: {
|
|
13814
|
+
type: getGraphQLInputType(resourceType, 'Create'),
|
|
13815
|
+
description: resourceType + ' Create',
|
|
13816
|
+
},
|
|
13817
|
+
};
|
|
13818
|
+
return args;
|
|
13819
|
+
}
|
|
13820
|
+
function buildUpdateArgs(resourceType) {
|
|
13821
|
+
const args = {
|
|
13822
|
+
id: {
|
|
13823
|
+
type: new GraphQLNonNull(GraphQLID),
|
|
13824
|
+
description: resourceType + ' ID',
|
|
13825
|
+
},
|
|
13826
|
+
res: {
|
|
13827
|
+
type: getGraphQLInputType(resourceType, 'Update'),
|
|
13828
|
+
description: resourceType + ' Update',
|
|
13829
|
+
},
|
|
13830
|
+
};
|
|
13831
|
+
return args;
|
|
13832
|
+
}
|
|
13833
|
+
function getOutputPropertyType(elementDefinition, typeName) {
|
|
13834
|
+
const graphqlType = getGraphQLOutputType(typeName);
|
|
13729
13835
|
if (elementDefinition.max === '*') {
|
|
13730
13836
|
return new GraphQLList(graphqlType);
|
|
13731
13837
|
}
|
|
@@ -13764,7 +13870,6 @@ function buildConnectionType(resourceType, resourceGraphQLType) {
|
|
|
13764
13870
|
* @param ctx The GraphQL context.
|
|
13765
13871
|
* @param info The GraphQL resolve info. This includes the schema, and additional field details.
|
|
13766
13872
|
* @returns Promise to read the resoures for the query.
|
|
13767
|
-
* @implements {GraphQLFieldResolver}
|
|
13768
13873
|
*/
|
|
13769
13874
|
async function resolveBySearch(source, args, ctx, info) {
|
|
13770
13875
|
const fieldName = info.fieldName;
|
|
@@ -13782,7 +13887,6 @@ async function resolveBySearch(source, args, ctx, info) {
|
|
|
13782
13887
|
* @param ctx The GraphQL context.
|
|
13783
13888
|
* @param info The GraphQL resolve info. This includes the schema, and additional field details.
|
|
13784
13889
|
* @returns Promise to read the resoures for the query.
|
|
13785
|
-
* @implements {GraphQLFieldResolver}
|
|
13786
13890
|
*/
|
|
13787
13891
|
async function resolveByConnectionApi(source, args, ctx, info) {
|
|
13788
13892
|
const fieldName = info.fieldName;
|
|
@@ -13812,7 +13916,6 @@ async function resolveByConnectionApi(source, args, ctx, info) {
|
|
|
13812
13916
|
* @param ctx The GraphQL context.
|
|
13813
13917
|
* @param info The GraphQL resolve info. This includes the schema, and additional field details.
|
|
13814
13918
|
* @returns Promise to read the resoure for the query.
|
|
13815
|
-
* @implements {GraphQLFieldResolver}
|
|
13816
13919
|
*/
|
|
13817
13920
|
async function resolveById(_source, args, ctx, info) {
|
|
13818
13921
|
try {
|
|
@@ -13829,7 +13932,6 @@ async function resolveById(_source, args, ctx, info) {
|
|
|
13829
13932
|
* @param _args The GraphQL search arguments.
|
|
13830
13933
|
* @param ctx The GraphQL context.
|
|
13831
13934
|
* @returns Promise to read the resoure(s) for the query.
|
|
13832
|
-
* @implements {GraphQLFieldResolver}
|
|
13833
13935
|
*/
|
|
13834
13936
|
async function resolveByReference(source, _args, ctx) {
|
|
13835
13937
|
try {
|
|
@@ -13844,14 +13946,13 @@ async function resolveByReference(source, _args, ctx) {
|
|
|
13844
13946
|
* When loading a resource via reference, GraphQL needs to know the type of the resource.
|
|
13845
13947
|
* @param resource The loaded resource.
|
|
13846
13948
|
* @returns The GraphQL type of the resource.
|
|
13847
|
-
* @implements {GraphQLTypeResolver}
|
|
13848
13949
|
*/
|
|
13849
13950
|
function resolveTypeByReference(resource) {
|
|
13850
13951
|
const resourceType = resource?.resourceType;
|
|
13851
13952
|
if (!resourceType) {
|
|
13852
13953
|
return undefined;
|
|
13853
13954
|
}
|
|
13854
|
-
return
|
|
13955
|
+
return getGraphQLOutputType(resourceType).name;
|
|
13855
13956
|
}
|
|
13856
13957
|
/**
|
|
13857
13958
|
* GraphQL resolver for fields.
|
|
@@ -13862,7 +13963,6 @@ function resolveTypeByReference(resource) {
|
|
|
13862
13963
|
* @param _ctx The GraphQL context.
|
|
13863
13964
|
* @param info The GraphQL resolve info. This includes the field name.
|
|
13864
13965
|
* @returns Promise to read the resoure for the query.
|
|
13865
|
-
* @implements {GraphQLFieldResolver}
|
|
13866
13966
|
*/
|
|
13867
13967
|
async function resolveField(source, args, _ctx, info) {
|
|
13868
13968
|
const fieldValue = source?.[info.fieldName];
|
|
@@ -13885,6 +13985,68 @@ async function resolveField(source, args, _ctx, info) {
|
|
|
13885
13985
|
}
|
|
13886
13986
|
return array;
|
|
13887
13987
|
}
|
|
13988
|
+
/**
|
|
13989
|
+
* GraphQL resolver function for create requests.
|
|
13990
|
+
* The field name should end with "Create" (i.e., "PatientCreate" for updating a Patient).
|
|
13991
|
+
* The args should include the data to be created for the specified resource type.
|
|
13992
|
+
* @param _source The source/root object. In the case of creates, this is typically not used and is thus ignored.
|
|
13993
|
+
* @param args The GraphQL arguments, containing the new data for the resource.
|
|
13994
|
+
* @param ctx The GraphQL context. This includes the repository where resources are stored.
|
|
13995
|
+
* @param info The GraphQL resolve info. This includes the schema, field details, and other query-specific information.
|
|
13996
|
+
* @returns A Promise that resolves to the created resource, or undefined if the resource could not be found or updated.
|
|
13997
|
+
*/
|
|
13998
|
+
async function resolveByCreate(_source, args, ctx, info) {
|
|
13999
|
+
const fieldName = info.fieldName;
|
|
14000
|
+
// 'Create.length'=== 6 && 'Update.length' === 6
|
|
14001
|
+
const resourceType = fieldName.substring(0, fieldName.length - 6);
|
|
14002
|
+
const resourceArgs = args.res;
|
|
14003
|
+
if (resourceArgs.resourceType !== resourceType) {
|
|
14004
|
+
return [badRequest('Invalid resourceType')];
|
|
14005
|
+
}
|
|
14006
|
+
const resource = await ctx.repo.createResource(resourceArgs);
|
|
14007
|
+
return resource;
|
|
14008
|
+
}
|
|
14009
|
+
// Mutation Resolvers
|
|
14010
|
+
/**
|
|
14011
|
+
* GraphQL resolver function for update requests.
|
|
14012
|
+
* The field name should end with "Update" (i.e., "PatientUpdate" for updating a Patient).
|
|
14013
|
+
* The args should include the data to be updated for the specified resource type.
|
|
14014
|
+
* @param _source The source/root object. In the case of updates, this is typically not used and is thus ignored.
|
|
14015
|
+
* @param args The GraphQL arguments, containing the new data for the resource.
|
|
14016
|
+
* @param ctx The GraphQL context. This includes the repository where resources are stored.
|
|
14017
|
+
* @param info The GraphQL resolve info. This includes the schema, field details, and other query-specific information.
|
|
14018
|
+
* @returns A Promise that resolves to the updated resource, or undefined if the resource could not be found or updated.
|
|
14019
|
+
*/
|
|
14020
|
+
async function resolveByUpdate(_source, args, ctx, info) {
|
|
14021
|
+
const fieldName = info.fieldName;
|
|
14022
|
+
// 'Create.length'=== 6 && 'Update.length' === 6
|
|
14023
|
+
const resourceType = fieldName.substring(0, fieldName.length - 6);
|
|
14024
|
+
const resourceArgs = args.res;
|
|
14025
|
+
const resourceId = args.id;
|
|
14026
|
+
if (resourceArgs.resourceType !== resourceType) {
|
|
14027
|
+
return [badRequest('Invalid resourceType')];
|
|
14028
|
+
}
|
|
14029
|
+
if (resourceId !== resourceArgs.id) {
|
|
14030
|
+
return [badRequest('Incorrect ID')];
|
|
14031
|
+
}
|
|
14032
|
+
const resource = await ctx.repo.updateResource(resourceArgs);
|
|
14033
|
+
return resource;
|
|
14034
|
+
}
|
|
14035
|
+
/**
|
|
14036
|
+
* GraphQL resolver function for delete requests.
|
|
14037
|
+
* The field name should end with "Delete" (e.g., "PatientDelete" for deleting a Patient).
|
|
14038
|
+
* The args should include the ID of the resource to be deleted.
|
|
14039
|
+
* @param _source The source/root object. In the case of deletions, this is typically not used and is thus ignored.
|
|
14040
|
+
* @param args The GraphQL arguments, containing the ID of the resource to be deleted.
|
|
14041
|
+
* @param ctx The GraphQL context. This includes the repository where resources are stored.
|
|
14042
|
+
* @param info The GraphQL resolve info. This includes the schema, field details, and other query-specific information.
|
|
14043
|
+
* @returns A Promise that resolves when the resource has been deleted. No value is returned.
|
|
14044
|
+
*/
|
|
14045
|
+
async function resolveByDelete(_source, args, ctx, info) {
|
|
14046
|
+
const fieldName = info.fieldName;
|
|
14047
|
+
const resourceType = fieldName.substring(0, fieldName.length - 'Delete'.length);
|
|
14048
|
+
await ctx.repo.deleteResource(resourceType, args.id);
|
|
14049
|
+
}
|
|
13888
14050
|
function parseSearchArgs(resourceType, source, args) {
|
|
13889
14051
|
let referenceFilter = undefined;
|
|
13890
14052
|
if (source) {
|
|
@@ -14109,8 +14271,9 @@ async function patchResource(req, repo) {
|
|
|
14109
14271
|
return [allOk, resource];
|
|
14110
14272
|
}
|
|
14111
14273
|
class FhirRouter {
|
|
14112
|
-
constructor() {
|
|
14274
|
+
constructor(options = {}) {
|
|
14113
14275
|
this.router = new Router();
|
|
14276
|
+
this.options = options;
|
|
14114
14277
|
this.router.add('POST', '', batch);
|
|
14115
14278
|
this.router.add('GET', ':resourceType', search);
|
|
14116
14279
|
this.router.add('POST', ':resourceType/_search', searchByPost);
|
|
@@ -14148,7 +14311,6 @@ class BaseRepository {
|
|
|
14148
14311
|
* The return value is the resource, if available; otherwise, undefined.
|
|
14149
14312
|
*
|
|
14150
14313
|
* See FHIR search for full details: https://www.hl7.org/fhir/search.html
|
|
14151
|
-
*
|
|
14152
14314
|
* @param searchRequest The FHIR search request.
|
|
14153
14315
|
* @returns Promise to the first search result or undefined.
|
|
14154
14316
|
*/
|
|
@@ -14164,7 +14326,6 @@ class BaseRepository {
|
|
|
14164
14326
|
* The return value is an array of resources.
|
|
14165
14327
|
*
|
|
14166
14328
|
* See FHIR search for full details: https://www.hl7.org/fhir/search.html
|
|
14167
|
-
*
|
|
14168
14329
|
* @param searchRequest The FHIR search request.
|
|
14169
14330
|
* @returns Promise to the array of search results.
|
|
14170
14331
|
*/
|