@medplum/core 2.0.6 → 2.0.9
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.cjs +248 -334
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/esm/client.mjs +8 -5
- package/dist/esm/client.mjs.map +1 -1
- package/dist/esm/index.min.mjs +1 -1
- package/dist/esm/index.mjs +3 -3
- package/dist/esm/outcomes.mjs +21 -3
- package/dist/esm/outcomes.mjs.map +1 -1
- package/dist/esm/search/details.mjs +1 -1
- package/dist/esm/search/details.mjs.map +1 -1
- package/dist/esm/search/search.mjs +215 -111
- package/dist/esm/search/search.mjs.map +1 -1
- package/dist/types/client.d.ts +11 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/outcomes.d.ts +6 -0
- package/dist/types/search/search.d.ts +16 -5
- package/package.json +1 -1
- package/dist/esm/search/parse.mjs +0 -218
- package/dist/esm/search/parse.mjs.map +0 -1
- package/dist/types/search/parse.d.ts +0 -17
- package/tsconfig.build.json +0 -9
package/dist/esm/index.mjs
CHANGED
|
@@ -12,13 +12,13 @@ export { FhirFilterComparison, FhirFilterConnective, FhirFilterNegation } from '
|
|
|
12
12
|
export { formatAddress, formatCodeableConcept, formatCoding, formatDate, formatDateTime, formatFamilyName, formatGivenName, formatHumanName, formatMoney, formatObservationValue, formatPeriod, formatQuantity, formatRange, formatTime, formatTiming, isValidDate } from './format.mjs';
|
|
13
13
|
export { Hl7Context, Hl7Field, Hl7Message, Hl7Segment } from './hl7.mjs';
|
|
14
14
|
export { parseJWTPayload } from './jwt.mjs';
|
|
15
|
-
export { OperationOutcomeError, allOk, assertOk, badRequest, created, forbidden, getStatus, gone, isGone, isNotFound, isOk, isOperationOutcome, normalizeErrorString, normalizeOperationOutcome, notFound, notModified, tooManyRequests, unauthorized, validationError } from './outcomes.mjs';
|
|
15
|
+
export { OperationOutcomeError, allOk, assertOk, badRequest, created, forbidden, getStatus, gone, isGone, isNotFound, isOk, isOperationOutcome, normalizeErrorString, normalizeOperationOutcome, notFound, notModified, operationOutcomeToString, tooManyRequests, unauthorized, validationError } from './outcomes.mjs';
|
|
16
16
|
export { ReadablePromise } from './readablepromise.mjs';
|
|
17
17
|
export { FhirSchemaValidator, checkForNull, createStructureIssue, isResourceType, validateResource, validateResourceType } from './schema.mjs';
|
|
18
18
|
export { SearchParameterType, getExpressionForResourceType, getSearchParameterDetails } from './search/details.mjs';
|
|
19
19
|
export { matchesSearchRequest } from './search/match.mjs';
|
|
20
|
-
export { parseSearchRequest, parseSearchUrl } from './search/
|
|
21
|
-
export {
|
|
20
|
+
export { DEFAULT_SEARCH_COUNT, Operator, formatSearchQuery, parseSearchDefinition, parseSearchRequest, parseSearchUrl } from './search/search.mjs';
|
|
21
|
+
export { ClientStorage, MemoryStorage } from './storage.mjs';
|
|
22
22
|
export { PropertyType, buildTypeName, getElementDefinition, getElementDefinitionTypeName, getPropertyDisplayName, getResourceTypeSchema, getResourceTypes, getSearchParameters, globalSchema, indexSearchParameter, indexSearchParameterBundle, indexStructureDefinition, indexStructureDefinitionBundle, isReference, isResource, isResourceTypeSchema } from './types.mjs';
|
|
23
23
|
export { arrayBufferToBase64, arrayBufferToHex, calculateAge, calculateAgeString, capitalize, createReference, deepClone, deepEquals, findObservationInterval, findObservationReferenceRange, getCodeBySystem, getDateProperty, getDisplayString, getExtension, getExtensionValue, getIdentifier, getImageSrc, getQuestionnaireAnswers, getReferenceString, isEmpty, isLowerCase, isObject, isProfileResource, isStringArray, isUUID, matchesRange, preciseEquals, preciseGreaterThan, preciseGreaterThanOrEquals, preciseLessThan, preciseLessThanOrEquals, preciseRound, resolveId, setCodeBySystem, stringify } from './utils.mjs';
|
|
24
24
|
//# sourceMappingURL=index.mjs.map
|
package/dist/esm/outcomes.mjs
CHANGED
|
@@ -192,7 +192,7 @@ function assertOk(outcome, resource) {
|
|
|
192
192
|
}
|
|
193
193
|
class OperationOutcomeError extends Error {
|
|
194
194
|
constructor(outcome, cause) {
|
|
195
|
-
super(outcome
|
|
195
|
+
super(operationOutcomeToString(outcome));
|
|
196
196
|
this.outcome = outcome;
|
|
197
197
|
this.cause = cause;
|
|
198
198
|
}
|
|
@@ -227,10 +227,28 @@ function normalizeErrorString(error) {
|
|
|
227
227
|
return error.message;
|
|
228
228
|
}
|
|
229
229
|
if (isOperationOutcome(error)) {
|
|
230
|
-
return error
|
|
230
|
+
return operationOutcomeToString(error);
|
|
231
231
|
}
|
|
232
232
|
return JSON.stringify(error);
|
|
233
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Returns a string represenation of the operation outcome.
|
|
236
|
+
* @param outcome The operation outcome.
|
|
237
|
+
* @returns The string representation of the operation outcome.
|
|
238
|
+
*/
|
|
239
|
+
function operationOutcomeToString(outcome) {
|
|
240
|
+
const strs = [];
|
|
241
|
+
if (outcome.issue) {
|
|
242
|
+
for (const issue of outcome.issue) {
|
|
243
|
+
let issueStr = issue.details?.text || 'Unknown error';
|
|
244
|
+
if (issue.expression?.length) {
|
|
245
|
+
issueStr += ` (${issue.expression.join(', ')})`;
|
|
246
|
+
}
|
|
247
|
+
strs.push(issueStr);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return strs.length > 0 ? strs.join('; ') : 'Unknown error';
|
|
251
|
+
}
|
|
234
252
|
|
|
235
|
-
export { OperationOutcomeError, allOk, assertOk, badRequest, created, forbidden, getStatus, gone, isGone, isNotFound, isOk, isOperationOutcome, normalizeErrorString, normalizeOperationOutcome, notFound, notModified, tooManyRequests, unauthorized, validationError };
|
|
253
|
+
export { OperationOutcomeError, allOk, assertOk, badRequest, created, forbidden, getStatus, gone, isGone, isNotFound, isOk, isOperationOutcome, normalizeErrorString, normalizeOperationOutcome, notFound, notModified, operationOutcomeToString, tooManyRequests, unauthorized, validationError };
|
|
236
254
|
//# sourceMappingURL=outcomes.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outcomes.mjs","sources":["../../src/outcomes.ts"],"sourcesContent":["import { OperationOutcome } from '@medplum/fhirtypes';\n\nconst OK_ID = 'ok';\nconst CREATED_ID = 'created';\nconst GONE_ID = 'gone';\nconst NOT_MODIFIED_ID = 'not-modified';\nconst NOT_FOUND_ID = 'not-found';\nconst UNAUTHORIZED_ID = 'unauthorized';\nconst FORBIDDEN_ID = 'forbidden';\nconst TOO_MANY_REQUESTS_ID = 'too-many-requests';\n\nexport const allOk: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: OK_ID,\n issue: [\n {\n severity: 'information',\n code: 'informational',\n details: {\n text: 'All OK',\n },\n },\n ],\n};\n\nexport const created: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: CREATED_ID,\n issue: [\n {\n severity: 'information',\n code: 'informational',\n details: {\n text: 'Created',\n },\n },\n ],\n};\n\nexport const notModified: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: NOT_MODIFIED_ID,\n issue: [\n {\n severity: 'information',\n code: 'informational',\n details: {\n text: 'Not Modified',\n },\n },\n ],\n};\n\nexport const notFound: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: NOT_FOUND_ID,\n issue: [\n {\n severity: 'error',\n code: 'not-found',\n details: {\n text: 'Not found',\n },\n },\n ],\n};\n\nexport const unauthorized: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: UNAUTHORIZED_ID,\n issue: [\n {\n severity: 'error',\n code: 'login',\n details: {\n text: 'Unauthorized',\n },\n },\n ],\n};\n\nexport const forbidden: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: FORBIDDEN_ID,\n issue: [\n {\n severity: 'error',\n code: 'forbidden',\n details: {\n text: 'Forbidden',\n },\n },\n ],\n};\n\nexport const gone: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: GONE_ID,\n issue: [\n {\n severity: 'error',\n code: 'deleted',\n details: {\n text: 'Gone',\n },\n },\n ],\n};\n\nexport const tooManyRequests: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: TOO_MANY_REQUESTS_ID,\n issue: [\n {\n severity: 'error',\n code: 'throttled',\n details: {\n text: 'Too Many Requests',\n },\n },\n ],\n};\n\nexport function badRequest(details: string, expression?: string): OperationOutcome {\n return {\n resourceType: 'OperationOutcome',\n issue: [\n {\n severity: 'error',\n code: 'invalid',\n details: {\n text: details,\n },\n expression: expression ? [expression] : undefined,\n },\n ],\n };\n}\n\nexport function validationError(details: string): OperationOutcome {\n return {\n resourceType: 'OperationOutcome',\n issue: [\n {\n severity: 'error',\n code: 'structure',\n details: {\n text: details,\n },\n },\n ],\n };\n}\n\nexport function isOperationOutcome(value: unknown): value is OperationOutcome {\n return typeof value === 'object' && value !== null && (value as any).resourceType === 'OperationOutcome';\n}\n\nexport function isOk(outcome: OperationOutcome): boolean {\n return outcome.id === OK_ID || outcome.id === CREATED_ID || outcome.id === NOT_MODIFIED_ID;\n}\n\nexport function isNotFound(outcome: OperationOutcome): boolean {\n return outcome.id === NOT_FOUND_ID;\n}\n\nexport function isGone(outcome: OperationOutcome): boolean {\n return outcome.id === GONE_ID;\n}\n\nexport function getStatus(outcome: OperationOutcome): number {\n if (outcome.id === OK_ID) {\n return 200;\n } else if (outcome.id === CREATED_ID) {\n return 201;\n } else if (outcome.id === NOT_MODIFIED_ID) {\n return 304;\n } else if (outcome.id === UNAUTHORIZED_ID) {\n return 401;\n } else if (outcome.id === FORBIDDEN_ID) {\n return 403;\n } else if (outcome.id === NOT_FOUND_ID) {\n return 404;\n } else if (outcome.id === GONE_ID) {\n return 410;\n } else if (outcome.id === TOO_MANY_REQUESTS_ID) {\n return 429;\n } else {\n return 400;\n }\n}\n\n/**\n * Asserts that the operation completed successfully and that the resource is defined.\n * @param outcome The operation outcome.\n * @param resource The resource that may or may not have been returned.\n */\nexport function assertOk<T>(outcome: OperationOutcome, resource: T | undefined): asserts resource is T {\n if (!isOk(outcome) || resource === undefined) {\n throw new OperationOutcomeError(outcome);\n }\n}\n\nexport class OperationOutcomeError extends Error {\n readonly outcome: OperationOutcome;\n\n constructor(outcome: OperationOutcome, cause?: unknown) {\n super(outcome?.issue?.[0].details?.text);\n this.outcome = outcome;\n this.cause = cause;\n }\n}\n\n/**\n * Normalizes an error object into an OperationOutcome.\n * @param error The error value which could be a string, Error, OperationOutcome, or other unknown type.\n * @returns The normalized OperationOutcome.\n */\nexport function normalizeOperationOutcome(error: unknown): OperationOutcome {\n if (error instanceof OperationOutcomeError) {\n return error.outcome;\n }\n if (isOperationOutcome(error)) {\n return error;\n }\n return badRequest(normalizeErrorString(error));\n}\n\n/**\n * Normalizes an error object into a displayable error string.\n * @param error The error value which could be a string, Error, OperationOutcome, or other unknown type.\n * @returns A display string for the error.\n */\nexport function normalizeErrorString(error: unknown): string {\n if (!error) {\n return 'Unknown error';\n }\n if (typeof error === 'string') {\n return error;\n }\n if (error instanceof Error) {\n return error.message;\n }\n if (isOperationOutcome(error)) {\n return error.issue?.[0]?.details?.text ?? 'Unknown error';\n }\n return JSON.stringify(error);\n}\n"],"names":[],"mappings":"AAEA,MAAM,KAAK,GAAG,IAAI,CAAC;AACnB,MAAM,UAAU,GAAG,SAAS,CAAC;AAC7B,MAAM,OAAO,GAAG,MAAM,CAAC;AACvB,MAAM,eAAe,GAAG,cAAc,CAAC;AACvC,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,MAAM,eAAe,GAAG,cAAc,CAAC;AACvC,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAEpC,MAAA,KAAK,GAAqB;AACrC,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,EAAE,EAAE,KAAK;AACT,IAAA,KAAK,EAAE;AACL,QAAA;AACE,YAAA,QAAQ,EAAE,aAAa;AACvB,YAAA,IAAI,EAAE,eAAe;AACrB,YAAA,OAAO,EAAE;AACP,gBAAA,IAAI,EAAE,QAAQ;AACf,aAAA;AACF,SAAA;AACF,KAAA;EACD;AAEW,MAAA,OAAO,GAAqB;AACvC,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,EAAE,EAAE,UAAU;AACd,IAAA,KAAK,EAAE;AACL,QAAA;AACE,YAAA,QAAQ,EAAE,aAAa;AACvB,YAAA,IAAI,EAAE,eAAe;AACrB,YAAA,OAAO,EAAE;AACP,gBAAA,IAAI,EAAE,SAAS;AAChB,aAAA;AACF,SAAA;AACF,KAAA;EACD;AAEW,MAAA,WAAW,GAAqB;AAC3C,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,EAAE,EAAE,eAAe;AACnB,IAAA,KAAK,EAAE;AACL,QAAA;AACE,YAAA,QAAQ,EAAE,aAAa;AACvB,YAAA,IAAI,EAAE,eAAe;AACrB,YAAA,OAAO,EAAE;AACP,gBAAA,IAAI,EAAE,cAAc;AACrB,aAAA;AACF,SAAA;AACF,KAAA;EACD;AAEW,MAAA,QAAQ,GAAqB;AACxC,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,EAAE,EAAE,YAAY;AAChB,IAAA,KAAK,EAAE;AACL,QAAA;AACE,YAAA,QAAQ,EAAE,OAAO;AACjB,YAAA,IAAI,EAAE,WAAW;AACjB,YAAA,OAAO,EAAE;AACP,gBAAA,IAAI,EAAE,WAAW;AAClB,aAAA;AACF,SAAA;AACF,KAAA;EACD;AAEW,MAAA,YAAY,GAAqB;AAC5C,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,EAAE,EAAE,eAAe;AACnB,IAAA,KAAK,EAAE;AACL,QAAA;AACE,YAAA,QAAQ,EAAE,OAAO;AACjB,YAAA,IAAI,EAAE,OAAO;AACb,YAAA,OAAO,EAAE;AACP,gBAAA,IAAI,EAAE,cAAc;AACrB,aAAA;AACF,SAAA;AACF,KAAA;EACD;AAEW,MAAA,SAAS,GAAqB;AACzC,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,EAAE,EAAE,YAAY;AAChB,IAAA,KAAK,EAAE;AACL,QAAA;AACE,YAAA,QAAQ,EAAE,OAAO;AACjB,YAAA,IAAI,EAAE,WAAW;AACjB,YAAA,OAAO,EAAE;AACP,gBAAA,IAAI,EAAE,WAAW;AAClB,aAAA;AACF,SAAA;AACF,KAAA;EACD;AAEW,MAAA,IAAI,GAAqB;AACpC,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,EAAE,EAAE,OAAO;AACX,IAAA,KAAK,EAAE;AACL,QAAA;AACE,YAAA,QAAQ,EAAE,OAAO;AACjB,YAAA,IAAI,EAAE,SAAS;AACf,YAAA,OAAO,EAAE;AACP,gBAAA,IAAI,EAAE,MAAM;AACb,aAAA;AACF,SAAA;AACF,KAAA;EACD;AAEW,MAAA,eAAe,GAAqB;AAC/C,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,EAAE,EAAE,oBAAoB;AACxB,IAAA,KAAK,EAAE;AACL,QAAA;AACE,YAAA,QAAQ,EAAE,OAAO;AACjB,YAAA,IAAI,EAAE,WAAW;AACjB,YAAA,OAAO,EAAE;AACP,gBAAA,IAAI,EAAE,mBAAmB;AAC1B,aAAA;AACF,SAAA;AACF,KAAA;EACD;AAEc,SAAA,UAAU,CAAC,OAAe,EAAE,UAAmB,EAAA;IAC7D,OAAO;AACL,QAAA,YAAY,EAAE,kBAAkB;AAChC,QAAA,KAAK,EAAE;AACL,YAAA;AACE,gBAAA,QAAQ,EAAE,OAAO;AACjB,gBAAA,IAAI,EAAE,SAAS;AACf,gBAAA,OAAO,EAAE;AACP,oBAAA,IAAI,EAAE,OAAO;AACd,iBAAA;gBACD,UAAU,EAAE,UAAU,GAAG,CAAC,UAAU,CAAC,GAAG,SAAS;AAClD,aAAA;AACF,SAAA;KACF,CAAC;AACJ,CAAC;AAEK,SAAU,eAAe,CAAC,OAAe,EAAA;IAC7C,OAAO;AACL,QAAA,YAAY,EAAE,kBAAkB;AAChC,QAAA,KAAK,EAAE;AACL,YAAA;AACE,gBAAA,QAAQ,EAAE,OAAO;AACjB,gBAAA,IAAI,EAAE,WAAW;AACjB,gBAAA,OAAO,EAAE;AACP,oBAAA,IAAI,EAAE,OAAO;AACd,iBAAA;AACF,aAAA;AACF,SAAA;KACF,CAAC;AACJ,CAAC;AAEK,SAAU,kBAAkB,CAAC,KAAc,EAAA;AAC/C,IAAA,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAK,KAAa,CAAC,YAAY,KAAK,kBAAkB,CAAC;AAC3G,CAAC;AAEK,SAAU,IAAI,CAAC,OAAyB,EAAA;AAC5C,IAAA,OAAO,OAAO,CAAC,EAAE,KAAK,KAAK,IAAI,OAAO,CAAC,EAAE,KAAK,UAAU,IAAI,OAAO,CAAC,EAAE,KAAK,eAAe,CAAC;AAC7F,CAAC;AAEK,SAAU,UAAU,CAAC,OAAyB,EAAA;AAClD,IAAA,OAAO,OAAO,CAAC,EAAE,KAAK,YAAY,CAAC;AACrC,CAAC;AAEK,SAAU,MAAM,CAAC,OAAyB,EAAA;AAC9C,IAAA,OAAO,OAAO,CAAC,EAAE,KAAK,OAAO,CAAC;AAChC,CAAC;AAEK,SAAU,SAAS,CAAC,OAAyB,EAAA;AACjD,IAAA,IAAI,OAAO,CAAC,EAAE,KAAK,KAAK,EAAE;AACxB,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AAAM,SAAA,IAAI,OAAO,CAAC,EAAE,KAAK,UAAU,EAAE;AACpC,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AAAM,SAAA,IAAI,OAAO,CAAC,EAAE,KAAK,eAAe,EAAE;AACzC,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AAAM,SAAA,IAAI,OAAO,CAAC,EAAE,KAAK,eAAe,EAAE;AACzC,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AAAM,SAAA,IAAI,OAAO,CAAC,EAAE,KAAK,YAAY,EAAE;AACtC,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AAAM,SAAA,IAAI,OAAO,CAAC,EAAE,KAAK,YAAY,EAAE;AACtC,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AAAM,SAAA,IAAI,OAAO,CAAC,EAAE,KAAK,OAAO,EAAE;AACjC,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AAAM,SAAA,IAAI,OAAO,CAAC,EAAE,KAAK,oBAAoB,EAAE;AAC9C,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AAAM,SAAA;AACL,QAAA,OAAO,GAAG,CAAC;AACZ,KAAA;AACH,CAAC;AAED;;;;AAIG;AACa,SAAA,QAAQ,CAAI,OAAyB,EAAE,QAAuB,EAAA;IAC5E,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC5C,QAAA,MAAM,IAAI,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC1C,KAAA;AACH,CAAC;AAEK,MAAO,qBAAsB,SAAQ,KAAK,CAAA;IAG9C,WAAY,CAAA,OAAyB,EAAE,KAAe,EAAA;AACpD,QAAA,KAAK,CAAC,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACzC,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;AACvB,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;KACpB;AACF,CAAA;AAED;;;;AAIG;AACG,SAAU,yBAAyB,CAAC,KAAc,EAAA;IACtD,IAAI,KAAK,YAAY,qBAAqB,EAAE;QAC1C,OAAO,KAAK,CAAC,OAAO,CAAC;AACtB,KAAA;AACD,IAAA,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE;AAC7B,QAAA,OAAO,KAAK,CAAC;AACd,KAAA;AACD,IAAA,OAAO,UAAU,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;;;AAIG;AACG,SAAU,oBAAoB,CAAC,KAAc,EAAA;IACjD,IAAI,CAAC,KAAK,EAAE;AACV,QAAA,OAAO,eAAe,CAAC;AACxB,KAAA;AACD,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7B,QAAA,OAAO,KAAK,CAAC;AACd,KAAA;IACD,IAAI,KAAK,YAAY,KAAK,EAAE;QAC1B,OAAO,KAAK,CAAC,OAAO,CAAC;AACtB,KAAA;AACD,IAAA,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE;AAC7B,QAAA,OAAO,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,IAAI,eAAe,CAAC;AAC3D,KAAA;AACD,IAAA,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B;;;;"}
|
|
1
|
+
{"version":3,"file":"outcomes.mjs","sources":["../../src/outcomes.ts"],"sourcesContent":["import { OperationOutcome } from '@medplum/fhirtypes';\n\nconst OK_ID = 'ok';\nconst CREATED_ID = 'created';\nconst GONE_ID = 'gone';\nconst NOT_MODIFIED_ID = 'not-modified';\nconst NOT_FOUND_ID = 'not-found';\nconst UNAUTHORIZED_ID = 'unauthorized';\nconst FORBIDDEN_ID = 'forbidden';\nconst TOO_MANY_REQUESTS_ID = 'too-many-requests';\n\nexport const allOk: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: OK_ID,\n issue: [\n {\n severity: 'information',\n code: 'informational',\n details: {\n text: 'All OK',\n },\n },\n ],\n};\n\nexport const created: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: CREATED_ID,\n issue: [\n {\n severity: 'information',\n code: 'informational',\n details: {\n text: 'Created',\n },\n },\n ],\n};\n\nexport const notModified: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: NOT_MODIFIED_ID,\n issue: [\n {\n severity: 'information',\n code: 'informational',\n details: {\n text: 'Not Modified',\n },\n },\n ],\n};\n\nexport const notFound: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: NOT_FOUND_ID,\n issue: [\n {\n severity: 'error',\n code: 'not-found',\n details: {\n text: 'Not found',\n },\n },\n ],\n};\n\nexport const unauthorized: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: UNAUTHORIZED_ID,\n issue: [\n {\n severity: 'error',\n code: 'login',\n details: {\n text: 'Unauthorized',\n },\n },\n ],\n};\n\nexport const forbidden: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: FORBIDDEN_ID,\n issue: [\n {\n severity: 'error',\n code: 'forbidden',\n details: {\n text: 'Forbidden',\n },\n },\n ],\n};\n\nexport const gone: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: GONE_ID,\n issue: [\n {\n severity: 'error',\n code: 'deleted',\n details: {\n text: 'Gone',\n },\n },\n ],\n};\n\nexport const tooManyRequests: OperationOutcome = {\n resourceType: 'OperationOutcome',\n id: TOO_MANY_REQUESTS_ID,\n issue: [\n {\n severity: 'error',\n code: 'throttled',\n details: {\n text: 'Too Many Requests',\n },\n },\n ],\n};\n\nexport function badRequest(details: string, expression?: string): OperationOutcome {\n return {\n resourceType: 'OperationOutcome',\n issue: [\n {\n severity: 'error',\n code: 'invalid',\n details: {\n text: details,\n },\n expression: expression ? [expression] : undefined,\n },\n ],\n };\n}\n\nexport function validationError(details: string): OperationOutcome {\n return {\n resourceType: 'OperationOutcome',\n issue: [\n {\n severity: 'error',\n code: 'structure',\n details: {\n text: details,\n },\n },\n ],\n };\n}\n\nexport function isOperationOutcome(value: unknown): value is OperationOutcome {\n return typeof value === 'object' && value !== null && (value as any).resourceType === 'OperationOutcome';\n}\n\nexport function isOk(outcome: OperationOutcome): boolean {\n return outcome.id === OK_ID || outcome.id === CREATED_ID || outcome.id === NOT_MODIFIED_ID;\n}\n\nexport function isNotFound(outcome: OperationOutcome): boolean {\n return outcome.id === NOT_FOUND_ID;\n}\n\nexport function isGone(outcome: OperationOutcome): boolean {\n return outcome.id === GONE_ID;\n}\n\nexport function getStatus(outcome: OperationOutcome): number {\n if (outcome.id === OK_ID) {\n return 200;\n } else if (outcome.id === CREATED_ID) {\n return 201;\n } else if (outcome.id === NOT_MODIFIED_ID) {\n return 304;\n } else if (outcome.id === UNAUTHORIZED_ID) {\n return 401;\n } else if (outcome.id === FORBIDDEN_ID) {\n return 403;\n } else if (outcome.id === NOT_FOUND_ID) {\n return 404;\n } else if (outcome.id === GONE_ID) {\n return 410;\n } else if (outcome.id === TOO_MANY_REQUESTS_ID) {\n return 429;\n } else {\n return 400;\n }\n}\n\n/**\n * Asserts that the operation completed successfully and that the resource is defined.\n * @param outcome The operation outcome.\n * @param resource The resource that may or may not have been returned.\n */\nexport function assertOk<T>(outcome: OperationOutcome, resource: T | undefined): asserts resource is T {\n if (!isOk(outcome) || resource === undefined) {\n throw new OperationOutcomeError(outcome);\n }\n}\n\nexport class OperationOutcomeError extends Error {\n readonly outcome: OperationOutcome;\n\n constructor(outcome: OperationOutcome, cause?: unknown) {\n super(operationOutcomeToString(outcome));\n this.outcome = outcome;\n this.cause = cause;\n }\n}\n\n/**\n * Normalizes an error object into an OperationOutcome.\n * @param error The error value which could be a string, Error, OperationOutcome, or other unknown type.\n * @returns The normalized OperationOutcome.\n */\nexport function normalizeOperationOutcome(error: unknown): OperationOutcome {\n if (error instanceof OperationOutcomeError) {\n return error.outcome;\n }\n if (isOperationOutcome(error)) {\n return error;\n }\n return badRequest(normalizeErrorString(error));\n}\n\n/**\n * Normalizes an error object into a displayable error string.\n * @param error The error value which could be a string, Error, OperationOutcome, or other unknown type.\n * @returns A display string for the error.\n */\nexport function normalizeErrorString(error: unknown): string {\n if (!error) {\n return 'Unknown error';\n }\n if (typeof error === 'string') {\n return error;\n }\n if (error instanceof Error) {\n return error.message;\n }\n if (isOperationOutcome(error)) {\n return operationOutcomeToString(error);\n }\n return JSON.stringify(error);\n}\n\n/**\n * Returns a string represenation of the operation outcome.\n * @param outcome The operation outcome.\n * @returns The string representation of the operation outcome.\n */\nexport function operationOutcomeToString(outcome: OperationOutcome): string {\n const strs = [];\n if (outcome.issue) {\n for (const issue of outcome.issue) {\n let issueStr = issue.details?.text || 'Unknown error';\n if (issue.expression?.length) {\n issueStr += ` (${issue.expression.join(', ')})`;\n }\n strs.push(issueStr);\n }\n }\n return strs.length > 0 ? strs.join('; ') : 'Unknown error';\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -146,7 +146,7 @@ function simplifyExpression(input) {
|
|
|
146
146
|
if (result.includes('[0]')) {
|
|
147
147
|
result = result.replaceAll('[0]', '');
|
|
148
148
|
}
|
|
149
|
-
const stopStrings = [' != ', ' as ', '.as(', '.exists(', '.where('];
|
|
149
|
+
const stopStrings = [' != ', ' as ', '.as(', '.exists(', '.resolve(', '.where('];
|
|
150
150
|
for (const stopString of stopStrings) {
|
|
151
151
|
if (result.includes(stopString)) {
|
|
152
152
|
result = result.substring(0, result.indexOf(stopString));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"details.mjs","sources":["../../../src/search/details.ts"],"sourcesContent":["import { ElementDefinition, SearchParameter } from '@medplum/fhirtypes';\nimport { buildTypeName, getElementDefinition, globalSchema, PropertyType } from '../types';\nimport { capitalize } from '../utils';\n\nexport enum SearchParameterType {\n BOOLEAN = 'BOOLEAN',\n NUMBER = 'NUMBER',\n QUANTITY = 'QUANTITY',\n TEXT = 'TEXT',\n REFERENCE = 'REFERENCE',\n DATE = 'DATE',\n DATETIME = 'DATETIME',\n PERIOD = 'PERIOD',\n}\n\nexport interface SearchParameterDetails {\n readonly columnName: string;\n readonly type: SearchParameterType;\n readonly elementDefinition?: ElementDefinition;\n readonly array?: boolean;\n}\n\n/**\n * Returns the type details of a SearchParameter.\n *\n * The SearchParameter resource has a \"type\" parameter, but that is missing some critical information.\n *\n * For example:\n * 1) The \"date\" type includes \"date\", \"datetime\", and \"period\".\n * 2) The \"token\" type includes enums and booleans.\n * 3) Arrays/multiple values are not reflected at all.\n *\n * @param resourceType The root resource type.\n * @param searchParam The search parameter.\n * @returns The search parameter type details.\n */\nexport function getSearchParameterDetails(resourceType: string, searchParam: SearchParameter): SearchParameterDetails {\n let result: SearchParameterDetails | undefined =\n globalSchema.types[resourceType]?.searchParamsDetails?.[searchParam.code as string];\n if (!result) {\n result = buildSearchParamterDetails(resourceType, searchParam);\n }\n return result;\n}\n\nfunction setSearchParamterDetails(resourceType: string, code: string, details: SearchParameterDetails): void {\n const typeSchema = globalSchema.types[resourceType];\n if (!typeSchema.searchParamsDetails) {\n typeSchema.searchParamsDetails = {};\n }\n typeSchema.searchParamsDetails[code] = details;\n}\n\nfunction buildSearchParamterDetails(resourceType: string, searchParam: SearchParameter): SearchParameterDetails {\n const code = searchParam.code as string;\n const columnName = convertCodeToColumnName(code);\n const expression = getExpressionForResourceType(resourceType, searchParam.expression as string)?.split('.');\n if (!expression) {\n // This happens on compound types\n // In the future, explore returning multiple column definitions\n return { columnName, type: SearchParameterType.TEXT };\n }\n\n const defaultType = getSearchParameterType(searchParam);\n let baseType = resourceType;\n let elementDefinition = undefined;\n let propertyType = undefined;\n let array = false;\n\n for (let i = 1; i < expression.length; i++) {\n const propertyName = expression[i];\n elementDefinition = getElementDefinition(baseType, propertyName);\n if (!elementDefinition) {\n throw new Error(`Element definition not found for ${resourceType} ${searchParam.code}`);\n }\n\n if (elementDefinition.max === '*') {\n array = true;\n }\n\n propertyType = elementDefinition.type?.[0].code;\n if (!propertyType) {\n // This happens when one of parent properties uses contentReference\n // In the future, explore following the reference\n return { columnName, type: defaultType, array };\n }\n\n if (i < expression.length - 1) {\n if (isBackboneElement(propertyType)) {\n baseType = buildTypeName(elementDefinition.path?.split('.') as string[]);\n } else {\n baseType = propertyType;\n }\n }\n }\n\n const type = getSearchParameterType(searchParam, propertyType as PropertyType);\n const result = { columnName, type, elementDefinition, array };\n setSearchParamterDetails(resourceType, code, result);\n return result;\n}\n\nfunction isBackboneElement(propertyType: string): boolean {\n return propertyType === 'Element' || propertyType === 'BackboneElement';\n}\n\n/**\n * Converts a hyphen-delimited code to camelCase string.\n * @param code The search parameter code.\n * @returns The SQL column name.\n */\nfunction convertCodeToColumnName(code: string): string {\n return code.split('-').reduce((result, word, index) => result + (index ? capitalize(word) : word), '');\n}\n\nfunction getSearchParameterType(searchParam: SearchParameter, propertyType?: PropertyType): SearchParameterType {\n let type = SearchParameterType.TEXT;\n switch (searchParam.type) {\n case 'date':\n if (propertyType === PropertyType.dateTime || propertyType === PropertyType.instant) {\n type = SearchParameterType.DATETIME;\n } else {\n type = SearchParameterType.DATE;\n }\n break;\n case 'number':\n type = SearchParameterType.NUMBER;\n break;\n case 'quantity':\n type = SearchParameterType.QUANTITY;\n break;\n case 'reference':\n type = SearchParameterType.REFERENCE;\n break;\n case 'token':\n if (propertyType === 'boolean') {\n type = SearchParameterType.BOOLEAN;\n }\n break;\n }\n return type;\n}\n\nexport function getExpressionForResourceType(resourceType: string, expression: string): string | undefined {\n const expressions = expression.split(' | ');\n for (const e of expressions) {\n if (isIgnoredExpression(e)) {\n continue;\n }\n const simplified = simplifyExpression(e);\n if (simplified.startsWith(resourceType + '.')) {\n return simplified;\n }\n }\n return undefined;\n}\n\nfunction isIgnoredExpression(input: string): boolean {\n return input.includes(' as Period') || input.includes(' as SampledDate');\n}\n\nfunction simplifyExpression(input: string): string {\n let result = input.trim();\n\n if (result.startsWith('(') && result.endsWith(')')) {\n result = result.substring(1, result.length - 1);\n }\n\n if (result.includes('[0]')) {\n result = result.replaceAll('[0]', '');\n }\n\n const stopStrings = [' != ', ' as ', '.as(', '.exists(', '.where('];\n for (const stopString of stopStrings) {\n if (result.includes(stopString)) {\n result = result.substring(0, result.indexOf(stopString));\n }\n }\n\n return result;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"details.mjs","sources":["../../../src/search/details.ts"],"sourcesContent":["import { ElementDefinition, SearchParameter } from '@medplum/fhirtypes';\nimport { buildTypeName, getElementDefinition, globalSchema, PropertyType } from '../types';\nimport { capitalize } from '../utils';\n\nexport enum SearchParameterType {\n BOOLEAN = 'BOOLEAN',\n NUMBER = 'NUMBER',\n QUANTITY = 'QUANTITY',\n TEXT = 'TEXT',\n REFERENCE = 'REFERENCE',\n DATE = 'DATE',\n DATETIME = 'DATETIME',\n PERIOD = 'PERIOD',\n}\n\nexport interface SearchParameterDetails {\n readonly columnName: string;\n readonly type: SearchParameterType;\n readonly elementDefinition?: ElementDefinition;\n readonly array?: boolean;\n}\n\n/**\n * Returns the type details of a SearchParameter.\n *\n * The SearchParameter resource has a \"type\" parameter, but that is missing some critical information.\n *\n * For example:\n * 1) The \"date\" type includes \"date\", \"datetime\", and \"period\".\n * 2) The \"token\" type includes enums and booleans.\n * 3) Arrays/multiple values are not reflected at all.\n *\n * @param resourceType The root resource type.\n * @param searchParam The search parameter.\n * @returns The search parameter type details.\n */\nexport function getSearchParameterDetails(resourceType: string, searchParam: SearchParameter): SearchParameterDetails {\n let result: SearchParameterDetails | undefined =\n globalSchema.types[resourceType]?.searchParamsDetails?.[searchParam.code as string];\n if (!result) {\n result = buildSearchParamterDetails(resourceType, searchParam);\n }\n return result;\n}\n\nfunction setSearchParamterDetails(resourceType: string, code: string, details: SearchParameterDetails): void {\n const typeSchema = globalSchema.types[resourceType];\n if (!typeSchema.searchParamsDetails) {\n typeSchema.searchParamsDetails = {};\n }\n typeSchema.searchParamsDetails[code] = details;\n}\n\nfunction buildSearchParamterDetails(resourceType: string, searchParam: SearchParameter): SearchParameterDetails {\n const code = searchParam.code as string;\n const columnName = convertCodeToColumnName(code);\n const expression = getExpressionForResourceType(resourceType, searchParam.expression as string)?.split('.');\n if (!expression) {\n // This happens on compound types\n // In the future, explore returning multiple column definitions\n return { columnName, type: SearchParameterType.TEXT };\n }\n\n const defaultType = getSearchParameterType(searchParam);\n let baseType = resourceType;\n let elementDefinition = undefined;\n let propertyType = undefined;\n let array = false;\n\n for (let i = 1; i < expression.length; i++) {\n const propertyName = expression[i];\n elementDefinition = getElementDefinition(baseType, propertyName);\n if (!elementDefinition) {\n throw new Error(`Element definition not found for ${resourceType} ${searchParam.code}`);\n }\n\n if (elementDefinition.max === '*') {\n array = true;\n }\n\n propertyType = elementDefinition.type?.[0].code;\n if (!propertyType) {\n // This happens when one of parent properties uses contentReference\n // In the future, explore following the reference\n return { columnName, type: defaultType, array };\n }\n\n if (i < expression.length - 1) {\n if (isBackboneElement(propertyType)) {\n baseType = buildTypeName(elementDefinition.path?.split('.') as string[]);\n } else {\n baseType = propertyType;\n }\n }\n }\n\n const type = getSearchParameterType(searchParam, propertyType as PropertyType);\n const result = { columnName, type, elementDefinition, array };\n setSearchParamterDetails(resourceType, code, result);\n return result;\n}\n\nfunction isBackboneElement(propertyType: string): boolean {\n return propertyType === 'Element' || propertyType === 'BackboneElement';\n}\n\n/**\n * Converts a hyphen-delimited code to camelCase string.\n * @param code The search parameter code.\n * @returns The SQL column name.\n */\nfunction convertCodeToColumnName(code: string): string {\n return code.split('-').reduce((result, word, index) => result + (index ? capitalize(word) : word), '');\n}\n\nfunction getSearchParameterType(searchParam: SearchParameter, propertyType?: PropertyType): SearchParameterType {\n let type = SearchParameterType.TEXT;\n switch (searchParam.type) {\n case 'date':\n if (propertyType === PropertyType.dateTime || propertyType === PropertyType.instant) {\n type = SearchParameterType.DATETIME;\n } else {\n type = SearchParameterType.DATE;\n }\n break;\n case 'number':\n type = SearchParameterType.NUMBER;\n break;\n case 'quantity':\n type = SearchParameterType.QUANTITY;\n break;\n case 'reference':\n type = SearchParameterType.REFERENCE;\n break;\n case 'token':\n if (propertyType === 'boolean') {\n type = SearchParameterType.BOOLEAN;\n }\n break;\n }\n return type;\n}\n\nexport function getExpressionForResourceType(resourceType: string, expression: string): string | undefined {\n const expressions = expression.split(' | ');\n for (const e of expressions) {\n if (isIgnoredExpression(e)) {\n continue;\n }\n const simplified = simplifyExpression(e);\n if (simplified.startsWith(resourceType + '.')) {\n return simplified;\n }\n }\n return undefined;\n}\n\nfunction isIgnoredExpression(input: string): boolean {\n return input.includes(' as Period') || input.includes(' as SampledDate');\n}\n\nfunction simplifyExpression(input: string): string {\n let result = input.trim();\n\n if (result.startsWith('(') && result.endsWith(')')) {\n result = result.substring(1, result.length - 1);\n }\n\n if (result.includes('[0]')) {\n result = result.replaceAll('[0]', '');\n }\n\n const stopStrings = [' != ', ' as ', '.as(', '.exists(', '.resolve(', '.where('];\n for (const stopString of stopStrings) {\n if (result.includes(stopString)) {\n result = result.substring(0, result.indexOf(stopString));\n }\n }\n\n return result;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { globalSchema } from '../types.mjs';
|
|
2
|
+
|
|
1
3
|
const DEFAULT_SEARCH_COUNT = 20;
|
|
2
4
|
/**
|
|
3
5
|
* Search operators.
|
|
@@ -30,134 +32,236 @@ var Operator;
|
|
|
30
32
|
Operator["OF_TYPE"] = "of-type";
|
|
31
33
|
// All
|
|
32
34
|
Operator["MISSING"] = "missing";
|
|
35
|
+
// Reference
|
|
36
|
+
Operator["IDENTIFIER"] = "identifier";
|
|
33
37
|
})(Operator || (Operator = {}));
|
|
34
|
-
const MODIFIER_OPERATORS = [
|
|
35
|
-
Operator.CONTAINS,
|
|
36
|
-
Operator.EXACT,
|
|
37
|
-
Operator.TEXT,
|
|
38
|
-
Operator.NOT,
|
|
39
|
-
Operator.ABOVE,
|
|
40
|
-
Operator.BELOW,
|
|
41
|
-
Operator.IN,
|
|
42
|
-
Operator.NOT_IN,
|
|
43
|
-
Operator.OF_TYPE,
|
|
44
|
-
Operator.MISSING,
|
|
45
|
-
];
|
|
46
|
-
const PREFIX_OPERATORS = [
|
|
47
|
-
Operator.NOT_EQUALS,
|
|
48
|
-
Operator.GREATER_THAN,
|
|
49
|
-
Operator.LESS_THAN,
|
|
50
|
-
Operator.GREATER_THAN_OR_EQUALS,
|
|
51
|
-
Operator.LESS_THAN_OR_EQUALS,
|
|
52
|
-
Operator.STARTS_AFTER,
|
|
53
|
-
Operator.ENDS_BEFORE,
|
|
54
|
-
Operator.APPROXIMATELY,
|
|
55
|
-
];
|
|
56
38
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* See
|
|
60
|
-
|
|
39
|
+
* Parameter names may specify a modifier as a suffix.
|
|
40
|
+
* The modifiers are separated from the parameter name by a colon.
|
|
41
|
+
* See: https://www.hl7.org/fhir/search.html#modifiers
|
|
42
|
+
*/
|
|
43
|
+
const MODIFIER_OPERATORS = {
|
|
44
|
+
contains: Operator.CONTAINS,
|
|
45
|
+
exact: Operator.EXACT,
|
|
46
|
+
above: Operator.ABOVE,
|
|
47
|
+
below: Operator.BELOW,
|
|
48
|
+
text: Operator.TEXT,
|
|
49
|
+
not: Operator.NOT,
|
|
50
|
+
in: Operator.IN,
|
|
51
|
+
'not-in': Operator.NOT_IN,
|
|
52
|
+
'of-type': Operator.OF_TYPE,
|
|
53
|
+
missing: Operator.MISSING,
|
|
54
|
+
identifier: Operator.IDENTIFIER,
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* For the ordered parameter types of number, date, and quantity,
|
|
58
|
+
* a prefix to the parameter value may be used to control the nature
|
|
59
|
+
* of the matching.
|
|
60
|
+
* See: https://www.hl7.org/fhir/search.html#prefix
|
|
61
|
+
*/
|
|
62
|
+
const PREFIX_OPERATORS = {
|
|
63
|
+
eq: Operator.EQUALS,
|
|
64
|
+
ne: Operator.NOT_EQUALS,
|
|
65
|
+
lt: Operator.LESS_THAN,
|
|
66
|
+
le: Operator.LESS_THAN_OR_EQUALS,
|
|
67
|
+
gt: Operator.GREATER_THAN,
|
|
68
|
+
ge: Operator.GREATER_THAN_OR_EQUALS,
|
|
69
|
+
sa: Operator.STARTS_AFTER,
|
|
70
|
+
eb: Operator.ENDS_BEFORE,
|
|
71
|
+
ap: Operator.APPROXIMATELY,
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Parses a search URL into a search request.
|
|
75
|
+
* @param resourceType The FHIR resource type.
|
|
76
|
+
* @param query The collection of query string parameters.
|
|
77
|
+
* @returns A parsed SearchRequest.
|
|
78
|
+
*/
|
|
79
|
+
function parseSearchRequest(resourceType, query) {
|
|
80
|
+
return parseSearchImpl(resourceType, query);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Parses a search URL into a search request.
|
|
84
|
+
* @param url The search URL.
|
|
85
|
+
* @returns A parsed SearchRequest.
|
|
86
|
+
*/
|
|
87
|
+
function parseSearchUrl(url) {
|
|
88
|
+
const resourceType = url.pathname.split('/').filter(Boolean).pop();
|
|
89
|
+
return parseSearchImpl(resourceType, Object.fromEntries(url.searchParams.entries()));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parses a URL string into a SearchRequest.
|
|
61
93
|
* @param url The URL to parse.
|
|
62
94
|
* @returns Parsed search definition.
|
|
63
95
|
*/
|
|
64
96
|
function parseSearchDefinition(url) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
let offset = undefined;
|
|
75
|
-
let count = undefined;
|
|
76
|
-
let total = undefined;
|
|
77
|
-
params.forEach((value, key) => {
|
|
78
|
-
if (key === '_fields') {
|
|
79
|
-
fields = value.split(',');
|
|
80
|
-
}
|
|
81
|
-
else if (key === '_offset') {
|
|
82
|
-
offset = parseInt(value);
|
|
97
|
+
return parseSearchUrl(new URL(url, 'https://example.com/'));
|
|
98
|
+
}
|
|
99
|
+
function parseSearchImpl(resourceType, query) {
|
|
100
|
+
const searchRequest = {
|
|
101
|
+
resourceType,
|
|
102
|
+
};
|
|
103
|
+
for (const [key, value] of Object.entries(query)) {
|
|
104
|
+
if (Array.isArray(value)) {
|
|
105
|
+
value.forEach((element) => parseKeyValue(searchRequest, key, element));
|
|
83
106
|
}
|
|
84
|
-
else
|
|
85
|
-
|
|
107
|
+
else {
|
|
108
|
+
parseKeyValue(searchRequest, key, value ?? '');
|
|
86
109
|
}
|
|
87
|
-
|
|
88
|
-
|
|
110
|
+
}
|
|
111
|
+
return searchRequest;
|
|
112
|
+
}
|
|
113
|
+
function parseKeyValue(searchRequest, key, value) {
|
|
114
|
+
let code;
|
|
115
|
+
let modifier;
|
|
116
|
+
const colonIndex = key.indexOf(':');
|
|
117
|
+
if (colonIndex >= 0) {
|
|
118
|
+
code = key.substring(0, colonIndex);
|
|
119
|
+
modifier = key.substring(colonIndex + 1);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
code = key;
|
|
123
|
+
modifier = '';
|
|
124
|
+
}
|
|
125
|
+
switch (code) {
|
|
126
|
+
case '_sort':
|
|
127
|
+
parseSortRule(searchRequest, value);
|
|
128
|
+
break;
|
|
129
|
+
case '_count':
|
|
130
|
+
searchRequest.count = parseInt(value);
|
|
131
|
+
break;
|
|
132
|
+
case '_offset':
|
|
133
|
+
searchRequest.offset = parseInt(value);
|
|
134
|
+
break;
|
|
135
|
+
case '_total':
|
|
136
|
+
searchRequest.total = value;
|
|
137
|
+
break;
|
|
138
|
+
case '_summary':
|
|
139
|
+
searchRequest.total = 'estimate';
|
|
140
|
+
searchRequest.count = 0;
|
|
141
|
+
break;
|
|
142
|
+
case '_revinclude':
|
|
143
|
+
searchRequest.revInclude = value;
|
|
144
|
+
break;
|
|
145
|
+
case '_fields':
|
|
146
|
+
searchRequest.fields = value.split(',');
|
|
147
|
+
break;
|
|
148
|
+
default: {
|
|
149
|
+
const param = globalSchema.types[searchRequest.resourceType]?.searchParams?.[code];
|
|
150
|
+
if (param) {
|
|
151
|
+
parseParameter(searchRequest, param, modifier, value);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
parseUnknownParameter(searchRequest, code, modifier, value);
|
|
155
|
+
}
|
|
89
156
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function parseSortRule(searchRequest, value) {
|
|
160
|
+
for (const field of value.split(',')) {
|
|
161
|
+
let code;
|
|
162
|
+
let descending = false;
|
|
163
|
+
if (field.startsWith('-')) {
|
|
164
|
+
code = field.substring(1);
|
|
165
|
+
descending = true;
|
|
93
166
|
}
|
|
94
167
|
else {
|
|
95
|
-
|
|
96
|
-
filters.push(parseSearchFilter(key, value));
|
|
168
|
+
code = field;
|
|
97
169
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
offset,
|
|
104
|
-
count,
|
|
105
|
-
total,
|
|
106
|
-
sortRules,
|
|
107
|
-
};
|
|
170
|
+
if (!searchRequest.sortRules) {
|
|
171
|
+
searchRequest.sortRules = [];
|
|
172
|
+
}
|
|
173
|
+
searchRequest.sortRules.push({ code, descending });
|
|
174
|
+
}
|
|
108
175
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
*
|
|
118
|
-
* @param value The URL parameter value.
|
|
119
|
-
* @returns The parsed sort rule.
|
|
120
|
-
*/
|
|
121
|
-
function parseSortRule(value) {
|
|
122
|
-
if (value.startsWith('-')) {
|
|
123
|
-
return { code: value.substring(1), descending: true };
|
|
176
|
+
function parseParameter(searchRequest, searchParam, modifier, value) {
|
|
177
|
+
if (modifier === 'missing') {
|
|
178
|
+
addFilter(searchRequest, {
|
|
179
|
+
code: searchParam.code,
|
|
180
|
+
operator: Operator.MISSING,
|
|
181
|
+
value,
|
|
182
|
+
});
|
|
183
|
+
return;
|
|
124
184
|
}
|
|
125
|
-
|
|
126
|
-
|
|
185
|
+
switch (searchParam.type) {
|
|
186
|
+
case 'number':
|
|
187
|
+
case 'date':
|
|
188
|
+
parsePrefixType(searchRequest, searchParam, value);
|
|
189
|
+
break;
|
|
190
|
+
case 'reference':
|
|
191
|
+
case 'string':
|
|
192
|
+
case 'token':
|
|
193
|
+
case 'uri':
|
|
194
|
+
parseModifierType(searchRequest, searchParam, modifier, value);
|
|
195
|
+
break;
|
|
196
|
+
case 'quantity':
|
|
197
|
+
parseQuantity(searchRequest, searchParam, value);
|
|
198
|
+
break;
|
|
127
199
|
}
|
|
128
200
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
function
|
|
145
|
-
|
|
201
|
+
function parsePrefixType(searchRequest, param, input) {
|
|
202
|
+
const { operator, value } = parsePrefix(input);
|
|
203
|
+
addFilter(searchRequest, {
|
|
204
|
+
code: param.code,
|
|
205
|
+
operator,
|
|
206
|
+
value,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function parseModifierType(searchRequest, param, modifier, value) {
|
|
210
|
+
addFilter(searchRequest, {
|
|
211
|
+
code: param.code,
|
|
212
|
+
operator: parseModifier(modifier),
|
|
213
|
+
value,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function parseQuantity(searchRequest, param, input) {
|
|
217
|
+
const [prefixNumber, unitSystem, unitCode] = input.split('|');
|
|
218
|
+
const { operator, value } = parsePrefix(prefixNumber);
|
|
219
|
+
addFilter(searchRequest, {
|
|
220
|
+
code: param.code,
|
|
221
|
+
operator,
|
|
222
|
+
value,
|
|
223
|
+
unitSystem,
|
|
224
|
+
unitCode,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function parseUnknownParameter(searchRequest, code, modifier, value) {
|
|
146
228
|
let operator = Operator.EQUALS;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (modifierIndex !== -1) {
|
|
150
|
-
operator = modifier;
|
|
151
|
-
code = code.substring(0, modifierIndex);
|
|
152
|
-
}
|
|
229
|
+
if (modifier) {
|
|
230
|
+
operator = modifier;
|
|
153
231
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
value
|
|
232
|
+
else if (value.length >= 2) {
|
|
233
|
+
const prefix = value.substring(0, 2);
|
|
234
|
+
if (prefix in PREFIX_OPERATORS) {
|
|
235
|
+
if (value.length === 2 || value.at(2)?.match(/\d/)) {
|
|
236
|
+
operator = prefix;
|
|
237
|
+
value = value.substring(prefix.length);
|
|
238
|
+
}
|
|
158
239
|
}
|
|
159
240
|
}
|
|
160
|
-
|
|
241
|
+
addFilter(searchRequest, {
|
|
242
|
+
code,
|
|
243
|
+
operator,
|
|
244
|
+
value,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function parsePrefix(input) {
|
|
248
|
+
const prefix = input.substring(0, 2);
|
|
249
|
+
const prefixOperator = PREFIX_OPERATORS[prefix];
|
|
250
|
+
if (prefixOperator) {
|
|
251
|
+
return { operator: prefixOperator, value: input.substring(2) };
|
|
252
|
+
}
|
|
253
|
+
return { operator: Operator.EQUALS, value: input };
|
|
254
|
+
}
|
|
255
|
+
function parseModifier(modifier) {
|
|
256
|
+
return MODIFIER_OPERATORS[modifier] || Operator.EQUALS;
|
|
257
|
+
}
|
|
258
|
+
function addFilter(searchRequest, filter) {
|
|
259
|
+
if (searchRequest.filters) {
|
|
260
|
+
searchRequest.filters.push(filter);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
searchRequest.filters = [filter];
|
|
264
|
+
}
|
|
161
265
|
}
|
|
162
266
|
/**
|
|
163
267
|
* Formats a search definition object into a query string.
|
|
@@ -192,13 +296,13 @@ function formatSearchQuery(definition) {
|
|
|
192
296
|
return '?' + params.join('&');
|
|
193
297
|
}
|
|
194
298
|
function formatFilter(filter) {
|
|
195
|
-
const modifier =
|
|
196
|
-
const prefix =
|
|
299
|
+
const modifier = filter.operator in MODIFIER_OPERATORS ? ':' + filter.operator : '';
|
|
300
|
+
const prefix = filter.operator != Operator.EQUALS && filter.operator in PREFIX_OPERATORS ? filter.operator : '';
|
|
197
301
|
return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
|
|
198
302
|
}
|
|
199
303
|
function formatSortRules(sortRules) {
|
|
200
304
|
return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');
|
|
201
305
|
}
|
|
202
306
|
|
|
203
|
-
export { DEFAULT_SEARCH_COUNT, Operator, formatSearchQuery, parseSearchDefinition };
|
|
307
|
+
export { DEFAULT_SEARCH_COUNT, Operator, formatSearchQuery, parseSearchDefinition, parseSearchRequest, parseSearchUrl };
|
|
204
308
|
//# sourceMappingURL=search.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.mjs","sources":["../../../src/search/search.ts"],"sourcesContent":["import { ResourceType } from '@medplum/fhirtypes';\n\nexport const DEFAULT_SEARCH_COUNT = 20;\n\nexport interface SearchRequest {\n readonly resourceType: ResourceType;\n filters?: Filter[];\n sortRules?: SortRule[];\n offset?: number;\n count?: number;\n fields?: string[];\n name?: string;\n total?: 'none' | 'estimate' | 'accurate';\n revInclude?: string;\n}\n\nexport interface Filter {\n code: string;\n operator: Operator;\n value: string;\n unitSystem?: string;\n unitCode?: string;\n}\n\nexport interface SortRule {\n code: string;\n descending?: boolean;\n}\n\n/**\n * Search operators.\n * These operators represent \"modifiers\" and \"prefixes\" in FHIR search.\n * See: https://www.hl7.org/fhir/search.html\n */\nexport enum Operator {\n EQUALS = 'eq',\n NOT_EQUALS = 'ne',\n\n // Numbers\n GREATER_THAN = 'gt',\n LESS_THAN = 'lt',\n GREATER_THAN_OR_EQUALS = 'ge',\n LESS_THAN_OR_EQUALS = 'le',\n\n // Dates\n STARTS_AFTER = 'sa',\n ENDS_BEFORE = 'eb',\n APPROXIMATELY = 'ap',\n\n // String\n CONTAINS = 'contains',\n EXACT = 'exact',\n\n // Token\n TEXT = 'text',\n NOT = 'not',\n ABOVE = 'above',\n BELOW = 'below',\n IN = 'in',\n NOT_IN = 'not-in',\n OF_TYPE = 'of-type',\n\n // All\n MISSING = 'missing',\n}\n\nconst MODIFIER_OPERATORS: Operator[] = [\n Operator.CONTAINS,\n Operator.EXACT,\n Operator.TEXT,\n Operator.NOT,\n Operator.ABOVE,\n Operator.BELOW,\n Operator.IN,\n Operator.NOT_IN,\n Operator.OF_TYPE,\n Operator.MISSING,\n];\n\nconst PREFIX_OPERATORS: Operator[] = [\n Operator.NOT_EQUALS,\n Operator.GREATER_THAN,\n Operator.LESS_THAN,\n Operator.GREATER_THAN_OR_EQUALS,\n Operator.LESS_THAN_OR_EQUALS,\n Operator.STARTS_AFTER,\n Operator.ENDS_BEFORE,\n Operator.APPROXIMATELY,\n];\n\n/**\n * Parses a URL into a SearchRequest.\n *\n * See the FHIR search spec: http://hl7.org/fhir/r4/search.html\n *\n * @param url The URL to parse.\n * @returns Parsed search definition.\n */\nexport function parseSearchDefinition(url: string): SearchRequest {\n const location = new URL(url, 'https://example.com/');\n const resourceType = location.pathname\n .replace(/(^\\/)|(\\/$)/g, '') // Remove leading and trailing slashes\n .split('/')\n .pop() as ResourceType;\n const params = new URLSearchParams(location.search);\n let filters: Filter[] | undefined = undefined;\n let sortRules: SortRule[] | undefined = undefined;\n let fields: string[] | undefined = undefined;\n let offset = undefined;\n let count = undefined;\n let total = undefined;\n\n params.forEach((value, key) => {\n if (key === '_fields') {\n fields = value.split(',');\n } else if (key === '_offset') {\n offset = parseInt(value);\n } else if (key === '_count') {\n count = parseInt(value);\n } else if (key === '_total') {\n total = value;\n } else if (key === '_sort') {\n sortRules = sortRules || [];\n sortRules.push(parseSortRule(value));\n } else {\n filters = filters || [];\n filters.push(parseSearchFilter(key, value));\n }\n });\n\n return {\n resourceType,\n filters,\n fields,\n offset,\n count,\n total,\n sortRules,\n };\n}\n\n/**\n * Parses a URL query parameter into a sort rule.\n *\n * By default, the sort rule is the field name.\n *\n * Sort rules can be reversed into descending order by prefixing the field name with a minus sign.\n *\n * See sorting: http://hl7.org/fhir/r4/search.html#_sort\n *\n * @param value The URL parameter value.\n * @returns The parsed sort rule.\n */\nfunction parseSortRule(value: string): SortRule {\n if (value.startsWith('-')) {\n return { code: value.substring(1), descending: true };\n } else {\n return { code: value };\n }\n}\n\n/**\n * Parses a URL query parameter into a search filter.\n *\n * FHIR search filters can be specified as modifiers or prefixes.\n *\n * For string properties, modifiers are appended to the key, e.g. \"name:contains=eve\".\n *\n * For date and numeric properties, prefixes are prepended to the value, e.g. \"birthdate=gt2000\".\n *\n * See the FHIR search spec: http://hl7.org/fhir/r4/search.html\n *\n * @param key The URL parameter key.\n * @param value The URL parameter value.\n * @returns The parsed search filter.\n */\nfunction parseSearchFilter(key: string, value: string): Filter {\n let code = key;\n let operator = Operator.EQUALS;\n\n for (const modifier of MODIFIER_OPERATORS) {\n const modifierIndex = code.indexOf(':' + modifier);\n if (modifierIndex !== -1) {\n operator = modifier;\n code = code.substring(0, modifierIndex);\n }\n }\n\n for (const prefix of PREFIX_OPERATORS) {\n if (value.match(new RegExp('^' + prefix + '\\\\d'))) {\n operator = prefix;\n value = value.substring(prefix.length);\n }\n }\n\n return { code, operator, value };\n}\n\n/**\n * Formats a search definition object into a query string.\n * Note: The return value does not include the resource type.\n * @param {!SearchRequest} definition The search definition.\n * @returns Formatted URL.\n */\nexport function formatSearchQuery(definition: SearchRequest): string {\n const params: string[] = [];\n\n if (definition.fields) {\n params.push('_fields=' + definition.fields.join(','));\n }\n\n if (definition.filters) {\n definition.filters.forEach((filter) => params.push(formatFilter(filter)));\n }\n\n if (definition.sortRules && definition.sortRules.length > 0) {\n params.push(formatSortRules(definition.sortRules));\n }\n\n if (definition.offset !== undefined) {\n params.push('_offset=' + definition.offset);\n }\n\n if (definition.count !== undefined) {\n params.push('_count=' + definition.count);\n }\n\n if (definition.total !== undefined) {\n params.push('_total=' + definition.total);\n }\n\n if (params.length === 0) {\n return '';\n }\n\n params.sort();\n return '?' + params.join('&');\n}\n\nfunction formatFilter(filter: Filter): string {\n const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';\n const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';\n return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;\n}\n\nfunction formatSortRules(sortRules: SortRule[]): string {\n return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"search.mjs","sources":["../../../src/search/search.ts"],"sourcesContent":["import { ResourceType, SearchParameter } from '@medplum/fhirtypes';\nimport { globalSchema } from '../types';\n\nexport const DEFAULT_SEARCH_COUNT = 20;\n\nexport interface SearchRequest {\n readonly resourceType: ResourceType;\n filters?: Filter[];\n sortRules?: SortRule[];\n offset?: number;\n count?: number;\n fields?: string[];\n name?: string;\n total?: 'none' | 'estimate' | 'accurate';\n revInclude?: string;\n}\n\nexport interface Filter {\n code: string;\n operator: Operator;\n value: string;\n unitSystem?: string;\n unitCode?: string;\n}\n\nexport interface SortRule {\n code: string;\n descending?: boolean;\n}\n\n/**\n * Search operators.\n * These operators represent \"modifiers\" and \"prefixes\" in FHIR search.\n * See: https://www.hl7.org/fhir/search.html\n */\nexport enum Operator {\n EQUALS = 'eq',\n NOT_EQUALS = 'ne',\n\n // Numbers\n GREATER_THAN = 'gt',\n LESS_THAN = 'lt',\n GREATER_THAN_OR_EQUALS = 'ge',\n LESS_THAN_OR_EQUALS = 'le',\n\n // Dates\n STARTS_AFTER = 'sa',\n ENDS_BEFORE = 'eb',\n APPROXIMATELY = 'ap',\n\n // String\n CONTAINS = 'contains',\n EXACT = 'exact',\n\n // Token\n TEXT = 'text',\n NOT = 'not',\n ABOVE = 'above',\n BELOW = 'below',\n IN = 'in',\n NOT_IN = 'not-in',\n OF_TYPE = 'of-type',\n\n // All\n MISSING = 'missing',\n\n // Reference\n IDENTIFIER = 'identifier',\n}\n\n/**\n * Parameter names may specify a modifier as a suffix.\n * The modifiers are separated from the parameter name by a colon.\n * See: https://www.hl7.org/fhir/search.html#modifiers\n */\nconst MODIFIER_OPERATORS: Record<string, Operator> = {\n contains: Operator.CONTAINS,\n exact: Operator.EXACT,\n above: Operator.ABOVE,\n below: Operator.BELOW,\n text: Operator.TEXT,\n not: Operator.NOT,\n in: Operator.IN,\n 'not-in': Operator.NOT_IN,\n 'of-type': Operator.OF_TYPE,\n missing: Operator.MISSING,\n identifier: Operator.IDENTIFIER,\n};\n\n/**\n * For the ordered parameter types of number, date, and quantity,\n * a prefix to the parameter value may be used to control the nature\n * of the matching.\n * See: https://www.hl7.org/fhir/search.html#prefix\n */\nconst PREFIX_OPERATORS: Record<string, Operator> = {\n eq: Operator.EQUALS,\n ne: Operator.NOT_EQUALS,\n lt: Operator.LESS_THAN,\n le: Operator.LESS_THAN_OR_EQUALS,\n gt: Operator.GREATER_THAN,\n ge: Operator.GREATER_THAN_OR_EQUALS,\n sa: Operator.STARTS_AFTER,\n eb: Operator.ENDS_BEFORE,\n ap: Operator.APPROXIMATELY,\n};\n\n/**\n * Parses a search URL into a search request.\n * @param resourceType The FHIR resource type.\n * @param query The collection of query string parameters.\n * @returns A parsed SearchRequest.\n */\nexport function parseSearchRequest(\n resourceType: ResourceType,\n query: Record<string, string[] | string | undefined>\n): SearchRequest {\n return parseSearchImpl(resourceType, query);\n}\n\n/**\n * Parses a search URL into a search request.\n * @param url The search URL.\n * @returns A parsed SearchRequest.\n */\nexport function parseSearchUrl(url: URL): SearchRequest {\n const resourceType = url.pathname.split('/').filter(Boolean).pop() as ResourceType;\n return parseSearchImpl(resourceType, Object.fromEntries(url.searchParams.entries()));\n}\n\n/**\n * Parses a URL string into a SearchRequest.\n * @param url The URL to parse.\n * @returns Parsed search definition.\n */\nexport function parseSearchDefinition(url: string): SearchRequest {\n return parseSearchUrl(new URL(url, 'https://example.com/'));\n}\n\nfunction parseSearchImpl(\n resourceType: ResourceType,\n query: Record<string, string[] | string | undefined>\n): SearchRequest {\n const searchRequest: SearchRequest = {\n resourceType,\n };\n\n for (const [key, value] of Object.entries(query)) {\n if (Array.isArray(value)) {\n value.forEach((element) => parseKeyValue(searchRequest, key, element));\n } else {\n parseKeyValue(searchRequest, key, value ?? '');\n }\n }\n\n return searchRequest;\n}\n\nfunction parseKeyValue(searchRequest: SearchRequest, key: string, value: string): void {\n let code;\n let modifier;\n\n const colonIndex = key.indexOf(':');\n if (colonIndex >= 0) {\n code = key.substring(0, colonIndex);\n modifier = key.substring(colonIndex + 1);\n } else {\n code = key;\n modifier = '';\n }\n\n switch (code) {\n case '_sort':\n parseSortRule(searchRequest, value);\n break;\n\n case '_count':\n searchRequest.count = parseInt(value);\n break;\n\n case '_offset':\n searchRequest.offset = parseInt(value);\n break;\n\n case '_total':\n searchRequest.total = value as 'none' | 'estimate' | 'accurate';\n break;\n\n case '_summary':\n searchRequest.total = 'estimate';\n searchRequest.count = 0;\n break;\n\n case '_revinclude':\n searchRequest.revInclude = value;\n break;\n\n case '_fields':\n searchRequest.fields = value.split(',');\n break;\n\n default: {\n const param = globalSchema.types[searchRequest.resourceType]?.searchParams?.[code];\n if (param) {\n parseParameter(searchRequest, param, modifier, value);\n } else {\n parseUnknownParameter(searchRequest, code, modifier, value);\n }\n }\n }\n}\n\nfunction parseSortRule(searchRequest: SearchRequest, value: string): void {\n for (const field of value.split(',')) {\n let code;\n let descending = false;\n if (field.startsWith('-')) {\n code = field.substring(1);\n descending = true;\n } else {\n code = field;\n }\n if (!searchRequest.sortRules) {\n searchRequest.sortRules = [];\n }\n searchRequest.sortRules.push({ code, descending });\n }\n}\n\nfunction parseParameter(\n searchRequest: SearchRequest,\n searchParam: SearchParameter,\n modifier: string,\n value: string\n): void {\n if (modifier === 'missing') {\n addFilter(searchRequest, {\n code: searchParam.code as string,\n operator: Operator.MISSING,\n value,\n });\n return;\n }\n switch (searchParam.type) {\n case 'number':\n case 'date':\n parsePrefixType(searchRequest, searchParam, value);\n break;\n case 'reference':\n case 'string':\n case 'token':\n case 'uri':\n parseModifierType(searchRequest, searchParam, modifier, value);\n break;\n case 'quantity':\n parseQuantity(searchRequest, searchParam, value);\n break;\n }\n}\n\nfunction parsePrefixType(searchRequest: SearchRequest, param: SearchParameter, input: string): void {\n const { operator, value } = parsePrefix(input);\n addFilter(searchRequest, {\n code: param.code as string,\n operator,\n value,\n });\n}\n\nfunction parseModifierType(\n searchRequest: SearchRequest,\n param: SearchParameter,\n modifier: string,\n value: string\n): void {\n addFilter(searchRequest, {\n code: param.code as string,\n operator: parseModifier(modifier),\n value,\n });\n}\n\nfunction parseQuantity(searchRequest: SearchRequest, param: SearchParameter, input: string): void {\n const [prefixNumber, unitSystem, unitCode] = input.split('|');\n const { operator, value } = parsePrefix(prefixNumber);\n addFilter(searchRequest, {\n code: param.code as string,\n operator,\n value,\n unitSystem,\n unitCode,\n });\n}\n\nfunction parseUnknownParameter(searchRequest: SearchRequest, code: string, modifier: string, value: string): void {\n let operator = Operator.EQUALS;\n if (modifier) {\n operator = modifier as Operator;\n } else if (value.length >= 2) {\n const prefix = value.substring(0, 2);\n if (prefix in PREFIX_OPERATORS) {\n if (value.length === 2 || value.at(2)?.match(/\\d/)) {\n operator = prefix as Operator;\n value = value.substring(prefix.length);\n }\n }\n }\n\n addFilter(searchRequest, {\n code,\n operator,\n value,\n });\n}\n\nfunction parsePrefix(input: string): { operator: Operator; value: string } {\n const prefix = input.substring(0, 2);\n const prefixOperator = PREFIX_OPERATORS[prefix];\n if (prefixOperator) {\n return { operator: prefixOperator, value: input.substring(2) };\n }\n return { operator: Operator.EQUALS, value: input };\n}\n\nfunction parseModifier(modifier: string): Operator {\n return MODIFIER_OPERATORS[modifier] || Operator.EQUALS;\n}\n\nfunction addFilter(searchRequest: SearchRequest, filter: Filter): void {\n if (searchRequest.filters) {\n searchRequest.filters.push(filter);\n } else {\n searchRequest.filters = [filter];\n }\n}\n\n/**\n * Formats a search definition object into a query string.\n * Note: The return value does not include the resource type.\n * @param {!SearchRequest} definition The search definition.\n * @returns Formatted URL.\n */\nexport function formatSearchQuery(definition: SearchRequest): string {\n const params: string[] = [];\n\n if (definition.fields) {\n params.push('_fields=' + definition.fields.join(','));\n }\n\n if (definition.filters) {\n definition.filters.forEach((filter) => params.push(formatFilter(filter)));\n }\n\n if (definition.sortRules && definition.sortRules.length > 0) {\n params.push(formatSortRules(definition.sortRules));\n }\n\n if (definition.offset !== undefined) {\n params.push('_offset=' + definition.offset);\n }\n\n if (definition.count !== undefined) {\n params.push('_count=' + definition.count);\n }\n\n if (definition.total !== undefined) {\n params.push('_total=' + definition.total);\n }\n\n if (params.length === 0) {\n return '';\n }\n\n params.sort();\n return '?' + params.join('&');\n}\n\nfunction formatFilter(filter: Filter): string {\n const modifier = filter.operator in MODIFIER_OPERATORS ? ':' + filter.operator : '';\n const prefix = filter.operator != Operator.EQUALS && filter.operator in PREFIX_OPERATORS ? filter.operator : '';\n return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;\n}\n\nfunction formatSortRules(sortRules: SortRule[]): string {\n return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');\n}\n"],"names":[],"mappings":"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"}
|