@medplum/fhir-router 2.0.17 → 2.0.18

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.
@@ -13475,6 +13475,12 @@ spurious results.`);
13475
13475
  args: buildSearchArgs(resourceType),
13476
13476
  resolve: resolveBySearch,
13477
13477
  };
13478
+ // FHIR GraphQL Connection API
13479
+ fields[resourceType + 'Connection'] = {
13480
+ type: buildConnectionType(resourceType, graphQLType),
13481
+ args: buildSearchArgs(resourceType),
13482
+ resolve: resolveByConnectionApi,
13483
+ };
13478
13484
  }
13479
13485
  return new GraphQLSchema({
13480
13486
  query: new GraphQLObjectType({
@@ -13727,6 +13733,30 @@ spurious results.`);
13727
13733
  }
13728
13734
  return graphqlType;
13729
13735
  }
13736
+ function buildConnectionType(resourceType, resourceGraphQLType) {
13737
+ return new GraphQLObjectType({
13738
+ name: resourceType + 'Connection',
13739
+ fields: {
13740
+ count: { type: GraphQLInt },
13741
+ offset: { type: GraphQLInt },
13742
+ pageSize: { type: GraphQLInt },
13743
+ first: { type: GraphQLString },
13744
+ previous: { type: GraphQLString },
13745
+ next: { type: GraphQLString },
13746
+ last: { type: GraphQLString },
13747
+ edges: {
13748
+ type: new GraphQLList(new GraphQLObjectType({
13749
+ name: resourceType + 'ConnectionEdge',
13750
+ fields: {
13751
+ mode: { type: GraphQLString },
13752
+ score: { type: GraphQLFloat },
13753
+ resource: { type: resourceGraphQLType },
13754
+ },
13755
+ })),
13756
+ },
13757
+ },
13758
+ });
13759
+ }
13730
13760
  /**
13731
13761
  * GraphQL data loader for search requests.
13732
13762
  * The field name should always end with "List" (i.e., "Patient" search uses "PatientList").
@@ -13740,11 +13770,41 @@ spurious results.`);
13740
13770
  */
13741
13771
  async function resolveBySearch(source, args, ctx, info) {
13742
13772
  const fieldName = info.fieldName;
13743
- const resourceType = fieldName.substring(0, fieldName.length - 4); // Remove "List"
13773
+ const resourceType = fieldName.substring(0, fieldName.length - 'List'.length);
13744
13774
  const searchRequest = parseSearchArgs(resourceType, source, args);
13745
13775
  const bundle = await ctx.repo.search(searchRequest);
13746
13776
  return bundle.entry?.map((e) => e.resource);
13747
13777
  }
13778
+ /**
13779
+ * GraphQL data loader for search requests.
13780
+ * The field name should always end with "List" (i.e., "Patient" search uses "PatientList").
13781
+ * The search args should be FHIR search parameters.
13782
+ * @param source The source/root. This should always be null for our top level readers.
13783
+ * @param args The GraphQL search arguments.
13784
+ * @param ctx The GraphQL context.
13785
+ * @param info The GraphQL resolve info. This includes the schema, and additional field details.
13786
+ * @returns Promise to read the resoures for the query.
13787
+ * @implements {GraphQLFieldResolver}
13788
+ */
13789
+ async function resolveByConnectionApi(source, args, ctx, info) {
13790
+ const fieldName = info.fieldName;
13791
+ const resourceType = fieldName.substring(0, fieldName.length - 'Connection'.length);
13792
+ const searchRequest = parseSearchArgs(resourceType, source, args);
13793
+ if (isFieldRequested(info, 'count')) {
13794
+ searchRequest.total = 'accurate';
13795
+ }
13796
+ const bundle = await ctx.repo.search(searchRequest);
13797
+ return {
13798
+ count: bundle.total,
13799
+ offset: searchRequest.offset || 0,
13800
+ pageSize: searchRequest.count || core.DEFAULT_SEARCH_COUNT,
13801
+ edges: bundle.entry?.map((e) => ({
13802
+ mode: e.search?.mode,
13803
+ score: e.search?.score,
13804
+ resource: e.resource,
13805
+ })),
13806
+ };
13807
+ }
13748
13808
  /**
13749
13809
  * GraphQL data loader for ID requests.
13750
13810
  * The field name should always by the resource type.
@@ -13893,6 +13953,17 @@ spurious results.`);
13893
13953
  function getDepth(path) {
13894
13954
  return path.filter((p) => p === 'selections').length;
13895
13955
  }
13956
+ /**
13957
+ * Returns true if the field is requested in the GraphQL query.
13958
+ * @param info The GraphQL resolve info. This includes the field name.
13959
+ * @param fieldName The field name to check.
13960
+ * @returns True if the field is requested in the GraphQL query.
13961
+ */
13962
+ function isFieldRequested(info, fieldName) {
13963
+ return info.fieldNodes.some((fieldNode) => fieldNode.selectionSet?.selections.some((selection) => {
13964
+ return selection.kind === 'Field' && selection.name.value === fieldName;
13965
+ }));
13966
+ }
13896
13967
  /**
13897
13968
  * Returns an OperationOutcome for GraphQL errors.
13898
13969
  * @param errors Array of GraphQL errors.