use of org.activityinfo.model.formula.FormulaNode in project activityinfo by bedatadriven.
the class FormScanBatch method computePermissionFilter.
private Slot<TableFilter> computePermissionFilter(ResourceId formId) {
FormPermissions permissions = supervisor.getFormPermissions(formId);
if (!permissions.isVisible()) {
return new PendingSlot<>(TableFilter.NONE_SELECTED);
}
if (!permissions.hasVisibilityFilter()) {
return new PendingSlot<>(TableFilter.ALL_SELECTED);
}
// Otherwise apply per-record permissions
try {
FormTreeBuilder formTreeBuilder = new FormTreeBuilder(formClassProvider);
FormTree formTree = formTreeBuilder.queryTree(formId);
FormulaNode formula = FormulaParser.parse(permissions.getViewFilter());
QueryEvaluator evaluator = new QueryEvaluator(FilterLevel.NONE, formTree, this);
Slot<ColumnView> filterView = evaluator.evaluateExpression(formula);
return new MemoizedSlot<>(filterView, new Function<ColumnView, TableFilter>() {
@Override
public TableFilter apply(ColumnView columnView) {
return new TableFilter(columnView);
}
});
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to parse visibility filter", e);
LOGGER.severe("Error parsing visibility filter '" + permissions.getViewFilter() + " in form " + formId + ": " + e.getMessage() + ". " + "For security reasons, no results will be shown");
return new PendingSlot<>(TableFilter.NONE_SELECTED);
}
}
use of org.activityinfo.model.formula.FormulaNode in project activityinfo by bedatadriven.
the class NodeMatch method joinsTo.
private static List<JoinNode> joinsTo(List<List<FormTree.Node>> partitions, Optional<StatFunction> aggregation) {
/*
* Given a parent: "Site.Location.Territoire.District"
* This is represented as a tree of nodes:
* District -> Territoire -> Location -> Site
*
* We want to turn into a list of joins:
* (site field -> form site),
* (location field -> form school),
* (field territoire -> form Territoire)
* (field district -> form District)
*/
LinkedList<JoinNode> joins = new LinkedList<>();
for (int i = 0; i < partitions.size() - 1; i++) {
// Reference field that functions as a foreign key
List<FormTree.Node> left = partitions.get(i);
FormField leftField = left.get(0).getField();
ResourceId leftFormId = left.get(0).getDefiningFormClass().getId();
FormulaNode leftFieldExpr = toExpr(left);
// "RIGHT" side
// Joining fom left to right using resource ids (primary key)
List<FormTree.Node> right = partitions.get(i + 1);
ResourceId rightFormId = right.get(0).getDefiningFormClass().getId();
if (leftField.getType() instanceof ReferenceType) {
// Join based on the (left) foreign key ==> (right) primary key
joins.add(new JoinNode(JoinType.REFERENCE, leftFormId, leftFieldExpr, rightFormId, Optional.<StatFunction>absent()));
} else if (leftField.getType() instanceof SubFormReferenceType) {
joins.add(new JoinNode(JoinType.SUBFORM, leftFormId, new SymbolNode(ColumnModel.ID_SYMBOL), rightFormId, aggregation));
} else {
throw new IllegalStateException("Invalid field for joining: " + leftField.getType());
}
}
return joins;
}
use of org.activityinfo.model.formula.FormulaNode in project activityinfo by bedatadriven.
the class NodeMatch method toExpr.
private static FormulaNode toExpr(List<FormTree.Node> partition) {
Iterator<FormTree.Node> it = partition.iterator();
FormulaNode expr = new SymbolNode(it.next().getFieldId());
while (it.hasNext()) {
expr = new CompoundExpr(expr, new SymbolNode(it.next().getFieldId()));
}
return expr;
}
use of org.activityinfo.model.formula.FormulaNode in project activityinfo by bedatadriven.
the class LookupKeySetTest method simpleHierarchyTest.
/**
* In the case of a simple hierarchy, we are referencing a single form that
* in turn has key reference fields.
*
* For example, if the field references a Village form, this should yield:
*
* <pre>
* Province.Name
* ^
* |
* District.Name
* ^
* |
* Village.Name
* </pre>
*
* All fields are required because we ultimately need the reference to the village record.
*/
@Test
public void simpleHierarchyTest() {
TestingStorageProvider catalog = new TestingStorageProvider();
NfiForm nfiForm = catalog.getNfiForm();
VillageForm villageForm = catalog.getVillageForm();
AdminLevelForm territoryForm = catalog.getVillageForm().getParentForm();
AdminLevelForm provinceForm = territoryForm.getParentForm().get();
FormTree formTree = catalog.getFormTree(nfiForm.getFormId());
LookupKeySet lookupKeySet = new LookupKeySet(formTree, nfiForm.getVillageField());
// Keys need to be topologically sorted,
// with parent keys preceding child keys in the list
assertThat(lookupKeySet.getKey(0).getKeyLabel(), equalTo("Province Name"));
assertThat(lookupKeySet.getKey(1).getKeyLabel(), equalTo("Territory Name"));
assertThat(lookupKeySet.getKey(2).getKeyLabel(), equalTo("Village Name"));
SymbolNode villageName = Formulas.symbol(villageForm.getNameField().getId());
SymbolNode villageTerritory = new SymbolNode(villageForm.getAdminFieldId());
FormulaNode territoryName = new CompoundExpr(villageTerritory, territoryForm.getNameFieldId());
FormulaNode territoryProvince = new CompoundExpr(villageTerritory, territoryForm.getParentFieldId());
FormulaNode provinceName = new CompoundExpr(territoryProvince, provinceForm.getNameFieldId());
assertThat(lookupKeySet.getLeafKeys(), hasSize(1));
LookupKey leafKey = Iterables.getOnlyElement(lookupKeySet.getLeafKeys());
assertThat(leafKey.getKeyFormulas().values(), containsInAnyOrder(villageName, territoryName, provinceName));
}
use of org.activityinfo.model.formula.FormulaNode in project activityinfo by bedatadriven.
the class LookupKeySetTest method overlappingHierarchiesParse.
@Test
public void overlappingHierarchiesParse() {
TestingStorageProvider catalog = setup.getCatalog();
LocaliteForm localiteForm = catalog.getLocaliteForm();
FormTree formTree = setup.getFormTree(localiteForm.getFormId());
LookupKeySet lookupKeySet = new LookupKeySet(formTree, localiteForm.getAdminField());
Map<LookupKey, FormulaNode> formulas = lookupKeySet.getKeyFormulas(localiteForm.getAdminField().getId());
ParsedFormula province = new ParsedFormula(formTree, formulas.get(lookupKeySet.getKey(0)).asExpression());
assertThat(province.isValid(), equalTo(true));
assertThat(province.getResultType(), instanceOf(TextType.class));
}
Aggregations