Unable to alter state.data using alterState()

I get the error “Cannot read property ‘cha_msr’ of undefined” when attempting to run this script:

alterState(state => {
    state.data.cha_msr = {};
    state.data.cha_msr.meta_uuid = '1234';
    return state;
});

console.log('state.data.cha_msr.meta_uuid', state.data.cha_msr.meta_uuid);

Is it possible to add a value to the existing state.data object, and then access it later in the script?

Thanks.

1 Like

The tl;dr: (but please keep reading!!! :slight_smile: )

alterState(state => {
    state.data.cha_msr = {};
    state.data.cha_msr.meta_uuid = '1234';
    return state;
});

alterState(state => {
    console.log(state.data.cha_msr.meta_uuid)
    return state;
});

Great question! First, some background is definitely necessary. Please see:

  1. https://docs.openfn.org/documentation/jobs/understanding
  2. https://docs.openfn.org/documentation/jobs/operations

The big idea is that OpenFn is built around a series of operations that take some inputs (almost always including state) and return a Promise… this means that they intentionally block each other and when used properly, you can create long data pipelines that pass state from one operation to the next, waiting patiently for (and often using) the output of the previous operation as the input for the next.

So when you drop a naked console.log(...) in there, it’s actually getting evaluated at compile time, before you’ve done your alterState(...) and returned a new version of state. Wrapping that console.log in a proper operation (or using another operation) will do the trick. Assuming you’re using something like the dhis2 adaptor, I might refactor that code to look like:

alterState(state => (
    state.data.cha_msr = { meta_uuid = '1234' };
    return state;
});

createTEI({
  orgUnit: 'TSyzvBiovKh', // or whatever
  trackedEntityType: 'nEenWmSyUEp', // some type
  attributes: [{ attribute: 'lZGmxYbs97q', value: dataValue('cha_msr.meta_uuid') }, // your new thing!
})

The generic use case for this type of thing is:

get('/api/patientRegistry', { ...params });
post('/api/anotherService', { body: dataValue('somethingFromTheLastGET')});
alterState(state => {
  return {
    ...state,
    somethingComplex: state.data.homeVisits.filter(v => v.safeToRefer === 'true');
  }
});
post('/api/someFinalService', { body: state => state.somethingComplex });

You’re chaining these operations together to drive the workflow between a bunch of different systems, do data cleaning, mapping, transformation, etc.

Hope this helps! And keep the deep questions coming :mechanical_arm:

1 Like

Thanks @taylordowns2000 for the excellent explanation!

1 Like