Skip to content

Commit 92e0b72

Browse files
dhis2: Add paging examples and default async:false in tracker.import (#1681)
* feat: allow async value change Signed-off-by: Hunter Achieng <achienghunter@gmail.com> * feat: update tests Signed-off-by: Hunter Achieng <achienghunter@gmail.com> * feat: add changeset Signed-off-by: Hunter Achieng <achienghunter@gmail.com> * add integration tests for tracker.export * add pagination example * update example * update integration test * improve format * remove async and add pagination docs * update tracker unit tests * update changeset * fix typo * fix: update chngeset and tracker pagination examples Signed-off-by: Hunter Achieng <achienghunter@gmail.com> * fix: update docs Signed-off-by: Hunter Achieng <achienghunter@gmail.com> --------- Signed-off-by: Hunter Achieng <achienghunter@gmail.com> Co-authored-by: Emmanuel Evance <mtuchidev@gmail.com>
1 parent 8ddd143 commit 92e0b72

4 files changed

Lines changed: 262 additions & 82 deletions

File tree

.changeset/hip-planes-see.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@openfn/language-dhis2': minor
3+
---
4+
5+
Add async option to `tracker.import`.
6+
Improve `tracker.export` docs by adding a pagination example and
7+
linking pagination query parameters.

packages/dhis2/src/tracker.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import * as util from './util.js';
4747
* @param {string} strategy - The effect the import should have. Can either be CREATE, UPDATE, CREATE_AND_UPDATE and DELETE.
4848
* @param {object} payload - The data to be imported.
4949
* @param {TrackerOptions} [options] - An optional object containing parseAs, and apiVersion, and queries for the request
50+
* @param {boolean} [options.async=false] - Whether to perform the import asynchronously. Defaults to false. See [Sync and async imports](https://docs.dhis2.org/en/develop/using-the-api/dhis-core-version-master/tracker.html#sync-and-async)
5051
* @state {DHIS2State}
5152
* @returns {Operation}
5253
*/
@@ -57,7 +58,7 @@ function _import(strategy, payload, options = {}) {
5758
const [resolvedStrategy, resolvedPayload, resolvedOptions] =
5859
expandReferences(state, strategy, payload, options);
5960

60-
const { apiVersion, parseAs, ...query } = resolvedOptions;
61+
const { apiVersion, parseAs, async = false, ...query } = resolvedOptions;
6162

6263
const response = await util.request(state.configuration, {
6364
method: 'POST',
@@ -67,14 +68,14 @@ function _import(strategy, payload, options = {}) {
6768
...resolvedOptions,
6869
resolvedStrategy,
6970
},
70-
'tracker'
71+
'tracker',
7172
),
7273
options: {
7374
apiVersion,
7475
parseAs,
7576
query: {
7677
...query,
77-
async: false,
78+
async,
7879
},
7980
},
8081
data: resolvedPayload,
@@ -95,37 +96,38 @@ export { _import as import };
9596
* @example <caption>Export all enrollment resources</caption>
9697
* tracker.export('enrollments', {orgUnit: 'TSyzvBiovKh'});
9798
* @example <caption>Export all events</caption>
98-
* tracker.export('events')
99+
* tracker.export('events', { paging: false})
100+
* @example <caption>Export the first page of events with pagination metadata</caption>
101+
* tracker.export('events', { totalPages: true, pageSize: 1000, page: 1 })
99102
* @function
100103
* @param {string} path - Path to the resource, relative to the /tracker endpoint
101-
* @param {object} query - An object of query parameters to be encoded into the URL
104+
* @param {object} query - An object of query parameters to be encoded into the URL. Can include [pagination parameters](https://docs.dhis2.org/en/develop/using-the-api/dhis-core-version-master/tracker.html#request-parameters-for-pagination), filters, etc.
102105
* @param {TrackerOptions} [options] - An optional object containing parseAs, and apiVersion for the request
103106
* @state {DHIS2State}
104107
* @returns {Operation}
105108
*/
106-
function _export(path, query, options = {}) {
109+
function _export(path, query = {}, options = {}) {
107110
return async state => {
108111
console.log('Preparing tracker export operation...');
109112

110113
const [resolvedPath, resolvedQuery, resolvedOptions] = expandReferences(
111114
state,
112115
path,
113116
query,
114-
options
117+
options,
115118
);
116119

117120
const response = await util.request(state.configuration, {
118121
method: 'GET',
119122
path: util.prefixVersionToPath(
120123
state.configuration,
121124
resolvedOptions,
122-
`tracker/${resolvedPath}`
125+
`tracker/${resolvedPath}`,
123126
),
124127
options: {
125128
...resolvedOptions,
126129
query: {
127130
...resolvedQuery,
128-
async: false,
129131
},
130132
},
131133
});

packages/dhis2/test/integration.js

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import { expect } from 'chai';
22
import crypto from 'node:crypto';
3-
import { execute, create, update, upsert, get } from '../dist/index.js';
3+
import {
4+
execute,
5+
tracker,
6+
combine,
7+
create,
8+
update,
9+
upsert,
10+
each,
11+
get,
12+
fn,
13+
} from '../src/index.js';
414

515
const getRandomProgramPayload = () => {
616
const name = crypto.randomBytes(16).toString('hex');
@@ -471,4 +481,71 @@ describe('Integration tests', () => {
471481
);
472482
});
473483
});
484+
describe('tracker', () => {
485+
it('should export 50 events by default', async () => {
486+
// v2.41+ for older version `skipPaging: true`
487+
const state = {
488+
configuration,
489+
};
490+
const finalState = await execute(tracker.export('events'))(state);
491+
492+
expect(finalState.data.instances.length).to.eql(50);
493+
}).timeout(2e4);
494+
495+
it('should export 1000 events with pageSize 1000', async () => {
496+
const state = {
497+
configuration,
498+
};
499+
const { data } = await execute(
500+
tracker.export('events', { totalPages: true, pageSize: 1e3 }),
501+
)(state);
502+
503+
expect(Object.keys(data).sort()).to.eql([
504+
'instances',
505+
'page',
506+
'pageCount',
507+
'pageSize',
508+
'total',
509+
]);
510+
expect(data.instances.length).to.eql(1000);
511+
}).timeout(2e4);
512+
513+
it('should export all events with pagination', async () => {
514+
const state = {
515+
configuration,
516+
};
517+
const { data, results } = await execute(
518+
tracker.export('events', { totalPages: true, pageSize: 1e4 }),
519+
fn(state => {
520+
console.log(Object.keys(state.data));
521+
state.results = state.data.instances;
522+
const { page, pageSize, pageCount, total } = state.data;
523+
const remainingPages = pageCount - page;
524+
525+
state.pages = Array.from(
526+
{ length: remainingPages },
527+
(_, i) => page + i + 1,
528+
);
529+
state.pageSize = pageSize;
530+
return state;
531+
}),
532+
533+
each(
534+
state => state.pages,
535+
combine(
536+
tracker.export('events', state => ({
537+
pageSize: state.pageSize,
538+
page: state.data,
539+
})),
540+
fn(state => {
541+
state.results = state.results.concat(state.data.instances);
542+
return state;
543+
}),
544+
),
545+
),
546+
)(state);
547+
548+
expect(results).to.be.greaterThan(3e4);
549+
}).timeout(5e4);
550+
});
474551
});

0 commit comments

Comments
 (0)