Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RN-403 Clean up data services configuration #3783

Merged
merged 31 commits into from
Aug 5, 2022

Conversation

IgorNadj
Copy link
Contributor

@IgorNadj IgorNadj commented Mar 15, 2022

RN-403

Background:

#3783 (comment)

This is phase 1 of refactoring isDataRegional style config values.

Phase 1: data_element & data_group
Phase 2+: entity based resolution, detectDataServices, dhis_sync_queue, legacy report configs, legacy map overlay configs

Changes:

Phase 1 changes:

  • Migrate data_source config isDataRegional: bool -> dhisInstanceCode: string|null
  • Create DhisInstance as a first class model
  • Rename @tupaia/utils/dhis.js functions to legacy_*
  • Create new classes and functions in Data Broker which resolve which Dhis Instance to use

@IgorNadj IgorNadj marked this pull request as draft March 15, 2022 06:22
@IgorNadj IgorNadj force-pushed the rn-403-clean-up-data-services branch from fb18438 to ba2f6a2 Compare May 13, 2022 06:54
@IgorNadj IgorNadj marked this pull request as ready for review May 16, 2022 00:20
@IgorNadj IgorNadj changed the title Refactor: deprecate getDhisConfig Clean up data services configuration May 16, 2022
@@ -94,8 +94,8 @@ const SURVEY_COLUMNS = [
editConfig: {
options: SERVICE_TYPES,
setFieldsOnChange: (newValue, currentRecord) => {
const { isDataRegional = true } = currentRecord['data_source.config'];
const config = newValue === 'dhis' ? { isDataRegional } : {};
const { dhisInstanceCode = 'regional' } = currentRecord['data_source.config'];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throughout the codebase we hardcode which Dhis Instance should be the default. I have not cleaned this up, the PR was already getting too big, will leave for a separate PR in the future.

@@ -0,0 +1,8 @@
/**
Copy link
Contributor Author

@IgorNadj IgorNadj May 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existence of this file in __mocks__ tells jest to auto mock the utils package. The alternative of doing it in the test file itself doesn't work due to a limitation of jest.


return dhisApi;
export const stubGetDhisApi = mockDhisApi => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split this into two functions because we don't always need to stub as well as mock this import.

];

/**
* DataSources and Entities are linked to a specific DHIS server in many ways:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main explainer for how things work... FYI

@IgorNadj IgorNadj changed the title Clean up data services configuration RN-403 Clean up data services configuration May 16, 2022
Copy link
Collaborator

@rohan-bes rohan-bes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's looking really good man! Thanks so much for doing this!

Just a few comments, I might give this one a second pass. But first I was hoping we could have a bit of a high level chat? You've added dhis_instances here as a concept, but I had maybe thought we'd be adding data_services as a concept, where a data service could be:

  1. A specific dhis2 instance
  2. A data-lake instance
  3. The internal data-api instance
  4. etc.

Basically where we currently have data sources attached to a 'service type', they'd instead be linked to a specific service instance, which we could have many of.

Now all that wouldn't necessarily be in scope here, and we'd still need to use a lot of this cleanup code you've written anyway. Either way lets chat about it on Thursday and share thoughts?

* class model. We link data_source to dhis_instance via config option `data_source.config.dhisInstanceCode: <string>`.
*
* For entity based resolution, where previously we had isDataRegional = false, we now leave dhisInstanceCode
* not set, which indicates no specific dhisInstance, and that we need to resolve it from the entity.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be keen to chat on how we think we might wanna resolve this one in the long run? It's a bit of an awkward practice, and one that I think we've really moved away from. But there's still a lot of data elements that are present in multiple DHIS2 instances...

Copy link
Contributor Author

@IgorNadj IgorNadj May 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +60 to +74
const allDhisInstanceCodes = new Set();
const allDhisInstances = [];
for (const entityCode of entityCodes) {
const dhisInstance = await this.resolveSingleEntityCode(entityCode);
allDhisInstanceCodes.add(dhisInstance.code);
allDhisInstances.push(dhisInstance);
}
if (allDhisInstanceCodes.size > 1) {
throw new Error(
`All entities must use the same DHIS2 instance (got [${[...allDhisInstanceCodes].join(
',',
)}])`,
);
}
return allDhisInstances[0];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const allDhisInstanceCodes = new Set();
const allDhisInstances = [];
for (const entityCode of entityCodes) {
const dhisInstance = await this.resolveSingleEntityCode(entityCode);
allDhisInstanceCodes.add(dhisInstance.code);
allDhisInstances.push(dhisInstance);
}
if (allDhisInstanceCodes.size > 1) {
throw new Error(
`All entities must use the same DHIS2 instance (got [${[...allDhisInstanceCodes].join(
',',
)}])`,
);
}
return allDhisInstances[0];
const serverName = await legacy_getDhisServerName({
isDataRegional: false,
entityCodes,
});
return this.getFromServerName(serverName);

Would this work? Just cos legacy_getDhisServerName() takes entityCodes and already does the validation to ensure they all use the same serverName..?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left this as multiple single calls to legacy_getDhisServerName to make mocking easier. This way we can have a test in data-broker to make sure an error gets thrown if it resolves to multiple dhis servers. I thought about having this test in utils, on the legacy_getDhisServerName function, but I thought it might make more sense to have it on the non-legacy side of the codebase rather than the legacy side. I think the reason was that the legacy side is really hard to write tests for because mocking is hard. As this class should disappear once the data is cleaned up, are you happy to leave as is?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup that sounds reasonable to me 👍

Copy link
Collaborator

@rohan-bes rohan-bes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @IgorNadj this is a great step forward! Hopefully we can pick up and carry on with phase 2 before too long.

A small comment from the first pass, but overall really happy and approving. Really appreciate the tests and comments btw (this is all becoming rather arcane knowledge)

Thoughts around testing on this? What's the regression risk looking like? Obviously there's a bunch of vizes... Does this break older survey import files too?

fieldName: 'dhisInstanceCode',
optionsEndpoint: 'dhisInstances',
optionLabelKey: 'dhisInstances.code',
optionValueKey: 'dhisInstances.code',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reckon it's a tad awkward to leave this field empty if using country specific server? The code kinda forces us in this direction tho huh? Might be nice if we could have a 'Country specific server' option in the UI which sets it as undefined in the backend...

Copy link
Contributor Author

@IgorNadj IgorNadj May 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't love it either. Were you thinking something like this? https://linear.app/bes/issue/RN-403#comment-deae01b8

I have set this field label to "DHIS Server", and this should encourage people to fill it out.

As we don't need the entity based resolution functionality (In this investigation I confirmed we don't have any data elements that are stored on multiple DHIS Servers, so there is a 1:1 map), after changing all of these from null to a specific DHIS Server, I will create a new PR to set this column to NOT NULL.

Here is the new card for this cleanup: https://linear.app/bes/issue/RN-558/specify-dhis-server-explicitly

Comment on lines 8 to 13
const areDifferentAllowingNull = (a, b) => {
if (a === null && b === null) return false;
if (a === null && b !== null) return true;
if (a !== null && b === null) return true;
return a !== b;
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiousity, how is this different to a !== b? null !== null => false right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good catch, updated.

packages/data-broker/src/__mocks__/utils.js Show resolved Hide resolved
packages/utils/src/legacyDhis.js Show resolved Hide resolved
@IgorNadj
Copy link
Contributor Author

You've added dhis_instances here as a concept, but I had maybe thought we'd be adding data_services as a concept

Discussed, data_service was the plan originally, but it wound up being harder than expected because doing so would mean removing data_source.service_type which would mean lots of changes throughout the codebase to find the service type for a data source, converting sync code to async for the lookup etc. We still want to do this, I just reduced the scope of this PR to get a chewable bite out of the problem.

@IgorNadj
Copy link
Contributor Author

IgorNadj commented Jun 3, 2022

TODO: remove ability for users to import/set dhisInstanceCode as null. We don't want new dataElements/groups to use entity based resolution. There are no cases where want to do this out of necessity where a DE/DG lives on multiple DHIS Servers legitimately: https://linear.app/bes/issue/RN-537#comment-bf70ca96

Have created a cleanup card, after which I will create a new PR to not allow null.

@IgorNadj IgorNadj force-pushed the rn-403-clean-up-data-services branch from ef6e5f0 to c5ee57b Compare June 16, 2022 01:51
@IgorNadj
Copy link
Contributor Author

Have rebased on dev, fixed up PR from feedback.

@IgorNadj IgorNadj requested a review from rohan-bes June 16, 2022 01:52
Copy link
Collaborator

@rohan-bes rohan-bes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff @IgorNadj really appreciate all this work!

@IgorNadj IgorNadj force-pushed the rn-403-clean-up-data-services branch from db491d7 to f6413a5 Compare August 5, 2022 03:44
@IgorNadj IgorNadj merged commit 9ca901c into dev Aug 5, 2022
@IgorNadj IgorNadj deleted the rn-403-clean-up-data-services branch August 5, 2022 05:56
@IgorNadj IgorNadj mentioned this pull request Aug 5, 2022
3 tasks
@chris-pollard chris-pollard mentioned this pull request Aug 8, 2022
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants