aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query-viatra/src/test
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2023-03-31 17:31:46 +0200
committerLibravatar GitHub <noreply@github.com>2023-03-31 17:31:46 +0200
commit93f1d439f33a5139039fe93280bbfcae61a904ab (patch)
treee98eae681a866d2d0cd728885ed6c8f8fa65e9a2 /subprojects/store-query-viatra/src/test
parentrefactor: PartialInterpretation adapter naming (diff)
parentbuild: try to fix secret detection in workflow (diff)
downloadrefinery-93f1d439f33a5139039fe93280bbfcae61a904ab.tar.gz
refinery-93f1d439f33a5139039fe93280bbfcae61a904ab.tar.zst
refinery-93f1d439f33a5139039fe93280bbfcae61a904ab.zip
Merge pull request #24 from kris7t/partial-interpretation
Changes for supporting partial interpretation
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.java564
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java387
-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, 1900 insertions, 238 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 6a37b54a..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,41 +1,47 @@
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.model.ModelStore; 5import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.DNF;
6import tools.refinery.store.query.ModelQuery; 6import tools.refinery.store.query.ModelQuery;
7import tools.refinery.store.query.Variable; 7import tools.refinery.store.query.dnf.Dnf;
8import tools.refinery.store.query.atom.*; 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;
18import java.util.stream.Stream;
19 19
20import static org.junit.jupiter.api.Assertions.assertEquals; 20import static org.junit.jupiter.api.Assertions.assertThrows;
21import static tools.refinery.store.query.literal.Literals.assume;
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(new RelationViewAtom(personView, p1)) 37 .clause(personView.call(p1))
33 .build(); 38 .build();
34 39
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,31 +57,35 @@ 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 new RelationViewAtom(personView, p1), 79 personView.call(p1),
71 new RelationViewAtom(personView, p2), 80 personView.call(p2),
72 new RelationViewAtom(friendMustView, p1, p2) 81 friendMustView.call(p1, p2)
73 ) 82 )
74 .build(); 83 .build();
75 84
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,90 +102,39 @@ 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 106
100 queryEngine.flushChanges(); 107 queryEngine.flushChanges();
101 assertEquals(3, predicateResultSet.countResults()); 108 assertResults(Map.of(
102 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); 109 Tuple.of(0, 1), true,
110 Tuple.of(1, 0), true,
111 Tuple.of(1, 2), true,
112 Tuple.of(2, 1), false
113 ), predicateResultSet);
103 } 114 }
104 115
105 @Test 116 @QueryEngineTest
106 void andTest() { 117 void existTest(QueryEvaluationHint hint) {
107 var person = new Symbol<>("Person", 1, Boolean.class, false); 118 var person = new Symbol<>("Person", 1, Boolean.class, false);
108 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 119 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
109 var personView = new KeyOnlyRelationView<>(person); 120 var personView = new KeyOnlyRelationView<>(person);
110 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 121 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
111 122
112 var p1 = new Variable("p1"); 123 var p1 = Variable.of("p1");
113 var p2 = new Variable("p2"); 124 var p2 = Variable.of("p2");
114 var predicate = DNF.builder("RelationConstraint") 125 var predicate = Query.builder("RelationConstraint")
115 .parameters(p1, p2)
116 .clause(
117 new RelationViewAtom(personView, p1),
118 new RelationViewAtom(personView, p2),
119 new RelationViewAtom(friendMustView, p1, p2),
120 new RelationViewAtom(friendMustView, p2, p1)
121 )
122 .build();
123
124 var store = ModelStore.builder()
125 .symbols(person, friend)
126 .with(ViatraModelQuery.ADAPTER)
127 .queries(predicate)
128 .build();
129
130 var model = store.createEmptyModel();
131 var personInterpretation = model.getInterpretation(person);
132 var friendInterpretation = model.getInterpretation(friend);
133 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
134 var predicateResultSet = queryEngine.getResultSet(predicate);
135
136 assertEquals(0, predicateResultSet.countResults());
137
138 personInterpretation.put(Tuple.of(0), true);
139 personInterpretation.put(Tuple.of(1), true);
140 personInterpretation.put(Tuple.of(2), true);
141
142 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
143 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
144
145 queryEngine.flushChanges();
146 assertEquals(0, predicateResultSet.countResults());
147
148 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
149 queryEngine.flushChanges();
150 assertEquals(2, predicateResultSet.countResults());
151 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0)));
152
153 friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE);
154 queryEngine.flushChanges();
155 assertEquals(4, predicateResultSet.countResults());
156 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2),
157 Tuple.of(2, 0)));
158 }
159
160 @Test
161 void existTest() {
162 var person = new Symbol<>("Person", 1, Boolean.class, false);
163 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
164 var personView = new KeyOnlyRelationView<>(person);
165 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
166
167 var p1 = new Variable("p1");
168 var p2 = new Variable("p2");
169 var predicate = DNF.builder("RelationConstraint")
170 .parameters(p1) 126 .parameters(p1)
171 .clause( 127 .clause(
172 new RelationViewAtom(personView, p1), 128 personView.call(p1),
173 new RelationViewAtom(personView, p2), 129 personView.call(p2),
174 new RelationViewAtom(friendMustView, p1, p2) 130 friendMustView.call(p1, p2)
175 ) 131 )
176 .build(); 132 .build();
177 133
178 var store = ModelStore.builder() 134 var store = ModelStore.builder()
179 .symbols(person, friend) 135 .symbols(person, friend)
180 .with(ViatraModelQuery.ADAPTER) 136 .with(ViatraModelQuery.ADAPTER)
137 .defaultHint(hint)
181 .queries(predicate) 138 .queries(predicate)
182 .build(); 139 .build();
183 140
@@ -194,16 +151,19 @@ class QueryTest {
194 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); 151 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
195 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); 152 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
196 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 153 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
197 154 friendInterpretation.put(Tuple.of(3, 2), TruthValue.TRUE);
198 assertEquals(0, predicateResultSet.countResults());
199 155
200 queryEngine.flushChanges(); 156 queryEngine.flushChanges();
201 assertEquals(2, predicateResultSet.countResults()); 157 assertResults(Map.of(
202 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);
203 } 163 }
204 164
205 @Test 165 @QueryEngineTest
206 void orTest() { 166 void orTest(QueryEvaluationHint hint) {
207 var person = new Symbol<>("Person", 1, Boolean.class, false); 167 var person = new Symbol<>("Person", 1, Boolean.class, false);
208 var animal = new Symbol<>("Animal", 1, Boolean.class, false); 168 var animal = new Symbol<>("Animal", 1, Boolean.class, false);
209 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 169 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
@@ -211,25 +171,26 @@ class QueryTest {
211 var animalView = new KeyOnlyRelationView<>(animal); 171 var animalView = new KeyOnlyRelationView<>(animal);
212 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 172 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
213 173
214 var p1 = new Variable("p1"); 174 var p1 = Variable.of("p1");
215 var p2 = new Variable("p2"); 175 var p2 = Variable.of("p2");
216 var predicate = DNF.builder("Or") 176 var predicate = Query.builder("Or")
217 .parameters(p1, p2) 177 .parameters(p1, p2)
218 .clause( 178 .clause(
219 new RelationViewAtom(personView, p1), 179 personView.call(p1),
220 new RelationViewAtom(personView, p2), 180 personView.call(p2),
221 new RelationViewAtom(friendMustView, p1, p2) 181 friendMustView.call(p1, p2)
222 ) 182 )
223 .clause( 183 .clause(
224 new RelationViewAtom(animalView, p1), 184 animalView.call(p1),
225 new RelationViewAtom(animalView, p2), 185 animalView.call(p2),
226 new RelationViewAtom(friendMustView, p1, p2) 186 friendMustView.call(p1, p2)
227 ) 187 )
228 .build(); 188 .build();
229 189
230 var store = ModelStore.builder() 190 var store = ModelStore.builder()
231 .symbols(person, animal, friend) 191 .symbols(person, animal, friend)
232 .with(ViatraModelQuery.ADAPTER) 192 .with(ViatraModelQuery.ADAPTER)
193 .defaultHint(hint)
233 .queries(predicate) 194 .queries(predicate)
234 .build(); 195 .build();
235 196
@@ -252,29 +213,35 @@ class QueryTest {
252 friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE); 213 friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE);
253 214
254 queryEngine.flushChanges(); 215 queryEngine.flushChanges();
255 assertEquals(2, predicateResultSet.countResults()); 216 assertResults(Map.of(
256 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);
257 } 223 }
258 224
259 @Test 225 @QueryEngineTest
260 void equalityTest() { 226 void equalityTest(QueryEvaluationHint hint) {
261 var person = new Symbol<>("Person", 1, Boolean.class, false); 227 var person = new Symbol<>("Person", 1, Boolean.class, false);
262 var personView = new KeyOnlyRelationView<>(person); 228 var personView = new KeyOnlyRelationView<>(person);
263 229
264 var p1 = new Variable("p1"); 230 var p1 = Variable.of("p1");
265 var p2 = new Variable("p2"); 231 var p2 = Variable.of("p2");
266 var predicate = DNF.builder("Equality") 232 var predicate = Query.builder("Equality")
267 .parameters(p1, p2) 233 .parameters(p1, p2)
268 .clause( 234 .clause(
269 new RelationViewAtom(personView, p1), 235 personView.call(p1),
270 new RelationViewAtom(personView, p2), 236 personView.call(p2),
271 new EquivalenceAtom(p1, p2) 237 p1.isEquivalent(p2)
272 ) 238 )
273 .build(); 239 .build();
274 240
275 var store = ModelStore.builder() 241 var store = ModelStore.builder()
276 .symbols(person) 242 .symbols(person)
277 .with(ViatraModelQuery.ADAPTER) 243 .with(ViatraModelQuery.ADAPTER)
244 .defaultHint(hint)
278 .queries(predicate) 245 .queries(predicate)
279 .build(); 246 .build();
280 247
@@ -288,34 +255,40 @@ class QueryTest {
288 personInterpretation.put(Tuple.of(2), true); 255 personInterpretation.put(Tuple.of(2), true);
289 256
290 queryEngine.flushChanges(); 257 queryEngine.flushChanges();
291 assertEquals(3, predicateResultSet.countResults()); 258 assertResults(Map.of(
292 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);
293 } 265 }
294 266
295 @Test 267 @QueryEngineTest
296 void inequalityTest() { 268 void inequalityTest(QueryEvaluationHint hint) {
297 var person = new Symbol<>("Person", 1, Boolean.class, false); 269 var person = new Symbol<>("Person", 1, Boolean.class, false);
298 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 270 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
299 var personView = new KeyOnlyRelationView<>(person); 271 var personView = new KeyOnlyRelationView<>(person);
300 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 272 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
301 273
302 var p1 = new Variable("p1"); 274 var p1 = Variable.of("p1");
303 var p2 = new Variable("p2"); 275 var p2 = Variable.of("p2");
304 var p3 = new Variable("p3"); 276 var p3 = Variable.of("p3");
305 var predicate = DNF.builder("Inequality") 277 var predicate = Query.builder("Inequality")
306 .parameters(p1, p2, p3) 278 .parameters(p1, p2, p3)
307 .clause( 279 .clause(
308 new RelationViewAtom(personView, p1), 280 personView.call(p1),
309 new RelationViewAtom(personView, p2), 281 personView.call(p2),
310 new RelationViewAtom(friendMustView, p1, p3), 282 friendMustView.call(p1, p3),
311 new RelationViewAtom(friendMustView, p2, p3), 283 friendMustView.call(p2, p3),
312 new EquivalenceAtom(false, p1, p2) 284 p1.notEquivalent(p2)
313 ) 285 )
314 .build(); 286 .build();
315 287
316 var store = ModelStore.builder() 288 var store = ModelStore.builder()
317 .symbols(person, friend) 289 .symbols(person, friend)
318 .with(ViatraModelQuery.ADAPTER) 290 .with(ViatraModelQuery.ADAPTER)
291 .defaultHint(hint)
319 .queries(predicate) 292 .queries(predicate)
320 .build(); 293 .build();
321 294
@@ -333,42 +306,46 @@ class QueryTest {
333 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 306 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
334 307
335 queryEngine.flushChanges(); 308 queryEngine.flushChanges();
336 assertEquals(2, predicateResultSet.countResults()); 309 assertResults(Map.of(
337 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);
338 } 314 }
339 315
340 @Test 316 @QueryEngineTest
341 void patternCallTest() { 317 void patternCallTest(QueryEvaluationHint hint) {
342 var person = new Symbol<>("Person", 1, Boolean.class, false); 318 var person = new Symbol<>("Person", 1, Boolean.class, false);
343 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 319 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
344 var personView = new KeyOnlyRelationView<>(person); 320 var personView = new KeyOnlyRelationView<>(person);
345 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 321 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
346 322
347 var p1 = new Variable("p1"); 323 var p1 = Variable.of("p1");
348 var p2 = new Variable("p2"); 324 var p2 = Variable.of("p2");
349 var friendPredicate = DNF.builder("RelationConstraint") 325 var friendPredicate = Dnf.builder("RelationConstraint")
350 .parameters(p1, p2) 326 .parameters(p1, p2)
351 .clause( 327 .clause(
352 new RelationViewAtom(personView, p1), 328 personView.call(p1),
353 new RelationViewAtom(personView, p2), 329 personView.call(p2),
354 new RelationViewAtom(friendMustView, p1, p2) 330 friendMustView.call(p1, p2)
355 ) 331 )
356 .build(); 332 .build();
357 333
358 var p3 = new Variable("p3"); 334 var p3 = Variable.of("p3");
359 var p4 = new Variable("p4"); 335 var p4 = Variable.of("p4");
360 var predicate = DNF.builder("PositivePatternCall") 336 var predicate = Query.builder("PositivePatternCall")
361 .parameters(p3, p4) 337 .parameters(p3, p4)
362 .clause( 338 .clause(
363 new RelationViewAtom(personView, p3), 339 personView.call(p3),
364 new RelationViewAtom(personView, p4), 340 personView.call(p4),
365 new DNFCallAtom(friendPredicate, p3, p4) 341 friendPredicate.call(p3, p4)
366 ) 342 )
367 .build(); 343 .build();
368 344
369 var store = ModelStore.builder() 345 var store = ModelStore.builder()
370 .symbols(person, friend) 346 .symbols(person, friend)
371 .with(ViatraModelQuery.ADAPTER) 347 .with(ViatraModelQuery.ADAPTER)
348 .defaultHint(hint)
372 .queries(predicate) 349 .queries(predicate)
373 .build(); 350 .build();
374 351
@@ -387,30 +364,36 @@ class QueryTest {
387 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 364 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
388 365
389 queryEngine.flushChanges(); 366 queryEngine.flushChanges();
390 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);
391 } 373 }
392 374
393 @Test 375 @QueryEngineTest
394 void negativeRelationViewTest() { 376 void negativeRelationViewTest(QueryEvaluationHint hint) {
395 var person = new Symbol<>("Person", 1, Boolean.class, false); 377 var person = new Symbol<>("Person", 1, Boolean.class, false);
396 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 378 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
397 var personView = new KeyOnlyRelationView<>(person); 379 var personView = new KeyOnlyRelationView<>(person);
398 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 380 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
399 381
400 var p1 = new Variable("p1"); 382 var p1 = Variable.of("p1");
401 var p2 = new Variable("p2"); 383 var p2 = Variable.of("p2");
402 var predicate = DNF.builder("NegativePatternCall") 384 var predicate = Query.builder("NegativePatternCall")
403 .parameters(p1, p2) 385 .parameters(p1, p2)
404 .clause( 386 .clause(
405 new RelationViewAtom(personView, p1), 387 personView.call(p1),
406 new RelationViewAtom(personView, p2), 388 personView.call(p2),
407 new RelationViewAtom(false, friendMustView, p1, p2) 389 not(friendMustView.call(p1, p2))
408 ) 390 )
409 .build(); 391 .build();
410 392
411 var store = ModelStore.builder() 393 var store = ModelStore.builder()
412 .symbols(person, friend) 394 .symbols(person, friend)
413 .with(ViatraModelQuery.ADAPTER) 395 .with(ViatraModelQuery.ADAPTER)
396 .defaultHint(hint)
414 .queries(predicate) 397 .queries(predicate)
415 .build(); 398 .build();
416 399
@@ -429,41 +412,53 @@ class QueryTest {
429 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 412 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
430 413
431 queryEngine.flushChanges(); 414 queryEngine.flushChanges();
432 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);
433 } 427 }
434 428
435 @Test 429 @QueryEngineTest
436 void negativePatternCallTest() { 430 void negativePatternCallTest(QueryEvaluationHint hint) {
437 var person = new Symbol<>("Person", 1, Boolean.class, false); 431 var person = new Symbol<>("Person", 1, Boolean.class, false);
438 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 432 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
439 var personView = new KeyOnlyRelationView<>(person); 433 var personView = new KeyOnlyRelationView<>(person);
440 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 434 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
441 435
442 var p1 = new Variable("p1"); 436 var p1 = Variable.of("p1");
443 var p2 = new Variable("p2"); 437 var p2 = Variable.of("p2");
444 var friendPredicate = DNF.builder("RelationConstraint") 438 var friendPredicate = Dnf.builder("RelationConstraint")
445 .parameters(p1, p2) 439 .parameters(p1, p2)
446 .clause( 440 .clause(
447 new RelationViewAtom(personView, p1), 441 personView.call(p1),
448 new RelationViewAtom(personView, p2), 442 personView.call(p2),
449 new RelationViewAtom(friendMustView, p1, p2) 443 friendMustView.call(p1, p2)
450 ) 444 )
451 .build(); 445 .build();
452 446
453 var p3 = new Variable("p3"); 447 var p3 = Variable.of("p3");
454 var p4 = new Variable("p4"); 448 var p4 = Variable.of("p4");
455 var predicate = DNF.builder("NegativePatternCall") 449 var predicate = Query.builder("NegativePatternCall")
456 .parameters(p3, p4) 450 .parameters(p3, p4)
457 .clause( 451 .clause(
458 new RelationViewAtom(personView, p3), 452 personView.call(p3),
459 new RelationViewAtom(personView, p4), 453 personView.call(p4),
460 new DNFCallAtom(false, friendPredicate, p3, p4) 454 not(friendPredicate.call(p3, p4))
461 ) 455 )
462 .build(); 456 .build();
463 457
464 var store = ModelStore.builder() 458 var store = ModelStore.builder()
465 .symbols(person, friend) 459 .symbols(person, friend)
466 .with(ViatraModelQuery.ADAPTER) 460 .with(ViatraModelQuery.ADAPTER)
461 .defaultHint(hint)
467 .queries(predicate) 462 .queries(predicate)
468 .build(); 463 .build();
469 464
@@ -482,30 +477,42 @@ class QueryTest {
482 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 477 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
483 478
484 queryEngine.flushChanges(); 479 queryEngine.flushChanges();
485 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);
486 } 492 }
487 493
488 @Test 494 @QueryEngineTest
489 void negativeRelationViewWithQuantificationTest() { 495 void negativeRelationViewWithQuantificationTest(QueryEvaluationHint hint) {
490 var person = new Symbol<>("Person", 1, Boolean.class, false); 496 var person = new Symbol<>("Person", 1, Boolean.class, false);
491 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 497 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
492 var personView = new KeyOnlyRelationView<>(person); 498 var personView = new KeyOnlyRelationView<>(person);
493 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 499 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
494 500
495 var p1 = new Variable("p1"); 501 var p1 = Variable.of("p1");
496 var p2 = new Variable("p2"); 502 var p2 = Variable.of("p2");
497 503
498 var predicate = DNF.builder("Count") 504 var predicate = Query.builder("Count")
499 .parameters(p1) 505 .parameters(p1)
500 .clause( 506 .clause(
501 new RelationViewAtom(personView, p1), 507 personView.call(p1),
502 new RelationViewAtom(false, friendMustView, p1, p2) 508 not(friendMustView.call(p1, p2))
503 ) 509 )
504 .build(); 510 .build();
505 511
506 var store = ModelStore.builder() 512 var store = ModelStore.builder()
507 .symbols(person, friend) 513 .symbols(person, friend)
508 .with(ViatraModelQuery.ADAPTER) 514 .with(ViatraModelQuery.ADAPTER)
515 .defaultHint(hint)
509 .queries(predicate) 516 .queries(predicate)
510 .build(); 517 .build();
511 518
@@ -523,39 +530,45 @@ class QueryTest {
523 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); 530 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
524 531
525 queryEngine.flushChanges(); 532 queryEngine.flushChanges();
526 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);
527 } 539 }
528 540
529 @Test 541 @QueryEngineTest
530 void negativeWithQuantificationTest() { 542 void negativeWithQuantificationTest(QueryEvaluationHint hint) {
531 var person = new Symbol<>("Person", 1, Boolean.class, false); 543 var person = new Symbol<>("Person", 1, Boolean.class, false);
532 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 544 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
533 var personView = new KeyOnlyRelationView<>(person); 545 var personView = new KeyOnlyRelationView<>(person);
534 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 546 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
535 547
536 var p1 = new Variable("p1"); 548 var p1 = Variable.of("p1");
537 var p2 = new Variable("p2"); 549 var p2 = Variable.of("p2");
538 550
539 var called = DNF.builder("Called") 551 var called = Dnf.builder("Called")
540 .parameters(p1, p2) 552 .parameters(p1, p2)
541 .clause( 553 .clause(
542 new RelationViewAtom(personView, p1), 554 personView.call(p1),
543 new RelationViewAtom(personView, p2), 555 personView.call(p2),
544 new RelationViewAtom(friendMustView, p1, p2) 556 friendMustView.call(p1, p2)
545 ) 557 )
546 .build(); 558 .build();
547 559
548 var predicate = DNF.builder("Count") 560 var predicate = Query.builder("Count")
549 .parameters(p1) 561 .parameters(p1)
550 .clause( 562 .clause(
551 new RelationViewAtom(personView, p1), 563 personView.call(p1),
552 new DNFCallAtom(false, called, p1, p2) 564 not(called.call(p1, p2))
553 ) 565 )
554 .build(); 566 .build();
555 567
556 var store = ModelStore.builder() 568 var store = ModelStore.builder()
557 .symbols(person, friend) 569 .symbols(person, friend)
558 .with(ViatraModelQuery.ADAPTER) 570 .with(ViatraModelQuery.ADAPTER)
571 .defaultHint(hint)
559 .queries(predicate) 572 .queries(predicate)
560 .build(); 573 .build();
561 574
@@ -573,30 +586,36 @@ class QueryTest {
573 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); 586 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
574 587
575 queryEngine.flushChanges(); 588 queryEngine.flushChanges();
576 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);
577 } 595 }
578 596
579 @Test 597 @QueryEngineTest
580 void transitiveRelationViewTest() { 598 void transitiveRelationViewTest(QueryEvaluationHint hint) {
581 var person = new Symbol<>("Person", 1, Boolean.class, false); 599 var person = new Symbol<>("Person", 1, Boolean.class, false);
582 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 600 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
583 var personView = new KeyOnlyRelationView<>(person); 601 var personView = new KeyOnlyRelationView<>(person);
584 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 602 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
585 603
586 var p1 = new Variable("p1"); 604 var p1 = Variable.of("p1");
587 var p2 = new Variable("p2"); 605 var p2 = Variable.of("p2");
588 var predicate = DNF.builder("TransitivePatternCall") 606 var predicate = Query.builder("TransitivePatternCall")
589 .parameters(p1, p2) 607 .parameters(p1, p2)
590 .clause( 608 .clause(
591 new RelationViewAtom(personView, p1), 609 personView.call(p1),
592 new RelationViewAtom(personView, p2), 610 personView.call(p2),
593 new RelationViewAtom(CallPolarity.TRANSITIVE, friendMustView, p1, p2) 611 friendMustView.callTransitive(p1, p2)
594 ) 612 )
595 .build(); 613 .build();
596 614
597 var store = ModelStore.builder() 615 var store = ModelStore.builder()
598 .symbols(person, friend) 616 .symbols(person, friend)
599 .with(ViatraModelQuery.ADAPTER) 617 .with(ViatraModelQuery.ADAPTER)
618 .defaultHint(hint)
600 .queries(predicate) 619 .queries(predicate)
601 .build(); 620 .build();
602 621
@@ -614,41 +633,53 @@ class QueryTest {
614 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 633 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
615 634
616 queryEngine.flushChanges(); 635 queryEngine.flushChanges();
617 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);
618 } 648 }
619 649
620 @Test 650 @QueryEngineTest
621 void transitivePatternCallTest() { 651 void transitivePatternCallTest(QueryEvaluationHint hint) {
622 var person = new Symbol<>("Person", 1, Boolean.class, false); 652 var person = new Symbol<>("Person", 1, Boolean.class, false);
623 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 653 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
624 var personView = new KeyOnlyRelationView<>(person); 654 var personView = new KeyOnlyRelationView<>(person);
625 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 655 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
626 656
627 var p1 = new Variable("p1"); 657 var p1 = Variable.of("p1");
628 var p2 = new Variable("p2"); 658 var p2 = Variable.of("p2");
629 var friendPredicate = DNF.builder("RelationConstraint") 659 var friendPredicate = Dnf.builder("RelationConstraint")
630 .parameters(p1, p2) 660 .parameters(p1, p2)
631 .clause( 661 .clause(
632 new RelationViewAtom(personView, p1), 662 personView.call(p1),
633 new RelationViewAtom(personView, p2), 663 personView.call(p2),
634 new RelationViewAtom(friendMustView, p1, p2) 664 friendMustView.call(p1, p2)
635 ) 665 )
636 .build(); 666 .build();
637 667
638 var p3 = new Variable("p3"); 668 var p3 = Variable.of("p3");
639 var p4 = new Variable("p4"); 669 var p4 = Variable.of("p4");
640 var predicate = DNF.builder("TransitivePatternCall") 670 var predicate = Query.builder("TransitivePatternCall")
641 .parameters(p3, p4) 671 .parameters(p3, p4)
642 .clause( 672 .clause(
643 new RelationViewAtom(personView, p3), 673 personView.call(p3),
644 new RelationViewAtom(personView, p4), 674 personView.call(p4),
645 new DNFCallAtom(CallPolarity.TRANSITIVE, friendPredicate, p3, p4) 675 friendPredicate.callTransitive(p3, p4)
646 ) 676 )
647 .build(); 677 .build();
648 678
649 var store = ModelStore.builder() 679 var store = ModelStore.builder()
650 .symbols(person, friend) 680 .symbols(person, friend)
651 .with(ViatraModelQuery.ADAPTER) 681 .with(ViatraModelQuery.ADAPTER)
682 .defaultHint(hint)
652 .queries(predicate) 683 .queries(predicate)
653 .build(); 684 .build();
654 685
@@ -666,16 +697,101 @@ class QueryTest {
666 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); 697 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
667 698
668 queryEngine.flushChanges(); 699 queryEngine.flushChanges();
669 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);
757 }
758
759 @Test
760 void alwaysFalseTest() {
761 var person = new Symbol<>("Person", 1, Boolean.class, false);
762
763 var p1 = Variable.of("p1");
764 var predicate = Query.builder("AlwaysFalse").parameters(p1).build();
765
766 var store = ModelStore.builder()
767 .symbols(person)
768 .with(ViatraModelQuery.ADAPTER)
769 .queries(predicate)
770 .build();
771
772 var model = store.createEmptyModel();
773 var personInterpretation = model.getInterpretation(person);
774 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
775 var predicateResultSet = queryEngine.getResultSet(predicate);
776
777 personInterpretation.put(Tuple.of(0), true);
778 personInterpretation.put(Tuple.of(1), true);
779 personInterpretation.put(Tuple.of(2), true);
780
781 queryEngine.flushChanges();
782 assertResults(Map.of(), predicateResultSet);
670 } 783 }
671 784
672 static void compareMatchSets(Stream<TupleLike> matchSet, Set<Tuple> expected) { 785 @Test
673 Set<Tuple> translatedMatchSet = new HashSet<>(); 786 void alwaysTrueTest() {
674 var iterator = matchSet.iterator(); 787 var person = new Symbol<>("Person", 1, Boolean.class, false);
675 while (iterator.hasNext()) { 788
676 var element = iterator.next(); 789 var p1 = Variable.of("p1");
677 translatedMatchSet.add(element.toTuple()); 790 var predicate = Query.builder("AlwaysTrue").parameters(p1).clause().build();
678 } 791
679 assertEquals(expected, translatedMatchSet); 792 var storeBuilder = ModelStore.builder().symbols(person);
793 var queryBuilder = storeBuilder.with(ViatraModelQuery.ADAPTER);
794
795 assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate));
680 } 796 }
681} 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 98995339..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,28 +1,162 @@
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;
8import tools.refinery.store.query.atom.RelationViewAtom; 9import tools.refinery.store.query.term.Variable;
10import tools.refinery.store.query.view.FilteredRelationView;
11import tools.refinery.store.query.view.FunctionalRelationView;
9import tools.refinery.store.query.view.KeyOnlyRelationView; 12import tools.refinery.store.query.view.KeyOnlyRelationView;
10import tools.refinery.store.representation.Symbol; 13import tools.refinery.store.representation.Symbol;
11import tools.refinery.store.tuple.Tuple; 14import tools.refinery.store.tuple.Tuple;
12 15
13import 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;
14 23
15class QueryTransactionTest { 24class QueryTransactionTest {
16 @Test 25 @Test
17 void flushTest() { 26 void flushTest() {
18 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);
19 var asset = new Symbol<>("Asset", 1, Boolean.class, false); 153 var asset = new Symbol<>("Asset", 1, Boolean.class, false);
20 var personView = new KeyOnlyRelationView<>(person); 154 var personView = new KeyOnlyRelationView<>(person);
21 155
22 var p1 = new Variable("p1"); 156 var p1 = Variable.of("p1");
23 var predicate = DNF.builder("TypeConstraint") 157 var predicate = Query.builder("TypeConstraint")
24 .parameters(p1) 158 .parameters(p1)
25 .clause(new RelationViewAtom(personView, p1)) 159 .clause(personView.call(p1))
26 .build(); 160 .build();
27 161
28 var store = ModelStore.builder() 162 var store = ModelStore.builder()
@@ -37,7 +171,6 @@ class QueryTransactionTest {
37 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 171 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
38 var predicateResultSet = queryEngine.getResultSet(predicate); 172 var predicateResultSet = queryEngine.getResultSet(predicate);
39 173
40 assertEquals(0, predicateResultSet.countResults());
41 assertFalse(queryEngine.hasPendingChanges()); 174 assertFalse(queryEngine.hasPendingChanges());
42 175
43 personInterpretation.put(Tuple.of(0), true); 176 personInterpretation.put(Tuple.of(0), true);
@@ -46,19 +179,245 @@ class QueryTransactionTest {
46 assetInterpretation.put(Tuple.of(1), true); 179 assetInterpretation.put(Tuple.of(1), true);
47 assetInterpretation.put(Tuple.of(2), true); 180 assetInterpretation.put(Tuple.of(2), true);
48 181
49 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);
50 assertTrue(queryEngine.hasPendingChanges()); 189 assertTrue(queryEngine.hasPendingChanges());
51 190
52 queryEngine.flushChanges(); 191 queryEngine.flushChanges();
53 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);
54 assertFalse(queryEngine.hasPendingChanges()); 199 assertFalse(queryEngine.hasPendingChanges());
55 200
56 personInterpretation.put(Tuple.of(4), true); 201 assetInterpretation.put(Tuple.of(3), true);
57 assertEquals(2, predicateResultSet.countResults()); 202 assertFalse(queryEngine.hasPendingChanges());
58 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);
59 266
60 queryEngine.flushChanges(); 267 queryEngine.flushChanges();
61 assertEquals(3, predicateResultSet.countResults()); 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);
313
314 queryEngine.flushChanges();
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);
62 assertFalse(queryEngine.hasPendingChanges()); 421 assertFalse(queryEngine.hasPendingChanges());
63 } 422 }
64} 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}