Skip to content
7 changes: 7 additions & 0 deletions .changeset/hip-planes-see.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@openfn/language-dhis2': minor
---

Add async option to `tracker.import`.
Improve `tracker.export` docs by adding a pagination example and
linking pagination query parameters.
20 changes: 11 additions & 9 deletions packages/dhis2/src/tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import * as util from './util.js';
* @param {string} strategy - The effect the import should have. Can either be CREATE, UPDATE, CREATE_AND_UPDATE and DELETE.
* @param {object} payload - The data to be imported.
* @param {TrackerOptions} [options] - An optional object containing parseAs, and apiVersion, and queries for the request
* @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)
* @state {DHIS2State}
* @returns {Operation}
*/
Expand All @@ -57,7 +58,7 @@ function _import(strategy, payload, options = {}) {
const [resolvedStrategy, resolvedPayload, resolvedOptions] =
expandReferences(state, strategy, payload, options);

const { apiVersion, parseAs, ...query } = resolvedOptions;
const { apiVersion, parseAs, async = false, ...query } = resolvedOptions;

const response = await util.request(state.configuration, {
method: 'POST',
Expand All @@ -67,14 +68,14 @@ function _import(strategy, payload, options = {}) {
...resolvedOptions,
resolvedStrategy,
},
'tracker'
'tracker',
),
options: {
apiVersion,
parseAs,
query: {
...query,
async: false,
async,
},
},
data: resolvedPayload,
Expand All @@ -95,37 +96,38 @@ export { _import as import };
* @example <caption>Export all enrollment resources</caption>
* tracker.export('enrollments', {orgUnit: 'TSyzvBiovKh'});
* @example <caption>Export all events</caption>
* tracker.export('events')
* tracker.export('events', { paging: false})
* @example <caption>Export the first page of events with pagination metadata</caption>
* tracker.export('events', { totalPages: true, pageSize: 1000, page: 1 })
* @function
* @param {string} path - Path to the resource, relative to the /tracker endpoint
* @param {object} query - An object of query parameters to be encoded into the URL
* @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.
* @param {TrackerOptions} [options] - An optional object containing parseAs, and apiVersion for the request
* @state {DHIS2State}
* @returns {Operation}
*/
function _export(path, query, options = {}) {
function _export(path, query = {}, options = {}) {
return async state => {
console.log('Preparing tracker export operation...');

const [resolvedPath, resolvedQuery, resolvedOptions] = expandReferences(
state,
path,
query,
options
options,
);

const response = await util.request(state.configuration, {
method: 'GET',
path: util.prefixVersionToPath(
state.configuration,
resolvedOptions,
`tracker/${resolvedPath}`
`tracker/${resolvedPath}`,
),
options: {
...resolvedOptions,
query: {
...resolvedQuery,
async: false,
},
},
});
Expand Down
79 changes: 78 additions & 1 deletion packages/dhis2/test/integration.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { expect } from 'chai';
import crypto from 'node:crypto';
import { execute, create, update, upsert, get } from '../dist/index.js';
import {
execute,
tracker,
combine,
create,
update,
upsert,
each,
get,
fn,
} from '../src/index.js';

const getRandomProgramPayload = () => {
const name = crypto.randomBytes(16).toString('hex');
Expand Down Expand Up @@ -471,4 +481,71 @@ describe('Integration tests', () => {
);
});
});
describe('tracker', () => {
it('should export 50 events by default', async () => {
// v2.41+ for older version `skipPaging: true`
const state = {
configuration,
};
const finalState = await execute(tracker.export('events'))(state);

expect(finalState.data.instances.length).to.eql(50);
}).timeout(2e4);

it('should export 1000 events with pageSize 1000', async () => {
const state = {
configuration,
};
const { data } = await execute(
tracker.export('events', { totalPages: true, pageSize: 1e3 }),
)(state);

expect(Object.keys(data).sort()).to.eql([
'instances',
'page',
'pageCount',
'pageSize',
'total',
]);
expect(data.instances.length).to.eql(1000);
}).timeout(2e4);

it('should export all events with pagination', async () => {
const state = {
configuration,
};
const { data, results } = await execute(
tracker.export('events', { totalPages: true, pageSize: 1e4 }),
fn(state => {
console.log(Object.keys(state.data));
state.results = state.data.instances;
const { page, pageSize, pageCount, total } = state.data;
const remainingPages = pageCount - page;

state.pages = Array.from(
{ length: remainingPages },
(_, i) => page + i + 1,
);
state.pageSize = pageSize;
return state;
}),

each(
state => state.pages,
combine(
tracker.export('events', state => ({
pageSize: state.pageSize,
page: state.data,
})),
fn(state => {
state.results = state.results.concat(state.data.instances);
return state;
}),
),
),
)(state);

expect(results).to.be.greaterThan(3e4);
}).timeout(5e4);
});
});
Loading
Loading