I am looking for a way of saving selected definitions of cohorts, data definitions, indicators along with the definitions in a custom module so that they can appear and be available on the reporting UI
@ssmusoke, I would encourage you to have a look at how this is currently being done in some existing modules. I can point you to a couple, notably the PIH distribution for our Malawi implementations. Most of the code to configure and save the various queries, data definitions, indicators, and reports can be seen in this package and sub-packages:
In our case above, the only definitions we actually save to the database are the reports - everything else is simply avaiable in a “DefinitionLibrary” or similar class that enables easy instatiation of definitions on demand in-memory. To set up all of the reports in the DB, there is a utility method you can call in the reporting module from your own module’s activator. In our case, in our Activator’s “started()” method, we simply call:
I’m happy to answer any questions at all around this code, and discuss possible alternative best practices you may come up with.
I know others have done similar things in their distribution modules to this. Some other examples I know of are:
Thanks @mseaton we have actually followed the PIH Malawi code to generate a report, however what is not clear is how to save the datasets and cohort definitions so that they are available on the reporting ui. This is because the users need to be able to build ad-hoc custom data exports which may not be available, so providing base cohorts and data elements would simplify this process
The technical answer is that saving a Cohort Definition, Data Definition, Indicator, or any definition at all is no different from saving a Report Definition. If you want to implement the same sort of code that ensures all of your definitions of various types are updated and consistent every time your module starts, you can probably just take much of the code that is in the “
ReportManagerUtil.setupAllReports” class above, and adapt it for use with other Definitions.
Most definitions have their own services, and they all extend a common abstract base class, so they all should have the same usage. eg.
The more complicated answer is that I’m not 100% sure how much utility there is in doing this at the moment. Most of the existing 1.x UI code doesn’t really provide many tools for working with these definitions, aside from constructing custom reports out of them. That’s a useful thing to be able to do, but what we really need is better tools (like the cohort builder, data export, etc) that could enable end users to compose these saved definitions together to do useful ad hoc reporting and analysis.
We are using the new Ref App UI not the legacy.
Is there an example of saving the different cohort and dataset definitions from static methods as used in PIH Malawi?
I don’t know of any examples that do that. If you’re using the RefApp UI there are even fewer reasons to do this however. There are virtually no tools for working with saved definitions other than Report Definitions in the 2.0 UI.
The one approach that is somewhat supported is using
DefinitionLibraries. This is the currently recommended approach for pre-creating definitions for users to use, rather than saving definitions in the database. The idea here is that definitions are available to create on-demand, and are exposed via Java annotations. This is the approach that the new Ad Hoc Analysis tool that @darius started writing for the Reference Application UI uses.
The reporting module exposes a simple built-in library that you can see as a starting point here:
And the framework code for defining and finding all definitions that are exposed in such libraries is in this package:
Then, the Ad Hoc Analysis tool uses these library-defined definitions, as you can see in this Controller:
@darius is probably the best person to explain this tool in more depth.
@mseaton @darius Looking around the database I have found a serialized_object table which has saved Cohort, Dataset and Report Definitions that I created via the UI. Is this a possible approach to take to persist definitions that we need to make available to users?
@ssmusoke - as I indicated earlier, [quote=“mseaton, post:4, topic:5630”] Most definitions have their own services, and they all extend a common abstract base class, so they all should have the same usage. eg. Context.getService(CohortDefinitionService.class).saveDefinition(definition); [/quote]
each definition type in the reporting module has a corresponding service which has methods for saving, deleting, loading, finding definitions of that type. Yes, these typically go in the serialized_object table, but I’m not sure why you would need or want to go there directly. The right solution is to use the appropriate service method(s) in the reporting API to manage your definition classes.
@mseaton I have this class to save the Cohort definitions to the database, however I ran into an issue with dimensions which do not persist. I am wondering should I be using the DefinitionSummaries or the actual cohort, dimension and other definition summaries.
@ssmusoke, if I’m understanding right, this is because your code is just loading and saving Cohort Definitions specifically. Dimensions are not Cohort Definitions. If you want to have your dimensions saved, you need to do the same with these. Or perhaps there is other code I should be looking at that demonstrates the issue you are facing?
@mseaton I am saving them using then documented definition summaries via the @DocumentedDefinition annotation from the definition libraries like https://github.com/ssmusoke/openmrs-module-aijar-reports/blob/master/api/src/main/java/org/openmrs/module/aijarreports/library/CommonCohortDefinitionLibrary.java
However this does not work for dimensions defined like in https://github.com/ssmusoke/openmrs-module-aijar-reports/blob/master/api/src/main/java/org/openmrs/module/aijarreports/library/CommonDimensionLibrary.java
So I am wondering how do I load the metadata for what I want to save from the definition library? Is there another way other than trying to access it through the @DocumentedDefinition annotation?
@ssmusoke find me on IRC and I’m happy to chat about it. If you can point me to the code that is failing and how you think it should behave (eg. a failing unit test with expected result) that would help.