@medplum/core 0.4.1 → 0.5.2

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/README.md CHANGED
@@ -124,4 +124,4 @@ medplum.readVersion('Patient', '123', '456');
124
124
 
125
125
  ## License
126
126
 
127
- Apache 2.0. Copyright © Medplum 2021
127
+ Apache 2.0. Copyright © Medplum 2022
package/dist/cjs/index.js CHANGED
@@ -644,13 +644,16 @@
644
644
  * @returns Parsed search definition.
645
645
  */
646
646
  function parseSearchDefinition(location) {
647
- const resourceType = location.pathname.split('/').pop();
647
+ const resourceType = location.pathname
648
+ .replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
649
+ .split('/')
650
+ .pop();
648
651
  const params = new URLSearchParams(location.search);
649
- const filters = [];
650
- const sortRules = [];
651
- let fields;
652
- let page = 0;
653
- let count = 10;
652
+ let filters = undefined;
653
+ let sortRules = undefined;
654
+ let fields = undefined;
655
+ let page = undefined;
656
+ let count = undefined;
654
657
  let total = undefined;
655
658
  params.forEach((value, key) => {
656
659
  if (key === '_fields') {
@@ -666,9 +669,11 @@
666
669
  total = value;
667
670
  }
668
671
  else if (key === '_sort') {
672
+ sortRules = sortRules || [];
669
673
  sortRules.push(parseSortRule(value));
670
674
  }
671
675
  else {
676
+ filters = filters || [];
672
677
  filters.push(parseSearchFilter(key, value));
673
678
  }
674
679
  });
@@ -747,13 +752,9 @@
747
752
  params.push('_fields=' + definition.fields.join(','));
748
753
  }
749
754
  if (definition.filters) {
750
- definition.filters.forEach((filter) => {
751
- const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
752
- const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
753
- params.push(`${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`);
754
- });
755
+ definition.filters.forEach((filter) => params.push(formatFilter(filter)));
755
756
  }
756
- if (definition.sortRules) {
757
+ if (definition.sortRules && definition.sortRules.length > 0) {
757
758
  params.push(formatSortRules(definition.sortRules));
758
759
  }
759
760
  if (definition.page && definition.page > 0) {
@@ -771,6 +772,11 @@
771
772
  params.sort();
772
773
  return '?' + params.join('&');
773
774
  }
775
+ function formatFilter(filter) {
776
+ const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
777
+ const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
778
+ return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
779
+ }
774
780
  function formatSortRules(sortRules) {
775
781
  if (!sortRules || sortRules.length === 0) {
776
782
  return '';
@@ -942,6 +948,21 @@
942
948
  function createSchema() {
943
949
  return { types: {} };
944
950
  }
951
+ function createTypeSchema(typeName, description) {
952
+ return {
953
+ display: typeName,
954
+ description,
955
+ properties: {},
956
+ searchParams: {
957
+ _lastUpdated: {
958
+ base: [typeName],
959
+ code: '_lastUpdated',
960
+ type: 'date',
961
+ expression: typeName + '.meta.lastUpdated',
962
+ },
963
+ },
964
+ };
965
+ }
945
966
  /**
946
967
  * Indexes a StructureDefinition for fast lookup.
947
968
  * See comments on IndexedStructureDefinition for more details.
@@ -954,11 +975,7 @@
954
975
  if (!typeName) {
955
976
  return;
956
977
  }
957
- schema.types[typeName] = {
958
- display: typeName,
959
- description: structureDefinition.description,
960
- properties: {},
961
- };
978
+ schema.types[typeName] = createTypeSchema(typeName, structureDefinition.description);
962
979
  const elements = (_a = structureDefinition.snapshot) === null || _a === void 0 ? void 0 : _a.element;
963
980
  if (elements) {
964
981
  // Filter out any elements missing path or type
@@ -986,12 +1003,8 @@
986
1003
  const parts = path.split('.');
987
1004
  const typeName = buildTypeName(parts);
988
1005
  if (!(typeName in schema.types)) {
989
- schema.types[typeName] = {
990
- display: typeName,
991
- description: element.definition,
992
- parentType: buildTypeName(parts.slice(0, parts.length - 1)),
993
- properties: {},
994
- };
1006
+ schema.types[typeName] = createTypeSchema(typeName, element.definition);
1007
+ schema.types[typeName].parentType = buildTypeName(parts.slice(0, parts.length - 1));
995
1008
  }
996
1009
  }
997
1010
  /**
@@ -1039,6 +1052,10 @@
1039
1052
  // For example, for path "Patient.birthDate"
1040
1053
  // the property name is "birthDate"
1041
1054
  const propertyName = property.path.replaceAll('[x]', '').split('.').pop();
1055
+ // Special case for ID
1056
+ if (propertyName === 'id') {
1057
+ return 'ID';
1058
+ }
1042
1059
  // Split by capital letters
1043
1060
  // Capitalize the first letter of each word
1044
1061
  // Join together with spaces in between
@@ -1340,7 +1357,9 @@
1340
1357
  SearchParameterList(base: "${encodeURIComponent(resourceType)}") {
1341
1358
  base,
1342
1359
  code,
1343
- type
1360
+ type,
1361
+ expression,
1362
+ target
1344
1363
  }
1345
1364
  }`.replace(/\s+/g, ' ');
1346
1365
  const response = (yield this.graphql(query));
@@ -1677,6 +1696,9 @@
1677
1696
  */
1678
1697
  function getSearchParameterDetails(structureDefinitions, resourceType, searchParam) {
1679
1698
  var _a, _b, _c, _d;
1699
+ if (searchParam.code === '_lastUpdated') {
1700
+ return { columnName: 'lastUpdated', type: exports.SearchParameterType.DATETIME };
1701
+ }
1680
1702
  const columnName = convertCodeToColumnName(searchParam.code);
1681
1703
  const expression = (_a = getExpressionForResourceType(resourceType, searchParam.expression)) === null || _a === void 0 ? void 0 : _a.split('.');
1682
1704
  if (!expression) {
@@ -1685,20 +1707,21 @@
1685
1707
  return { columnName, type: exports.SearchParameterType.TEXT };
1686
1708
  }
1687
1709
  let baseType = resourceType;
1710
+ let elementDefinition = undefined;
1688
1711
  let propertyType = undefined;
1689
1712
  let array = false;
1690
1713
  for (let i = 1; i < expression.length; i++) {
1691
1714
  const propertyName = expression[i];
1692
- const propertyDef = (_c = (_b = structureDefinitions.types[baseType]) === null || _b === void 0 ? void 0 : _b.properties) === null || _c === void 0 ? void 0 : _c[propertyName];
1693
- if (!propertyDef) {
1715
+ elementDefinition = (_c = (_b = structureDefinitions.types[baseType]) === null || _b === void 0 ? void 0 : _b.properties) === null || _c === void 0 ? void 0 : _c[propertyName];
1716
+ if (!elementDefinition) {
1694
1717
  // This happens on complex properties such as "collected[x]"/"collectedDateTime"/"collectedPeriod"
1695
1718
  // In the future, explore returning multiple column definitions
1696
1719
  return { columnName, type: exports.SearchParameterType.TEXT, array };
1697
1720
  }
1698
- if (propertyDef.max === '*') {
1721
+ if (elementDefinition.max === '*') {
1699
1722
  array = true;
1700
1723
  }
1701
- propertyType = (_d = propertyDef.type) === null || _d === void 0 ? void 0 : _d[0].code;
1724
+ propertyType = (_d = elementDefinition.type) === null || _d === void 0 ? void 0 : _d[0].code;
1702
1725
  if (!propertyType) {
1703
1726
  // This happens when one of parent properties uses contentReference
1704
1727
  // In the future, explore following the reference
@@ -1714,7 +1737,7 @@
1714
1737
  }
1715
1738
  }
1716
1739
  const type = getSearchParameterType(searchParam, propertyType);
1717
- return { columnName, type, array };
1740
+ return { columnName, type, elementDefinition, array };
1718
1741
  }
1719
1742
  /**
1720
1743
  * Converts a hyphen-delimited code to camelCase string.
@@ -1783,6 +1806,7 @@
1783
1806
  exports.capitalize = capitalize;
1784
1807
  exports.createReference = createReference;
1785
1808
  exports.createSchema = createSchema;
1809
+ exports.createTypeSchema = createTypeSchema;
1786
1810
  exports.created = created;
1787
1811
  exports.deepEquals = deepEquals;
1788
1812
  exports.formatAddress = formatAddress;