From eb779943b94b442b8e8646736cf81b48a2a4a02b Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Fri, 6 Sep 2024 15:41:48 +0300 Subject: [PATCH 01/24] Add cursor, dateFns and pagination --- packages/openmrs/ast.json | 86 +++++++++++++++++++++++++++++++++ packages/openmrs/src/Adaptor.js | 81 ++++++++++++++++++++++++------- 2 files changed, 149 insertions(+), 18 deletions(-) diff --git a/packages/openmrs/ast.json b/packages/openmrs/ast.json index a208d4d7b..c95119320 100644 --- a/packages/openmrs/ast.json +++ b/packages/openmrs/ast.json @@ -1294,6 +1294,92 @@ ] }, "valid": true + }, + { + "name": "cursor", + "params": [ + "value", + "options" + ], + "docs": { + "description": "Sets a cursor property on state.\nSupports natural language dates like `now`, `today`, `yesterday`, `n hours ago`, `n days ago`, and `start`,\nwhich will be converted relative to the environment (ie, the Lightning or CLI locale). Custom timezones\nare not yet supported.\nYou can provide a formatter to customise the final cursor value, which is useful for normalising\ndifferent inputs. The custom formatter runs after natural language date conversion.\nSee the usage guide at {@link https://docs.openfn.org/documentation/jobs/job-writing-guide#using-cursors}", + "tags": [ + { + "title": "public", + "description": null, + "type": null + }, + { + "title": "function", + "description": null, + "name": null + }, + { + "title": "example", + "description": "cursor($.cursor, { defaultValue: 'today' })", + "caption": "Use a cursor from state if present, or else use the default value" + }, + { + "title": "example", + "description": "cursor(22)", + "caption": "Use a pagination cursor" + }, + { + "title": "param", + "description": "the cursor value. Usually an ISO date, natural language date, or page number", + "type": { + "type": "NameExpression", + "name": "any" + }, + "name": "value" + }, + { + "title": "param", + "description": "options to control the cursor.", + "type": { + "type": "NameExpression", + "name": "object" + }, + "name": "options" + }, + { + "title": "param", + "description": "set the cursor key. Will persist through the whole run.", + "type": { + "type": "NameExpression", + "name": "string" + }, + "name": "options.key" + }, + { + "title": "param", + "description": "the value to use if value is falsy", + "type": { + "type": "NameExpression", + "name": "any" + }, + "name": "options.defaultValue" + }, + { + "title": "param", + "description": "custom formatter for the final cursor value", + "type": { + "type": "NameExpression", + "name": "Function" + }, + "name": "options.format" + }, + { + "title": "returns", + "description": null, + "type": { + "type": "NameExpression", + "name": "Operation" + } + } + ] + }, + "valid": false } ] } \ No newline at end of file diff --git a/packages/openmrs/src/Adaptor.js b/packages/openmrs/src/Adaptor.js index 2c43d7e91..74843de0d 100644 --- a/packages/openmrs/src/Adaptor.js +++ b/packages/openmrs/src/Adaptor.js @@ -175,19 +175,40 @@ export function post(path, data, callback = s => s) { */ export function searchPatient(query, callback = s => s) { return async state => { - const [resolvedQuery = {}] = expandReferences(state, query); + const [resolvedQuery] = expandReferences(state, query); console.log('Searching for patient with query:', resolvedQuery); - const response = await request( - state, - 'GET', - '/ws/rest/v1/patient', - {}, - resolvedQuery - ); - - console.log(`Found ${response.body.results.length} patients`); + let response; + let requestQuery = resolvedQuery; + let allowPagination = isNaN(requestQuery.startIndex); + + do { + // Make the first request + const res = await request( + state, + 'GET', + '/ws/rest/v1/patient', + {}, + requestQuery + ); + + response + ? response.body.results.push(...res.body.results) + : (response = res); + + if (res?.body?.links?.[0]?.rel === 'next') { + const urlObj = new URL(res.body.links[0].uri); + const params = new URLSearchParams(urlObj.search); + const startIndex = params.get('startIndex'); + + requestQuery = { ...requestQuery, startIndex }; + } else { + delete response.body.links; + // Exit the loop when no more data is available + break; + } + } while (allowPagination); return prepareNextState(state, response, callback); }; @@ -317,15 +338,37 @@ export function getEncounters(query, callback = s => s) { const [resolvedQuery] = expandReferences(state, query); console.log('Fetching encounters by query', resolvedQuery); - const response = await request( - state, - 'GET', - `/ws/rest/v1/encounter/`, - {}, - resolvedQuery - ); + let response; + let requestQuery = resolvedQuery; + let allowPagination = isNaN(requestQuery.startIndex); + + do { + const res = await request( + state, + 'GET', + `/ws/rest/v1/encounter/`, + {}, + requestQuery + ); + + response + ? response.body.results.push(...res.body.results) + : (response = res); + + if (res?.body?.links?.[0]?.rel === 'next') { + const urlObj = new URL(res.body.links[0].uri); + const params = new URLSearchParams(urlObj.search); + const startIndex = params.get('startIndex'); + + requestQuery = { ...requestQuery, startIndex }; + } else { + delete response.body.links; + // Exit the loop when no more data is available + break; + } + } while (allowPagination); + console.log(`Found ${response.body.results.length} results`); - console.log(`Found ${response.body.results.length}} results`); return prepareNextState(state, response, callback); }; } @@ -498,6 +541,8 @@ export { fnIf, field, fields, + cursor, + dateFns, sourceValue, merge, dataPath, From 91c797245a1525069bf587fce1bf21c32f44b0bb Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Fri, 6 Sep 2024 15:52:29 +0300 Subject: [PATCH 02/24] add changeset --- .changeset/wicked-carrots-whisper.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/wicked-carrots-whisper.md diff --git a/.changeset/wicked-carrots-whisper.md b/.changeset/wicked-carrots-whisper.md new file mode 100644 index 000000000..96296979a --- /dev/null +++ b/.changeset/wicked-carrots-whisper.md @@ -0,0 +1,7 @@ +--- +'@openfn/language-openmrs': minor +--- + +- Add pagination support for `getEncounter` and `searchPatient` operations +- Add `cursor` from `language/common` +- Add `dateFns` from `language/common` From 4ea2965e593bb3812b1817ef4a1e31dfd121d84e Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Fri, 6 Sep 2024 16:29:47 +0300 Subject: [PATCH 03/24] add cursor and dateFns --- packages/openmrs/ast.json | 86 +++++++++++++++++++++++++++++++++ packages/openmrs/src/Adaptor.js | 2 + 2 files changed, 88 insertions(+) diff --git a/packages/openmrs/ast.json b/packages/openmrs/ast.json index a208d4d7b..c95119320 100644 --- a/packages/openmrs/ast.json +++ b/packages/openmrs/ast.json @@ -1294,6 +1294,92 @@ ] }, "valid": true + }, + { + "name": "cursor", + "params": [ + "value", + "options" + ], + "docs": { + "description": "Sets a cursor property on state.\nSupports natural language dates like `now`, `today`, `yesterday`, `n hours ago`, `n days ago`, and `start`,\nwhich will be converted relative to the environment (ie, the Lightning or CLI locale). Custom timezones\nare not yet supported.\nYou can provide a formatter to customise the final cursor value, which is useful for normalising\ndifferent inputs. The custom formatter runs after natural language date conversion.\nSee the usage guide at {@link https://docs.openfn.org/documentation/jobs/job-writing-guide#using-cursors}", + "tags": [ + { + "title": "public", + "description": null, + "type": null + }, + { + "title": "function", + "description": null, + "name": null + }, + { + "title": "example", + "description": "cursor($.cursor, { defaultValue: 'today' })", + "caption": "Use a cursor from state if present, or else use the default value" + }, + { + "title": "example", + "description": "cursor(22)", + "caption": "Use a pagination cursor" + }, + { + "title": "param", + "description": "the cursor value. Usually an ISO date, natural language date, or page number", + "type": { + "type": "NameExpression", + "name": "any" + }, + "name": "value" + }, + { + "title": "param", + "description": "options to control the cursor.", + "type": { + "type": "NameExpression", + "name": "object" + }, + "name": "options" + }, + { + "title": "param", + "description": "set the cursor key. Will persist through the whole run.", + "type": { + "type": "NameExpression", + "name": "string" + }, + "name": "options.key" + }, + { + "title": "param", + "description": "the value to use if value is falsy", + "type": { + "type": "NameExpression", + "name": "any" + }, + "name": "options.defaultValue" + }, + { + "title": "param", + "description": "custom formatter for the final cursor value", + "type": { + "type": "NameExpression", + "name": "Function" + }, + "name": "options.format" + }, + { + "title": "returns", + "description": null, + "type": { + "type": "NameExpression", + "name": "Operation" + } + } + ] + }, + "valid": false } ] } \ No newline at end of file diff --git a/packages/openmrs/src/Adaptor.js b/packages/openmrs/src/Adaptor.js index 2c43d7e91..cb21b5d39 100644 --- a/packages/openmrs/src/Adaptor.js +++ b/packages/openmrs/src/Adaptor.js @@ -498,6 +498,8 @@ export { fnIf, field, fields, + cursor, + dateFns, sourceValue, merge, dataPath, From c8dbd21a97e114a3a3a6c48accce39264587c59a Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Mon, 9 Sep 2024 09:08:22 +0300 Subject: [PATCH 04/24] add changeset --- .changeset/light-forks-arrive.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/light-forks-arrive.md diff --git a/.changeset/light-forks-arrive.md b/.changeset/light-forks-arrive.md new file mode 100644 index 000000000..dd8dc3499 --- /dev/null +++ b/.changeset/light-forks-arrive.md @@ -0,0 +1,5 @@ +--- +'@openfn/language-openmrs': minor +--- + +Add cursor and dateFns helper functions From 780abc51fecd20a06fc0b1e2f6a1c065d7d9f19e Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Mon, 9 Sep 2024 13:53:24 +0300 Subject: [PATCH 05/24] update packages --- packages/openmrs/package.json | 13 +- pnpm-lock.yaml | 388 ++++++++++++++++++++++++++++------ 2 files changed, 335 insertions(+), 66 deletions(-) diff --git a/packages/openmrs/package.json b/packages/openmrs/package.json index c6cc39d11..0ae4c9cda 100644 --- a/packages/openmrs/package.json +++ b/packages/openmrs/package.json @@ -25,18 +25,17 @@ "configuration-schema.json" ], "dependencies": { - "@openfn/language-common": "2.0.1" + "@openfn/language-common": "workspace:*" }, "devDependencies": { "@openfn/simple-ast": "^0.4.1", - "assertion-error": "^1.0.1", - "chai": "^3.4.0", + "assertion-error": "^1.1.0", + "chai": "^5.1.1", "deep-eql": "^0.1.3", "esno": "^0.16.3", - "mocha": "^10.1.0", + "mocha": "^10.7.3", "nock": "^12.0.3", - "rimraf": "^3.0.2", - "sinon": "^1.17.2" + "rimraf": "^3.0.2" }, "type": "module", "exports": { @@ -48,4 +47,4 @@ "./package.json": "./package.json" }, "types": "types/index.d.ts" -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 193a24ef4..798f9d4ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1395,18 +1395,18 @@ importers: packages/openmrs: dependencies: '@openfn/language-common': - specifier: 2.0.1 + specifier: workspace:* version: link:../common devDependencies: '@openfn/simple-ast': specifier: ^0.4.1 version: 0.4.1 assertion-error: - specifier: ^1.0.1 + specifier: ^1.1.0 version: 1.1.0 chai: - specifier: ^3.4.0 - version: 3.5.0 + specifier: ^5.1.1 + version: 5.1.1 deep-eql: specifier: ^0.1.3 version: 0.1.3 @@ -1414,17 +1414,14 @@ importers: specifier: ^0.16.3 version: 0.16.3 mocha: - specifier: ^10.1.0 - version: 10.2.0 + specifier: ^10.7.3 + version: 10.7.3 nock: specifier: ^12.0.3 version: 12.0.3 rimraf: specifier: ^3.0.2 version: 3.0.2 - sinon: - specifier: ^1.17.2 - version: 1.17.7 packages/openspp: dependencies: @@ -2205,12 +2202,12 @@ packages: '@jridgewell/trace-mapping': 0.3.20 dev: true - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.20 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 /@azure/abort-controller@1.1.0: resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} @@ -2437,6 +2434,7 @@ packages: dependencies: '@babel/highlight': 7.22.20 chalk: 2.4.2 + dev: true /@babel/code-frame@7.24.7: resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} @@ -2444,11 +2442,15 @@ packages: dependencies: '@babel/highlight': 7.24.7 picocolors: 1.0.1 - dev: true /@babel/compat-data@7.23.2: resolution: {integrity: sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==} engines: {node: '>=6.9.0'} + dev: true + + /@babel/compat-data@7.25.4: + resolution: {integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==} + engines: {node: '>=6.9.0'} /@babel/core@7.19.6: resolution: {integrity: sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==} @@ -2473,22 +2475,22 @@ packages: - supports-color dev: true - /@babel/core@7.23.2: - resolution: {integrity: sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==} + /@babel/core@7.25.2: + resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} engines: {node: '>=6.9.0'} dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.22.13 - '@babel/generator': 7.23.0 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-module-transforms': 7.23.0(@babel/core@7.23.2) - '@babel/helpers': 7.23.2 - '@babel/parser': 7.23.0 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.2 - '@babel/types': 7.23.0 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helpers': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -2512,6 +2514,16 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 jsesc: 2.5.2 + dev: true + + /@babel/generator@7.25.6: + resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 /@babel/helper-compilation-targets@7.20.0(@babel/core@7.19.6): resolution: {integrity: sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==} @@ -2526,19 +2538,20 @@ packages: semver: 6.3.1 dev: true - /@babel/helper-compilation-targets@7.22.15: - resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + /@babel/helper-compilation-targets@7.25.2: + resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/compat-data': 7.23.2 - '@babel/helper-validator-option': 7.22.15 - browserslist: 4.22.1 + '@babel/compat-data': 7.25.4 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.23.3 lru-cache: 5.1.1 semver: 6.3.1 /@babel/helper-environment-visitor@7.22.20: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} + dev: true /@babel/helper-function-name@7.23.0: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} @@ -2546,18 +2559,30 @@ packages: dependencies: '@babel/template': 7.22.15 '@babel/types': 7.23.0 + dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.0 + dev: true /@babel/helper-module-imports@7.22.15: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.0 + dev: true + + /@babel/helper-module-imports@7.24.7: + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color /@babel/helper-module-transforms@7.19.6: resolution: {integrity: sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==} @@ -2575,30 +2600,42 @@ packages: - supports-color dev: true - /@babel/helper-module-transforms@7.23.0(@babel/core@7.23.2): - resolution: {integrity: sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==} + /@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.2 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color /@babel/helper-simple-access@7.22.5: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.0 + dev: true + + /@babel/helper-simple-access@7.24.7: + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.0 + dev: true /@babel/helper-string-parser@7.19.4: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} @@ -2609,6 +2646,10 @@ packages: resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} + /@babel/helper-string-parser@7.24.8: + resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} + engines: {node: '>=6.9.0'} + /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} @@ -2616,11 +2657,15 @@ packages: /@babel/helper-validator-identifier@7.24.7: resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-option@7.22.15: resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.24.8: + resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} + engines: {node: '>=6.9.0'} /@babel/helpers@7.20.0: resolution: {integrity: sha512-aGMjYraN0zosCEthoGLdqot1oRsmxVTQRHadsUPz5QM44Zej2PYRz7XiDE7GqnkZnNtLbOuxqoZw42vkU7+XEQ==} @@ -2633,15 +2678,12 @@ packages: - supports-color dev: true - /@babel/helpers@7.23.2: - resolution: {integrity: sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==} + /@babel/helpers@7.25.6: + resolution: {integrity: sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.2 - '@babel/types': 7.23.0 - transitivePeerDependencies: - - supports-color + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 /@babel/highlight@7.22.20: resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} @@ -2650,6 +2692,7 @@ packages: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 + dev: true /@babel/highlight@7.24.7: resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} @@ -2659,7 +2702,6 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.1 - dev: true /@babel/parser@7.20.0: resolution: {integrity: sha512-G9VgAhEaICnz8iiJeGJQyVl6J2nTjbW0xeisva0PK6XcKsga7BIaqm4ZF8Rg1Wbaqmy6znspNqhPaPkyukujzg==} @@ -2676,6 +2718,13 @@ packages: dependencies: '@babel/types': 7.23.0 + /@babel/parser@7.25.6: + resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.25.6 + /@babel/runtime@7.24.7: resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} @@ -2699,6 +2748,15 @@ packages: '@babel/code-frame': 7.22.13 '@babel/parser': 7.23.0 '@babel/types': 7.23.0 + dev: true + + /@babel/template@7.25.0: + resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 /@babel/traverse@7.20.0: resolution: {integrity: sha512-5+cAXQNARgjRUK0JWu2UBwja4JLSO/rBMPJzpsKb+oBF5xlUuCfljQepS4XypBQoiigL0VQjTZy6WiONtUdScQ==} @@ -2734,6 +2792,21 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color + dev: true + + /@babel/traverse@7.25.6: + resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + debug: 4.3.7(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color /@babel/types@7.20.0: resolution: {integrity: sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==} @@ -2752,6 +2825,14 @@ packages: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + /@babel/types@7.25.6: + resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + /@changesets/apply-release-plan@7.0.3: resolution: {integrity: sha512-klL6LCdmfbEe9oyfLxnidIf/stFXmrbFO/3gT5LU5pcyoZytzJe4gWpTBx3BPmyNPl16dZ1xrkcW7b98e3tYkA==} dependencies: @@ -3467,23 +3548,51 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + /@jridgewell/sourcemap-codec@1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + /@jridgewell/trace-mapping@0.3.20: resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -3590,7 +3699,7 @@ packages: resolution: {integrity: sha512-O0YUYgNkQpTadkUzviJShvw0JNz1rZex6aySq2rBF3I63qBo+OTi4TrQfr8lHqJXhrVMsBuW9tYOYwUGZ+aAqA==} hasBin: true dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.25.2 doctrine: 2.1.0 lodash.isequal: 4.5.0 yargs: 17.7.2 @@ -4262,6 +4371,11 @@ packages: engines: {node: '>=12'} dev: true + /assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + dev: true + /assign-symbols@1.0.0: resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} engines: {node: '>=0.10.0'} @@ -5343,6 +5457,17 @@ packages: electron-to-chromium: 1.4.557 node-releases: 2.0.13 update-browserslist-db: 1.0.13(browserslist@4.22.1) + dev: true + + /browserslist@4.23.3: + resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001659 + electron-to-chromium: 1.5.18 + node-releases: 2.0.18 + update-browserslist-db: 1.1.0(browserslist@4.23.3) /bson@1.1.6: resolution: {integrity: sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==} @@ -5496,6 +5621,10 @@ packages: /caniuse-lite@1.0.30001550: resolution: {integrity: sha512-p82WjBYIypO0ukTsd/FG3Xxs+4tFeaY9pfT4amQL8KWtYH7H9nYwReGAbMTJ0hsmRO8IfDtsS6p3ZWj8+1c2RQ==} + dev: true + + /caniuse-lite@1.0.30001659: + resolution: {integrity: sha512-Qxxyfv3RdHAfJcXelgf0hU4DFUVXBGTjqrBUZLUh8AtlGnsDo+CnncYtTd95+ZKfnANUOzxyIQCuU/UeBZBYoA==} /caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} @@ -5578,6 +5707,17 @@ packages: type-detect: 4.0.8 dev: true + /chai@5.1.1: + resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + engines: {node: '>=12'} + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.1 + pathval: 2.0.0 + dev: true + /chainsaw@0.1.0: resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} dependencies: @@ -5637,6 +5777,11 @@ packages: get-func-name: 2.0.2 dev: true + /check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + dev: true + /cheerio-select@2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} dependencies: @@ -6302,6 +6447,18 @@ packages: ms: 2.1.2 supports-color: 8.1.1 + /debug@4.3.7(supports-color@8.1.1): + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 8.1.1 + /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} @@ -6364,6 +6521,11 @@ packages: type-detect: 4.0.8 dev: true + /deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + dev: true + /deep-equal@1.1.1: resolution: {integrity: sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==} dependencies: @@ -6520,6 +6682,11 @@ packages: engines: {node: '>=0.3.1'} dev: true + /diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + dev: true + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -6631,6 +6798,10 @@ packages: /electron-to-chromium@1.4.557: resolution: {integrity: sha512-6x0zsxyMXpnMJnHrondrD3SuAeKcwij9S+83j2qHAQPXbGTDDfgImzzwgGlzrIcXbHQ42tkG4qA6U860cImNhw==} + dev: true + + /electron-to-chromium@1.5.18: + resolution: {integrity: sha512-1OfuVACu+zKlmjsNdcJuVQuVE61sZOLbNM4JAQ1Rvh6EOj0/EUKhMJjRH73InPlXSh8HIJk1cVZ8pyOV/FMdUQ==} /emittery@1.0.1: resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==} @@ -7151,6 +7322,10 @@ packages: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -8132,6 +8307,12 @@ packages: resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} dependencies: resolve-pkg-maps: 1.0.0 + dev: true + + /get-tsconfig@4.8.0: + resolution: {integrity: sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==} + dependencies: + resolve-pkg-maps: 1.0.0 /get-value@2.0.6: resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} @@ -8221,6 +8402,18 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: true + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -8369,7 +8562,7 @@ packages: source-map: 0.6.1 wordwrap: 1.0.0 optionalDependencies: - uglify-js: 3.18.0 + uglify-js: 3.19.3 dev: false /har-schema@2.0.0: @@ -8555,7 +8748,7 @@ packages: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: false @@ -9869,6 +10062,12 @@ packages: get-func-name: 2.0.2 dev: true + /loupe@3.1.1: + resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==} + dependencies: + get-func-name: 2.0.2 + dev: true + /lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} dependencies: @@ -10181,6 +10380,13 @@ packages: dependencies: brace-expansion: 2.0.1 + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@7.4.1: resolution: {integrity: sha512-Oz1iPEP+MGl7KS3SciLsLLcuZ7VsBfb7Qrz/jYt/s/sYAv272P26HSLz2f77Y6hzTKXiBi6g765fqpEDNc5fJw==} engines: {node: '>=10'} @@ -10302,6 +10508,33 @@ packages: yargs-unparser: 2.0.0 dev: true + /mocha@10.7.3: + resolution: {integrity: sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==} + engines: {node: '>= 14.0.0'} + hasBin: true + dependencies: + ansi-colors: 4.1.3 + browser-stdout: 1.3.1 + chokidar: 3.6.0 + debug: 4.3.7(supports-color@8.1.1) + diff: 5.2.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 8.1.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.1.6 + ms: 2.1.3 + serialize-javascript: 6.0.2 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.5.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + yargs-unparser: 2.0.0 + dev: true + /mocha@7.2.0: resolution: {integrity: sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==} engines: {node: '>= 8.10.0'} @@ -10528,7 +10761,7 @@ packages: resolution: {integrity: sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==} engines: {node: '>= 10.13'} dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) json-stringify-safe: 5.0.1 lodash: 4.17.21 propagate: 2.0.1 @@ -10598,6 +10831,10 @@ packages: /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} /nofilter@3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} @@ -11179,6 +11416,11 @@ packages: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true + /pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + dev: true + /performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} dev: false @@ -11246,10 +11488,13 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true /picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - dev: true + + /picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -12151,6 +12396,12 @@ packages: dependencies: randombytes: 2.1.0 + /serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + dependencies: + randombytes: 2.1.0 + dev: true + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true @@ -13306,7 +13557,7 @@ packages: hasBin: true dependencies: esbuild: 0.18.20 - get-tsconfig: 4.7.5 + get-tsconfig: 4.8.0 source-map-support: 0.5.21 optionalDependencies: fsevents: 2.3.3 @@ -13515,8 +13766,8 @@ packages: resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} dev: false - /uglify-js@3.18.0: - resolution: {integrity: sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==} + /uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} hasBin: true requiresBuild: true @@ -13612,6 +13863,17 @@ packages: browserslist: 4.22.1 escalade: 3.1.1 picocolors: 1.0.0 + dev: true + + /update-browserslist-db@1.1.0(browserslist@4.23.3): + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.23.3 + escalade: 3.2.0 + picocolors: 1.1.0 /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -13884,6 +14146,10 @@ packages: /workerpool@6.2.1: resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} + /workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} + dev: true + /wrap-ansi@2.1.0: resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} engines: {node: '>=0.10.0'} @@ -14038,6 +14304,10 @@ packages: resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} engines: {node: '>=10'} + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -14103,12 +14373,12 @@ packages: engines: {node: '>=10'} dependencies: cliui: 7.0.4 - escalade: 3.1.1 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 y18n: 5.0.8 - yargs-parser: 20.2.4 + yargs-parser: 20.2.9 /yargs@17.6.0: resolution: {integrity: sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==} From c3ef47f7d3aadfb49893bd6aac8b9eb58e9247cd Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Mon, 9 Sep 2024 13:54:10 +0300 Subject: [PATCH 06/24] remove the example without caption --- packages/openmrs/ast.json | 90 --------------------------------------- 1 file changed, 90 deletions(-) diff --git a/packages/openmrs/ast.json b/packages/openmrs/ast.json index c95119320..bfbe00071 100644 --- a/packages/openmrs/ast.json +++ b/packages/openmrs/ast.json @@ -9,10 +9,6 @@ "docs": { "description": "Gets patient matching a uuid", "tags": [ - { - "title": "example", - "description": "getPatient(\"123\")" - }, { "title": "function", "description": null, @@ -1294,92 +1290,6 @@ ] }, "valid": true - }, - { - "name": "cursor", - "params": [ - "value", - "options" - ], - "docs": { - "description": "Sets a cursor property on state.\nSupports natural language dates like `now`, `today`, `yesterday`, `n hours ago`, `n days ago`, and `start`,\nwhich will be converted relative to the environment (ie, the Lightning or CLI locale). Custom timezones\nare not yet supported.\nYou can provide a formatter to customise the final cursor value, which is useful for normalising\ndifferent inputs. The custom formatter runs after natural language date conversion.\nSee the usage guide at {@link https://docs.openfn.org/documentation/jobs/job-writing-guide#using-cursors}", - "tags": [ - { - "title": "public", - "description": null, - "type": null - }, - { - "title": "function", - "description": null, - "name": null - }, - { - "title": "example", - "description": "cursor($.cursor, { defaultValue: 'today' })", - "caption": "Use a cursor from state if present, or else use the default value" - }, - { - "title": "example", - "description": "cursor(22)", - "caption": "Use a pagination cursor" - }, - { - "title": "param", - "description": "the cursor value. Usually an ISO date, natural language date, or page number", - "type": { - "type": "NameExpression", - "name": "any" - }, - "name": "value" - }, - { - "title": "param", - "description": "options to control the cursor.", - "type": { - "type": "NameExpression", - "name": "object" - }, - "name": "options" - }, - { - "title": "param", - "description": "set the cursor key. Will persist through the whole run.", - "type": { - "type": "NameExpression", - "name": "string" - }, - "name": "options.key" - }, - { - "title": "param", - "description": "the value to use if value is falsy", - "type": { - "type": "NameExpression", - "name": "any" - }, - "name": "options.defaultValue" - }, - { - "title": "param", - "description": "custom formatter for the final cursor value", - "type": { - "type": "NameExpression", - "name": "Function" - }, - "name": "options.format" - }, - { - "title": "returns", - "description": null, - "type": { - "type": "NameExpression", - "name": "Operation" - } - } - ] - }, - "valid": false } ] } \ No newline at end of file From ec55e95815037016c7c6e7ffbb720f819cccb12e Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Mon, 9 Sep 2024 13:55:34 +0300 Subject: [PATCH 07/24] remove pagination code --- packages/openmrs/src/Adaptor.js | 77 ++++++--------------------------- 1 file changed, 14 insertions(+), 63 deletions(-) diff --git a/packages/openmrs/src/Adaptor.js b/packages/openmrs/src/Adaptor.js index 74843de0d..36bba383c 100644 --- a/packages/openmrs/src/Adaptor.js +++ b/packages/openmrs/src/Adaptor.js @@ -27,8 +27,6 @@ export function execute(...operations) { /** * Gets patient matching a uuid - * @example - * getPatient("123") * @function * @public * @param {string} uuid - A uuid for the patient @@ -179,36 +177,13 @@ export function searchPatient(query, callback = s => s) { console.log('Searching for patient with query:', resolvedQuery); - let response; - let requestQuery = resolvedQuery; - let allowPagination = isNaN(requestQuery.startIndex); - - do { - // Make the first request - const res = await request( - state, - 'GET', - '/ws/rest/v1/patient', - {}, - requestQuery - ); - - response - ? response.body.results.push(...res.body.results) - : (response = res); - - if (res?.body?.links?.[0]?.rel === 'next') { - const urlObj = new URL(res.body.links[0].uri); - const params = new URLSearchParams(urlObj.search); - const startIndex = params.get('startIndex'); - - requestQuery = { ...requestQuery, startIndex }; - } else { - delete response.body.links; - // Exit the loop when no more data is available - break; - } - } while (allowPagination); + const response = await request( + state, + 'GET', + '/ws/rest/v1/patient', + {}, + resolvedQuery + ); return prepareNextState(state, response, callback); }; @@ -338,35 +313,13 @@ export function getEncounters(query, callback = s => s) { const [resolvedQuery] = expandReferences(state, query); console.log('Fetching encounters by query', resolvedQuery); - let response; - let requestQuery = resolvedQuery; - let allowPagination = isNaN(requestQuery.startIndex); - - do { - const res = await request( - state, - 'GET', - `/ws/rest/v1/encounter/`, - {}, - requestQuery - ); - - response - ? response.body.results.push(...res.body.results) - : (response = res); - - if (res?.body?.links?.[0]?.rel === 'next') { - const urlObj = new URL(res.body.links[0].uri); - const params = new URLSearchParams(urlObj.search); - const startIndex = params.get('startIndex'); - - requestQuery = { ...requestQuery, startIndex }; - } else { - delete response.body.links; - // Exit the loop when no more data is available - break; - } - } while (allowPagination); + const response = await request( + state, + 'GET', + `/ws/rest/v1/encounter/`, + {}, + resolvedQuery + ); console.log(`Found ${response.body.results.length} results`); return prepareNextState(state, response, callback); @@ -541,8 +494,6 @@ export { fnIf, field, fields, - cursor, - dateFns, sourceValue, merge, dataPath, From 8823610b1c0e653d0e9ce45000673dfa15d1dedb Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Mon, 9 Sep 2024 13:56:06 +0300 Subject: [PATCH 08/24] add autoFetchRequest helper function --- packages/openmrs/src/Utils.js | 46 ++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/packages/openmrs/src/Utils.js b/packages/openmrs/src/Utils.js index 3c189ee4f..81316b838 100644 --- a/packages/openmrs/src/Utils.js +++ b/packages/openmrs/src/Utils.js @@ -2,11 +2,11 @@ import { composeNextState } from '@openfn/language-common'; import { request as commonRequest, makeBasicAuthHeader, - logResponse + logResponse, } from '@openfn/language-common/util'; export const prepareNextState = (state, response, callback) => { - const { body, ...responseWithoutBody } = response + const { body, ...responseWithoutBody } = response; const nextState = { ...composeNextState(state, response.body), response: responseWithoutBody, @@ -21,18 +21,52 @@ export function request(state, method, path, data, params) { const options = { body: data, - headers: { ...headers, 'content-type': 'application/json', }, - query: params, - parseAs: 'json', }; const url = `${instanceUrl}${path}`; - return commonRequest(method, url, options).then(response => logResponse(response)); + return autoFetchRequest(method, url, options); } + +const autoFetchRequest = async (method, url, options) => { + let allResponses; + let reqQuery = options?.query; + let allowPagination = isNaN(reqQuery?.startIndex); + + do { + const response = await commonRequest(method, url, { + ...options, + query: reqQuery ?? {}, + }); + logResponse(response); + + allResponses + ? allResponses.body.results.push(...response.body.results) + : (allResponses = response); + + const nextUrl = response?.body?.links?.find( + link => link.rel === 'next' + )?.uri; + + if (nextUrl) { + console.log(`Found ${response.body.results.length} results`); + console.log(`Fetching next page from ${nextUrl}`); + const urlObj = new URL(nextUrl); + const params = new URLSearchParams(urlObj.search); + const startIndex = params.get('startIndex'); + + reqQuery = { ...reqQuery, startIndex }; + } else { + delete allResponses.body.links; + break; + } + } while (allowPagination); + + return allResponses; +}; From 20e077de4b5d7afb99c32c55e550d2124f9aaf73 Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Mon, 9 Sep 2024 13:56:26 +0300 Subject: [PATCH 09/24] add unit test --- packages/openmrs/test/index.js | 278 +++++++++++++++++++++++++++++++-- 1 file changed, 263 insertions(+), 15 deletions(-) diff --git a/packages/openmrs/test/index.js b/packages/openmrs/test/index.js index 075079398..b3bb401e4 100644 --- a/packages/openmrs/test/index.js +++ b/packages/openmrs/test/index.js @@ -1,19 +1,31 @@ -import chai from 'chai'; -const { expect } = chai; -import Adaptor from '../src'; +import { enableMockClient } from '@openfn/language-common/util'; +import { expect } from 'chai'; +import { request } from '../src/Utils'; -const { execute } = Adaptor; +import { + execute, + get, + post, + searchPatient, + getPatient, + searchPerson, +} from '../src'; + +const testServer = enableMockClient('https://fn.openmrs.org'); +const jsonHeaders = { + headers: { + 'Content-Type': 'application/json', + }, +}; +const configuration = { + username: 'test', + password: 'strongpassword', + instanceUrl: 'https://fn.openmrs.org', +}; -// TODO: mock a connection for the login. describe('execute', () => { - it.skip('executes each operation in sequence', done => { - let state = { - configuration: { - username: 'test', - password: '123', - instanceUrl: 'https://www.openmrs.org', - }, - }; + it('executes each operation in sequence', done => { + let state = { configuration }; let operations = [ state => { return { counter: 1 }; @@ -34,10 +46,10 @@ describe('execute', () => { .catch(done); }); - it.skip('assigns references, data to the initialState', () => { + it('assigns references, data to the initialState', () => { let state = {}; - let finalState = execute()(state); + execute()(state); execute()(state).then(finalState => { expect(finalState).to.eql({ @@ -47,3 +59,239 @@ describe('execute', () => { }); }); }); + +describe('request', () => { + it('should search for a patient', async () => { + testServer + .intercept({ + path: '/ws/rest/v1/patient', + query: { q: 'Sarah 1' }, + method: 'GET', + }) + .reply(200, { results: [{ display: 'Sarah 1' }] }, { ...jsonHeaders }); + const state = { configuration }; + + const { body } = await request( + state, + 'GET', + '/ws/rest/v1/patient', + {}, + { q: 'Sarah 1' } + ); + + expect(body.results[0].display).to.eql('Sarah 1'); + }); + it('should auto-fetch patients with a limit', async () => { + testServer + .intercept({ + path: '/ws/rest/v1/patient', + query: { q: 'Sarah', limit: 1 }, + method: 'GET', + }) + .reply( + 200, + { + results: [{ display: 'Sarah 1' }], + links: [ + { + rel: 'next', + uri: 'https://fn.openmrs.org/ws/rest/v1/patient?q=Sarah&limit=1&startIndex=1', + resourceAlias: null, + }, + ], + }, + { ...jsonHeaders } + ); + testServer + .intercept({ + path: '/ws/rest/v1/patient', + query: { q: 'Sarah', limit: 1, startIndex: 1 }, + method: 'GET', + }) + .reply( + 200, + { + results: [{ display: 'Sarah 2' }], + }, + { ...jsonHeaders } + ); + + const state = { configuration }; + const { body } = await request( + state, + 'GET', + '/ws/rest/v1/patient', + {}, + { q: 'Sarah', limit: 1 } + ); + expect(body.results[0].display).to.eql('Sarah 1'); + expect(body.results[1].display).to.eql('Sarah 2'); + }); + + it('should not auto-fetch if the user sets startIdex', async () => { + testServer + .intercept({ + path: '/ws/rest/v1/patient', + query: { q: 'Sarah', limit: 1, startIndex: 1 }, + method: 'GET', + }) + .reply( + 200, + { + results: [{ display: 'Sarah 2' }], + }, + { ...jsonHeaders } + ); + + const state = { configuration }; + const { body } = await request( + state, + 'GET', + '/ws/rest/v1/patient', + {}, + { q: 'Sarah', limit: 1, startIndex: 1 } + ); + + expect(body.results[0].display).to.eql('Sarah 2'); + }); +}); + +describe('get', () => { + before(() => { + testServer + .intercept({ + path: '/ws/rest/v1/encounter/123', + method: 'GET', + }) + .reply(200, { uuid: '123' }, { ...jsonHeaders }); + }); + + it('should get an encounter by uuid', async () => { + const state = { configuration }; + + const { data } = await execute(get('encounter/123'))(state); + + expect(data.uuid).to.eql('123'); + }); +}); + +describe('post', () => { + before(() => { + testServer + .intercept({ + path: '/ws/rest/v1/encounter', + method: 'POST', + }) + .reply(200, ({ body }) => body, { + ...jsonHeaders, + }); + }); + + it('should post an encounter', async () => { + const state = { configuration }; + + const { data } = await execute( + post('encounter', { + patient: '123', + encounterType: '123', + location: '123', + encounterProviders: [], + visit: { + patient: '123', + visitType: '123', + startDatetime: '2023-05-25T06:08:25.000+0000', + stopDatetime: '2023-05-25T06:09:25.000+0000', + }, + }) + )(state); + + expect(data.patient).to.eql('123'); + }); +}); + +describe('getPatient', () => { + before(() => { + testServer + .intercept({ + path: '/ws/rest/v1/patient/b52ec6f9-0e26-424c-a4a1-c64f9d571eb3', + method: 'GET', + }) + .reply( + 200, + { uuid: 'b52ec6f9-0e26-424c-a4a1-c64f9d571eb3' }, + { ...jsonHeaders } + ); + }); + + it('should get a patient by uuid', async () => { + const state = { configuration }; + + const { data } = await execute( + getPatient('b52ec6f9-0e26-424c-a4a1-c64f9d571eb3') + )(state); + + expect(data.uuid).to.eql('b52ec6f9-0e26-424c-a4a1-c64f9d571eb3'); + }); +}); + +describe('searchPerson', () => { + before(() => { + testServer + .intercept({ + path: '/ws/rest/v1/person?q=Sarah', + method: 'GET', + }) + .reply( + 200, + { results: [{ display: 'Sarah' }] }, + { + headers: { + 'Content-Type': 'application/json', + }, + } + ); + }); + + it('should search for a person', async () => { + const state = { configuration }; + + const { data } = await execute( + searchPerson({ + q: 'Sarah', + }) + )(state); + + expect(data.results[0].display).to.eql('Sarah'); + }); +}); + +describe('searchPatient', () => { + before(() => { + testServer + .intercept({ + path: '/ws/rest/v1/patient?q=Sarah', + method: 'GET', + }) + .reply( + 200, + { results: [{ display: 'Sarah' }] }, + { + headers: { + 'Content-Type': 'application/json', + }, + } + ); + }); + + it('should search for a patient', async () => { + const state = { configuration }; + + const { data } = await execute( + searchPatient({ + q: 'Sarah', + }) + )(state); + + expect(data.results[0].display).to.eql('Sarah'); + }); +}); From 6044dd7a3c9305abcd634ca8be2f7f791c30703e Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Mon, 9 Sep 2024 13:56:37 +0300 Subject: [PATCH 10/24] update changeset --- .changeset/wicked-carrots-whisper.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.changeset/wicked-carrots-whisper.md b/.changeset/wicked-carrots-whisper.md index 96296979a..2dd334d64 100644 --- a/.changeset/wicked-carrots-whisper.md +++ b/.changeset/wicked-carrots-whisper.md @@ -2,6 +2,4 @@ '@openfn/language-openmrs': minor --- -- Add pagination support for `getEncounter` and `searchPatient` operations -- Add `cursor` from `language/common` -- Add `dateFns` from `language/common` +- Add pagination support on request helper function From 05625f9d6853a9345de917a35b8671992ae84b37 Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Mon, 9 Sep 2024 14:00:45 +0300 Subject: [PATCH 11/24] improve log --- packages/openmrs/src/Utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/openmrs/src/Utils.js b/packages/openmrs/src/Utils.js index 81316b838..824284d5d 100644 --- a/packages/openmrs/src/Utils.js +++ b/packages/openmrs/src/Utils.js @@ -55,7 +55,7 @@ const autoFetchRequest = async (method, url, options) => { )?.uri; if (nextUrl) { - console.log(`Found ${response.body.results.length} results`); + console.log(`Fetched ${response.body.results.length} results`); console.log(`Fetching next page from ${nextUrl}`); const urlObj = new URL(nextUrl); const params = new URLSearchParams(urlObj.search); From 2b0dcdceb91725f8e763c068e7266f69059316a8 Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 13:14:16 +0300 Subject: [PATCH 12/24] minor improvements --- packages/openmrs/test/index.js | 71 ++++++++++++++-------------------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/packages/openmrs/test/index.js b/packages/openmrs/test/index.js index b3bb401e4..3f381a278 100644 --- a/packages/openmrs/test/index.js +++ b/packages/openmrs/test/index.js @@ -3,12 +3,12 @@ import { expect } from 'chai'; import { request } from '../src/Utils'; import { - execute, get, post, - searchPatient, + execute, getPatient, searchPerson, + searchPatient, } from '../src'; const testServer = enableMockClient('https://fn.openmrs.org'); @@ -61,7 +61,7 @@ describe('execute', () => { }); describe('request', () => { - it('should search for a patient', async () => { + it('should GET with a query', async () => { testServer .intercept({ path: '/ws/rest/v1/patient', @@ -129,6 +129,26 @@ describe('request', () => { }); it('should not auto-fetch if the user sets startIdex', async () => { + testServer + .intercept({ + path: '/ws/rest/v1/patient', + query: { q: 'Sarah', limit: 1 }, + method: 'GET', + }) + .reply( + 200, + { + results: [{ display: 'Sarah 1' }], + links: [ + { + rel: 'next', + uri: 'https://fn.openmrs.org/ws/rest/v1/patient?q=Sarah&limit=1&startIndex=1', + resourceAlias: null, + }, + ], + }, + { ...jsonHeaders } + ); testServer .intercept({ path: '/ws/rest/v1/patient', @@ -157,18 +177,15 @@ describe('request', () => { }); describe('get', () => { - before(() => { + it('should get an encounter by uuid', async () => { testServer .intercept({ path: '/ws/rest/v1/encounter/123', method: 'GET', }) .reply(200, { uuid: '123' }, { ...jsonHeaders }); - }); - it('should get an encounter by uuid', async () => { const state = { configuration }; - const { data } = await execute(get('encounter/123'))(state); expect(data.uuid).to.eql('123'); @@ -176,7 +193,7 @@ describe('get', () => { }); describe('post', () => { - before(() => { + it('should post an encounter', async () => { testServer .intercept({ path: '/ws/rest/v1/encounter', @@ -185,11 +202,8 @@ describe('post', () => { .reply(200, ({ body }) => body, { ...jsonHeaders, }); - }); - it('should post an encounter', async () => { const state = { configuration }; - const { data } = await execute( post('encounter', { patient: '123', @@ -210,7 +224,7 @@ describe('post', () => { }); describe('getPatient', () => { - before(() => { + it('should get a patient by uuid', async () => { testServer .intercept({ path: '/ws/rest/v1/patient/b52ec6f9-0e26-424c-a4a1-c64f9d571eb3', @@ -221,11 +235,8 @@ describe('getPatient', () => { { uuid: 'b52ec6f9-0e26-424c-a4a1-c64f9d571eb3' }, { ...jsonHeaders } ); - }); - it('should get a patient by uuid', async () => { const state = { configuration }; - const { data } = await execute( getPatient('b52ec6f9-0e26-424c-a4a1-c64f9d571eb3') )(state); @@ -235,24 +246,13 @@ describe('getPatient', () => { }); describe('searchPerson', () => { - before(() => { + it('should search for a person', async () => { testServer .intercept({ path: '/ws/rest/v1/person?q=Sarah', method: 'GET', }) - .reply( - 200, - { results: [{ display: 'Sarah' }] }, - { - headers: { - 'Content-Type': 'application/json', - }, - } - ); - }); - - it('should search for a person', async () => { + .reply(200, { results: [{ display: 'Sarah' }] }, { ...jsonHeaders }); const state = { configuration }; const { data } = await execute( @@ -266,26 +266,15 @@ describe('searchPerson', () => { }); describe('searchPatient', () => { - before(() => { + it('should search for a patient', async () => { testServer .intercept({ path: '/ws/rest/v1/patient?q=Sarah', method: 'GET', }) - .reply( - 200, - { results: [{ display: 'Sarah' }] }, - { - headers: { - 'Content-Type': 'application/json', - }, - } - ); - }); + .reply(200, { results: [{ display: 'Sarah' }] }, { ...jsonHeaders }); - it('should search for a patient', async () => { const state = { configuration }; - const { data } = await execute( searchPatient({ q: 'Sarah', From 890bf21b9d9415f9a68e44bb95eab5b62c9f2e47 Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 13:15:04 +0300 Subject: [PATCH 13/24] remove autoFetchRequest --- packages/openmrs/src/Utils.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/packages/openmrs/src/Utils.js b/packages/openmrs/src/Utils.js index 824284d5d..1659d3328 100644 --- a/packages/openmrs/src/Utils.js +++ b/packages/openmrs/src/Utils.js @@ -15,7 +15,7 @@ export const prepareNextState = (state, response, callback) => { return callback(nextState); }; -export function request(state, method, path, data, params) { +export async function request(state, method, path, data, params) { const { instanceUrl, username, password } = state.configuration; const headers = makeBasicAuthHeader(username, password); @@ -31,19 +31,13 @@ export function request(state, method, path, data, params) { const url = `${instanceUrl}${path}`; - return autoFetchRequest(method, url, options); -} - -const autoFetchRequest = async (method, url, options) => { let allResponses; - let reqQuery = options?.query; - let allowPagination = isNaN(reqQuery?.startIndex); + let query = options?.query; + let allowPagination = isNaN(query?.startIndex); do { - const response = await commonRequest(method, url, { - ...options, - query: reqQuery ?? {}, - }); + const requestOptions = query ? { ...options, query } : options; + const response = await commonRequest(method, url, requestOptions); logResponse(response); allResponses @@ -61,7 +55,7 @@ const autoFetchRequest = async (method, url, options) => { const params = new URLSearchParams(urlObj.search); const startIndex = params.get('startIndex'); - reqQuery = { ...reqQuery, startIndex }; + query = { ...query, startIndex }; } else { delete allResponses.body.links; break; @@ -69,4 +63,4 @@ const autoFetchRequest = async (method, url, options) => { } while (allowPagination); return allResponses; -}; +} From 796bc5adce2a6cb382279af27ddd75aa9fdb42b1 Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 14:50:32 +0300 Subject: [PATCH 14/24] remove createEncounter and createPatient --- packages/openmrs/src/Adaptor.js | 126 +++++++++----------------------- packages/openmrs/test/index.js | 42 +++++++++++ 2 files changed, 78 insertions(+), 90 deletions(-) diff --git a/packages/openmrs/src/Adaptor.js b/packages/openmrs/src/Adaptor.js index 36bba383c..8613052b9 100644 --- a/packages/openmrs/src/Adaptor.js +++ b/packages/openmrs/src/Adaptor.js @@ -52,46 +52,6 @@ export function getPatient(uuid, callback = s => s) { }; } -/** - * Creates an encounter - * @example Create an encounter - * createEncounter({ - * encounterDatetime: '2023-05-25T06:08:25.000+0000', - * patient: '1fdaa696-e759-4a7d-a066-f1ae557c151b', - * encounterType: 'dd528487-82a5-4082-9c72-ed246bd49591', - * location: 'ba685651-ed3b-4e63-9b35-78893060758a', - * encounterProviders: [], - * visit: { - * patient: '1fdaa696-e759-4a7d-a066-f1ae557c151b', - * visitType: '7b0f5697-27e3-40c4-8bae-f4049abfb4ed', - * startDatetime: '2023-05-25T06:08:25.000+0000', - * stopDatetime: '2023-05-25T06:09:25.000+0000', - * }, - * }) - * @function - * @public - * @param {object} data - Data parameters of the encounter - * @param {function} [callback] - Optional callback to handle the response - * @returns {Operation} - */ -export function createEncounter(data, callback = s => s) { - return async state => { - const [resolvedData] = expandReferences(state, data); - - console.log(`Creating an encounter.`); - - const response = await request( - state, - 'POST', - '/ws/rest/v1/encounter', - resolvedData - ); - - console.log(`Created encounter with new UUID: ${response.body.id}`); - return prepareNextState(state, response, callback); - }; -} - /** * Make a get request to any OpenMRS endpoint * @example @@ -219,56 +179,6 @@ export function searchPerson(query, callback = s => s) { }; } -/** - * Creates a new patient - * @example - * createPatient({ - * identifiers: [ - * { - * identifier: '4023287', - * identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334', - * preferred: true, - * }, - * ], - * person: { - * gender: 'M', - * age: 42, - * birthdate: '1970-01-01T00:00:00.000+0100', - * birthdateEstimated: false, - * names: [ - * { - * givenName: 'Doe', - * familyName: 'John', - * }, - * ], - * }, - * }) - * @function - * @public - * @param {object} data - Object parameters of the patient - * @param {function} [callback] - Optional callback to handle the response - * @returns {Operation} - */ -export function createPatient(data, callback = s => s) { - return async state => { - const [resolvedData] = expandReferences(state, data); - console.log(`Creating a patient.`); - - const response = await request( - state, - 'POST', - '/ws/rest/v1/person', - resolvedData - ); - - console.log( - `Successfully created a patient with UUID: ${response?.body?.uuid}` - ); - - return prepareNextState(state, response, callback); - }; -} - /** * Gets encounter matching a uuid * @example @@ -353,6 +263,42 @@ export function getEncounters(query, callback = s => s) { * }, * ], * }); + * @example Create an encounter + * create("encounter", { + * encounterDatetime: '2023-05-25T06:08:25.000+0000', + * patient: '1fdaa696-e759-4a7d-a066-f1ae557c151b', + * encounterType: 'dd528487-82a5-4082-9c72-ed246bd49591', + * location: 'ba685651-ed3b-4e63-9b35-78893060758a', + * encounterProviders: [], + * visit: { + * patient: '1fdaa696-e759-4a7d-a066-f1ae557c151b', + * visitType: '7b0f5697-27e3-40c4-8bae-f4049abfb4ed', + * startDatetime: '2023-05-25T06:08:25.000+0000', + * stopDatetime: '2023-05-25T06:09:25.000+0000', + * }, + * }) + * @example Create a patient + * create("patient", { + * identifiers: [ + * { + * identifier: '4023287', + * identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334', + * preferred: true, + * }, + * ], + * person: { + * gender: 'M', + * age: 42, + * birthdate: '1970-01-01T00:00:00.000+0100', + * birthdateEstimated: false, + * names: [ + * { + * givenName: 'Doe', + * familyName: 'John', + * }, + * ], + * }, + * }) */ export function create(resourceType, data, callback = s => s) { return async state => { diff --git a/packages/openmrs/test/index.js b/packages/openmrs/test/index.js index 3f381a278..5c7269583 100644 --- a/packages/openmrs/test/index.js +++ b/packages/openmrs/test/index.js @@ -5,6 +5,7 @@ import { request } from '../src/Utils'; import { get, post, + create, execute, getPatient, searchPerson, @@ -223,6 +224,47 @@ describe('post', () => { }); }); +describe('create', () => { + it('should create a patient', async () => { + testServer + .intercept({ + path: '/ws/rest/v1/patient', + method: 'POST', + }) + .reply(200, ({ body }) => body, { + ...jsonHeaders, + }); + + const patient = { + identifiers: [ + { + identifier: '4023287', + identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334', + preferred: true, + }, + ], + person: { + gender: 'M', + age: 42, + birthdate: '1970-01-01T00:00:00.000+0100', + birthdateEstimated: false, + names: [ + { + givenName: 'Doe', + familyName: 'John', + }, + ], + }, + }; + const state = { configuration, patient }; + const { data } = await execute(create('patient', state => state.patient))( + state + ); + + expect(data).to.eql(patient); + }); +}); + describe('getPatient', () => { it('should get a patient by uuid', async () => { testServer From f9c6400e50ef98692359682317ea3c7ea15b02fd Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 14:58:16 +0300 Subject: [PATCH 15/24] update changeset --- .changeset/wicked-carrots-whisper.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/.changeset/wicked-carrots-whisper.md b/.changeset/wicked-carrots-whisper.md index 2dd334d64..c0f875dc2 100644 --- a/.changeset/wicked-carrots-whisper.md +++ b/.changeset/wicked-carrots-whisper.md @@ -1,5 +1,27 @@ --- -'@openfn/language-openmrs': minor +'@openfn/language-openmrs': major --- - Add pagination support on request helper function +- Remove `createEncounter` and `createPatient` functions + +### Breaking Changes + +The `createEncounter` and `createPatient` functions have been removed from the +OpenMRS adaptor. These functions were used to create new encounters and +patients. If you need to create new encounter or patient, you can use the +`create` function with the appropriate resource type. + +Fore example, to create a new encounter, you can use the following code: + +```js +create('encounter', $.encounter); +// $.encounter is an object that contains the encounter data +``` + +To create a new patient, you can use the following code: + +```js +create('patient', $.patient); +// $.patient is an object that contains the patient data +``` From cc8e5c40ce9fa6a02a81649755517b1d7c646efc Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 14:59:08 +0300 Subject: [PATCH 16/24] update docs --- packages/openmrs/ast.json | 123 ++++---------------------------------- 1 file changed, 10 insertions(+), 113 deletions(-) diff --git a/packages/openmrs/ast.json b/packages/openmrs/ast.json index bfbe00071..274d1ca2f 100644 --- a/packages/openmrs/ast.json +++ b/packages/openmrs/ast.json @@ -57,63 +57,6 @@ }, "valid": true }, - { - "name": "createEncounter", - "params": [ - "data", - "callback" - ], - "docs": { - "description": "Creates an encounter", - "tags": [ - { - "title": "example", - "description": "createEncounter({\n encounterDatetime: '2023-05-25T06:08:25.000+0000',\n patient: '1fdaa696-e759-4a7d-a066-f1ae557c151b',\n encounterType: 'dd528487-82a5-4082-9c72-ed246bd49591',\n location: 'ba685651-ed3b-4e63-9b35-78893060758a',\n encounterProviders: [],\n visit: {\n patient: '1fdaa696-e759-4a7d-a066-f1ae557c151b',\n visitType: '7b0f5697-27e3-40c4-8bae-f4049abfb4ed',\n startDatetime: '2023-05-25T06:08:25.000+0000',\n stopDatetime: '2023-05-25T06:09:25.000+0000',\n },\n})", - "caption": "Create an encounter" - }, - { - "title": "function", - "description": null, - "name": null - }, - { - "title": "public", - "description": null, - "type": null - }, - { - "title": "param", - "description": "Data parameters of the encounter", - "type": { - "type": "NameExpression", - "name": "object" - }, - "name": "data" - }, - { - "title": "param", - "description": "Optional callback to handle the response", - "type": { - "type": "OptionalType", - "expression": { - "type": "NameExpression", - "name": "function" - } - }, - "name": "callback" - }, - { - "title": "returns", - "description": null, - "type": { - "type": "NameExpression", - "name": "Operation" - } - } - ] - }, - "valid": true - }, { "name": "get", "params": [ @@ -358,62 +301,6 @@ }, "valid": true }, - { - "name": "createPatient", - "params": [ - "data", - "callback" - ], - "docs": { - "description": "Creates a new patient", - "tags": [ - { - "title": "example", - "description": "createPatient({\n identifiers: [\n {\n identifier: '4023287',\n identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334',\n preferred: true,\n },\n ],\n person: {\n gender: 'M',\n age: 42,\n birthdate: '1970-01-01T00:00:00.000+0100',\n birthdateEstimated: false,\n names: [\n {\n givenName: 'Doe',\n familyName: 'John',\n },\n ],\n },\n})" - }, - { - "title": "function", - "description": null, - "name": null - }, - { - "title": "public", - "description": null, - "type": null - }, - { - "title": "param", - "description": "Object parameters of the patient", - "type": { - "type": "NameExpression", - "name": "object" - }, - "name": "data" - }, - { - "title": "param", - "description": "Optional callback to handle the response", - "type": { - "type": "OptionalType", - "expression": { - "type": "NameExpression", - "name": "function" - } - }, - "name": "callback" - }, - { - "title": "returns", - "description": null, - "type": { - "type": "NameExpression", - "name": "Operation" - } - } - ] - }, - "valid": true - }, { "name": "getEncounter", "params": [ @@ -588,6 +475,16 @@ "title": "example", "description": "create(\"person\", {\n names: [\n {\n givenName: \"Mohit\",\n familyName: \"Kumar\",\n },\n ],\n gender: \"M\",\n birthdate: \"1997-09-02\",\n addresses: [\n {\n address1: \"30, Vivekananda Layout, Munnekolal,Marathahalli\",\n cityVillage: \"Bengaluru\",\n country: \"India\",\n postalCode: \"560037\",\n },\n ],\n});", "caption": "Create a person" + }, + { + "title": "example", + "description": "create(\"encounter\", {\n encounterDatetime: '2023-05-25T06:08:25.000+0000',\n patient: '1fdaa696-e759-4a7d-a066-f1ae557c151b',\n encounterType: 'dd528487-82a5-4082-9c72-ed246bd49591',\n location: 'ba685651-ed3b-4e63-9b35-78893060758a',\n encounterProviders: [],\n visit: {\n patient: '1fdaa696-e759-4a7d-a066-f1ae557c151b',\n visitType: '7b0f5697-27e3-40c4-8bae-f4049abfb4ed',\n startDatetime: '2023-05-25T06:08:25.000+0000',\n stopDatetime: '2023-05-25T06:09:25.000+0000',\n },\n})", + "caption": "Create an encounter" + }, + { + "title": "example", + "description": "create(\"patient\", {\n identifiers: [\n {\n identifier: '4023287',\n identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334',\n preferred: true,\n },\n ],\n person: {\n gender: 'M',\n age: 42,\n birthdate: '1970-01-01T00:00:00.000+0100',\n birthdateEstimated: false,\n names: [\n {\n givenName: 'Doe',\n familyName: 'John',\n },\n ],\n },\n})", + "caption": "Create a patient" } ] }, From bf6887c3d9688375eecfc86b3678c8ccea36ec21 Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 15:06:43 +0300 Subject: [PATCH 17/24] add if..else in allResponse assignment --- packages/openmrs/src/Utils.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/openmrs/src/Utils.js b/packages/openmrs/src/Utils.js index 1659d3328..4bd26d4b8 100644 --- a/packages/openmrs/src/Utils.js +++ b/packages/openmrs/src/Utils.js @@ -40,10 +40,11 @@ export async function request(state, method, path, data, params) { const response = await commonRequest(method, url, requestOptions); logResponse(response); - allResponses - ? allResponses.body.results.push(...response.body.results) - : (allResponses = response); - + if (allResponses) { + allResponses.body.results.push(...response.body.results); + } else { + allResponses = response; + } const nextUrl = response?.body?.links?.find( link => link.rel === 'next' )?.uri; From 58e7fb18400245e1bdb08bad09ddaffdbb010b6d Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 15:07:12 +0300 Subject: [PATCH 18/24] assert body.results.length === 1 --- packages/openmrs/test/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/openmrs/test/index.js b/packages/openmrs/test/index.js index 3f381a278..3883f7bf9 100644 --- a/packages/openmrs/test/index.js +++ b/packages/openmrs/test/index.js @@ -173,6 +173,7 @@ describe('request', () => { ); expect(body.results[0].display).to.eql('Sarah 2'); + expect(body.results.length).to.eql(1); }); }); From a1696314596891e2ed153ebddd41dc07ce386ebc Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 15:33:00 +0300 Subject: [PATCH 19/24] update changeset --- .changeset/wicked-carrots-whisper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/wicked-carrots-whisper.md b/.changeset/wicked-carrots-whisper.md index c0f875dc2..b8cd55e9d 100644 --- a/.changeset/wicked-carrots-whisper.md +++ b/.changeset/wicked-carrots-whisper.md @@ -5,7 +5,7 @@ - Add pagination support on request helper function - Remove `createEncounter` and `createPatient` functions -### Breaking Changes +### Migration Guide The `createEncounter` and `createPatient` functions have been removed from the OpenMRS adaptor. These functions were used to create new encounters and From 6d9f29269895430ce1dd1814666b3f0ead626a9c Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 15:33:22 +0300 Subject: [PATCH 20/24] rename test to index.test.js --- packages/openmrs/test/fixtures.json | 36 +++++++++ .../openmrs/test/{index.js => index.test.js} | 81 ++++++++++--------- 2 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 packages/openmrs/test/fixtures.json rename packages/openmrs/test/{index.js => index.test.js} (84%) diff --git a/packages/openmrs/test/fixtures.json b/packages/openmrs/test/fixtures.json new file mode 100644 index 000000000..ec55035c4 --- /dev/null +++ b/packages/openmrs/test/fixtures.json @@ -0,0 +1,36 @@ +{ + "patient": { + "identifiers": [ + { + "identifier": "4023287", + "identifierType": "05a29f94-c0ed-11e2-94be-8c13b969e334", + "preferred": true + } + ], + "person": { + "gender": "M", + "age": 42, + "birthdate": "1970-01-01T00:00:00.000+0100", + "birthdateEstimated": false, + "names": [ + { + "givenName": "Doe", + "familyName": "John" + } + ] + } + }, + "encounter": { + "patient": "1fdaa696-e759-4a7d-a066-f1ae557c151b", + "encounterDatetime": "2023-05-25T06:08:25.000+0000", + "encounterType": "dd528487-82a5-4082-9c72-ed246bd49591", + "location": "ba685651-ed3b-4e63-9b35-78893060758a", + "encounterProviders": [], + "visit": { + "patient": "1fdaa696-e759-4a7d-a066-f1ae557c151b", + "visitType": "7b0f5697-27e3-40c4-8bae-f4049abfb4ed", + "startDatetime": "2023-05-25T06:08:25.000+0000", + "stopDatetime": "2023-05-25T06:09:25.000+0000" + } + } +} \ No newline at end of file diff --git a/packages/openmrs/test/index.js b/packages/openmrs/test/index.test.js similarity index 84% rename from packages/openmrs/test/index.js rename to packages/openmrs/test/index.test.js index 5c7269583..a2205fe38 100644 --- a/packages/openmrs/test/index.js +++ b/packages/openmrs/test/index.test.js @@ -1,6 +1,7 @@ import { enableMockClient } from '@openfn/language-common/util'; import { expect } from 'chai'; import { request } from '../src/Utils'; +import testData from './fixtures.json' assert { type: 'json' }; import { get, @@ -204,23 +205,13 @@ describe('post', () => { ...jsonHeaders, }); - const state = { configuration }; - const { data } = await execute( - post('encounter', { - patient: '123', - encounterType: '123', - location: '123', - encounterProviders: [], - visit: { - patient: '123', - visitType: '123', - startDatetime: '2023-05-25T06:08:25.000+0000', - stopDatetime: '2023-05-25T06:09:25.000+0000', - }, - }) - )(state); + const { encounter } = testData; + const state = { configuration, encounter }; + const { data } = await execute(post('encounter', state => state.encounter))( + state + ); - expect(data.patient).to.eql('123'); + expect(data.patient).to.eql('1fdaa696-e759-4a7d-a066-f1ae557c151b'); }); }); @@ -235,27 +226,7 @@ describe('create', () => { ...jsonHeaders, }); - const patient = { - identifiers: [ - { - identifier: '4023287', - identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334', - preferred: true, - }, - ], - person: { - gender: 'M', - age: 42, - birthdate: '1970-01-01T00:00:00.000+0100', - birthdateEstimated: false, - names: [ - { - givenName: 'Doe', - familyName: 'John', - }, - ], - }, - }; + const { patient } = testData; const state = { configuration, patient }; const { data } = await execute(create('patient', state => state.patient))( state @@ -263,6 +234,42 @@ describe('create', () => { expect(data).to.eql(patient); }); + it('should throw an error if the resource is not found', async () => { + testServer + .intercept({ + path: '/ws/rest/v1/wrong-resource', + method: 'POST', + }) + .reply(404, { error: 'Not Found' }, { ...jsonHeaders }); + + const state = { configuration }; + try { + await execute(create('wrong-resource'))(state); + } catch (error) { + expect(error.body.error).to.eql('Not Found'); + } + }); + it('should expand references', async () => { + const { patient } = testData; + testServer + .intercept({ + path: '/ws/rest/v1/patient', + method: 'POST', + }) + .reply( + 200, + ({ body }) => { + expect(body).to.eql(JSON.stringify(patient)); + return body; + }, + { + ...jsonHeaders, + } + ); + + const state = { configuration, patient }; + await execute(create('patient', state => state.patient))(state); + }); }); describe('getPatient', () => { From 8b2effc82dbacbccbd27a28210279105afc6fc92 Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Wed, 11 Sep 2024 17:58:15 +0300 Subject: [PATCH 21/24] update changeset --- .changeset/wicked-carrots-whisper.md | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/.changeset/wicked-carrots-whisper.md b/.changeset/wicked-carrots-whisper.md index b8cd55e9d..2d36ef2a0 100644 --- a/.changeset/wicked-carrots-whisper.md +++ b/.changeset/wicked-carrots-whisper.md @@ -8,20 +8,4 @@ ### Migration Guide The `createEncounter` and `createPatient` functions have been removed from the -OpenMRS adaptor. These functions were used to create new encounters and -patients. If you need to create new encounter or patient, you can use the -`create` function with the appropriate resource type. - -Fore example, to create a new encounter, you can use the following code: - -```js -create('encounter', $.encounter); -// $.encounter is an object that contains the encounter data -``` - -To create a new patient, you can use the following code: - -```js -create('patient', $.patient); -// $.patient is an object that contains the patient data -``` +OpenMRS adaptor. Use the `create` function with the appropriate resource type. From cff65e6d3573fbd9a2a672c9318731e383f532e6 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Wed, 11 Sep 2024 16:16:53 +0100 Subject: [PATCH 22/24] fix changelog --- .changeset/wicked-carrots-whisper.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.changeset/wicked-carrots-whisper.md b/.changeset/wicked-carrots-whisper.md index 2d36ef2a0..7a04efc16 100644 --- a/.changeset/wicked-carrots-whisper.md +++ b/.changeset/wicked-carrots-whisper.md @@ -9,3 +9,15 @@ The `createEncounter` and `createPatient` functions have been removed from the OpenMRS adaptor. Use the `create` function with the appropriate resource type. + +To create a new encounter, you can use the following code: + +```js +create('encounter', $.encounter); +``` + +To create a new patient, you can use the following code: + +```js +create('patient', $.patient); +``` From 15698f989b27e5f56c6bce29e02063b730a8d9d4 Mon Sep 17 00:00:00 2001 From: Emmanuel Evance Date: Thu, 12 Sep 2024 10:41:33 +0300 Subject: [PATCH 23/24] update changelog and bump version --- .changeset/light-forks-arrive.md | 5 ----- .changeset/wicked-carrots-whisper.md | 23 ---------------------- packages/openmrs/CHANGELOG.md | 29 ++++++++++++++++++++++++++++ packages/openmrs/package.json | 2 +- 4 files changed, 30 insertions(+), 29 deletions(-) delete mode 100644 .changeset/light-forks-arrive.md delete mode 100644 .changeset/wicked-carrots-whisper.md diff --git a/.changeset/light-forks-arrive.md b/.changeset/light-forks-arrive.md deleted file mode 100644 index dd8dc3499..000000000 --- a/.changeset/light-forks-arrive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@openfn/language-openmrs': minor ---- - -Add cursor and dateFns helper functions diff --git a/.changeset/wicked-carrots-whisper.md b/.changeset/wicked-carrots-whisper.md deleted file mode 100644 index 7a04efc16..000000000 --- a/.changeset/wicked-carrots-whisper.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@openfn/language-openmrs': major ---- - -- Add pagination support on request helper function -- Remove `createEncounter` and `createPatient` functions - -### Migration Guide - -The `createEncounter` and `createPatient` functions have been removed from the -OpenMRS adaptor. Use the `create` function with the appropriate resource type. - -To create a new encounter, you can use the following code: - -```js -create('encounter', $.encounter); -``` - -To create a new patient, you can use the following code: - -```js -create('patient', $.patient); -``` diff --git a/packages/openmrs/CHANGELOG.md b/packages/openmrs/CHANGELOG.md index 43a491bd6..836ecf649 100644 --- a/packages/openmrs/CHANGELOG.md +++ b/packages/openmrs/CHANGELOG.md @@ -1,5 +1,34 @@ # @openfn/language-openmrs +## 4.0.0 + +### Major Changes + +- 91c7972: - Add pagination support on request helper function + + - Remove `createEncounter` and `createPatient` functions + + ### Migration Guide + + The `createEncounter` and `createPatient` functions have been removed from the + OpenMRS adaptor. Use the `create` function with the appropriate resource type. + + To create a new encounter, you can use the following code: + + ```js + create('encounter', $.encounter); + ``` + + To create a new patient, you can use the following code: + + ```js + create('patient', $.patient); + ``` + +### Minor Changes + +- c8dbd21: Add cursor and dateFns helper functions + ## 3.1.4 ### Patch Changes diff --git a/packages/openmrs/package.json b/packages/openmrs/package.json index 0ae4c9cda..600cf2999 100644 --- a/packages/openmrs/package.json +++ b/packages/openmrs/package.json @@ -1,6 +1,6 @@ { "name": "@openfn/language-openmrs", - "version": "3.1.4", + "version": "4.0.0", "description": "OpenMRS Language Pack for OpenFn", "homepage": "https://docs.openfn.org", "repository": { From 24c984e79e504c20bf2f8bda29a8a08c331e8f5c Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Thu, 12 Sep 2024 09:54:54 +0100 Subject: [PATCH 24/24] openrms: update changelog --- packages/openmrs/CHANGELOG.md | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/packages/openmrs/CHANGELOG.md b/packages/openmrs/CHANGELOG.md index 836ecf649..8cf940d62 100644 --- a/packages/openmrs/CHANGELOG.md +++ b/packages/openmrs/CHANGELOG.md @@ -4,30 +4,29 @@ ### Major Changes -- 91c7972: - Add pagination support on request helper function +- Remove `createEncounter` and `createPatient` functions +- Add pagination support on request helper function - - Remove `createEncounter` and `createPatient` functions +### Minor Changes - ### Migration Guide +- c8dbd21: Add cursor and dateFns helper functions - The `createEncounter` and `createPatient` functions have been removed from the - OpenMRS adaptor. Use the `create` function with the appropriate resource type. +### Migration Guide - To create a new encounter, you can use the following code: +The `createEncounter` and `createPatient` functions have been removed from the +OpenMRS adaptor. Use the `create` function with the appropriate resource type. - ```js - create('encounter', $.encounter); - ``` +To create a new encounter, you can use the following code: - To create a new patient, you can use the following code: +```js +create('encounter', $.encounter); +``` - ```js - create('patient', $.patient); - ``` +To create a new patient, you can use the following code: -### Minor Changes - -- c8dbd21: Add cursor and dateFns helper functions +```js +create('patient', $.patient); +``` ## 3.1.4