aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query-viatra/src/test
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-03-07 16:26:26 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-03-31 15:38:59 +0200
commit372058e54825ab58a66c25ae528e81a656c22659 (patch)
tree3686057057ebcad2faae7233dc691ecacc3e9fe2 /subprojects/store-query-viatra/src/test
parentrefactor: use Cursor in query result sets (diff)
downloadrefinery-372058e54825ab58a66c25ae528e81a656c22659.tar.gz
refinery-372058e54825ab58a66c25ae528e81a656c22659.tar.zst
refinery-372058e54825ab58a66c25ae528e81a656c22659.zip
feat: terms and improved query evaluation
* Implement data terms for computations in queries. * Function-like queries with computed results. * Improved query evaluation, including positive and negative diagonal cosntraints. * Preliminary local search support. * Changes to the DNF representation for count and aggregation support. feat: terms wip feat: query terms wip feat: query evaluation, diagonal constraints, local search wip fix reasoning compilation wip
Diffstat (limited to 'subprojects/store-query-viatra/src/test')
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java471
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java607
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java428
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java384
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java52
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java22
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java16
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java19
8 files changed, 1810 insertions, 189 deletions
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java
new file mode 100644
index 00000000..90229b73
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java
@@ -0,0 +1,471 @@
1package tools.refinery.store.query.viatra;
2
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.ModelQuery;
6import tools.refinery.store.query.dnf.Dnf;
7import tools.refinery.store.query.dnf.Query;
8import tools.refinery.store.query.term.Variable;
9import tools.refinery.store.query.viatra.tests.QueryEngineTest;
10import tools.refinery.store.query.view.FunctionalRelationView;
11import tools.refinery.store.query.view.KeyOnlyRelationView;
12import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.tuple.Tuple;
14
15import java.util.Map;
16import java.util.Optional;
17
18import static tools.refinery.store.query.literal.Literals.not;
19import static tools.refinery.store.query.term.int_.IntTerms.INT_SUM;
20import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults;
21import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
22
23class DiagonalQueryTest {
24 @QueryEngineTest
25 void inputKeyNegationTest(QueryEvaluationHint hint) {
26 var person = new Symbol<>("Person", 1, Boolean.class, false);
27 var symbol = new Symbol<>("symbol", 4, Boolean.class, false);
28 var personView = new KeyOnlyRelationView<>(person);
29 var symbolView = new KeyOnlyRelationView<>(symbol);
30
31 var p1 = Variable.of("p1");
32 var p2 = Variable.of("p2");
33 var query = Query.builder("Diagonal")
34 .parameter(p1)
35 .clause(
36 personView.call(p1),
37 not(symbolView.call(p1, p1, p2, p2))
38 )
39 .build();
40
41 var store = ModelStore.builder()
42 .symbols(person, symbol)
43 .with(ViatraModelQuery.ADAPTER)
44 .defaultHint(hint)
45 .queries(query)
46 .build();
47
48 var model = store.createEmptyModel();
49 var personInterpretation = model.getInterpretation(person);
50 var symbolInterpretation = model.getInterpretation(symbol);
51 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
52 var queryResultSet = queryEngine.getResultSet(query);
53
54 personInterpretation.put(Tuple.of(0), true);
55 personInterpretation.put(Tuple.of(1), true);
56 personInterpretation.put(Tuple.of(2), true);
57
58 symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true);
59 symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true);
60 symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true);
61 symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true);
62
63 queryEngine.flushChanges();
64 assertResults(Map.of(
65 Tuple.of(0), false,
66 Tuple.of(1), true,
67 Tuple.of(2), true,
68 Tuple.of(3), false
69 ), queryResultSet);
70 }
71
72 @QueryEngineTest
73 void subQueryNegationTest(QueryEvaluationHint hint) {
74 var person = new Symbol<>("Person", 1, Boolean.class, false);
75 var symbol = new Symbol<>("symbol", 4, Boolean.class, false);
76 var personView = new KeyOnlyRelationView<>(person);
77 var symbolView = new KeyOnlyRelationView<>(symbol);
78
79 var p1 = Variable.of("p1");
80 var p2 = Variable.of("p2");
81 var p3 = Variable.of("p3");
82 var p4 = Variable.of("p4");
83 var subQuery = Dnf.builder("SubQuery")
84 .parameters(p1, p2, p3, p4)
85 .clause(
86 personView.call(p1),
87 symbolView.call(p1, p2, p3, p4)
88 )
89 .clause(
90 personView.call(p2),
91 symbolView.call(p1, p2, p3, p4)
92 )
93 .build();
94 var query = Query.builder("Diagonal")
95 .parameter(p1)
96 .clause(
97 personView.call(p1),
98 not(subQuery.call(p1, p1, p2, p2))
99 )
100 .build();
101
102 var store = ModelStore.builder()
103 .symbols(person, symbol)
104 .with(ViatraModelQuery.ADAPTER)
105 .defaultHint(hint)
106 .queries(query)
107 .build();
108
109 var model = store.createEmptyModel();
110 var personInterpretation = model.getInterpretation(person);
111 var symbolInterpretation = model.getInterpretation(symbol);
112 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
113 var queryResultSet = queryEngine.getResultSet(query);
114
115 personInterpretation.put(Tuple.of(0), true);
116 personInterpretation.put(Tuple.of(1), true);
117 personInterpretation.put(Tuple.of(2), true);
118
119 symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true);
120 symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true);
121 symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true);
122 symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true);
123
124 queryEngine.flushChanges();
125 assertResults(Map.of(
126 Tuple.of(0), false,
127 Tuple.of(1), true,
128 Tuple.of(2), true,
129 Tuple.of(3), false
130 ), queryResultSet);
131 }
132
133 @QueryEngineTest
134 void inputKeyCountTest(QueryEvaluationHint hint) {
135 var person = new Symbol<>("Person", 1, Boolean.class, false);
136 var symbol = new Symbol<>("symbol", 4, Boolean.class, false);
137 var personView = new KeyOnlyRelationView<>(person);
138 var symbolView = new KeyOnlyRelationView<>(symbol);
139
140 var p1 = Variable.of("p1");
141 var p2 = Variable.of("p2");
142 var x = Variable.of("x", Integer.class);
143 var query = Query.builder("Diagonal")
144 .parameter(p1)
145 .output(x)
146 .clause(
147 personView.call(p1),
148 x.assign(symbolView.count(p1, p1, p2, p2))
149 )
150 .build();
151
152 var store = ModelStore.builder()
153 .symbols(person, symbol)
154 .with(ViatraModelQuery.ADAPTER)
155 .defaultHint(hint)
156 .queries(query)
157 .build();
158
159 var model = store.createEmptyModel();
160 var personInterpretation = model.getInterpretation(person);
161 var symbolInterpretation = model.getInterpretation(symbol);
162 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
163 var queryResultSet = queryEngine.getResultSet(query);
164
165 personInterpretation.put(Tuple.of(0), true);
166 personInterpretation.put(Tuple.of(1), true);
167 personInterpretation.put(Tuple.of(2), true);
168
169 symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true);
170 symbolInterpretation.put(Tuple.of(0, 0, 2, 2), true);
171 symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true);
172 symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true);
173 symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true);
174
175 queryEngine.flushChanges();
176 assertNullableResults(Map.of(
177 Tuple.of(0), Optional.of(2),
178 Tuple.of(1), Optional.of(0),
179 Tuple.of(2), Optional.of(0),
180 Tuple.of(3), Optional.empty()
181 ), queryResultSet);
182 }
183
184 @QueryEngineTest
185 void subQueryCountTest(QueryEvaluationHint hint) {
186 var person = new Symbol<>("Person", 1, Boolean.class, false);
187 var symbol = new Symbol<>("symbol", 4, Boolean.class, false);
188 var personView = new KeyOnlyRelationView<>(person);
189 var symbolView = new KeyOnlyRelationView<>(symbol);
190
191 var p1 = Variable.of("p1");
192 var p2 = Variable.of("p2");
193 var p3 = Variable.of("p3");
194 var p4 = Variable.of("p4");
195 var x = Variable.of("x", Integer.class);
196 var subQuery = Dnf.builder("SubQuery")
197 .parameters(p1, p2, p3, p4)
198 .clause(
199 personView.call(p1),
200 symbolView.call(p1, p2, p3, p4)
201 )
202 .clause(
203 personView.call(p2),
204 symbolView.call(p1, p2, p3, p4)
205 )
206 .build();
207 var query = Query.builder("Diagonal")
208 .parameter(p1)
209 .output(x)
210 .clause(
211 personView.call(p1),
212 x.assign(subQuery.count(p1, p1, p2, p2))
213 )
214 .build();
215
216 var store = ModelStore.builder()
217 .symbols(person, symbol)
218 .with(ViatraModelQuery.ADAPTER)
219 .defaultHint(hint)
220 .queries(query)
221 .build();
222
223 var model = store.createEmptyModel();
224 var personInterpretation = model.getInterpretation(person);
225 var symbolInterpretation = model.getInterpretation(symbol);
226 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
227 var queryResultSet = queryEngine.getResultSet(query);
228
229 personInterpretation.put(Tuple.of(0), true);
230 personInterpretation.put(Tuple.of(1), true);
231 personInterpretation.put(Tuple.of(2), true);
232
233 symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true);
234 symbolInterpretation.put(Tuple.of(0, 0, 2, 2), true);
235 symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true);
236 symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true);
237 symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true);
238
239 queryEngine.flushChanges();
240 assertNullableResults(Map.of(
241 Tuple.of(0), Optional.of(2),
242 Tuple.of(1), Optional.of(0),
243 Tuple.of(2), Optional.of(0),
244 Tuple.of(3), Optional.empty()
245 ), queryResultSet);
246 }
247
248 @QueryEngineTest
249 void inputKeyAggregationTest(QueryEvaluationHint hint) {
250 var person = new Symbol<>("Person", 1, Boolean.class, false);
251 var symbol = new Symbol<>("symbol", 4, Integer.class, null);
252 var personView = new KeyOnlyRelationView<>(person);
253 var symbolView = new FunctionalRelationView<>(symbol);
254
255 var p1 = Variable.of("p1");
256 var p2 = Variable.of("p2");
257 var x = Variable.of("x", Integer.class);
258 var y = Variable.of("y", Integer.class);
259 var query = Query.builder("Diagonal")
260 .parameter(p1)
261 .output(x)
262 .clause(
263 personView.call(p1),
264 x.assign(symbolView.aggregate(y, INT_SUM, p1, p1, p2, p2, y))
265 )
266 .build();
267
268 var store = ModelStore.builder()
269 .symbols(person, symbol)
270 .with(ViatraModelQuery.ADAPTER)
271 .defaultHint(hint)
272 .queries(query)
273 .build();
274
275 var model = store.createEmptyModel();
276 var personInterpretation = model.getInterpretation(person);
277 var symbolInterpretation = model.getInterpretation(symbol);
278 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
279 var queryResultSet = queryEngine.getResultSet(query);
280
281 personInterpretation.put(Tuple.of(0), true);
282 personInterpretation.put(Tuple.of(1), true);
283 personInterpretation.put(Tuple.of(2), true);
284
285 symbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1);
286 symbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2);
287 symbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10);
288 symbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11);
289 symbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12);
290
291 queryEngine.flushChanges();
292 assertNullableResults(Map.of(
293 Tuple.of(0), Optional.of(3),
294 Tuple.of(1), Optional.of(0),
295 Tuple.of(2), Optional.of(0),
296 Tuple.of(3), Optional.empty()
297 ), queryResultSet);
298 }
299
300 @QueryEngineTest
301 void subQueryAggregationTest(QueryEvaluationHint hint) {
302 var person = new Symbol<>("Person", 1, Boolean.class, false);
303 var symbol = new Symbol<>("symbol", 4, Integer.class, null);
304 var personView = new KeyOnlyRelationView<>(person);
305 var symbolView = new FunctionalRelationView<>(symbol);
306
307 var p1 = Variable.of("p1");
308 var p2 = Variable.of("p2");
309 var p3 = Variable.of("p3");
310 var p4 = Variable.of("p4");
311 var x = Variable.of("x", Integer.class);
312 var y = Variable.of("y", Integer.class);
313 var z = Variable.of("z", Integer.class);
314 var subQuery = Dnf.builder("SubQuery")
315 .parameters(p1, p2, p3, p4, x, y)
316 .clause(
317 personView.call(p1),
318 symbolView.call(p1, p2, p3, p4, x),
319 y.assign(x)
320 )
321 .clause(
322 personView.call(p2),
323 symbolView.call(p1, p2, p3, p4, x),
324 y.assign(x)
325 )
326 .build();
327 var query = Query.builder("Diagonal")
328 .parameter(p1)
329 .output(x)
330 .clause(
331 personView.call(p1),
332 x.assign(subQuery.aggregate(z, INT_SUM, p1, p1, p2, p2, z, z))
333 )
334 .build();
335
336 var store = ModelStore.builder()
337 .symbols(person, symbol)
338 .with(ViatraModelQuery.ADAPTER)
339 .defaultHint(hint)
340 .queries(query)
341 .build();
342
343 var model = store.createEmptyModel();
344 var personInterpretation = model.getInterpretation(person);
345 var symbolInterpretation = model.getInterpretation(symbol);
346 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
347 var queryResultSet = queryEngine.getResultSet(query);
348
349 personInterpretation.put(Tuple.of(0), true);
350 personInterpretation.put(Tuple.of(1), true);
351 personInterpretation.put(Tuple.of(2), true);
352
353 symbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1);
354 symbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2);
355 symbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10);
356 symbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11);
357 symbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12);
358
359 queryEngine.flushChanges();
360 assertNullableResults(Map.of(
361 Tuple.of(0), Optional.of(3),
362 Tuple.of(1), Optional.of(0),
363 Tuple.of(2), Optional.of(0),
364 Tuple.of(3), Optional.empty()
365 ), queryResultSet);
366 }
367
368 @QueryEngineTest
369 void inputKeyTransitiveTest(QueryEvaluationHint hint) {
370 var person = new Symbol<>("Person", 1, Boolean.class, false);
371 var symbol = new Symbol<>("symbol", 2, Boolean.class, false);
372 var personView = new KeyOnlyRelationView<>(person);
373 var symbolView = new KeyOnlyRelationView<>(symbol);
374
375 var p1 = Variable.of("p1");
376 var query = Query.builder("Diagonal")
377 .parameter(p1)
378 .clause(
379 personView.call(p1),
380 symbolView.callTransitive(p1, p1)
381 )
382 .build();
383
384 var store = ModelStore.builder()
385 .symbols(person, symbol)
386 .with(ViatraModelQuery.ADAPTER)
387 .defaultHint(hint)
388 .queries(query)
389 .build();
390
391 var model = store.createEmptyModel();
392 var personInterpretation = model.getInterpretation(person);
393 var symbolInterpretation = model.getInterpretation(symbol);
394 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
395 var queryResultSet = queryEngine.getResultSet(query);
396
397 personInterpretation.put(Tuple.of(0), true);
398 personInterpretation.put(Tuple.of(1), true);
399 personInterpretation.put(Tuple.of(2), true);
400
401 symbolInterpretation.put(Tuple.of(0, 0), true);
402 symbolInterpretation.put(Tuple.of(0, 1), true);
403 symbolInterpretation.put(Tuple.of(1, 2), true);
404
405 queryEngine.flushChanges();
406 assertResults(Map.of(
407 Tuple.of(0), true,
408 Tuple.of(1), false,
409 Tuple.of(2), false,
410 Tuple.of(3), false
411 ), queryResultSet);
412 }
413
414 @QueryEngineTest
415 void subQueryTransitiveTest(QueryEvaluationHint hint) {
416 var person = new Symbol<>("Person", 1, Boolean.class, false);
417 var symbol = new Symbol<>("symbol", 2, Boolean.class, false);
418 var personView = new KeyOnlyRelationView<>(person);
419 var symbolView = new KeyOnlyRelationView<>(symbol);
420
421 var p1 = Variable.of("p1");
422 var p2 = Variable.of("p2");
423 var subQuery = Dnf.builder("SubQuery")
424 .parameters(p1, p2)
425 .clause(
426 personView.call(p1),
427 symbolView.call(p1, p2)
428 )
429 .clause(
430 personView.call(p2),
431 symbolView.call(p1, p2)
432 )
433 .build();
434 var query = Query.builder("Diagonal")
435 .parameter(p1)
436 .clause(
437 personView.call(p1),
438 subQuery.callTransitive(p1, p1)
439 )
440 .build();
441
442 var store = ModelStore.builder()
443 .symbols(person, symbol)
444 .with(ViatraModelQuery.ADAPTER)
445 .defaultHint(hint)
446 .queries(query)
447 .build();
448
449 var model = store.createEmptyModel();
450 var personInterpretation = model.getInterpretation(person);
451 var symbolInterpretation = model.getInterpretation(symbol);
452 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
453 var queryResultSet = queryEngine.getResultSet(query);
454
455 personInterpretation.put(Tuple.of(0), true);
456 personInterpretation.put(Tuple.of(1), true);
457 personInterpretation.put(Tuple.of(2), true);
458
459 symbolInterpretation.put(Tuple.of(0, 0), true);
460 symbolInterpretation.put(Tuple.of(0, 1), true);
461 symbolInterpretation.put(Tuple.of(1, 2), true);
462
463 queryEngine.flushChanges();
464 assertResults(Map.of(
465 Tuple.of(0), true,
466 Tuple.of(1), false,
467 Tuple.of(2), false,
468 Tuple.of(3), false
469 ), queryResultSet);
470 }
471}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java
new file mode 100644
index 00000000..fa2a008f
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java
@@ -0,0 +1,607 @@
1package tools.refinery.store.query.viatra;
2
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4import tools.refinery.store.map.Cursor;
5import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.query.ModelQuery;
7import tools.refinery.store.query.dnf.Dnf;
8import tools.refinery.store.query.dnf.Query;
9import tools.refinery.store.query.term.Variable;
10import tools.refinery.store.query.viatra.tests.QueryEngineTest;
11import tools.refinery.store.query.view.FilteredRelationView;
12import tools.refinery.store.query.view.FunctionalRelationView;
13import tools.refinery.store.query.view.KeyOnlyRelationView;
14import tools.refinery.store.representation.Symbol;
15import tools.refinery.store.representation.TruthValue;
16import tools.refinery.store.tuple.Tuple;
17
18import java.util.Map;
19import java.util.Optional;
20
21import static org.hamcrest.MatcherAssert.assertThat;
22import static org.hamcrest.Matchers.is;
23import static org.hamcrest.Matchers.nullValue;
24import static org.junit.jupiter.api.Assertions.assertAll;
25import static org.junit.jupiter.api.Assertions.assertThrows;
26import static tools.refinery.store.query.literal.Literals.assume;
27import static tools.refinery.store.query.term.int_.IntTerms.*;
28import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults;
29import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
30
31class FunctionalQueryTest {
32 @QueryEngineTest
33 void inputKeyTest(QueryEvaluationHint hint) {
34 var person = new Symbol<>("Person", 1, Boolean.class, false);
35 var age = new Symbol<>("age", 1, Integer.class, null);
36 var personView = new KeyOnlyRelationView<>(person);
37 var ageView = new FunctionalRelationView<>(age);
38
39 var p1 = Variable.of("p1");
40 var x = Variable.of("x", Integer.class);
41 var query = Query.builder("InputKey")
42 .parameter(p1)
43 .output(x)
44 .clause(
45 personView.call(p1),
46 ageView.call(p1, x)
47 )
48 .build();
49
50 var store = ModelStore.builder()
51 .symbols(person, age)
52 .with(ViatraModelQuery.ADAPTER)
53 .defaultHint(hint)
54 .queries(query)
55 .build();
56
57 var model = store.createEmptyModel();
58 var personInterpretation = model.getInterpretation(person);
59 var ageInterpretation = model.getInterpretation(age);
60 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
61 var queryResultSet = queryEngine.getResultSet(query);
62
63 personInterpretation.put(Tuple.of(0), true);
64 personInterpretation.put(Tuple.of(1), true);
65
66 ageInterpretation.put(Tuple.of(0), 12);
67 ageInterpretation.put(Tuple.of(1), 24);
68 ageInterpretation.put(Tuple.of(2), 36);
69
70 queryEngine.flushChanges();
71 assertNullableResults(Map.of(
72 Tuple.of(0), Optional.of(12),
73 Tuple.of(1), Optional.of(24),
74 Tuple.of(2), Optional.empty()
75 ), queryResultSet);
76 }
77
78 @QueryEngineTest
79 void predicateTest(QueryEvaluationHint hint) {
80 var person = new Symbol<>("Person", 1, Boolean.class, false);
81 var age = new Symbol<>("age", 1, Integer.class, null);
82 var personView = new KeyOnlyRelationView<>(person);
83 var ageView = new FunctionalRelationView<>(age);
84
85 var p1 = Variable.of("p1");
86 var x = Variable.of("x", Integer.class);
87 var subQuery = Dnf.builder("SubQuery")
88 .parameters(p1, x)
89 .clause(
90 personView.call(p1),
91 ageView.call(p1, x)
92 )
93 .build();
94 var query = Query.builder("Predicate")
95 .parameter(p1)
96 .output(x)
97 .clause(
98 personView.call(p1),
99 subQuery.call(p1, x)
100 )
101 .build();
102
103 var store = ModelStore.builder()
104 .symbols(person, age)
105 .with(ViatraModelQuery.ADAPTER)
106 .defaultHint(hint)
107 .queries(query)
108 .build();
109
110 var model = store.createEmptyModel();
111 var personInterpretation = model.getInterpretation(person);
112 var ageInterpretation = model.getInterpretation(age);
113 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
114 var queryResultSet = queryEngine.getResultSet(query);
115
116 personInterpretation.put(Tuple.of(0), true);
117 personInterpretation.put(Tuple.of(1), true);
118
119 ageInterpretation.put(Tuple.of(0), 12);
120 ageInterpretation.put(Tuple.of(1), 24);
121 ageInterpretation.put(Tuple.of(2), 36);
122
123 queryEngine.flushChanges();
124 assertNullableResults(Map.of(
125 Tuple.of(0), Optional.of(12),
126 Tuple.of(1), Optional.of(24),
127 Tuple.of(2), Optional.empty()
128 ), queryResultSet);
129 }
130
131 @QueryEngineTest
132 void computationTest(QueryEvaluationHint hint) {
133 var person = new Symbol<>("Person", 1, Boolean.class, false);
134 var age = new Symbol<>("age", 1, Integer.class, null);
135 var personView = new KeyOnlyRelationView<>(person);
136 var ageView = new FunctionalRelationView<>(age);
137
138 var p1 = Variable.of("p1");
139 var x = Variable.of("x", Integer.class);
140 var y = Variable.of("y", Integer.class);
141 var query = Query.builder("Computation")
142 .parameter(p1)
143 .output(y)
144 .clause(
145 personView.call(p1),
146 ageView.call(p1, x),
147 y.assign(mul(x, constant(7)))
148 )
149 .build();
150
151 var store = ModelStore.builder()
152 .symbols(person, age)
153 .with(ViatraModelQuery.ADAPTER)
154 .defaultHint(hint)
155 .queries(query)
156 .build();
157
158 var model = store.createEmptyModel();
159 var personInterpretation = model.getInterpretation(person);
160 var ageInterpretation = model.getInterpretation(age);
161 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
162 var queryResultSet = queryEngine.getResultSet(query);
163
164 personInterpretation.put(Tuple.of(0), true);
165 personInterpretation.put(Tuple.of(1), true);
166
167 ageInterpretation.put(Tuple.of(0), 12);
168 ageInterpretation.put(Tuple.of(1), 24);
169
170 queryEngine.flushChanges();
171 assertNullableResults(Map.of(
172 Tuple.of(0), Optional.of(84),
173 Tuple.of(1), Optional.of(168),
174 Tuple.of(2), Optional.empty()
175 ), queryResultSet);
176 }
177
178 @QueryEngineTest
179 void inputKeyCountTest(QueryEvaluationHint hint) {
180 var person = new Symbol<>("Person", 1, Boolean.class, false);
181 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
182 var personView = new KeyOnlyRelationView<>(person);
183 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
184
185 var p1 = Variable.of("p1");
186 var p2 = Variable.of("p2");
187 var x = Variable.of("x", Integer.class);
188 var query = Query.builder("Count")
189 .parameter(p1)
190 .output(x)
191 .clause(
192 personView.call(p1),
193 x.assign(friendMustView.count(p1, p2))
194 )
195 .build();
196
197 var store = ModelStore.builder()
198 .symbols(person, friend)
199 .with(ViatraModelQuery.ADAPTER)
200 .defaultHint(hint)
201 .queries(query)
202 .build();
203
204 var model = store.createEmptyModel();
205 var personInterpretation = model.getInterpretation(person);
206 var friendInterpretation = model.getInterpretation(friend);
207 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
208 var queryResultSet = queryEngine.getResultSet(query);
209
210 personInterpretation.put(Tuple.of(0), true);
211 personInterpretation.put(Tuple.of(1), true);
212 personInterpretation.put(Tuple.of(2), true);
213
214 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
215 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
216 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
217
218 queryEngine.flushChanges();
219 assertNullableResults(Map.of(
220 Tuple.of(0), Optional.of(1),
221 Tuple.of(1), Optional.of(2),
222 Tuple.of(2), Optional.of(0),
223 Tuple.of(3), Optional.empty()
224 ), queryResultSet);
225 }
226
227 @QueryEngineTest
228 void predicateCountTest(QueryEvaluationHint hint) {
229 var person = new Symbol<>("Person", 1, Boolean.class, false);
230 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
231 var personView = new KeyOnlyRelationView<>(person);
232 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
233
234 var p1 = Variable.of("p1");
235 var p2 = Variable.of("p2");
236 var x = Variable.of("x", Integer.class);
237 var subQuery = Dnf.builder("SubQuery")
238 .parameters(p1, p2)
239 .clause(
240 personView.call(p1),
241 personView.call(p2),
242 friendMustView.call(p1, p2)
243 )
244 .build();
245 var query = Query.builder("Count")
246 .parameter(p1)
247 .output(x)
248 .clause(
249 personView.call(p1),
250 x.assign(subQuery.count(p1, p2))
251 )
252 .build();
253
254 var store = ModelStore.builder()
255 .symbols(person, friend)
256 .with(ViatraModelQuery.ADAPTER)
257 .defaultHint(hint)
258 .queries(query)
259 .build();
260
261 var model = store.createEmptyModel();
262 var personInterpretation = model.getInterpretation(person);
263 var friendInterpretation = model.getInterpretation(friend);
264 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
265 var queryResultSet = queryEngine.getResultSet(query);
266
267 personInterpretation.put(Tuple.of(0), true);
268 personInterpretation.put(Tuple.of(1), true);
269 personInterpretation.put(Tuple.of(2), true);
270
271 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
272 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
273 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
274
275 queryEngine.flushChanges();
276 assertNullableResults(Map.of(
277 Tuple.of(0), Optional.of(1),
278 Tuple.of(1), Optional.of(2),
279 Tuple.of(2), Optional.of(0),
280 Tuple.of(3), Optional.empty()
281 ), queryResultSet);
282 }
283
284 @QueryEngineTest
285 void inputKeyAggregationTest(QueryEvaluationHint hint) {
286 var age = new Symbol<>("age", 1, Integer.class, null);
287 var ageView = new FunctionalRelationView<>(age);
288
289 var p1 = Variable.of("p1");
290 var x = Variable.of("x", Integer.class);
291 var y = Variable.of("y", Integer.class);
292 var query = Query.builder("Aggregate")
293 .output(x)
294 .clause(
295 x.assign(ageView.aggregate(y, INT_SUM, p1, y))
296 )
297 .build();
298
299 var store = ModelStore.builder()
300 .symbols(age)
301 .with(ViatraModelQuery.ADAPTER)
302 .defaultHint(hint)
303 .queries(query)
304 .build();
305
306 var model = store.createEmptyModel();
307 var ageInterpretation = model.getInterpretation(age);
308 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
309 var queryResultSet = queryEngine.getResultSet(query);
310
311 ageInterpretation.put(Tuple.of(0), 12);
312 ageInterpretation.put(Tuple.of(1), 24);
313
314 queryEngine.flushChanges();
315 assertResults(Map.of(Tuple.of(), 36), queryResultSet);
316 }
317
318 @QueryEngineTest
319 void predicateAggregationTest(QueryEvaluationHint hint) {
320 var person = new Symbol<>("Person", 1, Boolean.class, false);
321 var age = new Symbol<>("age", 1, Integer.class, null);
322 var personView = new KeyOnlyRelationView<>(person);
323 var ageView = new FunctionalRelationView<>(age);
324
325 var p1 = Variable.of("p1");
326 var x = Variable.of("x", Integer.class);
327 var y = Variable.of("y", Integer.class);
328 var subQuery = Dnf.builder("SubQuery")
329 .parameters(p1, x)
330 .clause(
331 personView.call(p1),
332 ageView.call(p1, x)
333 )
334 .build();
335 var query = Query.builder("Aggregate")
336 .output(x)
337 .clause(
338 x.assign(subQuery.aggregate(y, INT_SUM, p1, y))
339 )
340 .build();
341
342 var store = ModelStore.builder()
343 .symbols(person, age)
344 .with(ViatraModelQuery.ADAPTER)
345 .defaultHint(hint)
346 .queries(query)
347 .build();
348
349 var model = store.createEmptyModel();
350 var personInterpretation = model.getInterpretation(person);
351 var ageInterpretation = model.getInterpretation(age);
352 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
353 var queryResultSet = queryEngine.getResultSet(query);
354
355 personInterpretation.put(Tuple.of(0), true);
356 personInterpretation.put(Tuple.of(1), true);
357
358 ageInterpretation.put(Tuple.of(0), 12);
359 ageInterpretation.put(Tuple.of(1), 24);
360
361 queryEngine.flushChanges();
362 assertResults(Map.of(Tuple.of(), 36), queryResultSet);
363 }
364
365 @QueryEngineTest
366 void extremeValueTest(QueryEvaluationHint hint) {
367 var person = new Symbol<>("Person", 1, Boolean.class, false);
368 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
369 var personView = new KeyOnlyRelationView<>(person);
370 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
371
372 var p1 = Variable.of("p1");
373 var p2 = Variable.of("p2");
374 var x = Variable.of("x", Integer.class);
375 var y = Variable.of("y", Integer.class);
376 var subQuery = Dnf.builder("SubQuery")
377 .parameters(p1, x)
378 .clause(
379 personView.call(p1),
380 x.assign(friendMustView.count(p1, p2))
381 )
382 .build();
383 var minQuery = Query.builder("Min")
384 .output(x)
385 .clause(
386 x.assign(subQuery.aggregate(y, INT_MIN, p1, y))
387 )
388 .build();
389 var maxQuery = Query.builder("Max")
390 .output(x)
391 .clause(
392 x.assign(subQuery.aggregate(y, INT_MAX, p1, y))
393 )
394 .build();
395
396 var store = ModelStore.builder()
397 .symbols(person, friend)
398 .with(ViatraModelQuery.ADAPTER)
399 .defaultHint(hint)
400 .queries(minQuery, maxQuery)
401 .build();
402
403 var model = store.createEmptyModel();
404 var personInterpretation = model.getInterpretation(person);
405 var friendInterpretation = model.getInterpretation(friend);
406 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
407 var minResultSet = queryEngine.getResultSet(minQuery);
408 var maxResultSet = queryEngine.getResultSet(maxQuery);
409
410 assertResults(Map.of(Tuple.of(), Integer.MAX_VALUE), minResultSet);
411 assertResults(Map.of(Tuple.of(), Integer.MIN_VALUE), maxResultSet);
412
413 personInterpretation.put(Tuple.of(0), true);
414 personInterpretation.put(Tuple.of(1), true);
415 personInterpretation.put(Tuple.of(2), true);
416
417 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
418 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
419 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
420
421 queryEngine.flushChanges();
422 assertResults(Map.of(Tuple.of(), 0), minResultSet);
423 assertResults(Map.of(Tuple.of(), 2), maxResultSet);
424
425 friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE);
426 friendInterpretation.put(Tuple.of(2, 1), TruthValue.TRUE);
427
428 queryEngine.flushChanges();
429 assertResults(Map.of(Tuple.of(), 1), minResultSet);
430 assertResults(Map.of(Tuple.of(), 2), maxResultSet);
431
432 friendInterpretation.put(Tuple.of(0, 1), TruthValue.FALSE);
433 friendInterpretation.put(Tuple.of(1, 0), TruthValue.FALSE);
434 friendInterpretation.put(Tuple.of(2, 0), TruthValue.FALSE);
435
436 queryEngine.flushChanges();
437 assertResults(Map.of(Tuple.of(), 0), minResultSet);
438 assertResults(Map.of(Tuple.of(), 1), maxResultSet);
439 }
440
441 @QueryEngineTest
442 void invalidComputationTest(QueryEvaluationHint hint) {
443 var person = new Symbol<>("Person", 1, Boolean.class, false);
444 var age = new Symbol<>("age", 1, Integer.class, null);
445 var personView = new KeyOnlyRelationView<>(person);
446 var ageView = new FunctionalRelationView<>(age);
447
448 var p1 = Variable.of("p1");
449 var x = Variable.of("x", Integer.class);
450 var y = Variable.of("y", Integer.class);
451 var query = Query.builder("InvalidComputation")
452 .parameter(p1)
453 .output(y)
454 .clause(
455 personView.call(p1),
456 ageView.call(p1, x),
457 y.assign(div(constant(120), x))
458 )
459 .build();
460
461 var store = ModelStore.builder()
462 .symbols(person, age)
463 .with(ViatraModelQuery.ADAPTER)
464 .defaultHint(hint)
465 .queries(query)
466 .build();
467
468 var model = store.createEmptyModel();
469 var personInterpretation = model.getInterpretation(person);
470 var ageInterpretation = model.getInterpretation(age);
471 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
472 var queryResultSet = queryEngine.getResultSet(query);
473
474 personInterpretation.put(Tuple.of(0), true);
475 personInterpretation.put(Tuple.of(1), true);
476
477 ageInterpretation.put(Tuple.of(0), 0);
478 ageInterpretation.put(Tuple.of(1), 30);
479
480 queryEngine.flushChanges();
481 assertNullableResults(Map.of(
482 Tuple.of(0), Optional.empty(),
483 Tuple.of(1), Optional.of(4),
484 Tuple.of(2), Optional.empty()
485 ), queryResultSet);
486 }
487
488 @QueryEngineTest
489 void invalidAssumeTest(QueryEvaluationHint hint) {
490 var person = new Symbol<>("Person", 1, Boolean.class, false);
491 var age = new Symbol<>("age", 1, Integer.class, null);
492 var personView = new KeyOnlyRelationView<>(person);
493 var ageView = new FunctionalRelationView<>(age);
494
495 var p1 = Variable.of("p1");
496 var x = Variable.of("x", Integer.class);
497 var query = Query.builder("InvalidComputation")
498 .parameter(p1)
499 .clause(
500 personView.call(p1),
501 ageView.call(p1, x),
502 assume(lessEq(div(constant(120), x), constant(5)))
503 )
504 .build();
505
506 var store = ModelStore.builder()
507 .symbols(person, age)
508 .with(ViatraModelQuery.ADAPTER)
509 .defaultHint(hint)
510 .queries(query)
511 .build();
512
513 var model = store.createEmptyModel();
514 var personInterpretation = model.getInterpretation(person);
515 var ageInterpretation = model.getInterpretation(age);
516 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
517 var queryResultSet = queryEngine.getResultSet(query);
518
519 personInterpretation.put(Tuple.of(0), true);
520 personInterpretation.put(Tuple.of(1), true);
521 personInterpretation.put(Tuple.of(2), true);
522
523 ageInterpretation.put(Tuple.of(0), 0);
524 ageInterpretation.put(Tuple.of(1), 30);
525 ageInterpretation.put(Tuple.of(2), 20);
526
527 queryEngine.flushChanges();
528 assertResults(Map.of(
529 Tuple.of(0), false,
530 Tuple.of(1), true,
531 Tuple.of(2), false,
532 Tuple.of(3), false
533 ), queryResultSet);
534 }
535
536 @QueryEngineTest
537 void notFunctionalTest(QueryEvaluationHint hint) {
538 var person = new Symbol<>("Person", 1, Boolean.class, false);
539 var age = new Symbol<>("age", 1, Integer.class, null);
540 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
541 var personView = new KeyOnlyRelationView<>(person);
542 var ageView = new FunctionalRelationView<>(age);
543 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
544
545 var p1 = Variable.of("p1");
546 var p2 = Variable.of("p2");
547 var x = Variable.of("x", Integer.class);
548 var query = Query.builder("NotFunctional")
549 .parameter(p1)
550 .output(x)
551 .clause(
552 personView.call(p1),
553 friendMustView.call(p1, p2),
554 ageView.call(p2, x)
555 )
556 .build();
557
558 var store = ModelStore.builder()
559 .symbols(person, age, friend)
560 .with(ViatraModelQuery.ADAPTER)
561 .defaultHint(hint)
562 .query(query)
563 .build();
564
565 var model = store.createEmptyModel();
566 var personInterpretation = model.getInterpretation(person);
567 var ageInterpretation = model.getInterpretation(age);
568 var friendInterpretation = model.getInterpretation(friend);
569 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
570 var queryResultSet = queryEngine.getResultSet(query);
571
572 personInterpretation.put(Tuple.of(0), true);
573 personInterpretation.put(Tuple.of(1), true);
574 personInterpretation.put(Tuple.of(2), true);
575
576 ageInterpretation.put(Tuple.of(0), 24);
577 ageInterpretation.put(Tuple.of(1), 30);
578 ageInterpretation.put(Tuple.of(2), 36);
579
580 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
581 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
582 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
583
584 queryEngine.flushChanges();
585 var invalidTuple = Tuple.of(1);
586 var cursor = queryResultSet.getAll();
587 assertAll(
588 () -> assertThat("value for key 0", queryResultSet.get(Tuple.of(0)), is(30)),
589 () -> assertThrows(IllegalStateException.class, () -> queryResultSet.get(invalidTuple),
590 "multiple values for key 1"),
591 () -> assertThat("value for key 2", queryResultSet.get(Tuple.of(2)), is(nullValue())),
592 () -> assertThat("value for key 3", queryResultSet.get(Tuple.of(3)), is(nullValue()))
593 );
594 if (hint.getQueryBackendRequirementType() != QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH) {
595 // Local search doesn't support throwing an error on multiple function return values.
596 assertThat("results size", queryResultSet.size(), is(2));
597 assertThrows(IllegalStateException.class, () -> enumerateValues(cursor), "move cursor");
598 }
599 }
600
601 private static void enumerateValues(Cursor<?, ?> cursor) {
602 //noinspection StatementWithEmptyBody
603 while (cursor.move()) {
604 // Nothing do, just let the cursor move through the result set.
605 }
606 }
607}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java
index 8b25419d..8a3f9d88 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java
@@ -1,33 +1,38 @@
1package tools.refinery.store.query.viatra; 1package tools.refinery.store.query.viatra;
2 2
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
3import org.junit.jupiter.api.Test; 4import org.junit.jupiter.api.Test;
4import tools.refinery.store.map.Cursor;
5import tools.refinery.store.model.ModelStore; 5import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.query.Dnf;
7import tools.refinery.store.query.ModelQuery; 6import tools.refinery.store.query.ModelQuery;
8import tools.refinery.store.query.Variable; 7import tools.refinery.store.query.dnf.Dnf;
8import tools.refinery.store.query.dnf.Query;
9import tools.refinery.store.query.term.Variable;
10import tools.refinery.store.query.viatra.tests.QueryEngineTest;
9import tools.refinery.store.query.view.FilteredRelationView; 11import tools.refinery.store.query.view.FilteredRelationView;
12import tools.refinery.store.query.view.FunctionalRelationView;
10import tools.refinery.store.query.view.KeyOnlyRelationView; 13import tools.refinery.store.query.view.KeyOnlyRelationView;
11import tools.refinery.store.representation.Symbol; 14import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.representation.TruthValue; 15import tools.refinery.store.representation.TruthValue;
13import tools.refinery.store.tuple.Tuple; 16import tools.refinery.store.tuple.Tuple;
14import tools.refinery.store.tuple.TupleLike;
15 17
16import java.util.HashSet; 18import java.util.Map;
17import java.util.Set;
18 19
19import static org.junit.jupiter.api.Assertions.*; 20import static org.junit.jupiter.api.Assertions.assertThrows;
21import static tools.refinery.store.query.literal.Literals.assume;
20import static tools.refinery.store.query.literal.Literals.not; 22import static tools.refinery.store.query.literal.Literals.not;
23import static tools.refinery.store.query.term.int_.IntTerms.constant;
24import static tools.refinery.store.query.term.int_.IntTerms.greaterEq;
25import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
21 26
22class QueryTest { 27class QueryTest {
23 @Test 28 @QueryEngineTest
24 void typeConstraintTest() { 29 void typeConstraintTest(QueryEvaluationHint hint) {
25 var person = new Symbol<>("Person", 1, Boolean.class, false); 30 var person = new Symbol<>("Person", 1, Boolean.class, false);
26 var asset = new Symbol<>("Asset", 1, Boolean.class, false); 31 var asset = new Symbol<>("Asset", 1, Boolean.class, false);
27 var personView = new KeyOnlyRelationView<>(person); 32 var personView = new KeyOnlyRelationView<>(person);
28 33
29 var p1 = new Variable("p1"); 34 var p1 = Variable.of("p1");
30 var predicate = Dnf.builder("TypeConstraint") 35 var predicate = Query.builder("TypeConstraint")
31 .parameters(p1) 36 .parameters(p1)
32 .clause(personView.call(p1)) 37 .clause(personView.call(p1))
33 .build(); 38 .build();
@@ -35,7 +40,8 @@ class QueryTest {
35 var store = ModelStore.builder() 40 var store = ModelStore.builder()
36 .symbols(person, asset) 41 .symbols(person, asset)
37 .with(ViatraModelQuery.ADAPTER) 42 .with(ViatraModelQuery.ADAPTER)
38 .queries(predicate) 43 .defaultHint(hint)
44 .query(predicate)
39 .build(); 45 .build();
40 46
41 var model = store.createEmptyModel(); 47 var model = store.createEmptyModel();
@@ -51,20 +57,23 @@ class QueryTest {
51 assetInterpretation.put(Tuple.of(2), true); 57 assetInterpretation.put(Tuple.of(2), true);
52 58
53 queryEngine.flushChanges(); 59 queryEngine.flushChanges();
54 assertEquals(2, predicateResultSet.countResults()); 60 assertResults(Map.of(
55 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1))); 61 Tuple.of(0), true,
62 Tuple.of(1), true,
63 Tuple.of(2), false
64 ), predicateResultSet);
56 } 65 }
57 66
58 @Test 67 @QueryEngineTest
59 void relationConstraintTest() { 68 void relationConstraintTest(QueryEvaluationHint hint) {
60 var person = new Symbol<>("Person", 1, Boolean.class, false); 69 var person = new Symbol<>("Person", 1, Boolean.class, false);
61 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 70 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
62 var personView = new KeyOnlyRelationView<>(person); 71 var personView = new KeyOnlyRelationView<>(person);
63 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 72 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
64 73
65 var p1 = new Variable("p1"); 74 var p1 = Variable.of("p1");
66 var p2 = new Variable("p2"); 75 var p2 = Variable.of("p2");
67 var predicate = Dnf.builder("RelationConstraint") 76 var predicate = Query.builder("RelationConstraint")
68 .parameters(p1, p2) 77 .parameters(p1, p2)
69 .clause( 78 .clause(
70 personView.call(p1), 79 personView.call(p1),
@@ -76,6 +85,7 @@ class QueryTest {
76 var store = ModelStore.builder() 85 var store = ModelStore.builder()
77 .symbols(person, friend) 86 .symbols(person, friend)
78 .with(ViatraModelQuery.ADAPTER) 87 .with(ViatraModelQuery.ADAPTER)
88 .defaultHint(hint)
79 .queries(predicate) 89 .queries(predicate)
80 .build(); 90 .build();
81 91
@@ -85,8 +95,6 @@ class QueryTest {
85 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 95 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
86 var predicateResultSet = queryEngine.getResultSet(predicate); 96 var predicateResultSet = queryEngine.getResultSet(predicate);
87 97
88 assertEquals(0, predicateResultSet.countResults());
89
90 personInterpretation.put(Tuple.of(0), true); 98 personInterpretation.put(Tuple.of(0), true);
91 personInterpretation.put(Tuple.of(1), true); 99 personInterpretation.put(Tuple.of(1), true);
92 personInterpretation.put(Tuple.of(2), true); 100 personInterpretation.put(Tuple.of(2), true);
@@ -94,83 +102,27 @@ class QueryTest {
94 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); 102 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
95 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); 103 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
96 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 104 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
97 105 friendInterpretation.put(Tuple.of(1, 3), TruthValue.TRUE);
98 assertEquals(0, predicateResultSet.countResults());
99 assertFalse(predicateResultSet.hasResult(Tuple.of(0, 1)));
100 assertFalse(predicateResultSet.hasResult(Tuple.of(0, 2)));
101 106
102 queryEngine.flushChanges(); 107 queryEngine.flushChanges();
103 assertEquals(3, predicateResultSet.countResults()); 108 assertResults(Map.of(
104 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); 109 Tuple.of(0, 1), true,
105 assertTrue(predicateResultSet.hasResult(Tuple.of(0, 1))); 110 Tuple.of(1, 0), true,
106 assertFalse(predicateResultSet.hasResult(Tuple.of(0, 2))); 111 Tuple.of(1, 2), true,
112 Tuple.of(2, 1), false
113 ), predicateResultSet);
107 } 114 }
108 115
109 @Test 116 @QueryEngineTest
110 void andTest() { 117 void existTest(QueryEvaluationHint hint) {
111 var person = new Symbol<>("Person", 1, Boolean.class, false); 118 var person = new Symbol<>("Person", 1, Boolean.class, false);
112 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 119 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
113 var personView = new KeyOnlyRelationView<>(person); 120 var personView = new KeyOnlyRelationView<>(person);
114 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 121 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
115 122
116 var p1 = new Variable("p1"); 123 var p1 = Variable.of("p1");
117 var p2 = new Variable("p2"); 124 var p2 = Variable.of("p2");
118 var predicate = Dnf.builder("RelationConstraint") 125 var predicate = Query.builder("RelationConstraint")
119 .parameters(p1, p2)
120 .clause(
121 personView.call(p1),
122 personView.call(p2),
123 friendMustView.call(p1, p2),
124 friendMustView.call(p2, p1)
125 )
126 .build();
127
128 var store = ModelStore.builder()
129 .symbols(person, friend)
130 .with(ViatraModelQuery.ADAPTER)
131 .queries(predicate)
132 .build();
133
134 var model = store.createEmptyModel();
135 var personInterpretation = model.getInterpretation(person);
136 var friendInterpretation = model.getInterpretation(friend);
137 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
138 var predicateResultSet = queryEngine.getResultSet(predicate);
139
140 assertEquals(0, predicateResultSet.countResults());
141
142 personInterpretation.put(Tuple.of(0), true);
143 personInterpretation.put(Tuple.of(1), true);
144 personInterpretation.put(Tuple.of(2), true);
145
146 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
147 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
148
149 queryEngine.flushChanges();
150 assertEquals(0, predicateResultSet.countResults());
151
152 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
153 queryEngine.flushChanges();
154 assertEquals(2, predicateResultSet.countResults());
155 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0)));
156
157 friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE);
158 queryEngine.flushChanges();
159 assertEquals(4, predicateResultSet.countResults());
160 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2),
161 Tuple.of(2, 0)));
162 }
163
164 @Test
165 void existTest() {
166 var person = new Symbol<>("Person", 1, Boolean.class, false);
167 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
168 var personView = new KeyOnlyRelationView<>(person);
169 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
170
171 var p1 = new Variable("p1");
172 var p2 = new Variable("p2");
173 var predicate = Dnf.builder("RelationConstraint")
174 .parameters(p1) 126 .parameters(p1)
175 .clause( 127 .clause(
176 personView.call(p1), 128 personView.call(p1),
@@ -182,6 +134,7 @@ class QueryTest {
182 var store = ModelStore.builder() 134 var store = ModelStore.builder()
183 .symbols(person, friend) 135 .symbols(person, friend)
184 .with(ViatraModelQuery.ADAPTER) 136 .with(ViatraModelQuery.ADAPTER)
137 .defaultHint(hint)
185 .queries(predicate) 138 .queries(predicate)
186 .build(); 139 .build();
187 140
@@ -198,16 +151,19 @@ class QueryTest {
198 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); 151 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
199 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); 152 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
200 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 153 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
201 154 friendInterpretation.put(Tuple.of(3, 2), TruthValue.TRUE);
202 assertEquals(0, predicateResultSet.countResults());
203 155
204 queryEngine.flushChanges(); 156 queryEngine.flushChanges();
205 assertEquals(2, predicateResultSet.countResults()); 157 assertResults(Map.of(
206 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1))); 158 Tuple.of(0), true,
159 Tuple.of(1), true,
160 Tuple.of(2), false,
161 Tuple.of(3), false
162 ), predicateResultSet);
207 } 163 }
208 164
209 @Test 165 @QueryEngineTest
210 void orTest() { 166 void orTest(QueryEvaluationHint hint) {
211 var person = new Symbol<>("Person", 1, Boolean.class, false); 167 var person = new Symbol<>("Person", 1, Boolean.class, false);
212 var animal = new Symbol<>("Animal", 1, Boolean.class, false); 168 var animal = new Symbol<>("Animal", 1, Boolean.class, false);
213 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 169 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
@@ -215,9 +171,9 @@ class QueryTest {
215 var animalView = new KeyOnlyRelationView<>(animal); 171 var animalView = new KeyOnlyRelationView<>(animal);
216 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 172 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
217 173
218 var p1 = new Variable("p1"); 174 var p1 = Variable.of("p1");
219 var p2 = new Variable("p2"); 175 var p2 = Variable.of("p2");
220 var predicate = Dnf.builder("Or") 176 var predicate = Query.builder("Or")
221 .parameters(p1, p2) 177 .parameters(p1, p2)
222 .clause( 178 .clause(
223 personView.call(p1), 179 personView.call(p1),
@@ -234,6 +190,7 @@ class QueryTest {
234 var store = ModelStore.builder() 190 var store = ModelStore.builder()
235 .symbols(person, animal, friend) 191 .symbols(person, animal, friend)
236 .with(ViatraModelQuery.ADAPTER) 192 .with(ViatraModelQuery.ADAPTER)
193 .defaultHint(hint)
237 .queries(predicate) 194 .queries(predicate)
238 .build(); 195 .build();
239 196
@@ -256,18 +213,23 @@ class QueryTest {
256 friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE); 213 friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE);
257 214
258 queryEngine.flushChanges(); 215 queryEngine.flushChanges();
259 assertEquals(2, predicateResultSet.countResults()); 216 assertResults(Map.of(
260 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(2, 3))); 217 Tuple.of(0, 1), true,
218 Tuple.of(0, 2), false,
219 Tuple.of(2, 3), true,
220 Tuple.of(3, 0), false,
221 Tuple.of(3, 2), false
222 ), predicateResultSet);
261 } 223 }
262 224
263 @Test 225 @QueryEngineTest
264 void equalityTest() { 226 void equalityTest(QueryEvaluationHint hint) {
265 var person = new Symbol<>("Person", 1, Boolean.class, false); 227 var person = new Symbol<>("Person", 1, Boolean.class, false);
266 var personView = new KeyOnlyRelationView<>(person); 228 var personView = new KeyOnlyRelationView<>(person);
267 229
268 var p1 = new Variable("p1"); 230 var p1 = Variable.of("p1");
269 var p2 = new Variable("p2"); 231 var p2 = Variable.of("p2");
270 var predicate = Dnf.builder("Equality") 232 var predicate = Query.builder("Equality")
271 .parameters(p1, p2) 233 .parameters(p1, p2)
272 .clause( 234 .clause(
273 personView.call(p1), 235 personView.call(p1),
@@ -279,6 +241,7 @@ class QueryTest {
279 var store = ModelStore.builder() 241 var store = ModelStore.builder()
280 .symbols(person) 242 .symbols(person)
281 .with(ViatraModelQuery.ADAPTER) 243 .with(ViatraModelQuery.ADAPTER)
244 .defaultHint(hint)
282 .queries(predicate) 245 .queries(predicate)
283 .build(); 246 .build();
284 247
@@ -292,21 +255,26 @@ class QueryTest {
292 personInterpretation.put(Tuple.of(2), true); 255 personInterpretation.put(Tuple.of(2), true);
293 256
294 queryEngine.flushChanges(); 257 queryEngine.flushChanges();
295 assertEquals(3, predicateResultSet.countResults()); 258 assertResults(Map.of(
296 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2))); 259 Tuple.of(0, 0), true,
260 Tuple.of(1, 1), true,
261 Tuple.of(2, 2), true,
262 Tuple.of(0, 1), false,
263 Tuple.of(3, 3), false
264 ), predicateResultSet);
297 } 265 }
298 266
299 @Test 267 @QueryEngineTest
300 void inequalityTest() { 268 void inequalityTest(QueryEvaluationHint hint) {
301 var person = new Symbol<>("Person", 1, Boolean.class, false); 269 var person = new Symbol<>("Person", 1, Boolean.class, false);
302 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 270 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
303 var personView = new KeyOnlyRelationView<>(person); 271 var personView = new KeyOnlyRelationView<>(person);
304 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 272 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
305 273
306 var p1 = new Variable("p1"); 274 var p1 = Variable.of("p1");
307 var p2 = new Variable("p2"); 275 var p2 = Variable.of("p2");
308 var p3 = new Variable("p3"); 276 var p3 = Variable.of("p3");
309 var predicate = Dnf.builder("Inequality") 277 var predicate = Query.builder("Inequality")
310 .parameters(p1, p2, p3) 278 .parameters(p1, p2, p3)
311 .clause( 279 .clause(
312 personView.call(p1), 280 personView.call(p1),
@@ -320,6 +288,7 @@ class QueryTest {
320 var store = ModelStore.builder() 288 var store = ModelStore.builder()
321 .symbols(person, friend) 289 .symbols(person, friend)
322 .with(ViatraModelQuery.ADAPTER) 290 .with(ViatraModelQuery.ADAPTER)
291 .defaultHint(hint)
323 .queries(predicate) 292 .queries(predicate)
324 .build(); 293 .build();
325 294
@@ -337,19 +306,22 @@ class QueryTest {
337 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 306 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
338 307
339 queryEngine.flushChanges(); 308 queryEngine.flushChanges();
340 assertEquals(2, predicateResultSet.countResults()); 309 assertResults(Map.of(
341 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2))); 310 Tuple.of(0, 1, 2), true,
311 Tuple.of(1, 0, 2), true,
312 Tuple.of(0, 0, 2), false
313 ), predicateResultSet);
342 } 314 }
343 315
344 @Test 316 @QueryEngineTest
345 void patternCallTest() { 317 void patternCallTest(QueryEvaluationHint hint) {
346 var person = new Symbol<>("Person", 1, Boolean.class, false); 318 var person = new Symbol<>("Person", 1, Boolean.class, false);
347 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 319 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
348 var personView = new KeyOnlyRelationView<>(person); 320 var personView = new KeyOnlyRelationView<>(person);
349 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 321 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
350 322
351 var p1 = new Variable("p1"); 323 var p1 = Variable.of("p1");
352 var p2 = new Variable("p2"); 324 var p2 = Variable.of("p2");
353 var friendPredicate = Dnf.builder("RelationConstraint") 325 var friendPredicate = Dnf.builder("RelationConstraint")
354 .parameters(p1, p2) 326 .parameters(p1, p2)
355 .clause( 327 .clause(
@@ -359,9 +331,9 @@ class QueryTest {
359 ) 331 )
360 .build(); 332 .build();
361 333
362 var p3 = new Variable("p3"); 334 var p3 = Variable.of("p3");
363 var p4 = new Variable("p4"); 335 var p4 = Variable.of("p4");
364 var predicate = Dnf.builder("PositivePatternCall") 336 var predicate = Query.builder("PositivePatternCall")
365 .parameters(p3, p4) 337 .parameters(p3, p4)
366 .clause( 338 .clause(
367 personView.call(p3), 339 personView.call(p3),
@@ -373,6 +345,7 @@ class QueryTest {
373 var store = ModelStore.builder() 345 var store = ModelStore.builder()
374 .symbols(person, friend) 346 .symbols(person, friend)
375 .with(ViatraModelQuery.ADAPTER) 347 .with(ViatraModelQuery.ADAPTER)
348 .defaultHint(hint)
376 .queries(predicate) 349 .queries(predicate)
377 .build(); 350 .build();
378 351
@@ -391,19 +364,24 @@ class QueryTest {
391 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 364 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
392 365
393 queryEngine.flushChanges(); 366 queryEngine.flushChanges();
394 assertEquals(3, predicateResultSet.countResults()); 367 assertResults(Map.of(
368 Tuple.of(0, 1), true,
369 Tuple.of(1, 0), true,
370 Tuple.of(1, 2), true,
371 Tuple.of(2, 1), false
372 ), predicateResultSet);
395 } 373 }
396 374
397 @Test 375 @QueryEngineTest
398 void negativeRelationViewTest() { 376 void negativeRelationViewTest(QueryEvaluationHint hint) {
399 var person = new Symbol<>("Person", 1, Boolean.class, false); 377 var person = new Symbol<>("Person", 1, Boolean.class, false);
400 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 378 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
401 var personView = new KeyOnlyRelationView<>(person); 379 var personView = new KeyOnlyRelationView<>(person);
402 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 380 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
403 381
404 var p1 = new Variable("p1"); 382 var p1 = Variable.of("p1");
405 var p2 = new Variable("p2"); 383 var p2 = Variable.of("p2");
406 var predicate = Dnf.builder("NegativePatternCall") 384 var predicate = Query.builder("NegativePatternCall")
407 .parameters(p1, p2) 385 .parameters(p1, p2)
408 .clause( 386 .clause(
409 personView.call(p1), 387 personView.call(p1),
@@ -415,6 +393,7 @@ class QueryTest {
415 var store = ModelStore.builder() 393 var store = ModelStore.builder()
416 .symbols(person, friend) 394 .symbols(person, friend)
417 .with(ViatraModelQuery.ADAPTER) 395 .with(ViatraModelQuery.ADAPTER)
396 .defaultHint(hint)
418 .queries(predicate) 397 .queries(predicate)
419 .build(); 398 .build();
420 399
@@ -433,18 +412,29 @@ class QueryTest {
433 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 412 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
434 413
435 queryEngine.flushChanges(); 414 queryEngine.flushChanges();
436 assertEquals(6, predicateResultSet.countResults()); 415 assertResults(Map.of(
416 Tuple.of(0, 0), true,
417 Tuple.of(0, 2), true,
418 Tuple.of(1, 1), true,
419 Tuple.of(2, 0), true,
420 Tuple.of(2, 1), true,
421 Tuple.of(2, 2), true,
422 Tuple.of(0, 1), false,
423 Tuple.of(1, 0), false,
424 Tuple.of(1, 2), false,
425 Tuple.of(0, 3), false
426 ), predicateResultSet);
437 } 427 }
438 428
439 @Test 429 @QueryEngineTest
440 void negativePatternCallTest() { 430 void negativePatternCallTest(QueryEvaluationHint hint) {
441 var person = new Symbol<>("Person", 1, Boolean.class, false); 431 var person = new Symbol<>("Person", 1, Boolean.class, false);
442 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 432 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
443 var personView = new KeyOnlyRelationView<>(person); 433 var personView = new KeyOnlyRelationView<>(person);
444 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 434 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
445 435
446 var p1 = new Variable("p1"); 436 var p1 = Variable.of("p1");
447 var p2 = new Variable("p2"); 437 var p2 = Variable.of("p2");
448 var friendPredicate = Dnf.builder("RelationConstraint") 438 var friendPredicate = Dnf.builder("RelationConstraint")
449 .parameters(p1, p2) 439 .parameters(p1, p2)
450 .clause( 440 .clause(
@@ -454,9 +444,9 @@ class QueryTest {
454 ) 444 )
455 .build(); 445 .build();
456 446
457 var p3 = new Variable("p3"); 447 var p3 = Variable.of("p3");
458 var p4 = new Variable("p4"); 448 var p4 = Variable.of("p4");
459 var predicate = Dnf.builder("NegativePatternCall") 449 var predicate = Query.builder("NegativePatternCall")
460 .parameters(p3, p4) 450 .parameters(p3, p4)
461 .clause( 451 .clause(
462 personView.call(p3), 452 personView.call(p3),
@@ -468,6 +458,7 @@ class QueryTest {
468 var store = ModelStore.builder() 458 var store = ModelStore.builder()
469 .symbols(person, friend) 459 .symbols(person, friend)
470 .with(ViatraModelQuery.ADAPTER) 460 .with(ViatraModelQuery.ADAPTER)
461 .defaultHint(hint)
471 .queries(predicate) 462 .queries(predicate)
472 .build(); 463 .build();
473 464
@@ -486,20 +477,31 @@ class QueryTest {
486 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 477 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
487 478
488 queryEngine.flushChanges(); 479 queryEngine.flushChanges();
489 assertEquals(6, predicateResultSet.countResults()); 480 assertResults(Map.of(
481 Tuple.of(0, 0), true,
482 Tuple.of(0, 2), true,
483 Tuple.of(1, 1), true,
484 Tuple.of(2, 0), true,
485 Tuple.of(2, 1), true,
486 Tuple.of(2, 2), true,
487 Tuple.of(0, 1), false,
488 Tuple.of(1, 0), false,
489 Tuple.of(1, 2), false,
490 Tuple.of(0, 3), false
491 ), predicateResultSet);
490 } 492 }
491 493
492 @Test 494 @QueryEngineTest
493 void negativeRelationViewWithQuantificationTest() { 495 void negativeRelationViewWithQuantificationTest(QueryEvaluationHint hint) {
494 var person = new Symbol<>("Person", 1, Boolean.class, false); 496 var person = new Symbol<>("Person", 1, Boolean.class, false);
495 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 497 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
496 var personView = new KeyOnlyRelationView<>(person); 498 var personView = new KeyOnlyRelationView<>(person);
497 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 499 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
498 500
499 var p1 = new Variable("p1"); 501 var p1 = Variable.of("p1");
500 var p2 = new Variable("p2"); 502 var p2 = Variable.of("p2");
501 503
502 var predicate = Dnf.builder("Count") 504 var predicate = Query.builder("Count")
503 .parameters(p1) 505 .parameters(p1)
504 .clause( 506 .clause(
505 personView.call(p1), 507 personView.call(p1),
@@ -510,6 +512,7 @@ class QueryTest {
510 var store = ModelStore.builder() 512 var store = ModelStore.builder()
511 .symbols(person, friend) 513 .symbols(person, friend)
512 .with(ViatraModelQuery.ADAPTER) 514 .with(ViatraModelQuery.ADAPTER)
515 .defaultHint(hint)
513 .queries(predicate) 516 .queries(predicate)
514 .build(); 517 .build();
515 518
@@ -527,18 +530,23 @@ class QueryTest {
527 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); 530 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
528 531
529 queryEngine.flushChanges(); 532 queryEngine.flushChanges();
530 assertEquals(2, predicateResultSet.countResults()); 533 assertResults(Map.of(
534 Tuple.of(0), false,
535 Tuple.of(1), true,
536 Tuple.of(2), true,
537 Tuple.of(3), false
538 ), predicateResultSet);
531 } 539 }
532 540
533 @Test 541 @QueryEngineTest
534 void negativeWithQuantificationTest() { 542 void negativeWithQuantificationTest(QueryEvaluationHint hint) {
535 var person = new Symbol<>("Person", 1, Boolean.class, false); 543 var person = new Symbol<>("Person", 1, Boolean.class, false);
536 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 544 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
537 var personView = new KeyOnlyRelationView<>(person); 545 var personView = new KeyOnlyRelationView<>(person);
538 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 546 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
539 547
540 var p1 = new Variable("p1"); 548 var p1 = Variable.of("p1");
541 var p2 = new Variable("p2"); 549 var p2 = Variable.of("p2");
542 550
543 var called = Dnf.builder("Called") 551 var called = Dnf.builder("Called")
544 .parameters(p1, p2) 552 .parameters(p1, p2)
@@ -549,7 +557,7 @@ class QueryTest {
549 ) 557 )
550 .build(); 558 .build();
551 559
552 var predicate = Dnf.builder("Count") 560 var predicate = Query.builder("Count")
553 .parameters(p1) 561 .parameters(p1)
554 .clause( 562 .clause(
555 personView.call(p1), 563 personView.call(p1),
@@ -560,6 +568,7 @@ class QueryTest {
560 var store = ModelStore.builder() 568 var store = ModelStore.builder()
561 .symbols(person, friend) 569 .symbols(person, friend)
562 .with(ViatraModelQuery.ADAPTER) 570 .with(ViatraModelQuery.ADAPTER)
571 .defaultHint(hint)
563 .queries(predicate) 572 .queries(predicate)
564 .build(); 573 .build();
565 574
@@ -577,19 +586,24 @@ class QueryTest {
577 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); 586 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
578 587
579 queryEngine.flushChanges(); 588 queryEngine.flushChanges();
580 assertEquals(2, predicateResultSet.countResults()); 589 assertResults(Map.of(
590 Tuple.of(0), false,
591 Tuple.of(1), true,
592 Tuple.of(2), true,
593 Tuple.of(3), false
594 ), predicateResultSet);
581 } 595 }
582 596
583 @Test 597 @QueryEngineTest
584 void transitiveRelationViewTest() { 598 void transitiveRelationViewTest(QueryEvaluationHint hint) {
585 var person = new Symbol<>("Person", 1, Boolean.class, false); 599 var person = new Symbol<>("Person", 1, Boolean.class, false);
586 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 600 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
587 var personView = new KeyOnlyRelationView<>(person); 601 var personView = new KeyOnlyRelationView<>(person);
588 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 602 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
589 603
590 var p1 = new Variable("p1"); 604 var p1 = Variable.of("p1");
591 var p2 = new Variable("p2"); 605 var p2 = Variable.of("p2");
592 var predicate = Dnf.builder("TransitivePatternCall") 606 var predicate = Query.builder("TransitivePatternCall")
593 .parameters(p1, p2) 607 .parameters(p1, p2)
594 .clause( 608 .clause(
595 personView.call(p1), 609 personView.call(p1),
@@ -601,6 +615,7 @@ class QueryTest {
601 var store = ModelStore.builder() 615 var store = ModelStore.builder()
602 .symbols(person, friend) 616 .symbols(person, friend)
603 .with(ViatraModelQuery.ADAPTER) 617 .with(ViatraModelQuery.ADAPTER)
618 .defaultHint(hint)
604 .queries(predicate) 619 .queries(predicate)
605 .build(); 620 .build();
606 621
@@ -618,18 +633,29 @@ class QueryTest {
618 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 633 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
619 634
620 queryEngine.flushChanges(); 635 queryEngine.flushChanges();
621 assertEquals(3, predicateResultSet.countResults()); 636 assertResults(Map.of(
637 Tuple.of(0, 0), false,
638 Tuple.of(0, 1), true,
639 Tuple.of(0, 2), true,
640 Tuple.of(1, 0), false,
641 Tuple.of(1, 1), false,
642 Tuple.of(1, 2), true,
643 Tuple.of(2, 0), false,
644 Tuple.of(2, 1), false,
645 Tuple.of(2, 2), false,
646 Tuple.of(2, 3), false
647 ), predicateResultSet);
622 } 648 }
623 649
624 @Test 650 @QueryEngineTest
625 void transitivePatternCallTest() { 651 void transitivePatternCallTest(QueryEvaluationHint hint) {
626 var person = new Symbol<>("Person", 1, Boolean.class, false); 652 var person = new Symbol<>("Person", 1, Boolean.class, false);
627 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 653 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
628 var personView = new KeyOnlyRelationView<>(person); 654 var personView = new KeyOnlyRelationView<>(person);
629 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 655 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
630 656
631 var p1 = new Variable("p1"); 657 var p1 = Variable.of("p1");
632 var p2 = new Variable("p2"); 658 var p2 = Variable.of("p2");
633 var friendPredicate = Dnf.builder("RelationConstraint") 659 var friendPredicate = Dnf.builder("RelationConstraint")
634 .parameters(p1, p2) 660 .parameters(p1, p2)
635 .clause( 661 .clause(
@@ -639,9 +665,9 @@ class QueryTest {
639 ) 665 )
640 .build(); 666 .build();
641 667
642 var p3 = new Variable("p3"); 668 var p3 = Variable.of("p3");
643 var p4 = new Variable("p4"); 669 var p4 = Variable.of("p4");
644 var predicate = Dnf.builder("TransitivePatternCall") 670 var predicate = Query.builder("TransitivePatternCall")
645 .parameters(p3, p4) 671 .parameters(p3, p4)
646 .clause( 672 .clause(
647 personView.call(p3), 673 personView.call(p3),
@@ -653,6 +679,7 @@ class QueryTest {
653 var store = ModelStore.builder() 679 var store = ModelStore.builder()
654 .symbols(person, friend) 680 .symbols(person, friend)
655 .with(ViatraModelQuery.ADAPTER) 681 .with(ViatraModelQuery.ADAPTER)
682 .defaultHint(hint)
656 .queries(predicate) 683 .queries(predicate)
657 .build(); 684 .build();
658 685
@@ -670,15 +697,71 @@ class QueryTest {
670 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 697 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
671 698
672 queryEngine.flushChanges(); 699 queryEngine.flushChanges();
673 assertEquals(3, predicateResultSet.countResults()); 700 assertResults(Map.of(
701 Tuple.of(0, 0), false,
702 Tuple.of(0, 1), true,
703 Tuple.of(0, 2), true,
704 Tuple.of(1, 0), false,
705 Tuple.of(1, 1), false,
706 Tuple.of(1, 2), true,
707 Tuple.of(2, 0), false,
708 Tuple.of(2, 1), false,
709 Tuple.of(2, 2), false,
710 Tuple.of(2, 3), false
711 ), predicateResultSet);
712 }
713
714 @QueryEngineTest
715 void assumeTest(QueryEvaluationHint hint) {
716 var person = new Symbol<>("Person", 1, Boolean.class, false);
717 var age = new Symbol<>("age", 1, Integer.class, null);
718 var personView = new KeyOnlyRelationView<>(person);
719 var ageView = new FunctionalRelationView<>(age);
720
721 var p1 = Variable.of("p1");
722 var x = Variable.of("x", Integer.class);
723 var query = Query.builder("Constraint")
724 .parameter(p1)
725 .clause(
726 personView.call(p1),
727 ageView.call(p1, x),
728 assume(greaterEq(x, constant(18)))
729 )
730 .build();
731
732 var store = ModelStore.builder()
733 .symbols(person, age)
734 .with(ViatraModelQuery.ADAPTER)
735 .defaultHint(hint)
736 .queries(query)
737 .build();
738
739 var model = store.createEmptyModel();
740 var personInterpretation = model.getInterpretation(person);
741 var ageInterpretation = model.getInterpretation(age);
742 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
743 var queryResultSet = queryEngine.getResultSet(query);
744
745 personInterpretation.put(Tuple.of(0), true);
746 personInterpretation.put(Tuple.of(1), true);
747
748 ageInterpretation.put(Tuple.of(0), 12);
749 ageInterpretation.put(Tuple.of(1), 24);
750
751 queryEngine.flushChanges();
752 assertResults(Map.of(
753 Tuple.of(0), false,
754 Tuple.of(1), true,
755 Tuple.of(2), false
756 ), queryResultSet);
674 } 757 }
675 758
676 @Test 759 @Test
677 void alwaysFalseTest() { 760 void alwaysFalseTest() {
678 var person = new Symbol<>("Person", 1, Boolean.class, false); 761 var person = new Symbol<>("Person", 1, Boolean.class, false);
679 762
680 var p1 = new Variable("p1"); 763 var p1 = Variable.of("p1");
681 var predicate = Dnf.builder("AlwaysFalse").parameters(p1).build(); 764 var predicate = Query.builder("AlwaysFalse").parameters(p1).build();
682 765
683 var store = ModelStore.builder() 766 var store = ModelStore.builder()
684 .symbols(person) 767 .symbols(person)
@@ -696,28 +779,19 @@ class QueryTest {
696 personInterpretation.put(Tuple.of(2), true); 779 personInterpretation.put(Tuple.of(2), true);
697 780
698 queryEngine.flushChanges(); 781 queryEngine.flushChanges();
699 assertEquals(0, predicateResultSet.countResults()); 782 assertResults(Map.of(), predicateResultSet);
700 } 783 }
701 784
702 @Test 785 @Test
703 void alwaysTrueTest() { 786 void alwaysTrueTest() {
704 var person = new Symbol<>("Person", 1, Boolean.class, false); 787 var person = new Symbol<>("Person", 1, Boolean.class, false);
705 788
706 var p1 = new Variable("p1"); 789 var p1 = Variable.of("p1");
707 var predicate = Dnf.builder("AlwaysTrue").parameters(p1).clause().build(); 790 var predicate = Query.builder("AlwaysTrue").parameters(p1).clause().build();
708 791
709 var storeBuilder = ModelStore.builder().symbols(person); 792 var storeBuilder = ModelStore.builder().symbols(person);
710 var queryBuilder = storeBuilder.with(ViatraModelQuery.ADAPTER); 793 var queryBuilder = storeBuilder.with(ViatraModelQuery.ADAPTER);
711 794
712 assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate)); 795 assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate));
713 } 796 }
714
715 private static void compareMatchSets(Cursor<TupleLike, Boolean> cursor, Set<Tuple> expected) {
716 Set<Tuple> translatedMatchSet = new HashSet<>();
717 while (cursor.move()) {
718 var element = cursor.getKey();
719 translatedMatchSet.add(element.toTuple());
720 }
721 assertEquals(expected, translatedMatchSet);
722 }
723} 797}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
index 461685b5..abd49341 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
@@ -1,25 +1,160 @@
1package tools.refinery.store.query.viatra; 1package tools.refinery.store.query.viatra;
2 2
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4import org.junit.jupiter.api.Disabled;
3import org.junit.jupiter.api.Test; 5import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.ModelStore; 6import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.Dnf;
6import tools.refinery.store.query.ModelQuery; 7import tools.refinery.store.query.ModelQuery;
7import tools.refinery.store.query.Variable; 8import tools.refinery.store.query.dnf.Query;
9import tools.refinery.store.query.term.Variable;
10import tools.refinery.store.query.view.FilteredRelationView;
11import tools.refinery.store.query.view.FunctionalRelationView;
8import tools.refinery.store.query.view.KeyOnlyRelationView; 12import tools.refinery.store.query.view.KeyOnlyRelationView;
9import tools.refinery.store.representation.Symbol; 13import tools.refinery.store.representation.Symbol;
10import tools.refinery.store.tuple.Tuple; 14import tools.refinery.store.tuple.Tuple;
11 15
12import static org.junit.jupiter.api.Assertions.*; 16import java.util.Map;
17import java.util.Optional;
18
19import static org.junit.jupiter.api.Assertions.assertFalse;
20import static org.junit.jupiter.api.Assertions.assertTrue;
21import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults;
22import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
13 23
14class QueryTransactionTest { 24class QueryTransactionTest {
15 @Test 25 @Test
16 void flushTest() { 26 void flushTest() {
17 var person = new Symbol<>("Person", 1, Boolean.class, false); 27 var person = new Symbol<>("Person", 1, Boolean.class, false);
28 var personView = new KeyOnlyRelationView<>(person);
29
30 var p1 = Variable.of("p1");
31 var predicate = Query.builder("TypeConstraint")
32 .parameters(p1)
33 .clause(personView.call(p1))
34 .build();
35
36 var store = ModelStore.builder()
37 .symbols(person)
38 .with(ViatraModelQuery.ADAPTER)
39 .queries(predicate)
40 .build();
41
42 var model = store.createEmptyModel();
43 var personInterpretation = model.getInterpretation(person);
44 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
45 var predicateResultSet = queryEngine.getResultSet(predicate);
46
47 assertResults(Map.of(
48 Tuple.of(0), false,
49 Tuple.of(1), false,
50 Tuple.of(2), false,
51 Tuple.of(3), false
52 ), predicateResultSet);
53 assertFalse(queryEngine.hasPendingChanges());
54
55 personInterpretation.put(Tuple.of(0), true);
56 personInterpretation.put(Tuple.of(1), true);
57
58 assertResults(Map.of(
59 Tuple.of(0), false,
60 Tuple.of(1), false,
61 Tuple.of(2), false,
62 Tuple.of(3), false
63 ), predicateResultSet);
64 assertTrue(queryEngine.hasPendingChanges());
65
66 queryEngine.flushChanges();
67 assertResults(Map.of(
68 Tuple.of(0), true,
69 Tuple.of(1), true,
70 Tuple.of(2), false,
71 Tuple.of(3), false
72 ), predicateResultSet);
73 assertFalse(queryEngine.hasPendingChanges());
74
75 personInterpretation.put(Tuple.of(1), false);
76 personInterpretation.put(Tuple.of(2), true);
77
78 assertResults(Map.of(
79 Tuple.of(0), true,
80 Tuple.of(1), true,
81 Tuple.of(2), false,
82 Tuple.of(3), false
83 ), predicateResultSet);
84 assertTrue(queryEngine.hasPendingChanges());
85
86 queryEngine.flushChanges();
87 assertResults(Map.of(
88 Tuple.of(0), true,
89 Tuple.of(1), false,
90 Tuple.of(2), true,
91 Tuple.of(3), false
92 ), predicateResultSet);
93 assertFalse(queryEngine.hasPendingChanges());
94 }
95
96 @Test
97 void localSearchTest() {
98 var person = new Symbol<>("Person", 1, Boolean.class, false);
99 var personView = new KeyOnlyRelationView<>(person);
100
101 var p1 = Variable.of("p1");
102 var predicate = Query.builder("TypeConstraint")
103 .parameters(p1)
104 .clause(personView.call(p1))
105 .build();
106
107 var store = ModelStore.builder()
108 .symbols(person)
109 .with(ViatraModelQuery.ADAPTER)
110 .defaultHint(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH))
111 .queries(predicate)
112 .build();
113
114 var model = store.createEmptyModel();
115 var personInterpretation = model.getInterpretation(person);
116 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
117 var predicateResultSet = queryEngine.getResultSet(predicate);
118
119 assertResults(Map.of(
120 Tuple.of(0), false,
121 Tuple.of(1), false,
122 Tuple.of(2), false,
123 Tuple.of(3), false
124 ), predicateResultSet);
125 assertFalse(queryEngine.hasPendingChanges());
126
127 personInterpretation.put(Tuple.of(0), true);
128 personInterpretation.put(Tuple.of(1), true);
129
130 assertResults(Map.of(
131 Tuple.of(0), true,
132 Tuple.of(1), true,
133 Tuple.of(2), false,
134 Tuple.of(3), false
135 ), predicateResultSet);
136 assertFalse(queryEngine.hasPendingChanges());
137
138 personInterpretation.put(Tuple.of(1), false);
139 personInterpretation.put(Tuple.of(2), true);
140
141 assertResults(Map.of(
142 Tuple.of(0), true,
143 Tuple.of(1), false,
144 Tuple.of(2), true,
145 Tuple.of(3), false
146 ), predicateResultSet);
147 assertFalse(queryEngine.hasPendingChanges());
148 }
149
150 @Test
151 void unrelatedChangesTest() {
152 var person = new Symbol<>("Person", 1, Boolean.class, false);
18 var asset = new Symbol<>("Asset", 1, Boolean.class, false); 153 var asset = new Symbol<>("Asset", 1, Boolean.class, false);
19 var personView = new KeyOnlyRelationView<>(person); 154 var personView = new KeyOnlyRelationView<>(person);
20 155
21 var p1 = new Variable("p1"); 156 var p1 = Variable.of("p1");
22 var predicate = Dnf.builder("TypeConstraint") 157 var predicate = Query.builder("TypeConstraint")
23 .parameters(p1) 158 .parameters(p1)
24 .clause(personView.call(p1)) 159 .clause(personView.call(p1))
25 .build(); 160 .build();
@@ -36,7 +171,6 @@ class QueryTransactionTest {
36 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 171 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
37 var predicateResultSet = queryEngine.getResultSet(predicate); 172 var predicateResultSet = queryEngine.getResultSet(predicate);
38 173
39 assertEquals(0, predicateResultSet.countResults());
40 assertFalse(queryEngine.hasPendingChanges()); 174 assertFalse(queryEngine.hasPendingChanges());
41 175
42 personInterpretation.put(Tuple.of(0), true); 176 personInterpretation.put(Tuple.of(0), true);
@@ -45,19 +179,245 @@ class QueryTransactionTest {
45 assetInterpretation.put(Tuple.of(1), true); 179 assetInterpretation.put(Tuple.of(1), true);
46 assetInterpretation.put(Tuple.of(2), true); 180 assetInterpretation.put(Tuple.of(2), true);
47 181
48 assertEquals(0, predicateResultSet.countResults()); 182 assertResults(Map.of(
183 Tuple.of(0), false,
184 Tuple.of(1), false,
185 Tuple.of(2), false,
186 Tuple.of(3), false,
187 Tuple.of(4), false
188 ), predicateResultSet);
49 assertTrue(queryEngine.hasPendingChanges()); 189 assertTrue(queryEngine.hasPendingChanges());
50 190
51 queryEngine.flushChanges(); 191 queryEngine.flushChanges();
52 assertEquals(2, predicateResultSet.countResults()); 192 assertResults(Map.of(
193 Tuple.of(0), true,
194 Tuple.of(1), true,
195 Tuple.of(2), false,
196 Tuple.of(3), false,
197 Tuple.of(4), false
198 ), predicateResultSet);
53 assertFalse(queryEngine.hasPendingChanges()); 199 assertFalse(queryEngine.hasPendingChanges());
54 200
55 personInterpretation.put(Tuple.of(4), true); 201 assetInterpretation.put(Tuple.of(3), true);
56 assertEquals(2, predicateResultSet.countResults()); 202 assertFalse(queryEngine.hasPendingChanges());
57 assertTrue(queryEngine.hasPendingChanges()); 203
204 assertResults(Map.of(
205 Tuple.of(0), true,
206 Tuple.of(1), true,
207 Tuple.of(2), false,
208 Tuple.of(3), false,
209 Tuple.of(4), false
210 ), predicateResultSet);
211
212 queryEngine.flushChanges();
213 assertResults(Map.of(
214 Tuple.of(0), true,
215 Tuple.of(1), true,
216 Tuple.of(2), false,
217 Tuple.of(3), false,
218 Tuple.of(4), false
219 ), predicateResultSet);
220 assertFalse(queryEngine.hasPendingChanges());
221 }
222
223 @Test
224 void tupleChangingChangeTest() {
225 var person = new Symbol<>("Person", 1, Boolean.class, false);
226 var age = new Symbol<>("age", 1, Integer.class, null);
227 var personView = new KeyOnlyRelationView<>(person);
228 var ageView = new FunctionalRelationView<>(age);
229
230 var p1 = Variable.of("p1");
231 var x = Variable.of("x", Integer.class);
232 var query = Query.builder()
233 .parameter(p1)
234 .output(x)
235 .clause(
236 personView.call(p1),
237 ageView.call(p1, x)
238 )
239 .build();
240
241 var store = ModelStore.builder()
242 .symbols(person, age)
243 .with(ViatraModelQuery.ADAPTER)
244 .query(query)
245 .build();
246
247 var model = store.createEmptyModel();
248 var personInterpretation = model.getInterpretation(person);
249 var ageInterpretation = model.getInterpretation(age);
250 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
251 var queryResultSet = queryEngine.getResultSet(query);
252
253 personInterpretation.put(Tuple.of(0), true);
254
255 ageInterpretation.put(Tuple.of(0), 24);
256
257 queryEngine.flushChanges();
258 assertResults(Map.of(Tuple.of(0), 24), queryResultSet);
259
260 ageInterpretation.put(Tuple.of(0), 25);
261
262 queryEngine.flushChanges();
263 assertResults(Map.of(Tuple.of(0), 25), queryResultSet);
264
265 ageInterpretation.put(Tuple.of(0), null);
266
267 queryEngine.flushChanges();
268 assertNullableResults(Map.of(Tuple.of(0), Optional.empty()), queryResultSet);
269 }
270
271 @Test
272 void tuplePreservingUnchangedTest() {
273 var person = new Symbol<>("Person", 1, Boolean.class, false);
274 var age = new Symbol<>("age", 1, Integer.class, null);
275 var personView = new KeyOnlyRelationView<>(person);
276 var adultView = new FilteredRelationView<>(age, "adult", n -> n != null && n >= 18);
277
278 var p1 = Variable.of("p1");
279 var x = Variable.of("x", Integer.class);
280 var query = Query.builder()
281 .parameter(p1)
282 .clause(
283 personView.call(p1),
284 adultView.call(p1)
285 )
286 .build();
287
288 var store = ModelStore.builder()
289 .symbols(person, age)
290 .with(ViatraModelQuery.ADAPTER)
291 .query(query)
292 .build();
293
294 var model = store.createEmptyModel();
295 var personInterpretation = model.getInterpretation(person);
296 var ageInterpretation = model.getInterpretation(age);
297 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
298 var queryResultSet = queryEngine.getResultSet(query);
299
300 personInterpretation.put(Tuple.of(0), true);
301
302 ageInterpretation.put(Tuple.of(0), 24);
303
304 queryEngine.flushChanges();
305 assertResults(Map.of(Tuple.of(0), true), queryResultSet);
306
307 ageInterpretation.put(Tuple.of(0), 25);
308
309 queryEngine.flushChanges();
310 assertResults(Map.of(Tuple.of(0), true), queryResultSet);
311
312 ageInterpretation.put(Tuple.of(0), 17);
58 313
59 queryEngine.flushChanges(); 314 queryEngine.flushChanges();
60 assertEquals(3, predicateResultSet.countResults()); 315 assertResults(Map.of(Tuple.of(0), false), queryResultSet);
316 }
317
318 @Disabled("TODO Fix DiffCursor")
319 @Test
320 void commitAfterFlushTest() {
321 var person = new Symbol<>("Person", 1, Boolean.class, false);
322 var personView = new KeyOnlyRelationView<>(person);
323
324 var p1 = Variable.of("p1");
325 var predicate = Query.builder("TypeConstraint")
326 .parameters(p1)
327 .clause(personView.call(p1))
328 .build();
329
330 var store = ModelStore.builder()
331 .symbols(person)
332 .with(ViatraModelQuery.ADAPTER)
333 .queries(predicate)
334 .build();
335
336 var model = store.createEmptyModel();
337 var personInterpretation = model.getInterpretation(person);
338 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
339 var predicateResultSet = queryEngine.getResultSet(predicate);
340
341 personInterpretation.put(Tuple.of(0), true);
342 personInterpretation.put(Tuple.of(1), true);
343
344 queryEngine.flushChanges();
345 assertResults(Map.of(
346 Tuple.of(0), true,
347 Tuple.of(1), true,
348 Tuple.of(2), false,
349 Tuple.of(3), false
350 ), predicateResultSet);
351
352 var state1 = model.commit();
353
354 personInterpretation.put(Tuple.of(1), false);
355 personInterpretation.put(Tuple.of(2), true);
356
357 queryEngine.flushChanges();
358 assertResults(Map.of(
359 Tuple.of(0), true,
360 Tuple.of(1), false,
361 Tuple.of(2), true,
362 Tuple.of(3), false
363 ), predicateResultSet);
364
365 model.restore(state1);
366
367 assertFalse(queryEngine.hasPendingChanges());
368 assertResults(Map.of(
369 Tuple.of(0), true,
370 Tuple.of(1), true,
371 Tuple.of(2), false,
372 Tuple.of(3), false
373 ), predicateResultSet);
374 }
375
376 @Disabled("TODO Fix DiffCursor")
377 @Test
378 void commitWithoutFlushTest() {
379 var person = new Symbol<>("Person", 1, Boolean.class, false);
380 var personView = new KeyOnlyRelationView<>(person);
381
382 var p1 = Variable.of("p1");
383 var predicate = Query.builder("TypeConstraint")
384 .parameters(p1)
385 .clause(personView.call(p1))
386 .build();
387
388 var store = ModelStore.builder()
389 .symbols(person)
390 .with(ViatraModelQuery.ADAPTER)
391 .queries(predicate)
392 .build();
393
394 var model = store.createEmptyModel();
395 var personInterpretation = model.getInterpretation(person);
396 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
397 var predicateResultSet = queryEngine.getResultSet(predicate);
398
399 personInterpretation.put(Tuple.of(0), true);
400 personInterpretation.put(Tuple.of(1), true);
401
402 assertResults(Map.of(), predicateResultSet);
403 assertTrue(queryEngine.hasPendingChanges());
404
405 var state1 = model.commit();
406
407 personInterpretation.put(Tuple.of(1), false);
408 personInterpretation.put(Tuple.of(2), true);
409
410 assertResults(Map.of(), predicateResultSet);
411 assertTrue(queryEngine.hasPendingChanges());
412
413 model.restore(state1);
414
415 assertResults(Map.of(
416 Tuple.of(0), true,
417 Tuple.of(1), true,
418 Tuple.of(2), false,
419 Tuple.of(3), false
420 ), predicateResultSet);
61 assertFalse(queryEngine.hasPendingChanges()); 421 assertFalse(queryEngine.hasPendingChanges());
62 } 422 }
63} 423}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
new file mode 100644
index 00000000..6f50ec73
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
@@ -0,0 +1,52 @@
1package tools.refinery.store.query.viatra.tests;
2
3import org.junit.jupiter.api.function.Executable;
4import tools.refinery.store.query.ResultSet;
5import tools.refinery.store.tuple.Tuple;
6
7import java.util.*;
8
9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.is;
11import static org.hamcrest.Matchers.nullValue;
12import static org.junit.jupiter.api.Assertions.assertAll;
13
14public final class QueryAssertions {
15 private QueryAssertions() {
16 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
17 }
18
19 public static <T> void assertNullableResults(Map<Tuple, Optional<T>> expected, ResultSet<T> resultSet) {
20 var nullableValuesMap = new LinkedHashMap<Tuple, T>(expected.size());
21 for (var entry : expected.entrySet()) {
22 nullableValuesMap.put(entry.getKey(), entry.getValue().orElse(null));
23 }
24 assertResults(nullableValuesMap, resultSet);
25 }
26
27 public static <T> void assertResults(Map<Tuple, T> expected, ResultSet<T> resultSet) {
28 var defaultValue = resultSet.getQuery().defaultValue();
29 var filteredExpected = new LinkedHashMap<Tuple, T>();
30 var executables = new ArrayList<Executable>();
31 for (var entry : expected.entrySet()) {
32 var key = entry.getKey();
33 var value = entry.getValue();
34 if (!Objects.equals(value, defaultValue)) {
35 filteredExpected.put(key, value);
36 }
37 executables.add(() -> assertThat("value for key " + key,resultSet.get(key), is(value)));
38 }
39 executables.add(() -> assertThat("results size", resultSet.size(), is(filteredExpected.size())));
40
41 var actual = new LinkedHashMap<Tuple, T>();
42 var cursor = resultSet.getAll();
43 while (cursor.move()) {
44 var key = cursor.getKey();
45 var previous = actual.put(key.toTuple(), cursor.getValue());
46 assertThat("duplicate value for key " + key, previous, nullValue());
47 }
48 executables.add(() -> assertThat("results cursor", actual, is(filteredExpected)));
49
50 assertAll(executables);
51 }
52}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java
new file mode 100644
index 00000000..b1818a17
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java
@@ -0,0 +1,22 @@
1package tools.refinery.store.query.viatra.tests;
2
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4
5/**
6 * Overrides {@link QueryEvaluationHint#toString()} for pretty names in parametric test names.
7 */
8class QueryBackendHint extends QueryEvaluationHint {
9 public QueryBackendHint(BackendRequirement backendRequirementType) {
10 super(null, backendRequirementType);
11 }
12
13 @Override
14 public String toString() {
15 return switch (getQueryBackendRequirementType()) {
16 case UNSPECIFIED -> "default";
17 case DEFAULT_CACHING -> "incremental";
18 case DEFAULT_SEARCH -> "localSearch";
19 default -> throw new IllegalStateException("Unknown BackendRequirement");
20 };
21 }
22}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java
new file mode 100644
index 00000000..f129520c
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java
@@ -0,0 +1,16 @@
1package tools.refinery.store.query.viatra.tests;
2
3import org.junit.jupiter.params.ParameterizedTest;
4import org.junit.jupiter.params.provider.ArgumentsSource;
5
6import java.lang.annotation.ElementType;
7import java.lang.annotation.Retention;
8import java.lang.annotation.RetentionPolicy;
9import java.lang.annotation.Target;
10
11@ParameterizedTest(name = "backend = {0}")
12@ArgumentsSource(QueryEvaluationHintSource.class)
13@Target(ElementType.METHOD)
14@Retention(RetentionPolicy.RUNTIME)
15public @interface QueryEngineTest {
16}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java
new file mode 100644
index 00000000..a55762e2
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java
@@ -0,0 +1,19 @@
1package tools.refinery.store.query.viatra.tests;
2
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4import org.junit.jupiter.api.extension.ExtensionContext;
5import org.junit.jupiter.params.provider.Arguments;
6import org.junit.jupiter.params.provider.ArgumentsProvider;
7
8import java.util.stream.Stream;
9
10public class QueryEvaluationHintSource implements ArgumentsProvider {
11 @Override
12 public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
13 return Stream.of(
14 Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.UNSPECIFIED)),
15 Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.DEFAULT_CACHING)),
16 Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH))
17 );
18 }
19}