/* * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors * * SPDX-License-Identifier: EPL-2.0 */ package tools.refinery.store.query.interpreter; import tools.refinery.interpreter.matchers.backend.QueryEvaluationHint; import org.junit.jupiter.api.Test; import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.ModelQueryAdapter; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.interpreter.tests.QueryEngineTest; import tools.refinery.store.query.view.AnySymbolView; import tools.refinery.store.query.view.FilteredView; import tools.refinery.store.query.view.FunctionView; import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.representation.TruthValue; import tools.refinery.store.tuple.Tuple; import java.util.List; import java.util.Map; import static tools.refinery.store.query.literal.Literals.check; import static tools.refinery.store.query.literal.Literals.not; import static tools.refinery.store.query.term.int_.IntTerms.constant; import static tools.refinery.store.query.term.int_.IntTerms.greaterEq; import static tools.refinery.store.query.interpreter.tests.QueryAssertions.assertResults; class QueryTest { private static final Symbol person = Symbol.of("Person", 1); private static final Symbol friend = Symbol.of("friend", 2, TruthValue.class, TruthValue.FALSE); private static final AnySymbolView personView = new KeyOnlyView<>(person); private static final AnySymbolView friendMustView = new FilteredView<>(friend, "must", TruthValue::must); @QueryEngineTest void typeConstraintTest(QueryEvaluationHint hint) { var asset = Symbol.of("Asset", 1); var predicate = Query.of("TypeConstraint", (builder, p1) -> builder.clause(personView.call(p1))); var store = ModelStore.builder() .symbols(person, asset) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var assetInterpretation = model.getInterpretation(asset); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); assetInterpretation.put(Tuple.of(1), true); assetInterpretation.put(Tuple.of(2), true); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0), true, Tuple.of(1), true, Tuple.of(2), false ), predicateResultSet); } @QueryEngineTest void relationConstraintTest(QueryEvaluationHint hint) { var predicate = Query.of("RelationConstraint", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), friendMustView.call(p1, p2) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 3), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 1), true, Tuple.of(1, 0), true, Tuple.of(1, 2), true, Tuple.of(2, 1), false ), predicateResultSet); } @QueryEngineTest void isConstantTest(QueryEvaluationHint hint) { var predicate = Query.of("RelationConstraint", (builder, p1, p2) -> builder.clause( personView.call(p1), p1.isConstant(1), friendMustView.call(p1, p2) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 1), false, Tuple.of(1, 0), true, Tuple.of(1, 2), true, Tuple.of(2, 1), false ), predicateResultSet); } @QueryEngineTest void existTest(QueryEvaluationHint hint) { var predicate = Query.of("Exists", (builder, p1) -> builder.clause((p2) -> List.of( personView.call(p1), personView.call(p2), friendMustView.call(p1, p2) ))); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); friendInterpretation.put(Tuple.of(3, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0), true, Tuple.of(1), true, Tuple.of(2), false, Tuple.of(3), false ), predicateResultSet); } @QueryEngineTest void orTest(QueryEvaluationHint hint) { var animal = Symbol.of("Animal", 1); var animalView = new KeyOnlyView<>(animal); var predicate = Query.of("Or", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), friendMustView.call(p1, p2) ).clause( animalView.call(p1), animalView.call(p2), friendMustView.call(p1, p2) )); var store = ModelStore.builder() .symbols(person, animal, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var animalInterpretation = model.getInterpretation(animal); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); animalInterpretation.put(Tuple.of(2), true); animalInterpretation.put(Tuple.of(3), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); friendInterpretation.put(Tuple.of(2, 3), TruthValue.TRUE); friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 1), true, Tuple.of(0, 2), false, Tuple.of(2, 3), true, Tuple.of(3, 0), false, Tuple.of(3, 2), false ), predicateResultSet); } @QueryEngineTest void equalityTest(QueryEvaluationHint hint) { var predicate = Query.of("Equality", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), p1.isEquivalent(p2) )); var store = ModelStore.builder() .symbols(person) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 0), true, Tuple.of(1, 1), true, Tuple.of(2, 2), true, Tuple.of(0, 1), false, Tuple.of(3, 3), false ), predicateResultSet); } @QueryEngineTest void inequalityTest(QueryEvaluationHint hint) { var predicate = Query.of("Inequality", (builder, p1, p2, p3) -> builder.clause( personView.call(p1), personView.call(p2), friendMustView.call(p1, p3), friendMustView.call(p2, p3), p1.notEquivalent(p2) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 1, 2), true, Tuple.of(1, 0, 2), true, Tuple.of(0, 0, 2), false ), predicateResultSet); } @QueryEngineTest void patternCallTest(QueryEvaluationHint hint) { var friendPredicate = Query.of("Friend", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), friendMustView.call(p1, p2) )); var predicate = Query.of("PositivePatternCall", (builder, p3, p4) -> builder.clause( personView.call(p3), personView.call(p4), friendPredicate.call(p3, p4) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 1), true, Tuple.of(1, 0), true, Tuple.of(1, 2), true, Tuple.of(2, 1), false ), predicateResultSet); } @QueryEngineTest void patternCallInputArgumentTest(QueryEvaluationHint hint) { var friendPredicate = Dnf.of("Friend", builder -> { var p1 = builder.parameter("p1", ParameterDirection.IN); var p2 = builder.parameter("p2", ParameterDirection.IN); builder.clause( personView.call(p1), personView.call(p2), friendMustView.call(p1, p2) ); }); var predicate = Query.of("PositivePatternCall", (builder, p3, p4) -> builder.clause( personView.call(p3), personView.call(p4), friendPredicate.call(p3, p4) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 1), true, Tuple.of(1, 0), true, Tuple.of(1, 2), true, Tuple.of(2, 1), false ), predicateResultSet); } @QueryEngineTest void negativeRelationViewTest(QueryEvaluationHint hint) { var predicate = Query.of("NegativePatternCall", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), not(friendMustView.call(p1, p2)) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 0), true, Tuple.of(0, 2), true, Tuple.of(1, 1), true, Tuple.of(2, 0), true, Tuple.of(2, 1), true, Tuple.of(2, 2), true, Tuple.of(0, 1), false, Tuple.of(1, 0), false, Tuple.of(1, 2), false, Tuple.of(0, 3), false ), predicateResultSet); } @QueryEngineTest void negativePatternCallTest(QueryEvaluationHint hint) { var friendPredicate = Query.of("Friend", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), friendMustView.call(p1, p2) )); var predicate = Query.of("NegativePatternCall", (builder, p3, p4) -> builder.clause( personView.call(p3), personView.call(p4), not(friendPredicate.call(p3, p4)) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 0), true, Tuple.of(0, 2), true, Tuple.of(1, 1), true, Tuple.of(2, 0), true, Tuple.of(2, 1), true, Tuple.of(2, 2), true, Tuple.of(0, 1), false, Tuple.of(1, 0), false, Tuple.of(1, 2), false, Tuple.of(0, 3), false ), predicateResultSet); } @QueryEngineTest void negativeRelationViewWithQuantificationTest(QueryEvaluationHint hint) { var predicate = Query.of("Negative", (builder, p1) -> builder.clause( personView.call(p1), not(friendMustView.call(p1, Variable.of())) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0), false, Tuple.of(1), true, Tuple.of(2), true, Tuple.of(3), false ), predicateResultSet); } @QueryEngineTest void negativeWithQuantificationTest(QueryEvaluationHint hint) { var called = Query.of("Called", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), friendMustView.call(p1, p2) )); var predicate = Query.of("Negative", (builder, p1) -> builder.clause( personView.call(p1), not(called.call(p1, Variable.of())) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0), false, Tuple.of(1), true, Tuple.of(2), true, Tuple.of(3), false ), predicateResultSet); } @QueryEngineTest void transitiveRelationViewTest(QueryEvaluationHint hint) { var predicate = Query.of("Transitive", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), friendMustView.callTransitive(p1, p2) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 0), false, Tuple.of(0, 1), true, Tuple.of(0, 2), true, Tuple.of(1, 0), false, Tuple.of(1, 1), false, Tuple.of(1, 2), true, Tuple.of(2, 0), false, Tuple.of(2, 1), false, Tuple.of(2, 2), false, Tuple.of(2, 3), false ), predicateResultSet); } @QueryEngineTest void transitivePatternCallTest(QueryEvaluationHint hint) { var called = Query.of("Called", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), friendMustView.call(p1, p2) )); var predicate = Query.of("Transitive", (builder, p1, p2) -> builder.clause( personView.call(p1), personView.call(p2), called.callTransitive(p1, p2) )); var store = ModelStore.builder() .symbols(person, friend) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 0), false, Tuple.of(0, 1), true, Tuple.of(0, 2), true, Tuple.of(1, 0), false, Tuple.of(1, 1), false, Tuple.of(1, 2), true, Tuple.of(2, 0), false, Tuple.of(2, 1), false, Tuple.of(2, 2), false, Tuple.of(2, 3), false ), predicateResultSet); } @Test void filteredIntegerViewTest() { var distance = Symbol.of("distance", 2, Integer.class); var nearView = new FilteredView<>(distance, value -> value < 2); var farView = new FilteredView<>(distance, value -> value >= 5); var dangerQuery = Query.of("danger", (builder, a1, a2) -> builder.clause((a3) -> List.of( a1.notEquivalent(a2), nearView.call(a1, a3), nearView.call(a2, a3), not(farView.call(a1, a2)) ))); var store = ModelStore.builder() .symbols(distance) .with(QueryInterpreterAdapter.builder() .queries(dangerQuery)) .build(); var model = store.createEmptyModel(); var distanceInterpretation = model.getInterpretation(distance); distanceInterpretation.put(Tuple.of(0, 1), 1); distanceInterpretation.put(Tuple.of(1, 0), 1); distanceInterpretation.put(Tuple.of(0, 2), 1); distanceInterpretation.put(Tuple.of(2, 0), 1); distanceInterpretation.put(Tuple.of(1, 2), 3); distanceInterpretation.put(Tuple.of(2, 1), 3); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var dangerResultSet = queryEngine.getResultSet(dangerQuery); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 1), false, Tuple.of(0, 2), false, Tuple.of(1, 2), true, Tuple.of(2, 1), true ), dangerResultSet); } @Test void filteredDoubleViewTest() { var distance = Symbol.of("distance", 2, Double.class); var nearView = new FilteredView<>(distance, value -> value < 2); var farView = new FilteredView<>(distance, value -> value >= 5); var dangerQuery = Query.of("danger", (builder, a1, a2) -> builder.clause((a3) -> List.of( a1.notEquivalent(a2), nearView.call(a1, a3), nearView.call(a2, a3), not(farView.call(a1, a2)) ))); var store = ModelStore.builder() .symbols(distance) .with(QueryInterpreterAdapter.builder() .queries(dangerQuery)) .build(); var model = store.createEmptyModel(); var distanceInterpretation = model.getInterpretation(distance); distanceInterpretation.put(Tuple.of(0, 1), 1.0); distanceInterpretation.put(Tuple.of(1, 0), 1.0); distanceInterpretation.put(Tuple.of(0, 2), 1.0); distanceInterpretation.put(Tuple.of(2, 0), 1.0); distanceInterpretation.put(Tuple.of(1, 2), 3.0); distanceInterpretation.put(Tuple.of(2, 1), 3.0); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var dangerResultSet = queryEngine.getResultSet(dangerQuery); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0, 1), false, Tuple.of(0, 2), false, Tuple.of(1, 2), true, Tuple.of(2, 1), true ), dangerResultSet); } @QueryEngineTest void assumeTest(QueryEvaluationHint hint) { var age = Symbol.of("age", 1, Integer.class); var ageView = new FunctionView<>(age); var query = Query.of("Constraint", (builder, p1) -> builder.clause(Integer.class, (x) -> List.of( personView.call(p1), ageView.call(p1, x), check(greaterEq(x, constant(18))) ))); var store = ModelStore.builder() .symbols(person, age) .with(QueryInterpreterAdapter.builder() .defaultHint(hint) .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); ageInterpretation.put(Tuple.of(0), 12); ageInterpretation.put(Tuple.of(1), 24); queryEngine.flushChanges(); assertResults(Map.of( Tuple.of(0), false, Tuple.of(1), true, Tuple.of(2), false ), queryResultSet); } @Test void alwaysFalseTest() { var predicate = Query.of("AlwaysFalse", builder -> builder.parameter("p1")); var store = ModelStore.builder() .symbols(person) .with(QueryInterpreterAdapter.builder() .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); queryEngine.flushChanges(); assertResults(Map.of(), predicateResultSet); } }