Skip to content

Commit 05c7de2

Browse files
committed
#836 - inMemory filtering after removing subquery for observations. ability to set server in dev settings
1 parent 3129731 commit 05c7de2

File tree

7 files changed

+51
-51
lines changed

7 files changed

+51
-51
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ rm_db:
191191
kill_realm_browser:
192192
pkill "Realm Browser" || true
193193

194-
open_db: rm_db get_db ## Open realmdb in Realm Browser
194+
open_db: rm_db get_db open_db_only
195+
open_db_only:
195196
$(call _open_resource,../db/default.realm)
196197
# </db>
197198

makefiles/util.mk

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,11 @@ open-ci-page:
33

44
open-checkout-hook:
55
vi .git/hooks/post-checkout
6+
7+
s3-dump-page:
8+
ifndef org
9+
@echo "Please provide org prefix in org param"
10+
exit 1
11+
else
12+
open "https://s3.console.aws.amazon.com/s3/buckets/prod-user-media?region=ap-south-1&prefix=$(org)/&showversions=false"
13+
endif

packages/openchs-android/package-lock.json

Lines changed: 9 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/openchs-android/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"lodash": "4.17.21",
5151
"moment": "2.29.4",
5252
"native-base": "3.4.9",
53-
"openchs-models": "1.27.18",
53+
"openchs-models": "1.27.19",
5454
"prop-types": "15.8.1",
5555
"react": "18.2.0",
5656
"react-native": "0.69.7",

packages/openchs-android/src/Playground.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function executeQuery(queryString, type) {
1313
objects = objects.filtered(queryString);
1414
return objects.map(_.identity).length;
1515
} catch (e) {
16+
console.error(e);
1617
return -1;
1718
}
1819
}

packages/openchs-android/src/service/CustomFilterService.js

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99
Concept,
1010
CustomFilter,
1111
GroupSubject,
12-
} from "avni-models";
12+
ObservationsHolder
13+
} from "openchs-models";
1314
import General from "../utility/General";
1415
import _ from "lodash";
1516
import ConceptService from "./ConceptService";
@@ -118,7 +119,7 @@ class CustomFilterService extends BaseService {
118119

119120
// Note that the query is run for every filter(concept) separately, this is because we don't have
120121
// joins in realm and after getting latest from each filter(concept) we need to query for selected concept answer.
121-
queryFromLatestObservation(schemaName, conceptFilters, selectedAnswerFilters, scopeFilters, sortFilter, indFunc, widget) {
122+
queryFromLatestObservation(schemaName, conceptFilters, selectedAnswerFilters, scopeFilters, sortFilter, indFunc, widget, inMemoryFilter) {
122123
const latestEncounters = this.db.objects(schemaName)
123124
.filtered(`voided = false `)
124125
//limit the scope of query by giving encounter/program uuid
@@ -129,15 +130,16 @@ class CustomFilterService extends BaseService {
129130
.filtered(_.isEmpty(sortFilter) ? 'uuid != null' : ` ${sortFilter} `);
130131

131132
return widget === CustomFilter.widget.Range ? this.filterForRangeWidgetType(latestEncounters, selectedAnswerFilters, indFunc)
132-
: this.filterForFixedWidgetType(latestEncounters, schemaName, selectedAnswerFilters, indFunc);
133+
: this.filterForFixedWidgetType(latestEncounters, schemaName, selectedAnswerFilters, indFunc, inMemoryFilter);
133134
}
134135

135-
filterForFixedWidgetType(latestEncounters, schemaName, selectedAnswerFilters, indFunc) {
136+
filterForFixedWidgetType(latestEncounters, schemaName, selectedAnswerFilters, indFunc, inMemoryFilter) {
136137
//cannot append next filtered to this query because sorting happens at the end of query and we will not get expected result.
137138
//so we get the most recent encounters from above query and pass it down to the next query.
138139
return _.isEmpty(latestEncounters) ? [] : [...latestEncounters
139140
//check if selected filter is present in the observations
140141
.filtered(` ${selectedAnswerFilters()} `)
142+
.filterInternal((obsHolder) => inMemoryFilter(obsHolder))
141143
.map(indFunc)
142144
];
143145
}
@@ -190,8 +192,8 @@ class CustomFilterService extends BaseService {
190192
const selectedOption = _.head(selectedOptions);
191193
switch (concept.datatype) {
192194
case (Concept.dataType.Coded) :
193-
const codedFilterQuery = _.map(selectedOptions, c => ` (concept.uuid == '${concept.uuid}' AND valueJSON CONTAINS[c] '${c.uuid}') `).join(" OR ");
194-
return () => this.getObsSubQueryForQuery(codedFilterQuery);
195+
const codedFilterQuery = _.map(selectedOptions, c => ` (observations.concept.uuid == '${concept.uuid}' AND observations.valueJSON CONTAINS[c] '${c.uuid}') `).join(" OR ");
196+
return () => codedFilterQuery;
195197
case (Concept.dataType.Text) :
196198
case (Concept.dataType.Notes) :
197199
case (Concept.dataType.Id) :
@@ -239,15 +241,15 @@ class CustomFilterService extends BaseService {
239241
return filter.join(" AND ");
240242
}
241243

242-
queryConceptTypeFilters(scope, scopeParameters, selectedAnswerFilters, conceptFilter, widget) {
244+
queryConceptTypeFilters(scope, scopeParameters, selectedAnswerFilters, conceptFilter, widget, inMemoryFilter) {
243245
switch (scope) {
244246
case CustomFilter.scope.ProgramEncounter : {
245247
const encounterOptions = _.map(scopeParameters.encounterTypeUUIDs, e => `encounterType.uuid == "${e}"`).join(" OR ");
246248
const programOptions = _.map(scopeParameters.programUUIDs, p => `programEnrolment.program.uuid == "${p}"`).join(" OR ");
247249
const scopeFilters = this.createProgramEncounterScopeFilter(encounterOptions, programOptions);
248250
const scopeFiltersWithNonExit = `(${scopeFilters}) and programEnrolment.programExitDateTime = null`;
249251
const sortFilter = 'TRUEPREDICATE sort(programEnrolment.individual.uuid asc , encounterDateTime desc) Distinct(programEnrolment.individual.uuid)';
250-
const individualUUIDs = this.queryFromLatestObservation(ProgramEncounter.schema.name, conceptFilter, selectedAnswerFilters, scopeFiltersWithNonExit, sortFilter, enc => enc.programEnrolment.individual.uuid, widget);
252+
const individualUUIDs = this.queryFromLatestObservation(ProgramEncounter.schema.name, conceptFilter, selectedAnswerFilters, scopeFiltersWithNonExit, sortFilter, enc => enc.programEnrolment.individual.uuid, widget, inMemoryFilter);
251253
this.updateIndividuals(individualUUIDs);
252254
break;
253255
}
@@ -256,20 +258,20 @@ class CustomFilterService extends BaseService {
256258
const scopeFilters = this.createProgramEncounterScopeFilter(null, programOptions);
257259
const scopeFiltersWithNonExit = `(${scopeFilters}) and programExitDateTime = null`;
258260
const sortFilter = 'TRUEPREDICATE sort(individual.uuid asc , enrolmentDateTime desc) Distinct(individual.uuid)';
259-
const individualUUIDs = this.queryFromLatestObservation(ProgramEnrolment.schema.name, conceptFilter, selectedAnswerFilters, scopeFiltersWithNonExit, sortFilter, enl => enl.individual.uuid, widget);
261+
const individualUUIDs = this.queryFromLatestObservation(ProgramEnrolment.schema.name, conceptFilter, selectedAnswerFilters, scopeFiltersWithNonExit, sortFilter, enl => enl.individual.uuid, widget, inMemoryFilter);
260262
this.updateIndividuals(individualUUIDs);
261263
break;
262264
}
263265
case CustomFilter.scope.Registration : {
264-
const individualUUIDs = this.queryFromLatestObservation(Individual.schema.name, null, selectedAnswerFilters, null, null, ind => ind.uuid, widget);
266+
const individualUUIDs = this.queryFromLatestObservation(Individual.schema.name, null, selectedAnswerFilters, null, null, ind => ind.uuid, widget, inMemoryFilter);
265267
this.updateIndividuals(individualUUIDs);
266268
break;
267269
}
268270
case CustomFilter.scope.Encounter : {
269271
const encounterOptions = _.map(scopeParameters.encounterTypeUUIDs, e => `encounterType.uuid == "${e}"`).join(" OR ");
270272
const scopeFilters = this.createProgramEncounterScopeFilter(encounterOptions, null);
271273
const sortFilter = 'TRUEPREDICATE sort(individual.uuid asc , encounterDateTime desc) Distinct(individual.uuid)';
272-
const individualUUIDs = this.queryFromLatestObservation(Encounter.schema.name, conceptFilter, selectedAnswerFilters, scopeFilters, sortFilter, enc => enc.individual.uuid, widget);
274+
const individualUUIDs = this.queryFromLatestObservation(Encounter.schema.name, conceptFilter, selectedAnswerFilters, scopeFilters, sortFilter, enc => enc.individual.uuid, widget, inMemoryFilter);
273275
this.updateIndividuals(individualUUIDs);
274276
break;
275277
}
@@ -292,7 +294,10 @@ class CustomFilterService extends BaseService {
292294
const conceptFilter = `observations.concept.uuid == "${conceptUUID}"`;
293295
switch (type) {
294296
case CustomFilter.type.Concept :
295-
this.queryConceptTypeFilters(scope, scopeParameters, selectedAnswerFilterQuery, conceptFilter, widget);
297+
const concept = this.getService(ConceptService).findByUUID(conceptUUID);
298+
const inMemoryFilter = concept.isCodedConcept() ?
299+
(obsHolder) => ObservationsHolder.hasAnyAnswer(obsHolder, conceptUUID, selectedOptions.map(x => x.uuid),) : null;
300+
this.queryConceptTypeFilters(scope, scopeParameters, selectedAnswerFilterQuery, conceptFilter, widget, inMemoryFilter);
296301
break;
297302
case CustomFilter.type.RegistrationDate:
298303
this.updateIndividuals(this.queryEntity(Individual.schema.name, selectedAnswerFilterQuery, null, ind => ind.uuid));

packages/openchs-android/src/views/settings/DevSettingsView.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import {Text, TouchableNativeFeedback, View} from "react-native";
1+
import {Text, TouchableNativeFeedback, View, TextInput, ScrollView} from "react-native";
22
import React from "react";
33
import AbstractComponent from "../../framework/view/AbstractComponent";
44
import Path from "../../framework/routing/Path";
55
import _ from "lodash";
66
import General from "../../utility/General";
7-
import {SettingsActionsNames as Actions} from "../../action/SettingsActions";
7+
import {SettingsActionsNames, SettingsActionsNames as Actions} from "../../action/SettingsActions";
88
import RadioGroup, {RadioLabelValue} from "../primitives/RadioGroup";
99
import Reducers from "../../reducer";
1010
import AppHeader from "../common/AppHeader";
@@ -15,7 +15,7 @@ import Styles from "../primitives/Styles";
1515
import Fonts from "../primitives/Fonts";
1616
import Colors from "../primitives/Colors";
1717
import RuleEvaluationService from "../../service/RuleEvaluationService";
18-
import {Rule} from 'avni-models';
18+
import {Rule} from 'openchs-models';
1919

2020
@Path('/devSettingsView')
2121
class DevSettingsView extends AbstractComponent {
@@ -58,26 +58,31 @@ class DevSettingsView extends AbstractComponent {
5858

5959
renderDevOptions() {
6060
if (__DEV__) {
61+
const {rulesToRun, settings} = this.state;
6162
const labelValues = Object.entries(this.entityMap)
6263
.map(([displayName, value]) => new RadioLabelValue(displayName, value));
6364
return (<View>
6465
<RadioGroup
6566
onPress={({value}) => this.dispatchAction(Actions.ON_RULE_CHANGE, {value: value})}
6667
labelValuePairs={labelValues}
6768
labelKey='Rules to run'
68-
selectionFn={(ruleToRun) => this.state.rulesToRun.indexOf(ruleToRun) > -1}
69+
selectionFn={(ruleToRun) => rulesToRun.indexOf(ruleToRun) > -1}
6970
validationError={null}
7071
multiSelect={true}
7172
style={{marginTop: Distances.VerticalSpacingBetweenFormElements}}
7273
/>
73-
<TouchableNativeFeedback onPress={() => this.runRules(this.state.rulesToRun)}>
74+
<TouchableNativeFeedback onPress={() => this.runRules(rulesToRun)}>
7475
<View style={Styles.basicPrimaryButtonView}>
7576
<Text style={{
7677
fontSize: Fonts.Medium,
7778
color: Colors.TextOnPrimaryColor
78-
}}>Run {this.state.rulesToRun.length === 0 ? 'All' : 'Selected'} Rules</Text>
79+
}}>Run {rulesToRun.length === 0 ? 'All' : 'Selected'} Rules</Text>
7980
</View>
8081
</TouchableNativeFeedback>
82+
<View style={{marginTop: 20}}>
83+
<Text>Server URL:</Text>
84+
<TextInput value={settings.serverURL} onChangeText={(text) => this.dispatchAction(Actions.ON_SERVER_URL_CHANGE, {value: text})}/>
85+
</View>
8186
</View>);
8287
}
8388
}
@@ -87,10 +92,10 @@ class DevSettingsView extends AbstractComponent {
8792
<CHSContainer>
8893
<CHSContent>
8994
<AppHeader title={'Dev Settings'}/>
90-
<View style={{paddingHorizontal: Distances.ContentDistanceFromEdge}}>
95+
<ScrollView style={{paddingHorizontal: Distances.ContentDistanceFromEdge}}>
9196
{this.renderDevOptions()}
9297
{this.renderLogLevels()}
93-
</View>
98+
</ScrollView>
9499
</CHSContent>
95100
</CHSContainer>
96101
);

0 commit comments

Comments
 (0)