@medplum/core 0.9.10 → 0.9.13
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/cody-pdf-test.js +1 -1
- package/dist/cjs/index.js +406 -337
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/index.min.js +1 -1
- package/dist/cjs/index.min.js.map +1 -1
- package/dist/esm/index.js +398 -338
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +1 -1
- package/dist/esm/index.min.js.map +1 -1
- package/dist/types/client.d.ts +61 -31
- package/dist/types/utils.d.ts +71 -1
- package/package.json +2 -2
- package/dist/types/pdf.d.ts +0 -5
- package/document.pdf +0 -0
- package/test.pdf +0 -1
- package/test2.pdf +0 -1
- package/test3.pdf.txt +0 -1
- package/test4.pdf +0 -1
- package/test5.pdf +0 -0
- package/test7-2.pdf +0 -1
- package/test7.pdf +0 -1
- package/test8-2.pdf +0 -0
- package/test8.pdf +0 -0
- package/test9-2.pdf +0 -0
- package/test9-3.pdf +0 -0
- package/test9-4.pdf +0 -0
- package/test9.pdf +0 -0
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.
|
|
@@ -810,106 +969,6 @@
|
|
|
810
969
|
}
|
|
811
970
|
}
|
|
812
971
|
|
|
813
|
-
/*
|
|
814
|
-
* This file attempts a unified "generatePdf" function that works both client-side and server-side.
|
|
815
|
-
* On client-side, it checks for a global "pdfMake" variable.
|
|
816
|
-
* On server-side, it dynamically loads "pdfmake" from the node_modules.
|
|
817
|
-
*/
|
|
818
|
-
function generatePdf(docDefinition, tableLayouts, fonts) {
|
|
819
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
820
|
-
// Setup sane defaults
|
|
821
|
-
// See: https://pdfmake.github.io/docs/0.1/document-definition-object/styling/
|
|
822
|
-
docDefinition.pageSize = docDefinition.pageSize || 'LETTER';
|
|
823
|
-
docDefinition.pageMargins = docDefinition.pageMargins || [60, 60, 60, 60];
|
|
824
|
-
docDefinition.pageOrientation = docDefinition.pageOrientation || 'portrait';
|
|
825
|
-
docDefinition.defaultStyle = docDefinition.defaultStyle || {};
|
|
826
|
-
docDefinition.defaultStyle.font = docDefinition.defaultStyle.font || 'Helvetica';
|
|
827
|
-
docDefinition.defaultStyle.fontSize = docDefinition.defaultStyle.fontSize || 11;
|
|
828
|
-
docDefinition.defaultStyle.lineHeight = docDefinition.defaultStyle.lineHeight || 2.0;
|
|
829
|
-
if (typeof window !== 'undefined' && typeof pdfMake !== 'undefined') {
|
|
830
|
-
return generatePdfClientSide(docDefinition, tableLayouts, fonts);
|
|
831
|
-
}
|
|
832
|
-
if (typeof process !== 'undefined' && typeof require !== 'undefined') {
|
|
833
|
-
return generatePdfServerSide(docDefinition, tableLayouts, fonts);
|
|
834
|
-
}
|
|
835
|
-
throw new Error('Unable to determine PDF environment');
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
function generatePdfServerSide(docDefinition, tableLayouts, fonts) {
|
|
839
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
840
|
-
if (!fonts) {
|
|
841
|
-
fonts = {
|
|
842
|
-
Helvetica: {
|
|
843
|
-
normal: 'Helvetica',
|
|
844
|
-
bold: 'Helvetica-Bold',
|
|
845
|
-
italics: 'Helvetica-Oblique',
|
|
846
|
-
bolditalics: 'Helvetica-BoldOblique',
|
|
847
|
-
},
|
|
848
|
-
};
|
|
849
|
-
}
|
|
850
|
-
return new Promise((resolve, reject) => {
|
|
851
|
-
try {
|
|
852
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
853
|
-
const PdfPrinter = require('pdfmake');
|
|
854
|
-
const printer = new PdfPrinter(fonts);
|
|
855
|
-
const pdfDoc = printer.createPdfKitDocument(docDefinition, { tableLayouts });
|
|
856
|
-
const chunks = [];
|
|
857
|
-
pdfDoc.on('data', (chunk) => chunks.push(chunk));
|
|
858
|
-
pdfDoc.on('end', () => resolve(concat(chunks)));
|
|
859
|
-
pdfDoc.on('error', reject);
|
|
860
|
-
pdfDoc.end();
|
|
861
|
-
}
|
|
862
|
-
catch (err) {
|
|
863
|
-
reject(err);
|
|
864
|
-
}
|
|
865
|
-
});
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
function generatePdfClientSide(docDefinition, tableLayouts, fonts) {
|
|
869
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
870
|
-
if (!fonts) {
|
|
871
|
-
fonts = {
|
|
872
|
-
Helvetica: {
|
|
873
|
-
normal: 'https://static.medplum.com/fonts/Helvetica.ttf',
|
|
874
|
-
bold: 'https://static.medplum.com/fonts/Helvetica-bold.ttf',
|
|
875
|
-
italics: 'https://static.medplum.com/fonts/Helvetica-italic.ttf',
|
|
876
|
-
bolditalics: 'https://static.medplum.com/fonts/Helvetica-bold-italic.ttf',
|
|
877
|
-
},
|
|
878
|
-
Roboto: {
|
|
879
|
-
normal: 'https://static.medplum.com/fonts/Roboto-Regular.ttf',
|
|
880
|
-
bold: 'https://static.medplum.com/fonts/Roboto-Medium.ttf',
|
|
881
|
-
italics: 'https://static.medplum.com/fonts/Roboto-Italic.ttf',
|
|
882
|
-
bolditalics: 'https://static.medplum.com/fonts/Roboto-MediumItalic.ttf',
|
|
883
|
-
},
|
|
884
|
-
Avenir: {
|
|
885
|
-
normal: 'https://static.medplum.com/fonts/avenir.ttf',
|
|
886
|
-
},
|
|
887
|
-
};
|
|
888
|
-
}
|
|
889
|
-
return new Promise((resolve) => {
|
|
890
|
-
pdfMake.createPdf(docDefinition, tableLayouts, fonts).getBlob(resolve);
|
|
891
|
-
});
|
|
892
|
-
});
|
|
893
|
-
}
|
|
894
|
-
/**
|
|
895
|
-
* Concatenates an array of Uint8Arrays into a single Uint8Array.
|
|
896
|
-
* @param arrays An array of arrays of bytes.
|
|
897
|
-
* @returns A single array of bytes.
|
|
898
|
-
*/
|
|
899
|
-
function concat(arrays) {
|
|
900
|
-
let len = 0;
|
|
901
|
-
for (const array of arrays) {
|
|
902
|
-
len += array.length;
|
|
903
|
-
}
|
|
904
|
-
const result = new Uint8Array(len);
|
|
905
|
-
let index = 0;
|
|
906
|
-
for (const array of arrays) {
|
|
907
|
-
result.set(array, index);
|
|
908
|
-
index += array.length;
|
|
909
|
-
}
|
|
910
|
-
return result;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
972
|
var _ReadablePromise_suspender, _ReadablePromise_status, _ReadablePromise_response, _ReadablePromise_error, _a;
|
|
914
973
|
/**
|
|
915
974
|
* The ReadablePromise class wraps a request promise suitable for React Suspense.
|
|
@@ -986,206 +1045,6 @@
|
|
|
986
1045
|
}
|
|
987
1046
|
_ReadablePromise_suspender = new WeakMap(), _ReadablePromise_status = new WeakMap(), _ReadablePromise_response = new WeakMap(), _ReadablePromise_error = new WeakMap(), _a = Symbol.toStringTag;
|
|
988
1047
|
|
|
989
|
-
const DEFAULT_SEARCH_COUNT = 20;
|
|
990
|
-
/**
|
|
991
|
-
* Search operators.
|
|
992
|
-
* These operators represent "modifiers" and "prefixes" in FHIR search.
|
|
993
|
-
* See: https://www.hl7.org/fhir/search.html
|
|
994
|
-
*/
|
|
995
|
-
exports.Operator = void 0;
|
|
996
|
-
(function (Operator) {
|
|
997
|
-
Operator["EQUALS"] = "eq";
|
|
998
|
-
Operator["NOT_EQUALS"] = "ne";
|
|
999
|
-
// Numbers
|
|
1000
|
-
Operator["GREATER_THAN"] = "gt";
|
|
1001
|
-
Operator["LESS_THAN"] = "lt";
|
|
1002
|
-
Operator["GREATER_THAN_OR_EQUALS"] = "ge";
|
|
1003
|
-
Operator["LESS_THAN_OR_EQUALS"] = "le";
|
|
1004
|
-
// Dates
|
|
1005
|
-
Operator["STARTS_AFTER"] = "sa";
|
|
1006
|
-
Operator["ENDS_BEFORE"] = "eb";
|
|
1007
|
-
Operator["APPROXIMATELY"] = "ap";
|
|
1008
|
-
// String
|
|
1009
|
-
Operator["CONTAINS"] = "contains";
|
|
1010
|
-
Operator["EXACT"] = "exact";
|
|
1011
|
-
// Token
|
|
1012
|
-
Operator["TEXT"] = "text";
|
|
1013
|
-
Operator["ABOVE"] = "above";
|
|
1014
|
-
Operator["BELOW"] = "below";
|
|
1015
|
-
Operator["IN"] = "in";
|
|
1016
|
-
Operator["NOT_IN"] = "not-in";
|
|
1017
|
-
Operator["OF_TYPE"] = "of-type";
|
|
1018
|
-
})(exports.Operator || (exports.Operator = {}));
|
|
1019
|
-
const MODIFIER_OPERATORS = [
|
|
1020
|
-
exports.Operator.CONTAINS,
|
|
1021
|
-
exports.Operator.EXACT,
|
|
1022
|
-
exports.Operator.TEXT,
|
|
1023
|
-
exports.Operator.ABOVE,
|
|
1024
|
-
exports.Operator.BELOW,
|
|
1025
|
-
exports.Operator.IN,
|
|
1026
|
-
exports.Operator.NOT_IN,
|
|
1027
|
-
exports.Operator.OF_TYPE,
|
|
1028
|
-
];
|
|
1029
|
-
const PREFIX_OPERATORS = [
|
|
1030
|
-
exports.Operator.NOT_EQUALS,
|
|
1031
|
-
exports.Operator.GREATER_THAN,
|
|
1032
|
-
exports.Operator.LESS_THAN,
|
|
1033
|
-
exports.Operator.GREATER_THAN_OR_EQUALS,
|
|
1034
|
-
exports.Operator.LESS_THAN_OR_EQUALS,
|
|
1035
|
-
exports.Operator.STARTS_AFTER,
|
|
1036
|
-
exports.Operator.ENDS_BEFORE,
|
|
1037
|
-
exports.Operator.APPROXIMATELY,
|
|
1038
|
-
];
|
|
1039
|
-
/**
|
|
1040
|
-
* Parses a URL into a SearchRequest.
|
|
1041
|
-
*
|
|
1042
|
-
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
1043
|
-
*
|
|
1044
|
-
* @param url The URL to parse.
|
|
1045
|
-
* @returns Parsed search definition.
|
|
1046
|
-
*/
|
|
1047
|
-
function parseSearchDefinition(url) {
|
|
1048
|
-
const location = new URL(url, 'https://example.com/');
|
|
1049
|
-
const resourceType = location.pathname
|
|
1050
|
-
.replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
|
|
1051
|
-
.split('/')
|
|
1052
|
-
.pop();
|
|
1053
|
-
const params = new URLSearchParams(location.search);
|
|
1054
|
-
let filters = undefined;
|
|
1055
|
-
let sortRules = undefined;
|
|
1056
|
-
let fields = undefined;
|
|
1057
|
-
let offset = undefined;
|
|
1058
|
-
let count = undefined;
|
|
1059
|
-
let total = undefined;
|
|
1060
|
-
params.forEach((value, key) => {
|
|
1061
|
-
if (key === '_fields') {
|
|
1062
|
-
fields = value.split(',');
|
|
1063
|
-
}
|
|
1064
|
-
else if (key === '_offset') {
|
|
1065
|
-
offset = parseInt(value);
|
|
1066
|
-
}
|
|
1067
|
-
else if (key === '_count') {
|
|
1068
|
-
count = parseInt(value);
|
|
1069
|
-
}
|
|
1070
|
-
else if (key === '_total') {
|
|
1071
|
-
total = value;
|
|
1072
|
-
}
|
|
1073
|
-
else if (key === '_sort') {
|
|
1074
|
-
sortRules = sortRules || [];
|
|
1075
|
-
sortRules.push(parseSortRule(value));
|
|
1076
|
-
}
|
|
1077
|
-
else {
|
|
1078
|
-
filters = filters || [];
|
|
1079
|
-
filters.push(parseSearchFilter(key, value));
|
|
1080
|
-
}
|
|
1081
|
-
});
|
|
1082
|
-
return {
|
|
1083
|
-
resourceType,
|
|
1084
|
-
filters,
|
|
1085
|
-
fields,
|
|
1086
|
-
offset,
|
|
1087
|
-
count,
|
|
1088
|
-
total,
|
|
1089
|
-
sortRules,
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
/**
|
|
1093
|
-
* Parses a URL query parameter into a sort rule.
|
|
1094
|
-
*
|
|
1095
|
-
* By default, the sort rule is the field name.
|
|
1096
|
-
*
|
|
1097
|
-
* Sort rules can be reversed into descending order by prefixing the field name with a minus sign.
|
|
1098
|
-
*
|
|
1099
|
-
* See sorting: http://hl7.org/fhir/r4/search.html#_sort
|
|
1100
|
-
*
|
|
1101
|
-
* @param value The URL parameter value.
|
|
1102
|
-
* @returns The parsed sort rule.
|
|
1103
|
-
*/
|
|
1104
|
-
function parseSortRule(value) {
|
|
1105
|
-
if (value.startsWith('-')) {
|
|
1106
|
-
return { code: value.substring(1), descending: true };
|
|
1107
|
-
}
|
|
1108
|
-
else {
|
|
1109
|
-
return { code: value };
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
/**
|
|
1113
|
-
* Parses a URL query parameter into a search filter.
|
|
1114
|
-
*
|
|
1115
|
-
* FHIR search filters can be specified as modifiers or prefixes.
|
|
1116
|
-
*
|
|
1117
|
-
* For string properties, modifiers are appended to the key, e.g. "name:contains=eve".
|
|
1118
|
-
*
|
|
1119
|
-
* For date and numeric properties, prefixes are prepended to the value, e.g. "birthdate=gt2000".
|
|
1120
|
-
*
|
|
1121
|
-
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
1122
|
-
*
|
|
1123
|
-
* @param key The URL parameter key.
|
|
1124
|
-
* @param value The URL parameter value.
|
|
1125
|
-
* @returns The parsed search filter.
|
|
1126
|
-
*/
|
|
1127
|
-
function parseSearchFilter(key, value) {
|
|
1128
|
-
let code = key;
|
|
1129
|
-
let operator = exports.Operator.EQUALS;
|
|
1130
|
-
for (const modifier of MODIFIER_OPERATORS) {
|
|
1131
|
-
const modifierIndex = code.indexOf(':' + modifier);
|
|
1132
|
-
if (modifierIndex !== -1) {
|
|
1133
|
-
operator = modifier;
|
|
1134
|
-
code = code.substring(0, modifierIndex);
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
for (const prefix of PREFIX_OPERATORS) {
|
|
1138
|
-
if (value.match(new RegExp('^' + prefix + '\\d'))) {
|
|
1139
|
-
operator = prefix;
|
|
1140
|
-
value = value.substring(prefix.length);
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
return { code, operator, value };
|
|
1144
|
-
}
|
|
1145
|
-
/**
|
|
1146
|
-
* Formats a search definition object into a query string.
|
|
1147
|
-
* Note: The return value does not include the resource type.
|
|
1148
|
-
* @param {!SearchRequest} definition The search definition.
|
|
1149
|
-
* @returns Formatted URL.
|
|
1150
|
-
*/
|
|
1151
|
-
function formatSearchQuery(definition) {
|
|
1152
|
-
const params = [];
|
|
1153
|
-
if (definition.fields) {
|
|
1154
|
-
params.push('_fields=' + definition.fields.join(','));
|
|
1155
|
-
}
|
|
1156
|
-
if (definition.filters) {
|
|
1157
|
-
definition.filters.forEach((filter) => params.push(formatFilter(filter)));
|
|
1158
|
-
}
|
|
1159
|
-
if (definition.sortRules && definition.sortRules.length > 0) {
|
|
1160
|
-
params.push(formatSortRules(definition.sortRules));
|
|
1161
|
-
}
|
|
1162
|
-
if (definition.offset !== undefined) {
|
|
1163
|
-
params.push('_offset=' + definition.offset);
|
|
1164
|
-
}
|
|
1165
|
-
if (definition.count !== undefined) {
|
|
1166
|
-
params.push('_count=' + definition.count);
|
|
1167
|
-
}
|
|
1168
|
-
if (definition.total !== undefined) {
|
|
1169
|
-
params.push('_total=' + definition.total);
|
|
1170
|
-
}
|
|
1171
|
-
if (params.length === 0) {
|
|
1172
|
-
return '';
|
|
1173
|
-
}
|
|
1174
|
-
params.sort();
|
|
1175
|
-
return '?' + params.join('&');
|
|
1176
|
-
}
|
|
1177
|
-
function formatFilter(filter) {
|
|
1178
|
-
const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
|
|
1179
|
-
const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
|
|
1180
|
-
return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
|
|
1181
|
-
}
|
|
1182
|
-
function formatSortRules(sortRules) {
|
|
1183
|
-
if (!sortRules || sortRules.length === 0) {
|
|
1184
|
-
return '';
|
|
1185
|
-
}
|
|
1186
|
-
return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
1048
|
var _ClientStorage_storage, _MemoryStorage_data;
|
|
1190
1049
|
/**
|
|
1191
1050
|
* The ClientStorage class is a utility class for storing strings and objects.
|
|
@@ -1474,7 +1333,7 @@
|
|
|
1474
1333
|
|
|
1475
1334
|
// PKCE auth ased on:
|
|
1476
1335
|
// https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
|
|
1477
|
-
var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_storage, _MedplumClient_schema, _MedplumClient_requestCache, _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_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_startPkce, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
|
|
1336
|
+
var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_createPdf, _MedplumClient_storage, _MedplumClient_schema, _MedplumClient_requestCache, _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_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_startPkce, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
|
|
1478
1337
|
const DEFAULT_BASE_URL = 'https://api.medplum.com/';
|
|
1479
1338
|
const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
|
|
1480
1339
|
const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
|
|
@@ -1524,7 +1383,7 @@
|
|
|
1524
1383
|
* Search for a `Patient` by name:
|
|
1525
1384
|
*
|
|
1526
1385
|
* ```typescript
|
|
1527
|
-
* const bundle = await medplum.search('Patient
|
|
1386
|
+
* const bundle = await medplum.search('Patient', 'name=Alice');
|
|
1528
1387
|
* console.log(bundle.total);
|
|
1529
1388
|
* ```
|
|
1530
1389
|
*/
|
|
@@ -1534,6 +1393,7 @@
|
|
|
1534
1393
|
super();
|
|
1535
1394
|
_MedplumClient_instances.add(this);
|
|
1536
1395
|
_MedplumClient_fetch.set(this, void 0);
|
|
1396
|
+
_MedplumClient_createPdf.set(this, void 0);
|
|
1537
1397
|
_MedplumClient_storage.set(this, void 0);
|
|
1538
1398
|
_MedplumClient_schema.set(this, void 0);
|
|
1539
1399
|
_MedplumClient_requestCache.set(this, void 0);
|
|
@@ -1558,6 +1418,7 @@
|
|
|
1558
1418
|
}
|
|
1559
1419
|
}
|
|
1560
1420
|
__classPrivateFieldSet(this, _MedplumClient_fetch, (options === null || options === void 0 ? void 0 : options.fetch) || window.fetch.bind(window), "f");
|
|
1421
|
+
__classPrivateFieldSet(this, _MedplumClient_createPdf, options === null || options === void 0 ? void 0 : options.createPdf, "f");
|
|
1561
1422
|
__classPrivateFieldSet(this, _MedplumClient_storage, new ClientStorage(), "f");
|
|
1562
1423
|
__classPrivateFieldSet(this, _MedplumClient_schema, createSchema(), "f");
|
|
1563
1424
|
__classPrivateFieldSet(this, _MedplumClient_requestCache, new LRUCache((_a = options === null || options === void 0 ? void 0 : options.resourceCacheSize) !== null && _a !== void 0 ? _a : DEFAULT_RESOURCE_CACHE_SIZE), "f");
|
|
@@ -1802,12 +1663,11 @@
|
|
|
1802
1663
|
* @param query The FHIR search query or structured query object.
|
|
1803
1664
|
* @returns The well-formed FHIR URL.
|
|
1804
1665
|
*/
|
|
1805
|
-
fhirSearchUrl(query) {
|
|
1806
|
-
|
|
1807
|
-
|
|
1666
|
+
fhirSearchUrl(resourceType, query) {
|
|
1667
|
+
const url = this.fhirUrl(resourceType);
|
|
1668
|
+
if (query) {
|
|
1669
|
+
url.search = query.toString();
|
|
1808
1670
|
}
|
|
1809
|
-
const url = this.fhirUrl(query.resourceType);
|
|
1810
|
-
url.search = formatSearchQuery(query);
|
|
1811
1671
|
return url;
|
|
1812
1672
|
}
|
|
1813
1673
|
/**
|
|
@@ -1816,21 +1676,7 @@
|
|
|
1816
1676
|
* Example using a FHIR search string:
|
|
1817
1677
|
*
|
|
1818
1678
|
* ```typescript
|
|
1819
|
-
* const bundle = await client.search('Patient
|
|
1820
|
-
* console.log(bundle);
|
|
1821
|
-
* ```
|
|
1822
|
-
*
|
|
1823
|
-
* Example using a structured search:
|
|
1824
|
-
*
|
|
1825
|
-
* ```typescript
|
|
1826
|
-
* const bundle = await client.search({
|
|
1827
|
-
* resourceType: 'Patient',
|
|
1828
|
-
* filters: [{
|
|
1829
|
-
* code: 'name',
|
|
1830
|
-
* operator: 'eq',
|
|
1831
|
-
* value: 'Alice',
|
|
1832
|
-
* }]
|
|
1833
|
-
* });
|
|
1679
|
+
* const bundle = await client.search('Patient', 'name=Alice');
|
|
1834
1680
|
* console.log(bundle);
|
|
1835
1681
|
* ```
|
|
1836
1682
|
*
|
|
@@ -1864,8 +1710,8 @@
|
|
|
1864
1710
|
* @param query The search query as either a string or a structured search object.
|
|
1865
1711
|
* @returns Promise to the search result bundle.
|
|
1866
1712
|
*/
|
|
1867
|
-
search(query, options = {}) {
|
|
1868
|
-
return this.get(this.fhirSearchUrl(query), options);
|
|
1713
|
+
search(resourceType, query, options = {}) {
|
|
1714
|
+
return this.get(this.fhirSearchUrl(resourceType, query), options);
|
|
1869
1715
|
}
|
|
1870
1716
|
/**
|
|
1871
1717
|
* Sends a FHIR search request for a single resource.
|
|
@@ -1875,7 +1721,7 @@
|
|
|
1875
1721
|
* Example using a FHIR search string:
|
|
1876
1722
|
*
|
|
1877
1723
|
* ```typescript
|
|
1878
|
-
* const patient = await client.searchOne('Patient
|
|
1724
|
+
* const patient = await client.searchOne('Patient', 'identifier=123');
|
|
1879
1725
|
* console.log(patient);
|
|
1880
1726
|
* ```
|
|
1881
1727
|
*
|
|
@@ -1886,17 +1732,18 @@
|
|
|
1886
1732
|
* @param query The search query as either a string or a structured search object.
|
|
1887
1733
|
* @returns Promise to the search result bundle.
|
|
1888
1734
|
*/
|
|
1889
|
-
searchOne(query, options = {}) {
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1892
|
-
|
|
1735
|
+
searchOne(resourceType, query, options = {}) {
|
|
1736
|
+
const url = this.fhirSearchUrl(resourceType, query);
|
|
1737
|
+
url.searchParams.set('_count', '1');
|
|
1738
|
+
url.searchParams.sort();
|
|
1739
|
+
const cacheKey = url.toString() + '-searchOne';
|
|
1893
1740
|
if (!(options === null || options === void 0 ? void 0 : options.cache)) {
|
|
1894
1741
|
const cached = __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").get(cacheKey);
|
|
1895
1742
|
if (cached) {
|
|
1896
1743
|
return cached;
|
|
1897
1744
|
}
|
|
1898
1745
|
}
|
|
1899
|
-
const promise = new ReadablePromise(this.search(
|
|
1746
|
+
const promise = new ReadablePromise(this.search(resourceType, url.searchParams, options).then((b) => { var _a, _b; return (_b = (_a = b.entry) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.resource; }));
|
|
1900
1747
|
__classPrivateFieldGet(this, _MedplumClient_requestCache, "f").set(cacheKey, promise);
|
|
1901
1748
|
return promise;
|
|
1902
1749
|
}
|
|
@@ -1908,7 +1755,7 @@
|
|
|
1908
1755
|
* Example using a FHIR search string:
|
|
1909
1756
|
*
|
|
1910
1757
|
* ```typescript
|
|
1911
|
-
* const patients = await client.searchResources('Patient
|
|
1758
|
+
* const patients = await client.searchResources('Patient', 'name=Alice');
|
|
1912
1759
|
* console.log(patients);
|
|
1913
1760
|
* ```
|
|
1914
1761
|
*
|
|
@@ -1919,15 +1766,16 @@
|
|
|
1919
1766
|
* @param query The search query as either a string or a structured search object.
|
|
1920
1767
|
* @returns Promise to the search result bundle.
|
|
1921
1768
|
*/
|
|
1922
|
-
searchResources(query, options = {}) {
|
|
1923
|
-
const
|
|
1769
|
+
searchResources(resourceType, query, options = {}) {
|
|
1770
|
+
const url = this.fhirSearchUrl(resourceType, query);
|
|
1771
|
+
const cacheKey = url.toString() + '-searchResources';
|
|
1924
1772
|
if (!(options === null || options === void 0 ? void 0 : options.cache)) {
|
|
1925
1773
|
const cached = __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").get(cacheKey);
|
|
1926
1774
|
if (cached) {
|
|
1927
1775
|
return cached;
|
|
1928
1776
|
}
|
|
1929
1777
|
}
|
|
1930
|
-
const promise = new ReadablePromise(this.search(query, options).then((b) => { var _a, _b; return (_b = (_a = b.entry) === null || _a === void 0 ? void 0 : _a.map((e) => e.resource)) !== null && _b !== void 0 ? _b : []; }));
|
|
1778
|
+
const promise = new ReadablePromise(this.search(resourceType, query, options).then((b) => { var _a, _b; return (_b = (_a = b.entry) === null || _a === void 0 ? void 0 : _a.map((e) => e.resource)) !== null && _b !== void 0 ? _b : []; }));
|
|
1931
1779
|
__classPrivateFieldGet(this, _MedplumClient_requestCache, "f").set(cacheKey, promise);
|
|
1932
1780
|
return promise;
|
|
1933
1781
|
}
|
|
@@ -1962,7 +1810,13 @@
|
|
|
1962
1810
|
*/
|
|
1963
1811
|
getCachedReference(reference) {
|
|
1964
1812
|
const refString = reference.reference;
|
|
1813
|
+
if (!refString) {
|
|
1814
|
+
return undefined;
|
|
1815
|
+
}
|
|
1965
1816
|
const [resourceType, id] = refString.split('/');
|
|
1817
|
+
if (!resourceType || !id) {
|
|
1818
|
+
return undefined;
|
|
1819
|
+
}
|
|
1966
1820
|
return this.getCached(resourceType, id);
|
|
1967
1821
|
}
|
|
1968
1822
|
/**
|
|
@@ -2008,6 +1862,9 @@
|
|
|
2008
1862
|
return new ReadablePromise(Promise.reject(new Error('Missing reference')));
|
|
2009
1863
|
}
|
|
2010
1864
|
const [resourceType, id] = refString.split('/');
|
|
1865
|
+
if (!resourceType || !id) {
|
|
1866
|
+
return new ReadablePromise(Promise.reject(new Error('Invalid reference')));
|
|
1867
|
+
}
|
|
2011
1868
|
return this.readResource(resourceType, id);
|
|
2012
1869
|
}
|
|
2013
1870
|
/**
|
|
@@ -2184,7 +2041,7 @@
|
|
|
2184
2041
|
createResourceIfNoneExist(resource, query) {
|
|
2185
2042
|
var _a;
|
|
2186
2043
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2187
|
-
return (_a = (yield this.searchOne(
|
|
2044
|
+
return ((_a = (yield this.searchOne(resource.resourceType, query))) !== null && _a !== void 0 ? _a : this.createResource(resource));
|
|
2188
2045
|
});
|
|
2189
2046
|
}
|
|
2190
2047
|
/**
|
|
@@ -2240,7 +2097,10 @@
|
|
|
2240
2097
|
*/
|
|
2241
2098
|
createPdf(docDefinition, filename, tableLayouts, fonts) {
|
|
2242
2099
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2243
|
-
|
|
2100
|
+
if (!__classPrivateFieldGet(this, _MedplumClient_createPdf, "f")) {
|
|
2101
|
+
throw new Error('PDF creation not enabled');
|
|
2102
|
+
}
|
|
2103
|
+
const blob = yield __classPrivateFieldGet(this, _MedplumClient_createPdf, "f").call(this, docDefinition, tableLayouts, fonts);
|
|
2244
2104
|
return this.createBinary(blob, filename, 'application/pdf');
|
|
2245
2105
|
});
|
|
2246
2106
|
}
|
|
@@ -2503,7 +2363,7 @@
|
|
|
2503
2363
|
});
|
|
2504
2364
|
}
|
|
2505
2365
|
}
|
|
2506
|
-
_MedplumClient_fetch = new WeakMap(), _MedplumClient_storage = new WeakMap(), _MedplumClient_schema = new WeakMap(), _MedplumClient_requestCache = new WeakMap(), _MedplumClient_baseUrl = new WeakMap(), _MedplumClient_clientId = new WeakMap(), _MedplumClient_authorizeUrl = new WeakMap(), _MedplumClient_tokenUrl = new WeakMap(), _MedplumClient_logoutUrl = new WeakMap(), _MedplumClient_onUnauthenticated = new WeakMap(), _MedplumClient_accessToken = new WeakMap(), _MedplumClient_refreshToken = new WeakMap(), _MedplumClient_refreshPromise = new WeakMap(), _MedplumClient_profilePromise = new WeakMap(), _MedplumClient_profile = new WeakMap(), _MedplumClient_config = new WeakMap(), _MedplumClient_instances = new WeakSet(), _MedplumClient_addLogin = function _MedplumClient_addLogin(newLogin) {
|
|
2366
|
+
_MedplumClient_fetch = new WeakMap(), _MedplumClient_createPdf = new WeakMap(), _MedplumClient_storage = new WeakMap(), _MedplumClient_schema = new WeakMap(), _MedplumClient_requestCache = new WeakMap(), _MedplumClient_baseUrl = new WeakMap(), _MedplumClient_clientId = new WeakMap(), _MedplumClient_authorizeUrl = new WeakMap(), _MedplumClient_tokenUrl = new WeakMap(), _MedplumClient_logoutUrl = new WeakMap(), _MedplumClient_onUnauthenticated = new WeakMap(), _MedplumClient_accessToken = new WeakMap(), _MedplumClient_refreshToken = new WeakMap(), _MedplumClient_refreshPromise = new WeakMap(), _MedplumClient_profilePromise = new WeakMap(), _MedplumClient_profile = new WeakMap(), _MedplumClient_config = new WeakMap(), _MedplumClient_instances = new WeakSet(), _MedplumClient_addLogin = function _MedplumClient_addLogin(newLogin) {
|
|
2507
2367
|
const logins = this.getLogins().filter((login) => { var _a, _b; return ((_a = login.profile) === null || _a === void 0 ? void 0 : _a.reference) !== ((_b = newLogin.profile) === null || _b === void 0 ? void 0 : _b.reference); });
|
|
2508
2368
|
logins.push(newLogin);
|
|
2509
2369
|
__classPrivateFieldGet(this, _MedplumClient_storage, "f").setObject('logins', logins);
|
|
@@ -5332,6 +5192,206 @@
|
|
|
5332
5192
|
}
|
|
5333
5193
|
}
|
|
5334
5194
|
|
|
5195
|
+
const DEFAULT_SEARCH_COUNT = 20;
|
|
5196
|
+
/**
|
|
5197
|
+
* Search operators.
|
|
5198
|
+
* These operators represent "modifiers" and "prefixes" in FHIR search.
|
|
5199
|
+
* See: https://www.hl7.org/fhir/search.html
|
|
5200
|
+
*/
|
|
5201
|
+
exports.Operator = void 0;
|
|
5202
|
+
(function (Operator) {
|
|
5203
|
+
Operator["EQUALS"] = "eq";
|
|
5204
|
+
Operator["NOT_EQUALS"] = "ne";
|
|
5205
|
+
// Numbers
|
|
5206
|
+
Operator["GREATER_THAN"] = "gt";
|
|
5207
|
+
Operator["LESS_THAN"] = "lt";
|
|
5208
|
+
Operator["GREATER_THAN_OR_EQUALS"] = "ge";
|
|
5209
|
+
Operator["LESS_THAN_OR_EQUALS"] = "le";
|
|
5210
|
+
// Dates
|
|
5211
|
+
Operator["STARTS_AFTER"] = "sa";
|
|
5212
|
+
Operator["ENDS_BEFORE"] = "eb";
|
|
5213
|
+
Operator["APPROXIMATELY"] = "ap";
|
|
5214
|
+
// String
|
|
5215
|
+
Operator["CONTAINS"] = "contains";
|
|
5216
|
+
Operator["EXACT"] = "exact";
|
|
5217
|
+
// Token
|
|
5218
|
+
Operator["TEXT"] = "text";
|
|
5219
|
+
Operator["ABOVE"] = "above";
|
|
5220
|
+
Operator["BELOW"] = "below";
|
|
5221
|
+
Operator["IN"] = "in";
|
|
5222
|
+
Operator["NOT_IN"] = "not-in";
|
|
5223
|
+
Operator["OF_TYPE"] = "of-type";
|
|
5224
|
+
})(exports.Operator || (exports.Operator = {}));
|
|
5225
|
+
const MODIFIER_OPERATORS = [
|
|
5226
|
+
exports.Operator.CONTAINS,
|
|
5227
|
+
exports.Operator.EXACT,
|
|
5228
|
+
exports.Operator.TEXT,
|
|
5229
|
+
exports.Operator.ABOVE,
|
|
5230
|
+
exports.Operator.BELOW,
|
|
5231
|
+
exports.Operator.IN,
|
|
5232
|
+
exports.Operator.NOT_IN,
|
|
5233
|
+
exports.Operator.OF_TYPE,
|
|
5234
|
+
];
|
|
5235
|
+
const PREFIX_OPERATORS = [
|
|
5236
|
+
exports.Operator.NOT_EQUALS,
|
|
5237
|
+
exports.Operator.GREATER_THAN,
|
|
5238
|
+
exports.Operator.LESS_THAN,
|
|
5239
|
+
exports.Operator.GREATER_THAN_OR_EQUALS,
|
|
5240
|
+
exports.Operator.LESS_THAN_OR_EQUALS,
|
|
5241
|
+
exports.Operator.STARTS_AFTER,
|
|
5242
|
+
exports.Operator.ENDS_BEFORE,
|
|
5243
|
+
exports.Operator.APPROXIMATELY,
|
|
5244
|
+
];
|
|
5245
|
+
/**
|
|
5246
|
+
* Parses a URL into a SearchRequest.
|
|
5247
|
+
*
|
|
5248
|
+
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
5249
|
+
*
|
|
5250
|
+
* @param url The URL to parse.
|
|
5251
|
+
* @returns Parsed search definition.
|
|
5252
|
+
*/
|
|
5253
|
+
function parseSearchDefinition(url) {
|
|
5254
|
+
const location = new URL(url, 'https://example.com/');
|
|
5255
|
+
const resourceType = location.pathname
|
|
5256
|
+
.replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
|
|
5257
|
+
.split('/')
|
|
5258
|
+
.pop();
|
|
5259
|
+
const params = new URLSearchParams(location.search);
|
|
5260
|
+
let filters = undefined;
|
|
5261
|
+
let sortRules = undefined;
|
|
5262
|
+
let fields = undefined;
|
|
5263
|
+
let offset = undefined;
|
|
5264
|
+
let count = undefined;
|
|
5265
|
+
let total = undefined;
|
|
5266
|
+
params.forEach((value, key) => {
|
|
5267
|
+
if (key === '_fields') {
|
|
5268
|
+
fields = value.split(',');
|
|
5269
|
+
}
|
|
5270
|
+
else if (key === '_offset') {
|
|
5271
|
+
offset = parseInt(value);
|
|
5272
|
+
}
|
|
5273
|
+
else if (key === '_count') {
|
|
5274
|
+
count = parseInt(value);
|
|
5275
|
+
}
|
|
5276
|
+
else if (key === '_total') {
|
|
5277
|
+
total = value;
|
|
5278
|
+
}
|
|
5279
|
+
else if (key === '_sort') {
|
|
5280
|
+
sortRules = sortRules || [];
|
|
5281
|
+
sortRules.push(parseSortRule(value));
|
|
5282
|
+
}
|
|
5283
|
+
else {
|
|
5284
|
+
filters = filters || [];
|
|
5285
|
+
filters.push(parseSearchFilter(key, value));
|
|
5286
|
+
}
|
|
5287
|
+
});
|
|
5288
|
+
return {
|
|
5289
|
+
resourceType,
|
|
5290
|
+
filters,
|
|
5291
|
+
fields,
|
|
5292
|
+
offset,
|
|
5293
|
+
count,
|
|
5294
|
+
total,
|
|
5295
|
+
sortRules,
|
|
5296
|
+
};
|
|
5297
|
+
}
|
|
5298
|
+
/**
|
|
5299
|
+
* Parses a URL query parameter into a sort rule.
|
|
5300
|
+
*
|
|
5301
|
+
* By default, the sort rule is the field name.
|
|
5302
|
+
*
|
|
5303
|
+
* Sort rules can be reversed into descending order by prefixing the field name with a minus sign.
|
|
5304
|
+
*
|
|
5305
|
+
* See sorting: http://hl7.org/fhir/r4/search.html#_sort
|
|
5306
|
+
*
|
|
5307
|
+
* @param value The URL parameter value.
|
|
5308
|
+
* @returns The parsed sort rule.
|
|
5309
|
+
*/
|
|
5310
|
+
function parseSortRule(value) {
|
|
5311
|
+
if (value.startsWith('-')) {
|
|
5312
|
+
return { code: value.substring(1), descending: true };
|
|
5313
|
+
}
|
|
5314
|
+
else {
|
|
5315
|
+
return { code: value };
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
/**
|
|
5319
|
+
* Parses a URL query parameter into a search filter.
|
|
5320
|
+
*
|
|
5321
|
+
* FHIR search filters can be specified as modifiers or prefixes.
|
|
5322
|
+
*
|
|
5323
|
+
* For string properties, modifiers are appended to the key, e.g. "name:contains=eve".
|
|
5324
|
+
*
|
|
5325
|
+
* For date and numeric properties, prefixes are prepended to the value, e.g. "birthdate=gt2000".
|
|
5326
|
+
*
|
|
5327
|
+
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
5328
|
+
*
|
|
5329
|
+
* @param key The URL parameter key.
|
|
5330
|
+
* @param value The URL parameter value.
|
|
5331
|
+
* @returns The parsed search filter.
|
|
5332
|
+
*/
|
|
5333
|
+
function parseSearchFilter(key, value) {
|
|
5334
|
+
let code = key;
|
|
5335
|
+
let operator = exports.Operator.EQUALS;
|
|
5336
|
+
for (const modifier of MODIFIER_OPERATORS) {
|
|
5337
|
+
const modifierIndex = code.indexOf(':' + modifier);
|
|
5338
|
+
if (modifierIndex !== -1) {
|
|
5339
|
+
operator = modifier;
|
|
5340
|
+
code = code.substring(0, modifierIndex);
|
|
5341
|
+
}
|
|
5342
|
+
}
|
|
5343
|
+
for (const prefix of PREFIX_OPERATORS) {
|
|
5344
|
+
if (value.match(new RegExp('^' + prefix + '\\d'))) {
|
|
5345
|
+
operator = prefix;
|
|
5346
|
+
value = value.substring(prefix.length);
|
|
5347
|
+
}
|
|
5348
|
+
}
|
|
5349
|
+
return { code, operator, value };
|
|
5350
|
+
}
|
|
5351
|
+
/**
|
|
5352
|
+
* Formats a search definition object into a query string.
|
|
5353
|
+
* Note: The return value does not include the resource type.
|
|
5354
|
+
* @param {!SearchRequest} definition The search definition.
|
|
5355
|
+
* @returns Formatted URL.
|
|
5356
|
+
*/
|
|
5357
|
+
function formatSearchQuery(definition) {
|
|
5358
|
+
const params = [];
|
|
5359
|
+
if (definition.fields) {
|
|
5360
|
+
params.push('_fields=' + definition.fields.join(','));
|
|
5361
|
+
}
|
|
5362
|
+
if (definition.filters) {
|
|
5363
|
+
definition.filters.forEach((filter) => params.push(formatFilter(filter)));
|
|
5364
|
+
}
|
|
5365
|
+
if (definition.sortRules && definition.sortRules.length > 0) {
|
|
5366
|
+
params.push(formatSortRules(definition.sortRules));
|
|
5367
|
+
}
|
|
5368
|
+
if (definition.offset !== undefined) {
|
|
5369
|
+
params.push('_offset=' + definition.offset);
|
|
5370
|
+
}
|
|
5371
|
+
if (definition.count !== undefined) {
|
|
5372
|
+
params.push('_count=' + definition.count);
|
|
5373
|
+
}
|
|
5374
|
+
if (definition.total !== undefined) {
|
|
5375
|
+
params.push('_total=' + definition.total);
|
|
5376
|
+
}
|
|
5377
|
+
if (params.length === 0) {
|
|
5378
|
+
return '';
|
|
5379
|
+
}
|
|
5380
|
+
params.sort();
|
|
5381
|
+
return '?' + params.join('&');
|
|
5382
|
+
}
|
|
5383
|
+
function formatFilter(filter) {
|
|
5384
|
+
const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
|
|
5385
|
+
const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
|
|
5386
|
+
return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
|
|
5387
|
+
}
|
|
5388
|
+
function formatSortRules(sortRules) {
|
|
5389
|
+
if (!sortRules || sortRules.length === 0) {
|
|
5390
|
+
return '';
|
|
5391
|
+
}
|
|
5392
|
+
return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');
|
|
5393
|
+
}
|
|
5394
|
+
|
|
5335
5395
|
exports.SearchParameterType = void 0;
|
|
5336
5396
|
(function (SearchParameterType) {
|
|
5337
5397
|
SearchParameterType["BOOLEAN"] = "BOOLEAN";
|
|
@@ -5490,11 +5550,13 @@
|
|
|
5490
5550
|
exports.created = created;
|
|
5491
5551
|
exports.deepEquals = deepEquals$1;
|
|
5492
5552
|
exports.evalFhirPath = evalFhirPath;
|
|
5553
|
+
exports.findObservationInterval = findObservationInterval;
|
|
5493
5554
|
exports.formatAddress = formatAddress;
|
|
5494
5555
|
exports.formatFamilyName = formatFamilyName;
|
|
5495
5556
|
exports.formatGivenName = formatGivenName;
|
|
5496
5557
|
exports.formatHumanName = formatHumanName;
|
|
5497
5558
|
exports.formatSearchQuery = formatSearchQuery;
|
|
5559
|
+
exports.getCodeBySystem = getCodeBySystem;
|
|
5498
5560
|
exports.getDateProperty = getDateProperty;
|
|
5499
5561
|
exports.getDisplayString = getDisplayString;
|
|
5500
5562
|
exports.getExpressionForResourceType = getExpressionForResourceType;
|
|
@@ -5517,11 +5579,18 @@
|
|
|
5517
5579
|
exports.isProfileResource = isProfileResource;
|
|
5518
5580
|
exports.isStringArray = isStringArray;
|
|
5519
5581
|
exports.isUUID = isUUID;
|
|
5582
|
+
exports.matchesRange = matchesRange;
|
|
5520
5583
|
exports.notFound = notFound;
|
|
5521
5584
|
exports.notModified = notModified;
|
|
5522
5585
|
exports.parseFhirPath = parseFhirPath;
|
|
5523
5586
|
exports.parseSearchDefinition = parseSearchDefinition;
|
|
5587
|
+
exports.preciseEquals = preciseEquals;
|
|
5588
|
+
exports.preciseGreaterThan = preciseGreaterThan;
|
|
5589
|
+
exports.preciseGreaterThanOrEquals = preciseGreaterThanOrEquals;
|
|
5590
|
+
exports.preciseLessThan = preciseLessThan;
|
|
5591
|
+
exports.preciseLessThanOrEquals = preciseLessThanOrEquals;
|
|
5524
5592
|
exports.resolveId = resolveId;
|
|
5593
|
+
exports.setCodeBySystem = setCodeBySystem;
|
|
5525
5594
|
exports.stringify = stringify;
|
|
5526
5595
|
exports.tokenize = tokenize;
|
|
5527
5596
|
|