aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query-interpreter/src/test/java/tools/refinery/store/query/interpreter/LeftJoinTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store-query-interpreter/src/test/java/tools/refinery/store/query/interpreter/LeftJoinTest.java')
-rw-r--r--subprojects/store-query-interpreter/src/test/java/tools/refinery/store/query/interpreter/LeftJoinTest.java129
1 files changed, 129 insertions, 0 deletions
diff --git a/subprojects/store-query-interpreter/src/test/java/tools/refinery/store/query/interpreter/LeftJoinTest.java b/subprojects/store-query-interpreter/src/test/java/tools/refinery/store/query/interpreter/LeftJoinTest.java
new file mode 100644
index 00000000..6633b3b1
--- /dev/null
+++ b/subprojects/store-query-interpreter/src/test/java/tools/refinery/store/query/interpreter/LeftJoinTest.java
@@ -0,0 +1,129 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.interpreter;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.logic.dnf.Query;
12import tools.refinery.logic.term.int_.IntTerms;
13import tools.refinery.store.query.view.AnySymbolView;
14import tools.refinery.store.query.view.FunctionView;
15import tools.refinery.store.query.view.KeyOnlyView;
16import tools.refinery.store.representation.Symbol;
17import tools.refinery.store.tuple.Tuple;
18
19import java.util.List;
20import java.util.Map;
21import java.util.Optional;
22
23import static tools.refinery.store.query.interpreter.tests.QueryAssertions.assertNullableResults;
24import static tools.refinery.store.query.interpreter.tests.QueryAssertions.assertResults;
25
26class LeftJoinTest {
27 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
28 private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class);
29 private static final AnySymbolView personView = new KeyOnlyView<>(person);
30 private static final FunctionView<Integer> ageView = new FunctionView<>(age);
31
32 @Test
33 void unarySymbolTest() {
34 var query = Query.of("Query", Integer.class, (builder, p1, output) -> builder
35 .clause(
36 personView.call(p1),
37 output.assign(ageView.leftJoin(18, p1))
38 ));
39
40 var store = ModelStore.builder()
41 .symbols(person, age)
42 .with(QueryInterpreterAdapter.builder()
43 .queries(query))
44 .build();
45
46 var model = store.createEmptyModel();
47 var personInterpretation = model.getInterpretation(person);
48 var ageInterpretation = model.getInterpretation(age);
49 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
50 var queryResultSet = queryEngine.getResultSet(query);
51
52 personInterpretation.put(Tuple.of(0), true);
53 personInterpretation.put(Tuple.of(1), true);
54 personInterpretation.put(Tuple.of(2), true);
55
56 ageInterpretation.put(Tuple.of(2), 24);
57
58 queryEngine.flushChanges();
59 assertNullableResults(Map.of(
60 Tuple.of(0), Optional.of(18),
61 Tuple.of(1), Optional.of(18),
62 Tuple.of(2), Optional.of(24),
63 Tuple.of(3), Optional.empty()
64 ), queryResultSet);
65
66 personInterpretation.put(Tuple.of(0), false);
67
68 ageInterpretation.put(Tuple.of(1), 20);
69 ageInterpretation.put(Tuple.of(2), null);
70
71 queryEngine.flushChanges();
72 assertNullableResults(Map.of(
73 Tuple.of(0), Optional.empty(),
74 Tuple.of(1), Optional.of(20),
75 Tuple.of(2), Optional.of(18),
76 Tuple.of(3), Optional.empty()
77 ), queryResultSet);
78 }
79
80 @Test
81 void unarySymbolWithAssignmentTest() {
82 // Tests an edge case where the outer joined variable is already bound in the query plan.
83 var query = Query.of("Query", (builder, p1) -> builder
84 .clause(Integer.class, v1 -> List.of(
85 personView.call(p1),
86 v1.assign(IntTerms.constant(18)),
87 v1.assign(ageView.leftJoin(18, p1))
88 )));
89
90 var store = ModelStore.builder()
91 .symbols(person, age)
92 .with(QueryInterpreterAdapter.builder()
93 .queries(query))
94 .build();
95
96 var model = store.createEmptyModel();
97 var personInterpretation = model.getInterpretation(person);
98 var ageInterpretation = model.getInterpretation(age);
99 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
100 var queryResultSet = queryEngine.getResultSet(query);
101
102 personInterpretation.put(Tuple.of(0), true);
103 personInterpretation.put(Tuple.of(1), true);
104 personInterpretation.put(Tuple.of(2), true);
105
106 ageInterpretation.put(Tuple.of(2), 24);
107
108 queryEngine.flushChanges();
109 assertResults(Map.of(
110 Tuple.of(0), true,
111 Tuple.of(1), true,
112 Tuple.of(2), false,
113 Tuple.of(3), false
114 ), queryResultSet);
115
116 personInterpretation.put(Tuple.of(0), false);
117
118 ageInterpretation.put(Tuple.of(1), 20);
119 ageInterpretation.put(Tuple.of(2), null);
120
121 queryEngine.flushChanges();
122 assertResults(Map.of(
123 Tuple.of(0), false,
124 Tuple.of(1), false,
125 Tuple.of(2), true,
126 Tuple.of(3), false
127 ), queryResultSet);
128 }
129}