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

FM2-130:Adding support for the FHIR Media resource #328

Draft
wants to merge 31 commits into
base: master
Choose a base branch
from

Conversation

tendomart
Copy link

@tendomart tendomart commented Feb 15, 2021

Description of what I changed

Adding support for the FHIR Media resource

Issue I worked on

see https://issues.openmrs.org/browse/FM2-

Checklist: I completed these to help reviewers :)

  • My IDE is configured to follow the code style of this project.

    No? Unsure? -> configure your IDE, format the code and add the changes with git add . && git commit --amend

  • I have added tests to cover my changes. (If you refactored
    existing code that was well tested you do not have to add tests)

    No? -> write tests and add them to this commit git add . && git commit --amend

  • I ran mvn clean package right before creating this pull request and
    added all formatting changes to my commit.

    No? -> execute above command

  • All new and existing tests passed.

    No? -> figure out why and add the fix to your commit. It is your responsibility to make sure your code works.

  • My pull request is based on the latest changes of the master branch.

    No? Unsure? -> execute command git pull --rebase upstream master

@ibacher @pmanko

https://issues.openmrs.org/browse/FM2-130

@tendomart
Copy link
Author

@ibacher @pmanko

1 .I just want to know wether this Handler has the required method implementation for doing  the required business. 

2.Would it make sense to design multiple ComplexObsHandler implementations for various MIME Types ?

Copy link
Member

@ibacher ibacher left a comment

Choose a reason for hiding this comment

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

@tendomart Thanks for this! I've left you some comments here and some additional pointers on the Jira issue. Please read through them and let me know if there are any points you need me to clarify, etc.


public interface FhirMediaService extends FhirService<Observation> {

Observation get(@Nonnull String uuid);
Copy link
Member

Choose a reason for hiding this comment

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

This seems to be unnecessary as it's already defined by the parent interface.


@Component
@Setter(AccessLevel.PACKAGE)
public class FhirMediaDaoImpl extends BaseFhirDao<Obs> implements FhirMediaDao, ComplexObsHandler {
Copy link
Member

Choose a reason for hiding this comment

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

This class definitely shouldn't be a ComplexObsHandler. That interface is only for classes which implement a specific type of ComplexObs, e.g., ImageHandler or PdfHandler or something like that.

@Component
@Setter(AccessLevel.PUBLIC)
@Order(Ordered.LOWEST_PRECEDENCE)
public class FhirMediaComplexObsHandler implements ComplexObsHandler, CustomDatatypeHandler {
Copy link
Member

Choose a reason for hiding this comment

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

We really, really don't need a FHIR-specific ComplexObsHandler we can rely on the ObsService to populate the ComplexObs data (if any)

@Transactional
@Setter(AccessLevel.PACKAGE)
@Getter(AccessLevel.PROTECTED)
public class FhirMediaServiceImpl implements FhirMediaService {
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason this doesn't extend BaseFhirService as that provides default implementations for all of the methods except search.


@Component
@Setter(AccessLevel.PACKAGE)
public class MediaTranslatorImpl implements MediaTranslator {
Copy link
Member

Choose a reason for hiding this comment

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

For the mappings to be added here, look at the ticket and the way we generally map those properties. Most of them have overlap with Obs, so the ObservationTranslatorImpl class would be a good place to start.

@Component("mediaFhirR4ResourceProvider")
@Qualifier("fhirResources")
@Setter(AccessLevel.PACKAGE)
public class MediaFhirResourceProvider implements IResourceProvider {
Copy link
Member

Choose a reason for hiding this comment

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

We need some actual resource methods here, similar to the other FhirResourceProvider classes.

Comment on lines 38 to 46
<bean name="handler" class="org.openmrs.module.fhir2.api.handler.FhirMediaComplexObsHandler">
<property name="handlers">
<map>
<entry>
<key><value>mediaHandler</value></key>
</entry>
</map>
</property>
</bean>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<bean name="handler" class="org.openmrs.module.fhir2.api.handler.FhirMediaComplexObsHandler">
<property name="handlers">
<map>
<entry>
<key><value>mediaHandler</value></key>
</entry>
</map>
</property>
</bean>

@ibacher ibacher marked this pull request as draft March 30, 2021 16:30
Comment on lines 104 to 110
private void handleMediaCreatedDate(Criteria criteria, DateRangeParam mediaCreatedDate) {
if(mediaCreatedDate != null){
if(lacksAlias(criteria, "dt")){
criteria.createAlias("mediaCreatedDate", "dt");
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This is superfluous. Ideally, you should re-use already existing functionality. i.e instead of this 👇🏾

case FhirConstants.MEDIA_CREATED_DATE_TIME:
     entry.getValue().forEach(createdDateTime -> handleDateRange(createdDateTime.getPropertyName(),
	(DateRangeParam) createdDateTime.getParam()).ifPresent(criteria::add));
    break;

re-use handleDateRange() which somehow you are using it. Probably, you should replace with;

case FhirConstants.DATE_RANGE_SEARCH_HANDLER:
    entry.getValue().forEach(dateRangeParam -> handleDateRange(dateRangeParam.getPropertyName(),
	(DateRangeParam) dateRangeParam.getParam()).ifPresent(criteria::add));
    break;

No need for the new constant and new method handleMediaCreatedDate(). This applies to encounterReference and the subjectReference - patient reference. Try re-using already existing functionality as much as possible.

Comment on lines 158 to +159
* crt.concept_source_id = (select concept_source_id from fhir_concept_source where url = ?)
* AND crt.code = ?
* AND crt.code = ?fhir_concept_source
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem right to me. Why did you change the example query?

@tendomart
Copy link
Author

tendomart commented Apr 7, 2021

oops true .Thanks @corneliouzbett this happened in my last commit yesterday . Prior to that all was well .And i didn't get time to review yesterday .Thanks again

@tendomart
Copy link
Author

Thanks @ibacher so then what will we use to map the remaining searchParams as most of the Fhir Media Params have no direct correlations with the Openmrs Obs and no handler implementations from fhir as well .

@ibacher
Copy link
Member

ibacher commented Apr 21, 2021

@tendomart Hopefully it's pretty straight-forward to create handle...() methods modelled on those from Obs or elsewhere in the code base.

@tendomart
Copy link
Author

Alright thanks alot .Sorry for late response , been doing some house cleaning on my Jira Dashboard .

package org.openmrs.module.fhir2.api.translators.impl;

import static org.hamcrest.Matchers.notNullValue;
import static org.springframework.test.util.MatcherAssertionErrors.assertThat;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
import static org.springframework.test.util.MatcherAssertionErrors.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.*;
Copy link
Member

Choose a reason for hiding this comment

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

Don't use star imports

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("mediaFhirR4ResourceProvider")
Copy link
Member

Choose a reason for hiding this comment

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

This needs to have a different name, e.g., mediaFhirR3ResourceProvider. This is one of the things causing testing errors.

import org.springframework.stereotype.Component;

@Component("mediaFhirR4ResourceProvider")
@Qualifier("fhirResources")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
@Qualifier("fhirResources")
@R3Provider

import org.springframework.stereotype.Component;

@Component("mediaFhirR4ResourceProvider")
@Qualifier("fhirResources")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
@Qualifier("fhirResources")
@R4Provider

@tendomart
Copy link
Author

@ibacher I just want to ask ,is this the new way of , to replace @Qualifier("fhirResources") with @R4Provider

@tendomart
Copy link
Author

Hi @ibacher i have tried to look around for a solution but failed to figure out why

```

@OverRide
public Obs get(@nonnull String uuid) {
return obsService.getObsByUuid(uuid);
}

@Override
public Obs createOrUpdate(@Nonnull Obs newEntry) {
	return obsService.saveObs(newEntry, FhirConstants.SAVED_SUCCESSFULLY);
}

@Override
public Obs delete(@Nonnull String uuid) {
	return super.delete(uuid);
}
either throws a NPE or returns a Null Object when actually the same implementation in `FhirConceptDaoImpl` works .Any thoughts.


@Test
public void get_shouldGetComplexObsByUuid() {
assertThat(dao.get("OBS_UUID"), notNullValue());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
assertThat(dao.get("OBS_UUID"), notNullValue());
assertThat(dao.get(OBS_UUID), notNullValue());


private static final String OBS_DATA_XML = "org/openmrs/module/fhir2/api/dao/impl/FhirObservationDaoImplTest_initial_data_suppl.xml";

private static final String OBS_UUID = "759a0d9e-ccf8-4f00-a045-6a94c43fbd6b";
Copy link
Member

Choose a reason for hiding this comment

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

Where did this UUID come from? In order to be able to load it from the database, it needs to be an Obs defined correctly in data that are loaded for this test. You probably want to ensure this test data is loaded and use the UUID from that.


@Override
protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams) {
theParams.getParameters().forEach(entry -> {
Copy link
Member

Choose a reason for hiding this comment

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

Here, we'll want to ensure that we're only searching ComplexObs and not just any Obs. This looks like it could be done as something like:

if (lacksAlias(criteria, "c")) {
	criteria.createAlias("concept", "c");
}

if (lacksAlias(criteria, "cdt")) {
    criteria.createAlias("c.datatype", "cdt");
}

criteria.add(eq("cdt.hl7_abbreviation", "ED"));

@tendomart
Copy link
Author

tendomart commented Jun 6, 2021

Thanks @ibacher for bringing this up . Iam still finding some trouble defining the search param . I have already identified them at https://www.hl7.org/fhir/DSTU2/media.html but i really don't understand the meaning of the aliases used here in any case .

For example in this case who will be using "c" ,"cd" and "EDT" . And why are you choosing , "concept" , "c.datatype" and "cdt.hl7_abbreviation" ? Only
Any clear documentation for this ?

@ibacher
Copy link
Member

ibacher commented Aug 31, 2021

@tendomart Sorry... I somehow missed the above question. The "c" and "cd" above are really just aliases for tables inside the criteria query. Just like in SQL you could write something like (this is similar to the query my code above is intended to generate):

select *
from concept c
join concept_data_type cdt on
  c.data_type_id = cdt.concept_data_type_id
where cdt.hl7_abbreviation = "ED"

Having an alias just allows us to refer to the property name in a shorter fashion.

The "ED" part actually comes from the code we use to determine whether or not a concept is a complex concept. See here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants