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

(feat) O3-3049: adding evaluated historical expression support #226

Merged
merged 18 commits into from
May 9, 2024

Conversation

arodidev
Copy link
Contributor

@arodidev arodidev commented Apr 25, 2024

Requirements

  • This PR has a title that briefly describes the work done including the ticket number. If there is a ticket, make sure your PR title includes a conventional commit label. See existing PR titles for inspiration.
  • My work conforms to the OpenMRS 3.0 Styleguide and design documentation.
  • My work includes tests or is validated by existing tests.

Summary

This introduces the ability for the user to get the historical value (the field's previous value) based on an evaluated expression provided on the form's schema.

Screenshots

https://www.loom.com/share/5ee375006f1b4cf4b9fdf9fcbcf78bc4

Related Issue

Other

@arodidev
Copy link
Contributor Author

arodidev commented Apr 25, 2024

Extends logic in this PR

@arodidev arodidev changed the title (feat) adding evaluated historical expression support (feat) O3-3049: adding evaluated historical expression support Apr 26, 2024
Copy link
Member

@samuelmale samuelmale left a comment

Choose a reason for hiding this comment

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

@arodidev can we have some unit tests coverage around this?


interface FieldComponentMap {
fieldComponent: React.ComponentType<FormFieldProps>;
fieldDescriptor: FormField;
handler: SubmissionHandler;
}

const historicalValueTransformer = (field, obs) => {
Copy link
Member

Choose a reason for hiding this comment

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

I believe we support this elsewhere in the framework. With existing support, what you're trying to achieve here has been abstracted within the handlers. @arodidev Can we do away with the duplication?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes @samuelmale the logic exists within the handlers, although it exists as part of a greater process which we do not need much of, eg. pulling the obs from the encounter, while in our case we already have the obs to be evaluated. I think this approach would render the returned obs from the evaluated historical expression to be obsolete.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would you suggest modifying the handler to accomodate instances where the obs is already present?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@samuelmale I'm requesting some guidance on this before progressing, thanks.

Comment on lines 99 to 102
const transformedHistoricalValue = historicalValue
? historicalValueTransformer(fieldDescriptor, historicalValue)
: null;

Copy link
Member

Choose a reason for hiding this comment

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

We shouldn't treat the historicalValue vs previousFieldValue as separate things, we should instead do something like:

const previousFieldValue = !isEmpty(fieldDescriptor.historicalExpression)
              ? evaluatePreviousValueFromHD(fieldDescriptor.historicalExpression)
              : pickPreviousValueFromEncounter(encounterContext.previousEncounter);

@@ -444,6 +444,17 @@ export class CommonExpressionHelpers {
return Promise.resolve(lazy);
};
}
export class HistoricalDataSourceService {
Copy link
Member

Choose a reason for hiding this comment

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

Can we move this to its own file? I also feel like it's valid to move the expression runner components out of the utils to a new folder "expression-runner".

// register dependencies
findAndRegisterReferencedFields(node, parts, fields);
//adds values to the determinants
Copy link
Member

Choose a reason for hiding this comment

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

Do you need this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will resolve

@arodidev arodidev marked this pull request as draft May 7, 2024 18:38
@CynthiaKamau
Copy link
Contributor

@arodidev is it possible to move this from draft?

@arodidev arodidev marked this pull request as ready for review May 8, 2024 19:07
Copy link
Member

@samuelmale samuelmale left a comment

Choose a reason for hiding this comment

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

@arodidev can you resolve the merge conflicts?

Comment on lines 61 to 72
if (!isEmpty(previousValue)) {
if (Array.isArray(previousValue)) {
const valuesToSet = previousValue.map((eachItem) => eachItem.value);
setFieldValue(question.id, valuesToSet);
onChange(question.id, valuesToSet, setErrors, setWarnings);
question.value = handler?.handleFieldSubmission(question, valuesToSet, encounterContext);
} else {
const valueToSet = [previousValue.value];
setFieldValue(question.id, valueToSet);
onChange(question.id, valueToSet, setErrors, setWarnings);
question.value = handler?.handleFieldSubmission(question, valueToSet, encounterContext);
}
Copy link
Member

Choose a reason for hiding this comment

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

To prevent the code duplication here, I would simply:

if (!isEmpty(previousValue) {
  const previousValues = Array.isArray(previousValue) ? previousValue.map(item => item.value) : [previousValue.value];

  // ....
  
}

default:
return value?.display;
}
};

export const historicalValueTransformer = (field: FormField, obs: OpenmrsObs) => {
Copy link
Member

Choose a reason for hiding this comment

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

const refineHistoricalValue = (field: FormField, value: OpenmrsObs) => {

OR

const extractObsValueAndDisplay = (field: FormField, obs: OpenmrsObs) => {

return formatDate(new Date(value?.display)) || formatDate(value?.value);
case 'checkbox':
return Array.isArray(value) ? previousValueDisplayForCheckbox(value) : null;
return Array.isArray(value) ? previousValueDisplayForCheckbox(value) : value.display;
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to receive a null or undefined argument for value?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No it is not. The following evaluations need to be truthy before the component is called.
encounterContext?.previousEncounter && (previousFieldValue || historicalValue) && (isTrue(fieldDescriptor.questionOptions.enablePreviousValue) || fieldDescriptor.historicalExpression)Ï

@@ -0,0 +1,11 @@
export class HistoricalDataSourceService {
Copy link
Member

Choose a reason for hiding this comment

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

It feels wrong having a service live under "utils", since it's Datasource related, I would rather move this to the "datasource" folder.

@arodidev
Copy link
Contributor Author

arodidev commented May 9, 2024

@samuelmale All comments on this PR have been resolved, I beleive it is ready to be merged.

Copy link
Member

@samuelmale samuelmale left a comment

Choose a reason for hiding this comment

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

LGTM

@samuelmale samuelmale merged commit 30cf1b1 into openmrs:main May 9, 2024
4 checks passed
vasharma05 pushed a commit that referenced this pull request May 27, 2024
* Initial commit(will remove the date bug fix)

* cleanup

* Getting the HD object to evaluate
tt
t

* aligning Hxp with previous value

* more cleanup

* resolving logic

* revamped transformer, migrated historical data source class

* combine hxp and previous value logic

* Added tests

* PR resolutions

* Fix CI build failure
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