@medplum/core 0.10.1 → 1.0.0

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.js CHANGED
@@ -305,7 +305,7 @@
305
305
  * @return Human friendly display string.
306
306
  */
307
307
  function getDisplayString(resource) {
308
- var _a, _b;
308
+ var _a;
309
309
  if (isProfileResource(resource)) {
310
310
  const profileName = getProfileResourceDisplayString(resource);
311
311
  if (profileName) {
@@ -320,7 +320,7 @@
320
320
  }
321
321
  if (resource.resourceType === 'Observation') {
322
322
  if ('code' in resource && ((_a = resource.code) === null || _a === void 0 ? void 0 : _a.text)) {
323
- return (_b = resource.code) === null || _b === void 0 ? void 0 : _b.text;
323
+ return resource.code.text;
324
324
  }
325
325
  }
326
326
  if (resource.resourceType === 'User') {
@@ -363,22 +363,23 @@
363
363
  * @returns The image URL for the resource or undefined.
364
364
  */
365
365
  function getImageSrc(resource) {
366
- if (isProfileResource(resource)) {
367
- const photos = resource.photo;
368
- if (photos) {
369
- for (const photo of photos) {
370
- const url = getPhotoImageSrc(photo);
371
- if (url) {
372
- return url;
373
- }
366
+ if (!('photo' in resource)) {
367
+ return undefined;
368
+ }
369
+ const photo = resource.photo;
370
+ if (!photo) {
371
+ return undefined;
372
+ }
373
+ if (Array.isArray(photo)) {
374
+ for (const p of photo) {
375
+ const url = getPhotoImageSrc(p);
376
+ if (url) {
377
+ return url;
374
378
  }
375
379
  }
376
380
  }
377
- if (resource.resourceType === 'Bot' && resource.photo) {
378
- const url = getPhotoImageSrc(resource.photo);
379
- if (url) {
380
- return url;
381
- }
381
+ else {
382
+ return getPhotoImageSrc(photo);
382
383
  }
383
384
  return undefined;
384
385
  }
@@ -807,12 +808,7 @@
807
808
  * @returns True if the two numbers are equal to the given precision.
808
809
  */
809
810
  function preciseEquals(a, b, precision) {
810
- if (precision) {
811
- return Math.abs(a - b) < Math.pow(10, -precision);
812
- }
813
- else {
814
- return a === b;
815
- }
811
+ return toPreciseInteger(a, precision) === toPreciseInteger(b, precision);
816
812
  }
817
813
  /**
818
814
  * Returns true if the first number is less than the second number to the given precision.
@@ -822,12 +818,7 @@
822
818
  * @returns True if the first number is less than the second number to the given precision.
823
819
  */
824
820
  function preciseLessThan(a, b, precision) {
825
- if (precision) {
826
- return a < b && Math.abs(a - b) > Math.pow(10, -precision);
827
- }
828
- else {
829
- return a < b;
830
- }
821
+ return toPreciseInteger(a, precision) < toPreciseInteger(b, precision);
831
822
  }
832
823
  /**
833
824
  * Returns true if the first number is greater than the second number to the given precision.
@@ -837,12 +828,7 @@
837
828
  * @returns True if the first number is greater than the second number to the given precision.
838
829
  */
839
830
  function preciseGreaterThan(a, b, precision) {
840
- if (precision) {
841
- return a > b && Math.abs(a - b) > Math.pow(10, -precision);
842
- }
843
- else {
844
- return a > b;
845
- }
831
+ return toPreciseInteger(a, precision) > toPreciseInteger(b, precision);
846
832
  }
847
833
  /**
848
834
  * Returns true if the first number is less than or equal to the second number to the given precision.
@@ -852,7 +838,7 @@
852
838
  * @returns True if the first number is less than or equal to the second number to the given precision.
853
839
  */
854
840
  function preciseLessThanOrEquals(a, b, precision) {
855
- return preciseLessThan(a, b, precision) || preciseEquals(a, b, precision);
841
+ return toPreciseInteger(a, precision) <= toPreciseInteger(b, precision);
856
842
  }
857
843
  /**
858
844
  * Returns true if the first number is greater than or equal to the second number to the given precision.
@@ -862,7 +848,20 @@
862
848
  * @returns True if the first number is greater than or equal to the second number to the given precision.
863
849
  */
864
850
  function preciseGreaterThanOrEquals(a, b, precision) {
865
- return preciseGreaterThan(a, b, precision) || preciseEquals(a, b, precision);
851
+ return toPreciseInteger(a, precision) >= toPreciseInteger(b, precision);
852
+ }
853
+ /**
854
+ * Returns an integer representation of the number with the given precision.
855
+ * For example, if precision is 2, then 1.2345 will be returned as 123.
856
+ * @param a The number.
857
+ * @param precision Optional precision in number of digits.
858
+ * @returns The integer with the given precision.
859
+ */
860
+ function toPreciseInteger(a, precision) {
861
+ if (precision === undefined) {
862
+ return a;
863
+ }
864
+ return Math.round(a * Math.pow(10, precision));
866
865
  }
867
866
 
868
867
  /**
@@ -6082,6 +6081,7 @@
6082
6081
  /**
6083
6082
  * Indexes a bundle of StructureDefinitions for faster lookup.
6084
6083
  * @param bundle A FHIR bundle StructureDefinition resources.
6084
+ * @see {@link IndexedStructureDefinition} for more details on indexed StructureDefinitions.
6085
6085
  */
6086
6086
  function indexStructureDefinitionBundle(bundle) {
6087
6087
  for (const entry of bundle.entry) {
@@ -6093,8 +6093,8 @@
6093
6093
  }
6094
6094
  /**
6095
6095
  * Indexes a StructureDefinition for fast lookup.
6096
- * See comments on IndexedStructureDefinition for more details.
6097
6096
  * @param structureDefinition The original StructureDefinition.
6097
+ * @see {@link IndexedStructureDefinition} for more details on indexed StructureDefinitions.
6098
6098
  */
6099
6099
  function indexStructureDefinition(structureDefinition) {
6100
6100
  var _a;
@@ -6114,8 +6114,9 @@
6114
6114
  * Indexes TypeSchema from an ElementDefinition.
6115
6115
  * In the common case, there will be many ElementDefinition instances per TypeSchema.
6116
6116
  * Only the first occurrence is saved.
6117
- * @param schema The output IndexedStructureDefinition.
6118
- * @param element The input ElementDefinition.
6117
+ * @param structureDefinition The parent type structure definition.
6118
+ * @param elementDefinition The element definition.
6119
+ * @see {@link IndexedStructureDefinition} for more details on indexed StructureDefinitions.
6119
6120
  */
6120
6121
  function indexType(structureDefinition, elementDefinition) {
6121
6122
  var _a, _b;
@@ -6131,8 +6132,8 @@
6131
6132
  }
6132
6133
  /**
6133
6134
  * Indexes PropertySchema from an ElementDefinition.
6134
- * @param schema The output IndexedStructureDefinition.
6135
6135
  * @param element The input ElementDefinition.
6136
+ * @see {@link IndexedStructureDefinition} for more details on indexed StructureDefinitions.
6136
6137
  */
6137
6138
  function indexProperty(element) {
6138
6139
  const path = element.path;
@@ -6148,11 +6149,24 @@
6148
6149
  const key = parts[parts.length - 1];
6149
6150
  typeSchema.properties[key] = element;
6150
6151
  }
6152
+ /**
6153
+ * Indexes a bundle of SearchParameter resources for faster lookup.
6154
+ * @param bundle A FHIR bundle SearchParameter resources.
6155
+ * @see {@link IndexedStructureDefinition} for more details on indexed StructureDefinitions.
6156
+ */
6157
+ function indexSearchParameterBundle(bundle) {
6158
+ for (const entry of bundle.entry) {
6159
+ const resource = entry.resource;
6160
+ if (resource.resourceType === 'SearchParameter') {
6161
+ indexSearchParameter(resource);
6162
+ }
6163
+ }
6164
+ }
6151
6165
  /**
6152
6166
  * Indexes a SearchParameter resource for fast lookup.
6153
6167
  * Indexes by SearchParameter.code, which is the query string parameter name.
6154
- * @param schema The output IndexedStructureDefinition.
6155
6168
  * @param searchParam The SearchParameter resource.
6169
+ * @see {@link IndexedStructureDefinition} for more details on indexed StructureDefinitions.
6156
6170
  */
6157
6171
  function indexSearchParameter(searchParam) {
6158
6172
  if (!searchParam.base) {
@@ -6177,6 +6191,12 @@
6177
6191
  type: 'date',
6178
6192
  expression: resourceType + '.meta.lastUpdated',
6179
6193
  },
6194
+ _compartment: {
6195
+ base: [resourceType],
6196
+ code: '_compartment',
6197
+ type: 'reference',
6198
+ expression: resourceType + '.meta.compartment',
6199
+ },
6180
6200
  };
6181
6201
  }
6182
6202
  typeSchema.searchParams[searchParam.code] = searchParam;
@@ -6245,7 +6265,7 @@
6245
6265
  // PKCE auth based on:
6246
6266
  // https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
6247
6267
  var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_createPdf, _MedplumClient_storage, _MedplumClient_requestCache, _MedplumClient_cacheTime, _MedplumClient_baseUrl, _MedplumClient_clientId, _MedplumClient_authorizeUrl, _MedplumClient_tokenUrl, _MedplumClient_logoutUrl, _MedplumClient_onUnauthenticated, _MedplumClient_accessToken, _MedplumClient_refreshToken, _MedplumClient_refreshPromise, _MedplumClient_profilePromise, _MedplumClient_profile, _MedplumClient_config, _MedplumClient_addLogin, _MedplumClient_refreshProfile, _MedplumClient_getCacheEntry, _MedplumClient_setCacheEntry, _MedplumClient_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
6248
- const MEDPLUM_VERSION = "0.10.1-221e9b95";
6268
+ const MEDPLUM_VERSION = "1.0.0-a614a88a";
6249
6269
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
6250
6270
  const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
6251
6271
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
@@ -6692,7 +6712,9 @@
6692
6712
  * See FHIR search for full details: https://www.hl7.org/fhir/search.html
6693
6713
  *
6694
6714
  * @category Search
6715
+ * @param resourceType The FHIR resource type.
6695
6716
  * @param query The search query as either a string or a structured search object.
6717
+ * @param options Optional fetch options.
6696
6718
  * @returns Promise to the search result bundle.
6697
6719
  */
6698
6720
  search(resourceType, query, options = {}) {
@@ -6715,7 +6737,9 @@
6715
6737
  * See FHIR search for full details: https://www.hl7.org/fhir/search.html
6716
6738
  *
6717
6739
  * @category Search
6740
+ * @param resourceType The FHIR resource type.
6718
6741
  * @param query The search query as either a string or a structured search object.
6742
+ * @param options Optional fetch options.
6719
6743
  * @returns Promise to the search result bundle.
6720
6744
  */
6721
6745
  searchOne(resourceType, query, options = {}) {
@@ -6748,7 +6772,9 @@
6748
6772
  * See FHIR search for full details: https://www.hl7.org/fhir/search.html
6749
6773
  *
6750
6774
  * @category Search
6775
+ * @param resourceType The FHIR resource type.
6751
6776
  * @param query The search query as either a string or a structured search object.
6777
+ * @param options Optional fetch options.
6752
6778
  * @returns Promise to the search result bundle.
6753
6779
  */
6754
6780
  searchResources(resourceType, query, options = {}) {
@@ -6769,6 +6795,7 @@
6769
6795
  * @category Search
6770
6796
  * @param system The ValueSet system url.
6771
6797
  * @param filter The search string.
6798
+ * @param options Optional fetch options.
6772
6799
  * @returns Promise to expanded ValueSet.
6773
6800
  */
6774
6801
  searchValueSet(system, filter, options = {}) {
@@ -6822,6 +6849,7 @@
6822
6849
  * @category Read
6823
6850
  * @param resourceType The FHIR resource type.
6824
6851
  * @param id The resource ID.
6852
+ * @param options Optional fetch options.
6825
6853
  * @returns The resource if available; undefined otherwise.
6826
6854
  */
6827
6855
  readResource(resourceType, id, options = {}) {
@@ -6844,6 +6872,7 @@
6844
6872
  *
6845
6873
  * @category Read
6846
6874
  * @param reference The FHIR reference object.
6875
+ * @param options Optional fetch options.
6847
6876
  * @returns The resource if available; undefined otherwise.
6848
6877
  */
6849
6878
  readReference(reference, options = {}) {
@@ -6862,7 +6891,6 @@
6862
6891
  * If the schema is not cached, returns undefined.
6863
6892
  * It is assumed that a client will call requestSchema before using this method.
6864
6893
  * @category Schema
6865
- * @param resourceType The FHIR resource type.
6866
6894
  * @returns The schema if immediately available, undefined otherwise.
6867
6895
  * @deprecated Use globalSchema instead.
6868
6896
  */
@@ -6937,6 +6965,7 @@
6937
6965
  * @category Read
6938
6966
  * @param resourceType The FHIR resource type.
6939
6967
  * @param id The resource ID.
6968
+ * @param options Optional fetch options.
6940
6969
  * @returns Promise to the resource history.
6941
6970
  */
6942
6971
  readHistory(resourceType, id, options = {}) {
@@ -6957,6 +6986,8 @@
6957
6986
  * @category Read
6958
6987
  * @param resourceType The FHIR resource type.
6959
6988
  * @param id The resource ID.
6989
+ * @param vid The version ID.
6990
+ * @param options Optional fetch options.
6960
6991
  * @returns The resource if available; undefined otherwise.
6961
6992
  */
6962
6993
  readVersion(resourceType, id, vid, options = {}) {
@@ -6966,6 +6997,7 @@
6966
6997
  *
6967
6998
  * @category Read
6968
6999
  * @param id The Patient Id
7000
+ * @param options Optional fetch options.
6969
7001
  * @returns A Bundle of all Resources related to the Patient
6970
7002
  */
6971
7003
  readPatientEverything(id, options = {}) {
@@ -7072,12 +7104,44 @@
7072
7104
  * @param contentType Content type for the binary.
7073
7105
  * @returns The result of the create operation.
7074
7106
  */
7075
- createBinary(data, filename, contentType) {
7107
+ createBinary(data, filename, contentType, onProgress) {
7076
7108
  const url = this.fhirUrl('Binary');
7077
7109
  if (filename) {
7078
7110
  url.searchParams.set('_filename', filename);
7079
7111
  }
7080
- return this.post(url, data, contentType);
7112
+ if (onProgress) {
7113
+ return this.uploadwithProgress(url, data, contentType, onProgress);
7114
+ }
7115
+ else {
7116
+ return this.post(url, data, contentType);
7117
+ }
7118
+ }
7119
+ uploadwithProgress(url, data, contentType, onProgress) {
7120
+ return new Promise((resolve, reject) => {
7121
+ const xhr = new XMLHttpRequest();
7122
+ xhr.responseType = 'json';
7123
+ xhr.onabort = () => reject(new Error('Request aborted'));
7124
+ xhr.onerror = () => reject(new Error('Request error'));
7125
+ if (onProgress) {
7126
+ xhr.upload.onprogress = (e) => onProgress(e);
7127
+ xhr.upload.onload = (e) => onProgress(e);
7128
+ }
7129
+ xhr.onload = () => {
7130
+ if (xhr.status >= 200 && xhr.status < 300) {
7131
+ resolve(xhr.response);
7132
+ }
7133
+ else {
7134
+ reject(new Error(xhr.statusText));
7135
+ }
7136
+ };
7137
+ xhr.open('POST', url);
7138
+ xhr.withCredentials = true;
7139
+ xhr.setRequestHeader('Authorization', 'Bearer ' + __classPrivateFieldGet(this, _MedplumClient_accessToken, "f"));
7140
+ xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, max-age=0');
7141
+ xhr.setRequestHeader('Content-Type', contentType);
7142
+ xhr.setRequestHeader('X-Medplum', 'extended');
7143
+ xhr.send(data);
7144
+ });
7081
7145
  }
7082
7146
  /**
7083
7147
  * Creates a PDF as a FHIR `Binary` resource based on pdfmake document definition.
@@ -7233,6 +7297,26 @@
7233
7297
  this.invalidateSearches(resourceType);
7234
7298
  return this.delete(this.fhirUrl(resourceType, id));
7235
7299
  }
7300
+ /**
7301
+ * Executes the validate operation with the provided resource.
7302
+ *
7303
+ * Example:
7304
+ *
7305
+ * ```typescript
7306
+ * const result = await medplum.validateResource({
7307
+ * resourceType: 'Patient',
7308
+ * name: [{ given: ['Alice'], family: 'Smith' }],
7309
+ * });
7310
+ * ```
7311
+ *
7312
+ * See the FHIR "$validate" operation for full details: https://www.hl7.org/fhir/resource-operation-validate.html
7313
+ *
7314
+ * @param resource The FHIR resource.
7315
+ * @returns The validate operation outcome.
7316
+ */
7317
+ validateResource(resource) {
7318
+ return this.post(this.fhirUrl(resource.resourceType, '$validate'), resource);
7319
+ }
7236
7320
  /**
7237
7321
  * Executes a batch or transaction of FHIR operations.
7238
7322
  *
@@ -10502,216 +10586,11 @@
10502
10586
  }
10503
10587
  }
10504
10588
 
10505
- const OK_ID = 'ok';
10506
- const CREATED_ID = 'created';
10507
- const GONE_ID = 'gone';
10508
- const NOT_MODIFIED_ID = 'not-modified';
10509
- const NOT_FOUND_ID = 'not-found';
10510
- const UNAUTHORIZED_ID = 'unauthorized';
10511
- const FORBIDDEN_ID = 'forbidden';
10512
- const TOO_MANY_REQUESTS_ID = 'too-many-requests';
10513
- const allOk = {
10514
- resourceType: 'OperationOutcome',
10515
- id: OK_ID,
10516
- issue: [
10517
- {
10518
- severity: 'information',
10519
- code: 'informational',
10520
- details: {
10521
- text: 'All OK',
10522
- },
10523
- },
10524
- ],
10525
- };
10526
- const created = {
10527
- resourceType: 'OperationOutcome',
10528
- id: CREATED_ID,
10529
- issue: [
10530
- {
10531
- severity: 'information',
10532
- code: 'informational',
10533
- details: {
10534
- text: 'Created',
10535
- },
10536
- },
10537
- ],
10538
- };
10539
- const notModified = {
10540
- resourceType: 'OperationOutcome',
10541
- id: NOT_MODIFIED_ID,
10542
- issue: [
10543
- {
10544
- severity: 'information',
10545
- code: 'informational',
10546
- details: {
10547
- text: 'Not Modified',
10548
- },
10549
- },
10550
- ],
10551
- };
10552
- const notFound = {
10553
- resourceType: 'OperationOutcome',
10554
- id: NOT_FOUND_ID,
10555
- issue: [
10556
- {
10557
- severity: 'error',
10558
- code: 'not-found',
10559
- details: {
10560
- text: 'Not found',
10561
- },
10562
- },
10563
- ],
10564
- };
10565
- const unauthorized = {
10566
- resourceType: 'OperationOutcome',
10567
- id: UNAUTHORIZED_ID,
10568
- issue: [
10569
- {
10570
- severity: 'error',
10571
- code: 'login',
10572
- details: {
10573
- text: 'Unauthorized',
10574
- },
10575
- },
10576
- ],
10577
- };
10578
- const forbidden = {
10579
- resourceType: 'OperationOutcome',
10580
- id: FORBIDDEN_ID,
10581
- issue: [
10582
- {
10583
- severity: 'error',
10584
- code: 'forbidden',
10585
- details: {
10586
- text: 'Forbidden',
10587
- },
10588
- },
10589
- ],
10590
- };
10591
- const gone = {
10592
- resourceType: 'OperationOutcome',
10593
- id: GONE_ID,
10594
- issue: [
10595
- {
10596
- severity: 'error',
10597
- code: 'deleted',
10598
- details: {
10599
- text: 'Gone',
10600
- },
10601
- },
10602
- ],
10603
- };
10604
- const tooManyRequests = {
10605
- resourceType: 'OperationOutcome',
10606
- id: TOO_MANY_REQUESTS_ID,
10607
- issue: [
10608
- {
10609
- severity: 'error',
10610
- code: 'throttled',
10611
- details: {
10612
- text: 'Too Many Requests',
10613
- },
10614
- },
10615
- ],
10616
- };
10617
- function badRequest(details, expression) {
10618
- return {
10619
- resourceType: 'OperationOutcome',
10620
- issue: [
10621
- {
10622
- severity: 'error',
10623
- code: 'invalid',
10624
- details: {
10625
- text: details,
10626
- },
10627
- expression: expression ? [expression] : undefined,
10628
- },
10629
- ],
10630
- };
10631
- }
10632
- function isOk(outcome) {
10633
- return outcome.id === OK_ID || outcome.id === CREATED_ID || outcome.id === NOT_MODIFIED_ID;
10634
- }
10635
- function isNotFound(outcome) {
10636
- return outcome.id === NOT_FOUND_ID;
10637
- }
10638
- function isGone(outcome) {
10639
- return outcome.id === GONE_ID;
10640
- }
10641
- function getStatus(outcome) {
10642
- if (outcome.id === OK_ID) {
10643
- return 200;
10644
- }
10645
- else if (outcome.id === CREATED_ID) {
10646
- return 201;
10647
- }
10648
- else if (outcome.id === NOT_MODIFIED_ID) {
10649
- return 304;
10650
- }
10651
- else if (outcome.id === UNAUTHORIZED_ID) {
10652
- return 401;
10653
- }
10654
- else if (outcome.id === FORBIDDEN_ID) {
10655
- return 403;
10656
- }
10657
- else if (outcome.id === NOT_FOUND_ID) {
10658
- return 404;
10659
- }
10660
- else if (outcome.id === GONE_ID) {
10661
- return 410;
10662
- }
10663
- else if (outcome.id === TOO_MANY_REQUESTS_ID) {
10664
- return 429;
10665
- }
10666
- else {
10667
- return 400;
10668
- }
10669
- }
10670
- /**
10671
- * Asserts that the operation completed successfully and that the resource is defined.
10672
- * @param outcome The operation outcome.
10673
- * @param resource The resource that may or may not have been returned.
10674
- */
10675
- function assertOk(outcome, resource) {
10676
- if (!isOk(outcome) || resource === undefined) {
10677
- throw new OperationOutcomeError(outcome);
10678
- }
10679
- }
10680
- class OperationOutcomeError extends Error {
10681
- constructor(outcome) {
10682
- var _a, _b;
10683
- super((_b = (_a = outcome === null || outcome === void 0 ? void 0 : outcome.issue) === null || _a === void 0 ? void 0 : _a[0].details) === null || _b === void 0 ? void 0 : _b.text);
10684
- this.outcome = outcome;
10685
- }
10686
- }
10589
+ const DEFAULT_SEARCH_COUNT = 20;
10687
10590
  /**
10688
- * Normalizes an error object into a displayable error string.
10689
- * @param error The error value which could be a string, Error, OperationOutcome, or other unknown type.
10690
- * @returns A display string for the error.
10691
- */
10692
- function normalizeErrorString(error) {
10693
- var _a, _b, _c, _d;
10694
- if (!error) {
10695
- return 'Unknown error';
10696
- }
10697
- if (typeof error === 'string') {
10698
- return error;
10699
- }
10700
- if (error instanceof Error) {
10701
- return error.message;
10702
- }
10703
- if (typeof error === 'object' && 'resourceType' in error) {
10704
- const outcome = error;
10705
- return (_d = (_c = (_b = (_a = outcome.issue) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.details) === null || _c === void 0 ? void 0 : _c.text) !== null && _d !== void 0 ? _d : 'Unknown error';
10706
- }
10707
- return JSON.stringify(error);
10708
- }
10709
-
10710
- const DEFAULT_SEARCH_COUNT = 20;
10711
- /**
10712
- * Search operators.
10713
- * These operators represent "modifiers" and "prefixes" in FHIR search.
10714
- * See: https://www.hl7.org/fhir/search.html
10591
+ * Search operators.
10592
+ * These operators represent "modifiers" and "prefixes" in FHIR search.
10593
+ * See: https://www.hl7.org/fhir/search.html
10715
10594
  */
10716
10595
  exports.Operator = void 0;
10717
10596
  (function (Operator) {
@@ -11069,6 +10948,361 @@
11069
10948
  return result;
11070
10949
  }
11071
10950
 
10951
+ /**
10952
+ * Determines if the resource matches the search request.
10953
+ * @param resource The resource that was created or updated.
10954
+ * @param searchRequest The subscription criteria as a search request.
10955
+ * @returns True if the resource satisfies the search request.
10956
+ */
10957
+ function matchesSearchRequest(resource, searchRequest) {
10958
+ if (searchRequest.resourceType !== resource.resourceType) {
10959
+ return false;
10960
+ }
10961
+ if (searchRequest.filters) {
10962
+ for (const filter of searchRequest.filters) {
10963
+ if (!matchesSearchFilter(resource, searchRequest, filter)) {
10964
+ return false;
10965
+ }
10966
+ }
10967
+ }
10968
+ return true;
10969
+ }
10970
+ /**
10971
+ * Determines if the resource matches the search filter.
10972
+ * @param resource The resource that was created or updated.
10973
+ * @param filter One of the filters of a subscription criteria.
10974
+ * @returns True if the resource satisfies the search filter.
10975
+ */
10976
+ function matchesSearchFilter(resource, searchRequest, filter) {
10977
+ var _a, _b;
10978
+ const searchParam = (_b = (_a = globalSchema.types[searchRequest.resourceType]) === null || _a === void 0 ? void 0 : _a.searchParams) === null || _b === void 0 ? void 0 : _b[filter.code];
10979
+ switch (searchParam === null || searchParam === void 0 ? void 0 : searchParam.type) {
10980
+ case 'reference':
10981
+ return matchesReferenceFilter(resource, filter, searchParam);
10982
+ case 'string':
10983
+ return matchesStringFilter(resource, filter, searchParam);
10984
+ case 'token':
10985
+ return matchesTokenFilter(resource, filter, searchParam);
10986
+ case 'date':
10987
+ return matchesDateFilter(resource, filter, searchParam);
10988
+ }
10989
+ // Unknown search parameter or search parameter type
10990
+ // Default fail the check
10991
+ return false;
10992
+ }
10993
+ function matchesReferenceFilter(resource, filter, searchParam) {
10994
+ const values = evalFhirPath(searchParam.expression, resource);
10995
+ const negated = isNegated(filter.operator);
10996
+ if (filter.value === '' && values.length === 0) {
10997
+ // If the filter operator is "equals", then the filter matches.
10998
+ // If the filter operator is "not equals", then the filter does not match.
10999
+ return filter.operator === exports.Operator.EQUALS;
11000
+ }
11001
+ // Normalize the values array into reference strings
11002
+ const references = values.map((value) => (typeof value === 'string' ? value : value.reference));
11003
+ for (const filterValue of filter.value.split(',')) {
11004
+ let match = references.includes(filterValue);
11005
+ if (!match && filter.code === '_compartment') {
11006
+ // Backwards compability for compartment search parameter
11007
+ // In previous versions, the resource type was not required in compartment values
11008
+ // So, "123" would match "Patient/123"
11009
+ // We need to maintain this behavior for backwards compatibility
11010
+ match = references.some((reference) => reference === null || reference === void 0 ? void 0 : reference.endsWith('/' + filterValue));
11011
+ }
11012
+ if (match) {
11013
+ return !negated;
11014
+ }
11015
+ }
11016
+ // If "not equals" and no matches, then return true
11017
+ // If "equals" and no matches, then return false
11018
+ return negated;
11019
+ }
11020
+ function matchesTokenFilter(resource, filter, searchParam) {
11021
+ const details = getSearchParameterDetails(resource.resourceType, searchParam);
11022
+ if (details.type === exports.SearchParameterType.BOOLEAN) {
11023
+ return matchesBooleanFilter(resource, filter, searchParam);
11024
+ }
11025
+ else {
11026
+ return matchesStringFilter(resource, filter, searchParam);
11027
+ }
11028
+ }
11029
+ function matchesBooleanFilter(resource, filter, searchParam) {
11030
+ const values = evalFhirPath(searchParam.expression, resource);
11031
+ const expected = filter.value === 'true';
11032
+ const result = values.includes(expected);
11033
+ return isNegated(filter.operator) ? !result : result;
11034
+ }
11035
+ function matchesStringFilter(resource, filter, searchParam) {
11036
+ const resourceValues = evalFhirPath(searchParam.expression, resource);
11037
+ const filterValues = filter.value.split(',');
11038
+ const negated = isNegated(filter.operator);
11039
+ for (const resourceValue of resourceValues) {
11040
+ for (const filterValue of filterValues) {
11041
+ const match = matchesStringValue(resourceValue, filter.operator, filterValue);
11042
+ if (match) {
11043
+ return !negated;
11044
+ }
11045
+ }
11046
+ }
11047
+ // If "not equals" and no matches, then return true
11048
+ // If "equals" and no matches, then return false
11049
+ return negated;
11050
+ }
11051
+ function matchesStringValue(resourceValue, operator, filterValue) {
11052
+ let str = '';
11053
+ if (resourceValue) {
11054
+ if (typeof resourceValue === 'string') {
11055
+ str = resourceValue;
11056
+ }
11057
+ else if (typeof resourceValue === 'object') {
11058
+ str = JSON.stringify(resourceValue);
11059
+ }
11060
+ }
11061
+ return str.toLowerCase().includes(filterValue.toLowerCase());
11062
+ }
11063
+ function matchesDateFilter(resource, filter, searchParam) {
11064
+ const resourceValues = evalFhirPath(searchParam.expression, resource);
11065
+ const filterValues = filter.value.split(',');
11066
+ const negated = isNegated(filter.operator);
11067
+ for (const resourceValue of resourceValues) {
11068
+ for (const filterValue of filterValues) {
11069
+ const match = matchesDateValue(resourceValue, filter.operator, filterValue);
11070
+ if (match) {
11071
+ return !negated;
11072
+ }
11073
+ }
11074
+ }
11075
+ // If "not equals" and no matches, then return true
11076
+ // If "equals" and no matches, then return false
11077
+ return negated;
11078
+ }
11079
+ function matchesDateValue(resourceValue, operator, filterValue) {
11080
+ switch (operator) {
11081
+ case exports.Operator.STARTS_AFTER:
11082
+ case exports.Operator.GREATER_THAN:
11083
+ return resourceValue > filterValue;
11084
+ case exports.Operator.GREATER_THAN_OR_EQUALS:
11085
+ return resourceValue >= filterValue;
11086
+ case exports.Operator.ENDS_BEFORE:
11087
+ case exports.Operator.LESS_THAN:
11088
+ return resourceValue < filterValue;
11089
+ case exports.Operator.LESS_THAN_OR_EQUALS:
11090
+ return resourceValue <= filterValue;
11091
+ case exports.Operator.EQUALS:
11092
+ case exports.Operator.NOT_EQUALS:
11093
+ return resourceValue === filterValue;
11094
+ }
11095
+ return false;
11096
+ }
11097
+ function isNegated(operator) {
11098
+ return operator === exports.Operator.NOT_EQUALS || operator === exports.Operator.NOT;
11099
+ }
11100
+
11101
+ const OK_ID = 'ok';
11102
+ const CREATED_ID = 'created';
11103
+ const GONE_ID = 'gone';
11104
+ const NOT_MODIFIED_ID = 'not-modified';
11105
+ const NOT_FOUND_ID = 'not-found';
11106
+ const UNAUTHORIZED_ID = 'unauthorized';
11107
+ const FORBIDDEN_ID = 'forbidden';
11108
+ const TOO_MANY_REQUESTS_ID = 'too-many-requests';
11109
+ const allOk = {
11110
+ resourceType: 'OperationOutcome',
11111
+ id: OK_ID,
11112
+ issue: [
11113
+ {
11114
+ severity: 'information',
11115
+ code: 'informational',
11116
+ details: {
11117
+ text: 'All OK',
11118
+ },
11119
+ },
11120
+ ],
11121
+ };
11122
+ const created = {
11123
+ resourceType: 'OperationOutcome',
11124
+ id: CREATED_ID,
11125
+ issue: [
11126
+ {
11127
+ severity: 'information',
11128
+ code: 'informational',
11129
+ details: {
11130
+ text: 'Created',
11131
+ },
11132
+ },
11133
+ ],
11134
+ };
11135
+ const notModified = {
11136
+ resourceType: 'OperationOutcome',
11137
+ id: NOT_MODIFIED_ID,
11138
+ issue: [
11139
+ {
11140
+ severity: 'information',
11141
+ code: 'informational',
11142
+ details: {
11143
+ text: 'Not Modified',
11144
+ },
11145
+ },
11146
+ ],
11147
+ };
11148
+ const notFound = {
11149
+ resourceType: 'OperationOutcome',
11150
+ id: NOT_FOUND_ID,
11151
+ issue: [
11152
+ {
11153
+ severity: 'error',
11154
+ code: 'not-found',
11155
+ details: {
11156
+ text: 'Not found',
11157
+ },
11158
+ },
11159
+ ],
11160
+ };
11161
+ const unauthorized = {
11162
+ resourceType: 'OperationOutcome',
11163
+ id: UNAUTHORIZED_ID,
11164
+ issue: [
11165
+ {
11166
+ severity: 'error',
11167
+ code: 'login',
11168
+ details: {
11169
+ text: 'Unauthorized',
11170
+ },
11171
+ },
11172
+ ],
11173
+ };
11174
+ const forbidden = {
11175
+ resourceType: 'OperationOutcome',
11176
+ id: FORBIDDEN_ID,
11177
+ issue: [
11178
+ {
11179
+ severity: 'error',
11180
+ code: 'forbidden',
11181
+ details: {
11182
+ text: 'Forbidden',
11183
+ },
11184
+ },
11185
+ ],
11186
+ };
11187
+ const gone = {
11188
+ resourceType: 'OperationOutcome',
11189
+ id: GONE_ID,
11190
+ issue: [
11191
+ {
11192
+ severity: 'error',
11193
+ code: 'deleted',
11194
+ details: {
11195
+ text: 'Gone',
11196
+ },
11197
+ },
11198
+ ],
11199
+ };
11200
+ const tooManyRequests = {
11201
+ resourceType: 'OperationOutcome',
11202
+ id: TOO_MANY_REQUESTS_ID,
11203
+ issue: [
11204
+ {
11205
+ severity: 'error',
11206
+ code: 'throttled',
11207
+ details: {
11208
+ text: 'Too Many Requests',
11209
+ },
11210
+ },
11211
+ ],
11212
+ };
11213
+ function badRequest(details, expression) {
11214
+ return {
11215
+ resourceType: 'OperationOutcome',
11216
+ issue: [
11217
+ {
11218
+ severity: 'error',
11219
+ code: 'invalid',
11220
+ details: {
11221
+ text: details,
11222
+ },
11223
+ expression: expression ? [expression] : undefined,
11224
+ },
11225
+ ],
11226
+ };
11227
+ }
11228
+ function isOk(outcome) {
11229
+ return outcome.id === OK_ID || outcome.id === CREATED_ID || outcome.id === NOT_MODIFIED_ID;
11230
+ }
11231
+ function isNotFound(outcome) {
11232
+ return outcome.id === NOT_FOUND_ID;
11233
+ }
11234
+ function isGone(outcome) {
11235
+ return outcome.id === GONE_ID;
11236
+ }
11237
+ function getStatus(outcome) {
11238
+ if (outcome.id === OK_ID) {
11239
+ return 200;
11240
+ }
11241
+ else if (outcome.id === CREATED_ID) {
11242
+ return 201;
11243
+ }
11244
+ else if (outcome.id === NOT_MODIFIED_ID) {
11245
+ return 304;
11246
+ }
11247
+ else if (outcome.id === UNAUTHORIZED_ID) {
11248
+ return 401;
11249
+ }
11250
+ else if (outcome.id === FORBIDDEN_ID) {
11251
+ return 403;
11252
+ }
11253
+ else if (outcome.id === NOT_FOUND_ID) {
11254
+ return 404;
11255
+ }
11256
+ else if (outcome.id === GONE_ID) {
11257
+ return 410;
11258
+ }
11259
+ else if (outcome.id === TOO_MANY_REQUESTS_ID) {
11260
+ return 429;
11261
+ }
11262
+ else {
11263
+ return 400;
11264
+ }
11265
+ }
11266
+ /**
11267
+ * Asserts that the operation completed successfully and that the resource is defined.
11268
+ * @param outcome The operation outcome.
11269
+ * @param resource The resource that may or may not have been returned.
11270
+ */
11271
+ function assertOk(outcome, resource) {
11272
+ if (!isOk(outcome) || resource === undefined) {
11273
+ throw new OperationOutcomeError(outcome);
11274
+ }
11275
+ }
11276
+ class OperationOutcomeError extends Error {
11277
+ constructor(outcome) {
11278
+ var _a, _b;
11279
+ super((_b = (_a = outcome === null || outcome === void 0 ? void 0 : outcome.issue) === null || _a === void 0 ? void 0 : _a[0].details) === null || _b === void 0 ? void 0 : _b.text);
11280
+ this.outcome = outcome;
11281
+ }
11282
+ }
11283
+ /**
11284
+ * Normalizes an error object into a displayable error string.
11285
+ * @param error The error value which could be a string, Error, OperationOutcome, or other unknown type.
11286
+ * @returns A display string for the error.
11287
+ */
11288
+ function normalizeErrorString(error) {
11289
+ var _a, _b, _c, _d;
11290
+ if (!error) {
11291
+ return 'Unknown error';
11292
+ }
11293
+ if (typeof error === 'string') {
11294
+ return error;
11295
+ }
11296
+ if (error instanceof Error) {
11297
+ return error.message;
11298
+ }
11299
+ if (typeof error === 'object' && 'resourceType' in error) {
11300
+ const outcome = error;
11301
+ return (_d = (_c = (_b = (_a = outcome.issue) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.details) === null || _c === void 0 ? void 0 : _c.text) !== null && _d !== void 0 ? _d : 'Unknown error';
11302
+ }
11303
+ return JSON.stringify(error);
11304
+ }
11305
+
11072
11306
  exports.AndAtom = AndAtom;
11073
11307
  exports.ArithemticOperatorAtom = ArithemticOperatorAtom;
11074
11308
  exports.AsAtom = AsAtom;
@@ -11158,6 +11392,7 @@
11158
11392
  exports.globalSchema = globalSchema;
11159
11393
  exports.gone = gone;
11160
11394
  exports.indexSearchParameter = indexSearchParameter;
11395
+ exports.indexSearchParameterBundle = indexSearchParameterBundle;
11161
11396
  exports.indexStructureDefinition = indexStructureDefinition;
11162
11397
  exports.indexStructureDefinitionBundle = indexStructureDefinitionBundle;
11163
11398
  exports.initFhirPathParserBuilder = initFhirPathParserBuilder;
@@ -11175,6 +11410,7 @@
11175
11410
  exports.isUUID = isUUID;
11176
11411
  exports.isValidDate = isValidDate;
11177
11412
  exports.matchesRange = matchesRange;
11413
+ exports.matchesSearchRequest = matchesSearchRequest;
11178
11414
  exports.normalizeErrorString = normalizeErrorString;
11179
11415
  exports.notFound = notFound;
11180
11416
  exports.notModified = notModified;
@@ -11196,7 +11432,5 @@
11196
11432
  exports.tooManyRequests = tooManyRequests;
11197
11433
  exports.unauthorized = unauthorized;
11198
11434
 
11199
- Object.defineProperty(exports, '__esModule', { value: true });
11200
-
11201
11435
  }));
11202
11436
  //# sourceMappingURL=index.js.map