@medplum/core 0.9.11 → 0.9.14

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
@@ -572,6 +572,165 @@
572
572
  function isLowerCase(c) {
573
573
  return c === c.toLowerCase();
574
574
  }
575
+ /**
576
+ * Tries to find a code string for a given system within a given codeable concept.
577
+ * @param concept The codeable concept.
578
+ * @param system The system string.
579
+ * @returns The code if found; otherwise undefined.
580
+ */
581
+ function getCodeBySystem(concept, system) {
582
+ var _a, _b;
583
+ return (_b = (_a = concept === null || concept === void 0 ? void 0 : concept.coding) === null || _a === void 0 ? void 0 : _a.find((coding) => coding.system === system)) === null || _b === void 0 ? void 0 : _b.code;
584
+ }
585
+ /**
586
+ * Sets a code for a given system within a given codeable concept.
587
+ * @param concept The codeable concept.
588
+ * @param system The system string.
589
+ * @param code The code value.
590
+ */
591
+ function setCodeBySystem(concept, system, code) {
592
+ var _a, _b;
593
+ if (!concept.coding) {
594
+ concept.coding = [];
595
+ }
596
+ const coding = (_a = concept.coding) === null || _a === void 0 ? void 0 : _a.find((c) => c.system === system);
597
+ if (coding) {
598
+ coding.code = code;
599
+ }
600
+ else {
601
+ (_b = concept.coding) === null || _b === void 0 ? void 0 : _b.push({ system, code });
602
+ }
603
+ }
604
+ /**
605
+ * Tries to find an observation interval for the given patient and value.
606
+ * @param definition The observation definition.
607
+ * @param patient The patient.
608
+ * @param value The observation value.
609
+ * @returns The observation interval if found; otherwise undefined.
610
+ */
611
+ function findObservationInterval(definition, patient, value, category) {
612
+ var _a;
613
+ return (_a = definition.qualifiedInterval) === null || _a === void 0 ? void 0 : _a.find((interval) => {
614
+ var _a;
615
+ return observationIntervalMatchesPatient(interval, patient) &&
616
+ observationIntervalMatchesValue(interval, value, (_a = definition.quantitativeDetails) === null || _a === void 0 ? void 0 : _a.decimalPrecision) &&
617
+ (category === undefined || interval.category === category);
618
+ });
619
+ }
620
+ /**
621
+ * Returns true if the patient matches the observation interval.
622
+ * @param interval The observation interval.
623
+ * @param patient The patient.
624
+ * @returns True if the patient matches the observation interval.
625
+ */
626
+ function observationIntervalMatchesPatient(interval, patient) {
627
+ return observationIntervalMatchesGender(interval, patient) && observationIntervalMatchesAge(interval, patient);
628
+ }
629
+ /**
630
+ * Returns true if the patient gender matches the observation interval.
631
+ * @param interval The observation interval.
632
+ * @param patient The patient.
633
+ * @returns True if the patient gender matches the observation interval.
634
+ */
635
+ function observationIntervalMatchesGender(interval, patient) {
636
+ return !interval.gender || interval.gender === patient.gender;
637
+ }
638
+ /**
639
+ * Returns true if the patient age matches the observation interval.
640
+ * @param interval The observation interval.
641
+ * @param patient The patient.
642
+ * @returns True if the patient age matches the observation interval.
643
+ */
644
+ function observationIntervalMatchesAge(interval, patient) {
645
+ return !interval.age || matchesRange(calculateAge(patient.birthDate).years, interval.age);
646
+ }
647
+ /**
648
+ * Returns true if the value matches the observation interval.
649
+ * @param interval The observation interval.
650
+ * @param value The observation value.
651
+ * @param precision Optional precision in number of digits.
652
+ * @returns True if the value matches the observation interval.
653
+ */
654
+ function observationIntervalMatchesValue(interval, value, precision) {
655
+ return !!interval.range && matchesRange(value, interval.range, precision);
656
+ }
657
+ /**
658
+ * Returns true if the value is in the range accounting for precision.
659
+ * @param value The numeric value.
660
+ * @param range The numeric range.
661
+ * @param precision Optional precision in number of digits.
662
+ * @returns True if the value is within the range.
663
+ */
664
+ function matchesRange(value, range, precision) {
665
+ var _a, _b;
666
+ return ((((_a = range.low) === null || _a === void 0 ? void 0 : _a.value) === undefined || preciseGreaterThanOrEquals(value, range.low.value, precision)) &&
667
+ (((_b = range.high) === null || _b === void 0 ? void 0 : _b.value) === undefined || preciseLessThanOrEquals(value, range.high.value, precision)));
668
+ }
669
+ /**
670
+ * Returns true if the two numbers are equal to the given precision.
671
+ * @param a The first number.
672
+ * @param b The second number.
673
+ * @param precision Optional precision in number of digits.
674
+ * @returns True if the two numbers are equal to the given precision.
675
+ */
676
+ function preciseEquals(a, b, precision) {
677
+ if (precision) {
678
+ return Math.abs(a - b) < Math.pow(10, -precision);
679
+ }
680
+ else {
681
+ return a === b;
682
+ }
683
+ }
684
+ /**
685
+ * Returns true if the first number is less than the second number to the given precision.
686
+ * @param a The first number.
687
+ * @param b The second number.
688
+ * @param precision Optional precision in number of digits.
689
+ * @returns True if the first number is less than the second number to the given precision.
690
+ */
691
+ function preciseLessThan(a, b, precision) {
692
+ if (precision) {
693
+ return a < b && Math.abs(a - b) > Math.pow(10, -precision);
694
+ }
695
+ else {
696
+ return a < b;
697
+ }
698
+ }
699
+ /**
700
+ * Returns true if the first number is greater than the second number to the given precision.
701
+ * @param a The first number.
702
+ * @param b The second number.
703
+ * @param precision Optional precision in number of digits.
704
+ * @returns True if the first number is greater than the second number to the given precision.
705
+ */
706
+ function preciseGreaterThan(a, b, precision) {
707
+ if (precision) {
708
+ return a > b && Math.abs(a - b) > Math.pow(10, -precision);
709
+ }
710
+ else {
711
+ return a > b;
712
+ }
713
+ }
714
+ /**
715
+ * Returns true if the first number is less than or equal to the second number to the given precision.
716
+ * @param a The first number.
717
+ * @param b The second number.
718
+ * @param precision Optional precision in number of digits.
719
+ * @returns True if the first number is less than or equal to the second number to the given precision.
720
+ */
721
+ function preciseLessThanOrEquals(a, b, precision) {
722
+ return preciseLessThan(a, b, precision) || preciseEquals(a, b, precision);
723
+ }
724
+ /**
725
+ * Returns true if the first number is greater than or equal to the second number to the given precision.
726
+ * @param a The first number.
727
+ * @param b The second number.
728
+ * @param precision Optional precision in number of digits.
729
+ * @returns True if the first number is greater than or equal to the second number to the given precision.
730
+ */
731
+ function preciseGreaterThanOrEquals(a, b, precision) {
732
+ return preciseGreaterThan(a, b, precision) || preciseEquals(a, b, precision);
733
+ }
575
734
 
576
735
  /**
577
736
  * Returns a cryptographically secure random string.
@@ -1224,7 +1383,7 @@
1224
1383
  * Search for a `Patient` by name:
1225
1384
  *
1226
1385
  * ```typescript
1227
- * const bundle = await medplum.search('Patient?name=Alice');
1386
+ * const bundle = await medplum.search('Patient', 'name=Alice');
1228
1387
  * console.log(bundle.total);
1229
1388
  * ```
1230
1389
  */
@@ -1506,7 +1665,9 @@
1506
1665
  */
1507
1666
  fhirSearchUrl(resourceType, query) {
1508
1667
  const url = this.fhirUrl(resourceType);
1509
- url.search = query.toString();
1668
+ if (query) {
1669
+ url.search = query.toString();
1670
+ }
1510
1671
  return url;
1511
1672
  }
1512
1673
  /**
@@ -1515,21 +1676,7 @@
1515
1676
  * Example using a FHIR search string:
1516
1677
  *
1517
1678
  * ```typescript
1518
- * const bundle = await client.search('Patient?name=Alice');
1519
- * console.log(bundle);
1520
- * ```
1521
- *
1522
- * Example using a structured search:
1523
- *
1524
- * ```typescript
1525
- * const bundle = await client.search({
1526
- * resourceType: 'Patient',
1527
- * filters: [{
1528
- * code: 'name',
1529
- * operator: 'eq',
1530
- * value: 'Alice',
1531
- * }]
1532
- * });
1679
+ * const bundle = await client.search('Patient', 'name=Alice');
1533
1680
  * console.log(bundle);
1534
1681
  * ```
1535
1682
  *
@@ -1574,7 +1721,7 @@
1574
1721
  * Example using a FHIR search string:
1575
1722
  *
1576
1723
  * ```typescript
1577
- * const patient = await client.searchOne('Patient?identifier=123');
1724
+ * const patient = await client.searchOne('Patient', 'identifier=123');
1578
1725
  * console.log(patient);
1579
1726
  * ```
1580
1727
  *
@@ -1608,7 +1755,7 @@
1608
1755
  * Example using a FHIR search string:
1609
1756
  *
1610
1757
  * ```typescript
1611
- * const patients = await client.searchResources('Patient?name=Alice');
1758
+ * const patients = await client.searchResources('Patient', 'name=Alice');
1612
1759
  * console.log(patients);
1613
1760
  * ```
1614
1761
  *
@@ -1663,7 +1810,13 @@
1663
1810
  */
1664
1811
  getCachedReference(reference) {
1665
1812
  const refString = reference.reference;
1813
+ if (!refString) {
1814
+ return undefined;
1815
+ }
1666
1816
  const [resourceType, id] = refString.split('/');
1817
+ if (!resourceType || !id) {
1818
+ return undefined;
1819
+ }
1667
1820
  return this.getCached(resourceType, id);
1668
1821
  }
1669
1822
  /**
@@ -1709,6 +1862,9 @@
1709
1862
  return new ReadablePromise(Promise.reject(new Error('Missing reference')));
1710
1863
  }
1711
1864
  const [resourceType, id] = refString.split('/');
1865
+ if (!resourceType || !id) {
1866
+ return new ReadablePromise(Promise.reject(new Error('Invalid reference')));
1867
+ }
1712
1868
  return this.readResource(resourceType, id);
1713
1869
  }
1714
1870
  /**
@@ -5394,11 +5550,13 @@
5394
5550
  exports.created = created;
5395
5551
  exports.deepEquals = deepEquals$1;
5396
5552
  exports.evalFhirPath = evalFhirPath;
5553
+ exports.findObservationInterval = findObservationInterval;
5397
5554
  exports.formatAddress = formatAddress;
5398
5555
  exports.formatFamilyName = formatFamilyName;
5399
5556
  exports.formatGivenName = formatGivenName;
5400
5557
  exports.formatHumanName = formatHumanName;
5401
5558
  exports.formatSearchQuery = formatSearchQuery;
5559
+ exports.getCodeBySystem = getCodeBySystem;
5402
5560
  exports.getDateProperty = getDateProperty;
5403
5561
  exports.getDisplayString = getDisplayString;
5404
5562
  exports.getExpressionForResourceType = getExpressionForResourceType;
@@ -5421,11 +5579,18 @@
5421
5579
  exports.isProfileResource = isProfileResource;
5422
5580
  exports.isStringArray = isStringArray;
5423
5581
  exports.isUUID = isUUID;
5582
+ exports.matchesRange = matchesRange;
5424
5583
  exports.notFound = notFound;
5425
5584
  exports.notModified = notModified;
5426
5585
  exports.parseFhirPath = parseFhirPath;
5427
5586
  exports.parseSearchDefinition = parseSearchDefinition;
5587
+ exports.preciseEquals = preciseEquals;
5588
+ exports.preciseGreaterThan = preciseGreaterThan;
5589
+ exports.preciseGreaterThanOrEquals = preciseGreaterThanOrEquals;
5590
+ exports.preciseLessThan = preciseLessThan;
5591
+ exports.preciseLessThanOrEquals = preciseLessThanOrEquals;
5428
5592
  exports.resolveId = resolveId;
5593
+ exports.setCodeBySystem = setCodeBySystem;
5429
5594
  exports.stringify = stringify;
5430
5595
  exports.tokenize = tokenize;
5431
5596