Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/hip-planes-see.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@openfn/language-dhis2': patch
---

Default `async:false` in `tracker.import` and add paging examples to
`tracker.export()`
44 changes: 35 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.
* @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,62 @@ 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 all events with pagination</caption>
* tracker.export('events', { totalPages: true, pageSize: 1e4 });
* fn(state => {
* state.results = state.data.instances;
* const { page, pageSize, pageCount, total } = state.data.pager;
* const remainingPages = pageCount - page;
*
* state.pages = Array.from({ length: remainingPages }, (_, i) => page + i + 1);
* state.pageSize = pageSize;
* return state;
* });
*
* each(
* $.pages,
* tracker
* .export('events', { pageSize: $.pageSize, page: $.data })
* .then(state => {
* state.results = state.results.concat(state.data.instances);
* return state;
* }),
* );
* @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, filters, etc.
* @param {number} [query.page=1] - Page number to return
* @param {number} [query.pageSize=50] - Number of results per page
* @param {boolean} [query.totalPages=false] - Whether to return total number of elements and pages
* @param {boolean} [query.paging=true] - Set to false to return all rows without paging
* @param {string} [query.order] - Comma-separated field:sortDirection pairs, e.g. `createdAt:desc`
* @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