aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query-viatra
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-01-23 20:27:55 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-01-29 00:02:28 +0100
commitd91acf3690682d243dbc150df902525b6e545c2f (patch)
treef39695cc193828df0b78030b5a56bd968e277457 /subprojects/store-query-viatra
parentchore(deps): bump dependencies (diff)
downloadrefinery-d91acf3690682d243dbc150df902525b6e545c2f.tar.gz
refinery-d91acf3690682d243dbc150df902525b6e545c2f.tar.zst
refinery-d91acf3690682d243dbc150df902525b6e545c2f.zip
refactor: Model store and query API
Use Adapters to simplify API usage.
Diffstat (limited to 'subprojects/store-query-viatra')
-rw-r--r--subprojects/store-query-viatra/build.gradle2
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java22
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java48
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java8
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java140
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java22
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java117
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java116
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java58
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraQueryableModel.java222
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java8
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java2
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java2
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java14
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java34
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java (renamed from subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SimplePQuery.java)7
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java (renamed from subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RawPatternMatcher.java)13
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java4
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java46
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java66
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java40
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java35
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java24
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java112
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java32
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java47
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java73
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java580
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java57
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java4
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java4
31 files changed, 1009 insertions, 950 deletions
diff --git a/subprojects/store-query-viatra/build.gradle b/subprojects/store-query-viatra/build.gradle
index 32a23fe7..c12b48fe 100644
--- a/subprojects/store-query-viatra/build.gradle
+++ b/subprojects/store-query-viatra/build.gradle
@@ -9,7 +9,7 @@ configurations.testRuntimeClasspath {
9 9
10dependencies { 10dependencies {
11 implementation libs.ecore 11 implementation libs.ecore
12 implementation libs.viatra 12 api libs.viatra
13 api project(':refinery-store') 13 api project(':refinery-store')
14 testImplementation libs.slf4j.simple 14 testImplementation libs.slf4j.simple
15 testImplementation libs.slf4j.log4j 15 testImplementation libs.slf4j.log4j
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java
new file mode 100644
index 00000000..ecac570b
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java
@@ -0,0 +1,22 @@
1package tools.refinery.store.query.viatra;
2
3import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
4import tools.refinery.store.model.ModelStoreBuilder;
5import tools.refinery.store.query.ModelQuery;
6import tools.refinery.store.query.ModelQueryAdapter;
7import tools.refinery.store.query.viatra.internal.ViatraModelQueryBuilderImpl;
8
9public final class ViatraModelQuery extends ModelAdapterBuilderFactory<ModelQueryAdapter, ViatraModelQueryStoreAdapter,
10 ViatraModelQueryBuilder> {
11 public static final ViatraModelQuery ADAPTER = new ViatraModelQuery();
12
13 private ViatraModelQuery() {
14 super(ModelQueryAdapter.class, ViatraModelQueryStoreAdapter.class, ViatraModelQueryBuilder.class);
15 extendsAdapter(ModelQuery.ADAPTER);
16 }
17
18 @Override
19 public ViatraModelQueryBuilder createBuilder(ModelStoreBuilder storeBuilder) {
20 return new ViatraModelQueryBuilderImpl(storeBuilder);
21 }
22}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
new file mode 100644
index 00000000..ee445a79
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
@@ -0,0 +1,48 @@
1package tools.refinery.store.query.viatra;
2
3import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
4import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory;
5import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
6import tools.refinery.store.model.ModelStore;
7import tools.refinery.store.query.DNF;
8import tools.refinery.store.query.ModelQueryBuilder;
9
10import java.util.Collection;
11import java.util.function.Function;
12
13@SuppressWarnings("UnusedReturnValue")
14public interface ViatraModelQueryBuilder extends ModelQueryBuilder {
15 ViatraModelQueryBuilder engineOptions(ViatraQueryEngineOptions engineOptions);
16
17 ViatraModelQueryBuilder defaultHint(QueryEvaluationHint queryEvaluationHint);
18
19 ViatraModelQueryBuilder backend(IQueryBackendFactory queryBackendFactory);
20
21 ViatraModelQueryBuilder cachingBackend(IQueryBackendFactory queryBackendFactory);
22
23 ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory);
24
25 @Override
26 default ViatraModelQueryBuilder queries(DNF... queries) {
27 ModelQueryBuilder.super.queries(queries);
28 return this;
29 }
30
31 @Override
32 default ViatraModelQueryBuilder queries(Collection<? extends DNF> queries) {
33 ModelQueryBuilder.super.queries(queries);
34 return this;
35 }
36
37 @Override
38 ViatraModelQueryBuilder query(DNF query);
39
40 ViatraModelQueryBuilder query(DNF query, QueryEvaluationHint queryEvaluationHint);
41
42 ViatraModelQueryBuilder computeHint(Function<DNF, QueryEvaluationHint> computeHint);
43
44 ViatraModelQueryBuilder hint(DNF dnf, QueryEvaluationHint queryEvaluationHint);
45
46 @Override
47 ViatraModelQueryStoreAdapter createStoreAdapter(ModelStore store);
48}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java
new file mode 100644
index 00000000..d52575d2
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java
@@ -0,0 +1,8 @@
1package tools.refinery.store.query.viatra;
2
3import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
4import tools.refinery.store.query.ModelQueryStoreAdapter;
5
6public interface ViatraModelQueryStoreAdapter extends ModelQueryStoreAdapter {
7 ViatraQueryEngineOptions getEngineOptions();
8}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java
deleted file mode 100644
index 94d2db4f..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java
+++ /dev/null
@@ -1,140 +0,0 @@
1package tools.refinery.store.query.viatra;
2
3import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
4import tools.refinery.store.model.ModelDiffCursor;
5import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.model.ModelStoreImpl;
7import tools.refinery.store.model.RelationLike;
8import tools.refinery.store.model.representation.AnyDataRepresentation;
9import tools.refinery.store.model.representation.DataRepresentation;
10import tools.refinery.store.query.DNF;
11import tools.refinery.store.query.DNFAnd;
12import tools.refinery.store.query.QueryableModel;
13import tools.refinery.store.query.QueryableModelStore;
14import tools.refinery.store.query.atom.*;
15import tools.refinery.store.query.viatra.internal.RawPatternMatcher;
16import tools.refinery.store.query.viatra.internal.ViatraQueryableModel;
17import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery;
18import tools.refinery.store.query.view.AnyRelationView;
19
20import java.util.Collections;
21import java.util.HashMap;
22import java.util.Map;
23import java.util.Set;
24
25public class ViatraQueryableModelStore implements QueryableModelStore {
26 protected final ModelStore store;
27
28 protected final Set<AnyRelationView> relationViews;
29
30 protected final Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates;
31
32 public ViatraQueryableModelStore(ModelStore store, Set<AnyRelationView> relationViews,
33 Set<DNF> predicates) {
34 this.store = store;
35 validateViews(store.getDataRepresentations(), relationViews);
36 this.relationViews = Collections.unmodifiableSet(relationViews);
37 validatePredicates(relationViews, predicates);
38 this.predicates = initPredicates(predicates);
39 }
40
41 public ViatraQueryableModelStore(Set<AnyDataRepresentation> dataRepresentations,
42 Set<AnyRelationView> relationViews, Set<DNF> predicates) {
43 this(new ModelStoreImpl(dataRepresentations), relationViews, predicates);
44 }
45
46 private void validateViews(Set<AnyDataRepresentation> dataRepresentations, Set<AnyRelationView> relationViews) {
47 for (var relationView : relationViews) {
48 if (!dataRepresentations.contains(relationView.getRepresentation())) {
49 throw new IllegalArgumentException("%s %s added to %s without a referred representation.".formatted(
50 DataRepresentation.class.getSimpleName(), relationView.getName(),
51 QueryableModelStore.class.getSimpleName()));
52 }
53 }
54 }
55
56 private void validatePredicates(Set<AnyRelationView> relationViews, Set<DNF> predicates) {
57 for (DNF dnfPredicate : predicates) {
58 for (DNFAnd clause : dnfPredicate.getClauses()) {
59 for (DNFAtom atom : clause.constraints()) {
60 if (atom instanceof RelationViewAtom relationViewAtom) {
61 validateRelationAtom(relationViews, dnfPredicate, relationViewAtom);
62 } else if (atom instanceof CallAtom<?> queryCallAtom) {
63 validatePredicateAtom(predicates, dnfPredicate, queryCallAtom);
64 } else if (!(atom instanceof EquivalenceAtom || atom instanceof ConstantAtom)) {
65 throw new IllegalArgumentException("Unknown constraint: " + atom.toString());
66 }
67 }
68 }
69 }
70 }
71
72 private void validateRelationAtom(Set<AnyRelationView> relationViews, DNF dnfPredicate,
73 RelationViewAtom relationViewAtom) {
74 if (!relationViews.contains(relationViewAtom.getTarget())) {
75 throw new IllegalArgumentException(
76 "%s %s contains reference to a view %s that is not in the model.".formatted(
77 DNF.class.getSimpleName(), dnfPredicate.getUniqueName(),
78 relationViewAtom.getTarget().getName()));
79 }
80 }
81
82 private void validatePredicateReference(Set<DNF> predicates, DNF dnfPredicate, RelationLike target) {
83 if (!(target instanceof DNF dnfTarget) || !predicates.contains(dnfTarget)) {
84 throw new IllegalArgumentException(
85 "%s %s contains reference to a predicate %s that is not in the model.".formatted(
86 DNF.class.getSimpleName(), dnfPredicate.getUniqueName(), target.getName()));
87 }
88 }
89
90 private void validatePredicateAtom(Set<DNF> predicates, DNF dnfPredicate, CallAtom<?> queryCallAtom) {
91 validatePredicateReference(predicates, dnfPredicate, queryCallAtom.getTarget());
92 }
93
94
95 private Map<DNF, GenericQuerySpecification<RawPatternMatcher>> initPredicates(Set<DNF> predicates) {
96 Map<DNF, GenericQuerySpecification<RawPatternMatcher>> result = new HashMap<>();
97 var dnf2PQuery = new DNF2PQuery();
98 for (DNF dnfPredicate : predicates) {
99 GenericQuerySpecification<RawPatternMatcher> query = dnf2PQuery.translate(dnfPredicate).build();
100 result.put(dnfPredicate, query);
101 }
102
103 return result;
104 }
105
106 @Override
107 public Set<AnyDataRepresentation> getDataRepresentations() {
108 return store.getDataRepresentations();
109 }
110
111 @Override
112 public Set<AnyRelationView> getViews() {
113 return this.relationViews;
114 }
115
116 @Override
117 public Set<DNF> getPredicates() {
118 return predicates.keySet();
119 }
120
121 @Override
122 public QueryableModel createModel() {
123 return new ViatraQueryableModel(this, this.store.createModel(), predicates);
124 }
125
126 @Override
127 public QueryableModel createModel(long state) {
128 return new ViatraQueryableModel(this, this.store.createModel(state), predicates);
129 }
130
131 @Override
132 public synchronized Set<Long> getStates() {
133 return this.store.getStates();
134 }
135
136 @Override
137 public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
138 return this.store.getDiffCursor(from, to);
139 }
140}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
index 133c4c72..21dcaf15 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
@@ -6,34 +6,20 @@ import org.eclipse.viatra.query.runtime.api.scope.IEngineContext;
6import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; 6import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener;
7import org.eclipse.viatra.query.runtime.api.scope.QueryScope; 7import org.eclipse.viatra.query.runtime.api.scope.QueryScope;
8import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.representation.Relation;
10import tools.refinery.store.query.viatra.internal.context.RelationalEngineContext; 9import tools.refinery.store.query.viatra.internal.context.RelationalEngineContext;
11import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; 10import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener;
12import tools.refinery.store.query.view.AnyRelationView; 11import tools.refinery.store.query.view.AnyRelationView;
13import tools.refinery.store.tuple.Tuple;
14 12
15import java.util.Set; 13import java.util.Collection;
16 14
17public class RelationalScope extends QueryScope { 15public class RelationalScope extends QueryScope {
18 private final Model model; 16 private final Model model;
19 17
20 private final ModelUpdateListener updateListener; 18 private final ModelUpdateListener updateListener;
21 19
22 public RelationalScope(Model model, Set<AnyRelationView> relationViews) { 20 public RelationalScope(Model model, Collection<AnyRelationView> relationViews) {
23 this.model = model; 21 this.model = model;
24 this.updateListener = new ModelUpdateListener(relationViews); 22 updateListener = new ModelUpdateListener(model, relationViews);
25 }
26
27 public <D> void processUpdate(Relation<D> relation, Tuple key, D oldValue, D newValue) {
28 updateListener.addUpdate(relation, key, oldValue, newValue);
29 }
30
31 public boolean hasChanges() {
32 return updateListener.hasChanges();
33 }
34
35 public void flush() {
36 updateListener.flush();
37 } 23 }
38 24
39 @Override 25 @Override
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java
new file mode 100644
index 00000000..3c276935
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java
@@ -0,0 +1,117 @@
1package tools.refinery.store.query.viatra.internal;
2
3import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
4import org.eclipse.viatra.query.runtime.api.GenericQueryGroup;
5import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
6import org.eclipse.viatra.query.runtime.internal.apiimpl.ViatraQueryEngineImpl;
7import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend;
8import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.DNF;
11import tools.refinery.store.query.ModelQueryAdapter;
12import tools.refinery.store.query.ModelQueryStoreAdapter;
13import tools.refinery.store.query.ResultSet;
14
15import java.lang.invoke.MethodHandle;
16import java.lang.invoke.MethodHandles;
17import java.util.*;
18
19public class ViatraModelQueryAdapterImpl implements ModelQueryAdapter {
20 private static final String DELAY_MESSAGE_DELIVERY_FIELD_NAME = "delayMessageDelivery";
21 private static final String QUERY_BACKENDS_FIELD_NAME = "queryBackends";
22
23 private final Model model;
24 private final ViatraModelQueryStoreAdapterImpl storeAdapter;
25 private final ViatraQueryEngineImpl queryEngine;
26 private final MethodHandle setUpdatePropagationDelayedHandle;
27 private final MethodHandle getQueryBackendsHandle;
28 private final Map<DNF, ResultSet> resultSets;
29
30 ViatraModelQueryAdapterImpl(Model model, ViatraModelQueryStoreAdapterImpl storeAdapter) {
31 this.model = model;
32 this.storeAdapter = storeAdapter;
33 var scope = new RelationalScope(model, storeAdapter.getRelationViews());
34 queryEngine = (ViatraQueryEngineImpl) AdvancedViatraQueryEngine.createUnmanagedEngine(scope);
35
36 try {
37 var lookup = MethodHandles.privateLookupIn(ViatraQueryEngineImpl.class, MethodHandles.lookup());
38 setUpdatePropagationDelayedHandle = lookup.findSetter(ViatraQueryEngineImpl.class,
39 DELAY_MESSAGE_DELIVERY_FIELD_NAME, Boolean.TYPE);
40 getQueryBackendsHandle = lookup.findGetter(ViatraQueryEngineImpl.class, QUERY_BACKENDS_FIELD_NAME,
41 Map.class);
42 } catch (IllegalAccessException | NoSuchFieldException e) {
43 throw new IllegalStateException("Cannot access private members of %s"
44 .formatted(ViatraQueryEngineImpl.class.getName()), e);
45 }
46
47 var querySpecifications = storeAdapter.getQuerySpecifications();
48 GenericQueryGroup.of(
49 Collections.<IQuerySpecification<?>>unmodifiableCollection(querySpecifications.values()).stream()
50 ).prepare(queryEngine);
51 resultSets = new HashMap<>(querySpecifications.size());
52 for (var entry : querySpecifications.entrySet()) {
53 var matcher = queryEngine.getMatcher(entry.getValue());
54 resultSets.put(entry.getKey(), matcher);
55 }
56
57 setUpdatePropagationDelayed(true);
58 }
59
60 private void setUpdatePropagationDelayed(boolean value) {
61 try {
62 setUpdatePropagationDelayedHandle.invokeExact(queryEngine, value);
63 } catch (Error e) {
64 // Fatal JVM errors should not be wrapped.
65 throw e;
66 } catch (Throwable e) {
67 throw new IllegalStateException("Cannot set %s".formatted(DELAY_MESSAGE_DELIVERY_FIELD_NAME), e);
68 }
69 }
70
71 private Collection<IQueryBackend> getQueryBackends() {
72 try {
73 @SuppressWarnings("unchecked")
74 var backendMap = (Map<IQueryBackendFactory, IQueryBackend>) getQueryBackendsHandle.invokeExact(queryEngine);
75 return backendMap.values();
76 } catch (Error e) {
77 // Fatal JVM errors should not be wrapped.
78 throw e;
79 } catch (Throwable e) {
80 throw new IllegalStateException("Cannot get %s".formatted(QUERY_BACKENDS_FIELD_NAME), e);
81 }
82 }
83
84 @Override
85 public Model getModel() {
86 return model;
87 }
88
89 @Override
90 public ModelQueryStoreAdapter getStoreAdapter() {
91 return storeAdapter;
92 }
93
94 @Override
95 public ResultSet getResultSet(DNF query) {
96 var resultSet = resultSets.get(query);
97 if (resultSet == null) {
98 throw new IllegalArgumentException("No matcher for query %s in model".formatted(query.name()));
99 }
100 return resultSet;
101 }
102
103 @Override
104 public void flushChanges() {
105 if (!queryEngine.isUpdatePropagationDelayed()) {
106 throw new IllegalStateException("Trying to flush changes while changes are already being flushed");
107 }
108 setUpdatePropagationDelayed(false);
109 try {
110 for (var queryBackend : getQueryBackends()) {
111 queryBackend.flushUpdates();
112 }
113 } finally {
114 setUpdatePropagationDelayed(true);
115 }
116 }
117}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java
new file mode 100644
index 00000000..5105c9a7
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java
@@ -0,0 +1,116 @@
1package tools.refinery.store.query.viatra.internal;
2
3import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
4import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
5import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchGenericBackendFactory;
6import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory;
7import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
8import org.eclipse.viatra.query.runtime.rete.matcher.ReteBackendFactory;
9import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.model.ModelStoreBuilder;
12import tools.refinery.store.query.DNF;
13import tools.refinery.store.query.viatra.ViatraModelQueryBuilder;
14import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery;
15import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher;
16
17import java.util.Collections;
18import java.util.LinkedHashMap;
19import java.util.Map;
20import java.util.function.Function;
21
22public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder {
23 private ViatraQueryEngineOptions.Builder engineOptionsBuilder;
24 private final DNF2PQuery dnf2PQuery = new DNF2PQuery();
25 private final Map<DNF, IQuerySpecification<RawPatternMatcher>> querySpecifications = new LinkedHashMap<>();
26
27 public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) {
28 super(storeBuilder);
29 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder()
30 .withDefaultBackend(ReteBackendFactory.INSTANCE)
31 .withDefaultCachingBackend(ReteBackendFactory.INSTANCE)
32 .withDefaultSearchBackend(LocalSearchGenericBackendFactory.INSTANCE);
33 }
34
35 @Override
36 public ViatraModelQueryBuilder engineOptions(ViatraQueryEngineOptions engineOptions) {
37 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder(engineOptions);
38 return this;
39 }
40
41 @Override
42 public ViatraModelQueryBuilder defaultHint(QueryEvaluationHint queryEvaluationHint) {
43 engineOptionsBuilder.withDefaultHint(queryEvaluationHint);
44 return this;
45 }
46
47 @Override
48 public ViatraModelQueryBuilder backend(IQueryBackendFactory queryBackendFactory) {
49 engineOptionsBuilder.withDefaultBackend(queryBackendFactory);
50 return this;
51 }
52
53 @Override
54 public ViatraModelQueryBuilder cachingBackend(IQueryBackendFactory queryBackendFactory) {
55 engineOptionsBuilder.withDefaultCachingBackend(queryBackendFactory);
56 return this;
57 }
58
59 @Override
60 public ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory) {
61 engineOptionsBuilder.withDefaultSearchBackend(queryBackendFactory);
62 return this;
63 }
64
65 @Override
66 public ViatraModelQueryBuilder query(DNF query) {
67 if (querySpecifications.containsKey(query)) {
68 throw new IllegalArgumentException("%s was already added to the query engine".formatted(query.name()));
69 }
70 var pQuery = dnf2PQuery.translate(query);
71 querySpecifications.put(query, pQuery.build());
72 return this;
73 }
74
75 @Override
76 public ViatraModelQueryBuilder query(DNF query, QueryEvaluationHint queryEvaluationHint) {
77 query(query);
78 hint(query, queryEvaluationHint);
79 return this;
80 }
81
82 @Override
83 public ViatraModelQueryBuilder computeHint(Function<DNF, QueryEvaluationHint> computeHint) {
84 dnf2PQuery.setComputeHint(computeHint);
85 return this;
86 }
87
88 @Override
89 public ViatraModelQueryBuilder hint(DNF dnf, QueryEvaluationHint queryEvaluationHint) {
90 var pQuery = dnf2PQuery.getAlreadyTranslated(dnf);
91 if (pQuery == null) {
92 throw new IllegalArgumentException(
93 "Cannot specify hint for %s, because it was not added to the query engine".formatted(dnf.name()));
94 }
95 pQuery.setEvaluationHints(queryEvaluationHint);
96 return this;
97 }
98
99 @Override
100 public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) {
101 validateSymbols(store);
102 return new ViatraModelQueryStoreAdapterImpl(store, engineOptionsBuilder.build(), dnf2PQuery.getRelationViews(),
103 Collections.unmodifiableMap(querySpecifications));
104 }
105
106 private void validateSymbols(ModelStore store) {
107 var symbols = store.getSymbols();
108 for (var relationView : dnf2PQuery.getRelationViews()) {
109 var symbol = relationView.getSymbol();
110 if (!symbols.contains(symbol)) {
111 throw new IllegalArgumentException("Cannot query relation view %s: symbol %s is not in the model"
112 .formatted(relationView, symbol));
113 }
114 }
115 }
116}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java
new file mode 100644
index 00000000..d77b7f4b
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java
@@ -0,0 +1,58 @@
1package tools.refinery.store.query.viatra.internal;
2
3import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
4import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
5import tools.refinery.store.model.Model;
6import tools.refinery.store.model.ModelStore;
7import tools.refinery.store.query.DNF;
8import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter;
9import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher;
10import tools.refinery.store.query.view.AnyRelationView;
11
12import java.util.Collection;
13import java.util.Map;
14
15public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAdapter {
16 private final ModelStore store;
17 private final ViatraQueryEngineOptions engineOptions;
18 private final Collection<AnyRelationView> relationViews;
19 private final Map<DNF, IQuerySpecification<RawPatternMatcher>> querySpecifications;
20
21 ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions,
22 Collection<AnyRelationView> relationViews,
23 Map<DNF, IQuerySpecification<RawPatternMatcher>> querySpecifications) {
24 this.store = store;
25 this.engineOptions = engineOptions;
26 this.relationViews = relationViews;
27 this.querySpecifications = querySpecifications;
28 }
29
30 @Override
31 public ModelStore getStore() {
32 return store;
33 }
34
35 @Override
36 public Collection<AnyRelationView> getRelationViews() {
37 return relationViews;
38 }
39
40 @Override
41 public Collection<DNF> getQueries() {
42 return querySpecifications.keySet();
43 }
44
45 Map<DNF, IQuerySpecification<RawPatternMatcher>> getQuerySpecifications() {
46 return querySpecifications;
47 }
48
49 @Override
50 public ViatraQueryEngineOptions getEngineOptions() {
51 return engineOptions;
52 }
53
54 @Override
55 public ViatraModelQueryAdapterImpl createModelAdapter(Model model) {
56 return new ViatraModelQueryAdapterImpl(model, this);
57 }
58}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraQueryableModel.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraQueryableModel.java
deleted file mode 100644
index 5b06e266..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraQueryableModel.java
+++ /dev/null
@@ -1,222 +0,0 @@
1package tools.refinery.store.query.viatra.internal;
2
3import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
4import org.eclipse.viatra.query.runtime.api.GenericQueryGroup;
5import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
6import org.eclipse.viatra.query.runtime.api.IQueryGroup;
7import tools.refinery.store.map.Cursor;
8import tools.refinery.store.map.DiffCursor;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelDiffCursor;
11import tools.refinery.store.model.representation.AnyDataRepresentation;
12import tools.refinery.store.model.representation.DataRepresentation;
13import tools.refinery.store.model.representation.Relation;
14import tools.refinery.store.query.QueryableModel;
15import tools.refinery.store.query.QueryableModelStore;
16import tools.refinery.store.query.DNF;
17import tools.refinery.store.tuple.Tuple;
18import tools.refinery.store.tuple.TupleLike;
19
20import java.util.HashMap;
21import java.util.Map;
22import java.util.Optional;
23import java.util.Set;
24import java.util.stream.Stream;
25
26public class ViatraQueryableModel implements QueryableModel {
27 protected final QueryableModelStore store;
28
29 protected final Model model;
30
31 protected final Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates2PQuery;
32
33 protected RelationalScope scope;
34
35 protected AdvancedViatraQueryEngine engine;
36
37 protected Map<DNF, RawPatternMatcher> predicate2Matcher;
38
39 public ViatraQueryableModel(QueryableModelStore store, Model model,
40 Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates2PQuery) {
41 this.store = store;
42 this.model = model;
43 this.predicates2PQuery = predicates2PQuery;
44 initEngine();
45 }
46
47 private void initEngine() {
48 this.scope = new RelationalScope(this.model, this.store.getViews());
49 this.engine = AdvancedViatraQueryEngine.createUnmanagedEngine(this.scope);
50 this.predicate2Matcher = initMatchers(this.engine, this.predicates2PQuery);
51 }
52
53 private Map<DNF, RawPatternMatcher> initMatchers(
54 AdvancedViatraQueryEngine engine,
55 Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates2pQuery) {
56 // 1. prepare group
57 IQueryGroup queryGroup = GenericQueryGroup.of(Set.copyOf(predicates2pQuery.values()));
58 engine.prepareGroup(queryGroup, null);
59
60 // 2. then get all matchers
61 Map<DNF, RawPatternMatcher> result = new HashMap<>();
62 for (var entry : predicates2pQuery.entrySet()) {
63 var matcher = engine.getMatcher(entry.getValue());
64 result.put(entry.getKey(), matcher);
65 }
66 return result;
67 }
68
69 @Override
70 public Set<AnyDataRepresentation> getDataRepresentations() {
71 return model.getDataRepresentations();
72 }
73
74 @Override
75 public Set<DNF> getPredicates() {
76 return store.getPredicates();
77 }
78
79 @Override
80 public <K, V> V get(DataRepresentation<K, V> representation, K key) {
81 return model.get(representation, key);
82 }
83
84 @Override
85 public <K, V> Cursor<K, V> getAll(DataRepresentation<K, V> representation) {
86 return model.getAll(representation);
87 }
88
89 @SuppressWarnings("unchecked")
90 @Override
91 public <K, V> V put(DataRepresentation<K, V> representation, K key, V value) {
92 V oldValue = this.model.put(representation, key, value);
93 if (representation instanceof Relation<?> relation) {
94 this.scope.processUpdate((Relation<V>) relation, (Tuple) key, oldValue, value);
95 }
96 return oldValue;
97 }
98
99 @Override
100 public <K, V> void putAll(DataRepresentation<K, V> representation, Cursor<K, V> cursor) {
101 if (representation instanceof Relation<?>) {
102 //noinspection RedundantSuppression
103 @SuppressWarnings("unchecked")
104 Relation<V> relation = (Relation<V>) representation;
105 while (cursor.move()) {
106 Tuple key = (Tuple) cursor.getKey();
107 V newValue = cursor.getValue();
108 V oldValue = this.model.put(relation, key, newValue);
109 this.scope.processUpdate(relation, key, oldValue, newValue);
110 }
111 } else {
112 this.model.putAll(representation, cursor);
113 }
114 }
115
116 @Override
117 public long getSize(AnyDataRepresentation representation) {
118 return model.getSize(representation);
119 }
120
121 protected RawPatternMatcher getMatcher(DNF predicate) {
122 var result = this.predicate2Matcher.get(predicate);
123 if (result == null) {
124 throw new IllegalArgumentException("Model does not contain predicate %s".formatted(predicate.getName()));
125 } else
126 return result;
127 }
128
129 protected void validateParameters(DNF predicate, Tuple parameters) {
130 int predicateArity = predicate.getParameters().size();
131 int parameterArity = parameters.getSize();
132 if (parameterArity != predicateArity) {
133 throw new IllegalArgumentException(
134 "Predicate %s with %d arity called with different number of parameters (%d)"
135 .formatted(predicate.getName(), predicateArity, parameterArity));
136 }
137 }
138
139 @Override
140 public boolean hasResult(DNF predicate) {
141 return getMatcher(predicate).hasResult();
142 }
143
144 @Override
145 public boolean hasResult(DNF predicate, Tuple parameters) {
146 validateParameters(predicate, parameters);
147 return getMatcher(predicate).hasResult(parameters);
148 }
149
150 @Override
151 public Optional<TupleLike> oneResult(DNF predicate) {
152 return getMatcher(predicate).oneResult();
153 }
154
155 @Override
156 public Optional<TupleLike> oneResult(DNF predicate, Tuple parameters) {
157 validateParameters(predicate, parameters);
158 return getMatcher(predicate).oneResult(parameters);
159 }
160
161 @Override
162 public Stream<TupleLike> allResults(DNF predicate) {
163 return getMatcher(predicate).allResults();
164 }
165
166 @Override
167 public Stream<TupleLike> allResults(DNF predicate, Tuple parameters) {
168 validateParameters(predicate, parameters);
169 return getMatcher(predicate).allResults(parameters);
170 }
171
172 @Override
173 public int countResults(DNF predicate) {
174 return getMatcher(predicate).countResults();
175 }
176
177 @Override
178 public int countResults(DNF predicate, Tuple parameters) {
179 validateParameters(predicate, parameters);
180 return getMatcher(predicate).countResults(parameters);
181
182 }
183
184 @Override
185 public boolean hasChanges() {
186 return scope.hasChanges();
187 }
188
189 @Override
190 public void flushChanges() {
191 this.scope.flush();
192 }
193
194 @Override
195 public ModelDiffCursor getDiffCursor(long to) {
196 return model.getDiffCursor(to);
197 }
198
199 @Override
200 public long commit() {
201 return this.model.commit();
202 }
203
204 @Override
205 public void restore(long state) {
206 restoreWithDiffReplay(state);
207 }
208
209 private void restoreWithDiffReplay(long state) {
210 var modelDiffCursor = getDiffCursor(state);
211 for (AnyDataRepresentation anyDataRepresentation : this.getDataRepresentations()) {
212 var dataRepresentation = (DataRepresentation<?, ?>) anyDataRepresentation;
213 restoreRepresentationWithDiffReplay(modelDiffCursor, dataRepresentation);
214 }
215 }
216
217 private <K, V> void restoreRepresentationWithDiffReplay(ModelDiffCursor modelDiffCursor,
218 DataRepresentation<K, V> dataRepresentation) {
219 DiffCursor<K, V> diffCursor = modelDiffCursor.getCursor(dataRepresentation);
220 this.putAll(dataRepresentation, diffCursor);
221 }
222}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java
index ffd5f6de..e0bca9e0 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java
@@ -2,10 +2,10 @@ package tools.refinery.store.query.viatra.internal.cardinality;
2 2
3import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator; 3import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator;
4import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; 4import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
5import tools.refinery.store.model.representation.cardinality.FiniteUpperCardinality; 5import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
6import tools.refinery.store.model.representation.cardinality.UnboundedUpperCardinality; 6import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality;
7import tools.refinery.store.model.representation.cardinality.UpperCardinalities; 7import tools.refinery.store.representation.cardinality.UpperCardinalities;
8import tools.refinery.store.model.representation.cardinality.UpperCardinality; 8import tools.refinery.store.representation.cardinality.UpperCardinality;
9 9
10import java.util.stream.Stream; 10import java.util.stream.Stream;
11 11
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
index d32d49ba..4eb8898b 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
@@ -5,7 +5,7 @@ import org.eclipse.viatra.query.runtime.api.scope.IEngineContext;
5import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; 5import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext;
6 6
7import tools.refinery.store.model.Model; 7import tools.refinery.store.model.Model;
8import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; 8import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener;
9 9
10public class RelationalEngineContext implements IEngineContext { 10public class RelationalEngineContext implements IEngineContext {
11 private final IBaseIndex baseIndex = new DummyBaseIndexer(); 11 private final IBaseIndex baseIndex = new DummyBaseIndexer();
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
index eb3c6fbd..47b83634 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
@@ -39,7 +39,7 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext {
39 39
40 public void ensureValidKey(IInputKey key) { 40 public void ensureValidKey(IInputKey key) {
41 if (!(key instanceof RelationViewWrapper)) { 41 if (!(key instanceof RelationViewWrapper)) {
42 throw new IllegalArgumentException("The input key %s is not a valid input key.".formatted(key)); 42 throw new IllegalArgumentException("The input key %s is not a valid input key".formatted(key));
43 } 43 }
44 } 44 }
45} 45}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
index e01525e0..7375b240 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
@@ -8,7 +8,7 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
8import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; 8import org.eclipse.viatra.query.runtime.matchers.util.Accuracy;
9import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; 10import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper;
11import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; 11import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener;
12import tools.refinery.store.query.view.AnyRelationView; 12import tools.refinery.store.query.view.AnyRelationView;
13import tools.refinery.store.query.view.RelationView; 13import tools.refinery.store.query.view.RelationView;
14 14
@@ -48,12 +48,12 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
48 48
49 @Override 49 @Override
50 public boolean isCoalescing() { 50 public boolean isCoalescing() {
51 return true; 51 return false;
52 } 52 }
53 53
54 @Override 54 @Override
55 public boolean isIndexed(IInputKey key, IndexingService service) { 55 public boolean isIndexed(IInputKey key, IndexingService service) {
56 if (key instanceof RelationView<?> relationalKey) { 56 if (key instanceof AnyRelationView relationalKey) {
57 return this.modelUpdateListener.containsRelationView(relationalKey); 57 return this.modelUpdateListener.containsRelationView(relationalKey);
58 } else { 58 } else {
59 return false; 59 return false;
@@ -63,7 +63,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
63 @Override 63 @Override
64 public void ensureIndexed(IInputKey key, IndexingService service) { 64 public void ensureIndexed(IInputKey key, IndexingService service) {
65 if (!isIndexed(key, service)) { 65 if (!isIndexed(key, service)) {
66 throw new IllegalStateException("Engine tries to index a new key " + key); 66 throw new IllegalStateException("Engine tries to index a new key %s".formatted(key));
67 } 67 }
68 } 68 }
69 69
@@ -73,7 +73,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
73 if (modelUpdateListener.containsRelationView(relationViewKey)) { 73 if (modelUpdateListener.containsRelationView(relationViewKey)) {
74 return relationViewKey; 74 return relationViewKey;
75 } else { 75 } else {
76 throw new IllegalStateException("Query is asking for non-indexed key"); 76 throw new IllegalStateException("Query is asking for non-indexed key %s".formatted(relationViewKey));
77 } 77 }
78 } else { 78 } else {
79 throw new IllegalStateException("Query is asking for non-relational key"); 79 throw new IllegalStateException("Query is asking for non-relational key");
@@ -131,7 +131,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
131 131
132 @Override 132 @Override
133 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { 133 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
134 var relationViewKey = (RelationView<?>) checkKey(key); 134 var relationViewKey = checkKey(key);
135 this.modelUpdateListener.addListener(key, relationViewKey, seed, listener); 135 this.modelUpdateListener.addListener(key, relationViewKey, seed, listener);
136 136
137 } 137 }
@@ -168,7 +168,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
168 } 168 }
169 169
170 @Override 170 @Override
171 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException { 171 public void executeAfterTraversal(Runnable runnable) {
172 runnable.run(); 172 runnable.run();
173 } 173 }
174} 174}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java
index aa3fba6e..2b5618d2 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java
@@ -1,5 +1,6 @@
1package tools.refinery.store.query.viatra.internal.pquery; 1package tools.refinery.store.query.viatra.internal.pquery;
2 2
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
3import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; 4import org.eclipse.viatra.query.runtime.matchers.psystem.PBody;
4import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; 5import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable;
5import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; 6import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality;
@@ -20,20 +21,28 @@ import tools.refinery.store.query.atom.*;
20import tools.refinery.store.query.view.AnyRelationView; 21import tools.refinery.store.query.view.AnyRelationView;
21 22
22import java.util.*; 23import java.util.*;
24import java.util.function.Function;
23import java.util.stream.Collectors; 25import java.util.stream.Collectors;
24 26
25public class DNF2PQuery { 27public class DNF2PQuery {
26 private final Set<DNF> translating = new LinkedHashSet<>(); 28 private final Set<DNF> translating = new LinkedHashSet<>();
27 29
28 private final Map<DNF, SimplePQuery> dnf2PQueryMap = new HashMap<>(); 30 private final Map<DNF, RawPQuery> dnf2PQueryMap = new HashMap<>();
29 31
30 private final Map<AnyRelationView, RelationViewWrapper> view2WrapperMap = new HashMap<>(); 32 private final Map<AnyRelationView, RelationViewWrapper> view2WrapperMap = new LinkedHashMap<>();
31 33
32 public SimplePQuery translate(DNF dnfQuery) { 34 private Function<DNF, QueryEvaluationHint> computeHint = dnf -> new QueryEvaluationHint(null,
35 QueryEvaluationHint.BackendRequirement.UNSPECIFIED);
36
37 public void setComputeHint(Function<DNF, QueryEvaluationHint> computeHint) {
38 this.computeHint = computeHint;
39 }
40
41 public RawPQuery translate(DNF dnfQuery) {
33 if (translating.contains(dnfQuery)) { 42 if (translating.contains(dnfQuery)) {
34 var path = translating.stream().map(DNF::getName).collect(Collectors.joining(" -> ")); 43 var path = translating.stream().map(DNF::name).collect(Collectors.joining(" -> "));
35 throw new IllegalStateException("Circular reference %s -> %s detected".formatted(path, 44 throw new IllegalStateException("Circular reference %s -> %s detected".formatted(path,
36 dnfQuery.getName())); 45 dnfQuery.name()));
37 } 46 }
38 // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant 47 // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant
39 // way, which would cause a ConcurrentModificationException with computeIfAbsent. 48 // way, which would cause a ConcurrentModificationException with computeIfAbsent.
@@ -50,8 +59,17 @@ public class DNF2PQuery {
50 return pQuery; 59 return pQuery;
51 } 60 }
52 61
53 private SimplePQuery doTranslate(DNF dnfQuery) { 62 public Collection<AnyRelationView> getRelationViews() {
54 var pQuery = new SimplePQuery(dnfQuery.getUniqueName()); 63 return Collections.unmodifiableCollection(view2WrapperMap.keySet());
64 }
65
66 public RawPQuery getAlreadyTranslated(DNF dnfQuery) {
67 return dnf2PQueryMap.get(dnfQuery);
68 }
69
70 private RawPQuery doTranslate(DNF dnfQuery) {
71 var pQuery = new RawPQuery(dnfQuery.getUniqueName());
72 pQuery.setEvaluationHints(computeHint.apply(dnfQuery));
55 73
56 Map<Variable, PParameter> parameters = new HashMap<>(); 74 Map<Variable, PParameter> parameters = new HashMap<>();
57 for (Variable variable : dnfQuery.getParameters()) { 75 for (Variable variable : dnfQuery.getParameters()) {
@@ -86,7 +104,7 @@ public class DNF2PQuery {
86 translateEquivalenceAtom(equivalenceAtom, body); 104 translateEquivalenceAtom(equivalenceAtom, body);
87 } else if (constraint instanceof RelationViewAtom relationViewAtom) { 105 } else if (constraint instanceof RelationViewAtom relationViewAtom) {
88 translateRelationViewAtom(relationViewAtom, body); 106 translateRelationViewAtom(relationViewAtom, body);
89 } else if (constraint instanceof CallAtom<?> callAtom) { 107 } else if (constraint instanceof DNFCallAtom callAtom) {
90 translateCallAtom(callAtom, body); 108 translateCallAtom(callAtom, body);
91 } else if (constraint instanceof ConstantAtom constantAtom) { 109 } else if (constraint instanceof ConstantAtom constantAtom) {
92 translateConstantAtom(constantAtom, body); 110 translateConstantAtom(constantAtom, body);
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SimplePQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java
index a367cbf2..5d0b9e82 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SimplePQuery.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java
@@ -3,27 +3,24 @@ package tools.refinery.store.query.viatra.internal.pquery;
3import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; 3import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
4import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; 4import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
5import org.eclipse.viatra.query.runtime.api.scope.QueryScope; 5import org.eclipse.viatra.query.runtime.api.scope.QueryScope;
6import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
7import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; 6import org.eclipse.viatra.query.runtime.matchers.psystem.PBody;
8import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery; 7import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery;
9import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; 8import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter;
10import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; 9import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility;
11import tools.refinery.store.query.viatra.internal.RawPatternMatcher;
12import tools.refinery.store.query.viatra.internal.RelationalScope; 10import tools.refinery.store.query.viatra.internal.RelationalScope;
13 11
14import java.util.LinkedHashSet; 12import java.util.LinkedHashSet;
15import java.util.List; 13import java.util.List;
16import java.util.Set; 14import java.util.Set;
17 15
18public class SimplePQuery extends BasePQuery { 16public class RawPQuery extends BasePQuery {
19 private final String fullyQualifiedName; 17 private final String fullyQualifiedName;
20 private List<PParameter> parameters; 18 private List<PParameter> parameters;
21 private final LinkedHashSet<PBody> bodies = new LinkedHashSet<>(); 19 private final LinkedHashSet<PBody> bodies = new LinkedHashSet<>();
22 20
23 public SimplePQuery(String name) { 21 public RawPQuery(String name) {
24 super(PVisibility.PUBLIC); 22 super(PVisibility.PUBLIC);
25 fullyQualifiedName = name; 23 fullyQualifiedName = name;
26 setEvaluationHints(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.UNSPECIFIED));
27 } 24 }
28 25
29 @Override 26 @Override
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RawPatternMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java
index 2c488319..e944e873 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RawPatternMatcher.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java
@@ -1,7 +1,8 @@
1package tools.refinery.store.query.viatra.internal; 1package tools.refinery.store.query.viatra.internal.pquery;
2 2
3import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; 3import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher;
4import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; 4import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
5import tools.refinery.store.query.ResultSet;
5import tools.refinery.store.query.viatra.ViatraTupleLike; 6import tools.refinery.store.query.viatra.ViatraTupleLike;
6import tools.refinery.store.tuple.Tuple; 7import tools.refinery.store.tuple.Tuple;
7import tools.refinery.store.tuple.TupleLike; 8import tools.refinery.store.tuple.TupleLike;
@@ -9,7 +10,7 @@ import tools.refinery.store.tuple.TupleLike;
9import java.util.Optional; 10import java.util.Optional;
10import java.util.stream.Stream; 11import java.util.stream.Stream;
11 12
12public class RawPatternMatcher extends GenericPatternMatcher { 13public class RawPatternMatcher extends GenericPatternMatcher implements ResultSet {
13 protected final Object[] empty; 14 protected final Object[] empty;
14 15
15 public RawPatternMatcher(GenericQuerySpecification<? extends GenericPatternMatcher> specification) { 16 public RawPatternMatcher(GenericQuerySpecification<? extends GenericPatternMatcher> specification) {
@@ -17,34 +18,42 @@ public class RawPatternMatcher extends GenericPatternMatcher {
17 empty = new Object[specification.getParameterNames().size()]; 18 empty = new Object[specification.getParameterNames().size()];
18 } 19 }
19 20
21 @Override
20 public boolean hasResult() { 22 public boolean hasResult() {
21 return backend.hasMatch(empty); 23 return backend.hasMatch(empty);
22 } 24 }
23 25
26 @Override
24 public boolean hasResult(Tuple parameters) { 27 public boolean hasResult(Tuple parameters) {
25 return backend.hasMatch(toParametersArray(parameters)); 28 return backend.hasMatch(toParametersArray(parameters));
26 } 29 }
27 30
31 @Override
28 public Optional<TupleLike> oneResult() { 32 public Optional<TupleLike> oneResult() {
29 return backend.getOneArbitraryMatch(empty).map(ViatraTupleLike::new); 33 return backend.getOneArbitraryMatch(empty).map(ViatraTupleLike::new);
30 } 34 }
31 35
36 @Override
32 public Optional<TupleLike> oneResult(Tuple parameters) { 37 public Optional<TupleLike> oneResult(Tuple parameters) {
33 return backend.getOneArbitraryMatch(toParametersArray(parameters)).map(ViatraTupleLike::new); 38 return backend.getOneArbitraryMatch(toParametersArray(parameters)).map(ViatraTupleLike::new);
34 } 39 }
35 40
41 @Override
36 public Stream<TupleLike> allResults() { 42 public Stream<TupleLike> allResults() {
37 return backend.getAllMatches(empty).map(ViatraTupleLike::new); 43 return backend.getAllMatches(empty).map(ViatraTupleLike::new);
38 } 44 }
39 45
46 @Override
40 public Stream<TupleLike> allResults(Tuple parameters) { 47 public Stream<TupleLike> allResults(Tuple parameters) {
41 return backend.getAllMatches(toParametersArray(parameters)).map(ViatraTupleLike::new); 48 return backend.getAllMatches(toParametersArray(parameters)).map(ViatraTupleLike::new);
42 } 49 }
43 50
51 @Override
44 public int countResults() { 52 public int countResults() {
45 return backend.countMatches(empty); 53 return backend.countMatches(empty);
46 } 54 }
47 55
56 @Override
48 public int countResults(Tuple parameters) { 57 public int countResults(Tuple parameters) {
49 return backend.countMatches(toParametersArray(parameters)); 58 return backend.countMatches(toParametersArray(parameters));
50 } 59 }
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java
index e48648bf..c442add8 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java
@@ -10,7 +10,7 @@ public class RelationViewWrapper extends BaseInputKeyWrapper<AnyRelationView> {
10 10
11 @Override 11 @Override
12 public String getPrettyPrintableName() { 12 public String getPrettyPrintableName() {
13 return wrappedKey.getName(); 13 return wrappedKey.name();
14 } 14 }
15 15
16 @Override 16 @Override
@@ -20,7 +20,7 @@ public class RelationViewWrapper extends BaseInputKeyWrapper<AnyRelationView> {
20 20
21 @Override 21 @Override
22 public int getArity() { 22 public int getArity() {
23 return wrappedKey.getArity(); 23 return wrappedKey.arity();
24 } 24 }
25 25
26 @Override 26 @Override
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java
new file mode 100644
index 00000000..1ae3daa7
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java
@@ -0,0 +1,46 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import tools.refinery.store.model.Model;
7import tools.refinery.store.query.view.AnyRelationView;
8import tools.refinery.store.query.view.RelationView;
9
10import java.util.Collection;
11import java.util.HashMap;
12import java.util.Map;
13
14public class ModelUpdateListener {
15 private final Map<AnyRelationView, RelationViewUpdateListener<?>> relationViewUpdateListeners;
16
17 public ModelUpdateListener(Model model, Collection<AnyRelationView> relationViews) {
18 relationViewUpdateListeners = new HashMap<>(relationViews.size());
19 for (var relationView : relationViews) {
20 registerView(model, (RelationView<?>) relationView);
21 }
22 }
23
24 private <T> void registerView(Model model, RelationView<T> relationView) {
25 var listener = RelationViewUpdateListener.of(relationView);
26 var interpretation = model.getInterpretation(relationView.getSymbol());
27 interpretation.addListener(listener, true);
28 relationViewUpdateListeners.put(relationView, listener);
29 }
30
31 public boolean containsRelationView(AnyRelationView relationView) {
32 return relationViewUpdateListeners.containsKey(relationView);
33 }
34
35 public void addListener(IInputKey key, AnyRelationView relationView, ITuple seed,
36 IQueryRuntimeContextListener listener) {
37 var relationViewUpdateListener = relationViewUpdateListeners.get(relationView);
38 relationViewUpdateListener.addFilter(key, seed, listener);
39 }
40
41 public void removeListener(IInputKey key, AnyRelationView relationView, ITuple seed,
42 IQueryRuntimeContextListener listener) {
43 var relationViewUpdateListener = relationViewUpdateListeners.get(relationView);
44 relationViewUpdateListener.removeFilter(key, seed, listener);
45 }
46}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java
new file mode 100644
index 00000000..221f1b4a
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java
@@ -0,0 +1,66 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
7
8import java.util.Arrays;
9import java.util.Objects;
10
11public final class RelationViewFilter {
12 private final IInputKey inputKey;
13 private final Object[] seed;
14 private final IQueryRuntimeContextListener listener;
15
16 public RelationViewFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) {
17 this.inputKey = inputKey;
18 this.seed = seedToArray(seed);
19 this.listener = listener;
20 }
21
22 public void update(Tuple updateTuple, boolean isInsertion) {
23 if (isMatching(updateTuple)) {
24 listener.update(inputKey, updateTuple, isInsertion);
25 }
26 }
27
28 private boolean isMatching(ITuple tuple) {
29 if (seed == null) {
30 return true;
31 }
32 int size = seed.length;
33 for (int i = 0; i < size; i++) {
34 var filterElement = seed[i];
35 if (filterElement != null && !filterElement.equals(tuple.get(i))) {
36 return false;
37 }
38 }
39 return true;
40 }
41
42 // Use <code>null</code> instead of an empty array to speed up comparisons.
43 @SuppressWarnings("squid:S1168")
44 private static Object[] seedToArray(ITuple seed) {
45 for (var element : seed.getElements()) {
46 if (element != null) {
47 return seed.getElements();
48 }
49 }
50 return null;
51 }
52
53 @Override
54 public boolean equals(Object obj) {
55 if (obj == this) return true;
56 if (obj == null || obj.getClass() != this.getClass()) return false;
57 var that = (RelationViewFilter) obj;
58 return Objects.equals(this.inputKey, that.inputKey) && Arrays.equals(this.seed, that.seed) &&
59 Objects.equals(this.listener, that.listener);
60 }
61
62 @Override
63 public int hashCode() {
64 return Objects.hash(inputKey, Arrays.hashCode(seed), listener);
65 }
66}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java
new file mode 100644
index 00000000..e0d44e34
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java
@@ -0,0 +1,40 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
7import tools.refinery.store.model.InterpretationListener;
8import tools.refinery.store.query.view.RelationView;
9import tools.refinery.store.query.view.TuplePreservingRelationView;
10
11import java.util.ArrayList;
12import java.util.List;
13
14public abstract class RelationViewUpdateListener<T> implements InterpretationListener<T> {
15 private final List<RelationViewFilter> filters = new ArrayList<>();
16
17 public void addFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) {
18 filters.add(new RelationViewFilter(inputKey, seed, listener));
19 }
20
21 public void removeFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) {
22 filters.remove(new RelationViewFilter(inputKey, seed, listener));
23 }
24
25 protected void processUpdate(Tuple tuple, boolean isInsertion) {
26 int size = filters.size();
27 // Use a for loop instead of a for-each loop to avoid <code>Iterator</code> allocation overhead.
28 //noinspection ForLoopReplaceableByForEach
29 for (int i = 0; i < size; i++) {
30 filters.get(i).update(tuple, isInsertion);
31 }
32 }
33
34 public static <T> RelationViewUpdateListener<T> of(RelationView<T> relationView) {
35 if (relationView instanceof TuplePreservingRelationView<T> tuplePreservingRelationView) {
36 return new TuplePreservingRelationViewUpdateListener<>(tuplePreservingRelationView);
37 }
38 return new TupleChangingRelationViewUpdateListener<>(relationView);
39 }
40}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java
new file mode 100644
index 00000000..c17e826d
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java
@@ -0,0 +1,35 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
4import tools.refinery.store.query.view.RelationView;
5import tools.refinery.store.tuple.Tuple;
6
7import java.util.Arrays;
8
9public class TupleChangingRelationViewUpdateListener<T> extends RelationViewUpdateListener<T> {
10 private final RelationView<T> relationView;
11
12 TupleChangingRelationViewUpdateListener(RelationView<T> relationView) {
13 this.relationView = relationView;
14 }
15
16 @Override
17 public void put(Tuple key, T fromValue, T toValue, boolean restoring) {
18 boolean fromPresent = relationView.filter(key, fromValue);
19 boolean toPresent = relationView.filter(key, toValue);
20 if (fromPresent) {
21 if (toPresent) { // value change
22 var fromArray = relationView.forwardMap(key, fromValue);
23 var toArray = relationView.forwardMap(key, toValue);
24 if (!Arrays.equals(fromArray, toArray)) {
25 processUpdate(Tuples.flatTupleOf(fromArray), false);
26 processUpdate(Tuples.flatTupleOf(toArray), true);
27 }
28 } else { // fromValue disappears
29 processUpdate(Tuples.flatTupleOf(relationView.forwardMap(key, fromValue)), false);
30 }
31 } else if (toPresent) { // toValue disappears
32 processUpdate(Tuples.flatTupleOf(relationView.forwardMap(key, toValue)), true);
33 }
34 }
35}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java
new file mode 100644
index 00000000..9c3ef61c
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java
@@ -0,0 +1,24 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
4import tools.refinery.store.query.view.TuplePreservingRelationView;
5import tools.refinery.store.tuple.Tuple;
6
7public class TuplePreservingRelationViewUpdateListener<T> extends RelationViewUpdateListener<T> {
8 private final TuplePreservingRelationView<T> view;
9
10 TuplePreservingRelationViewUpdateListener(TuplePreservingRelationView<T> view) {
11 this.view = view;
12 }
13
14 @Override
15 public void put(Tuple key, T fromValue, T toValue, boolean restoring) {
16 boolean fromPresent = view.filter(key, fromValue);
17 boolean toPresent = view.filter(key, toValue);
18 if (fromPresent == toPresent) {
19 return;
20 }
21 var translated = Tuples.flatTupleOf(view.forwardMap(key));
22 processUpdate(translated, toPresent);
23 }
24}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java
deleted file mode 100644
index 6a1d06a9..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java
+++ /dev/null
@@ -1,112 +0,0 @@
1package tools.refinery.store.query.viatra.internal.viewupdate;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import tools.refinery.store.model.representation.AnyRelation;
7import tools.refinery.store.query.view.AnyRelationView;
8import tools.refinery.store.tuple.Tuple;
9import tools.refinery.store.model.representation.Relation;
10import tools.refinery.store.query.view.RelationView;
11
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17public class ModelUpdateListener {
18 /**
19 * Collections of Relations and their Views.
20 */
21 private final Map<AnyRelation, Set<AnyRelationView>> relation2View;
22
23 /**
24 * Collection of Views and their buffers.
25 */
26 private final Map<AnyRelationView, Set<ViewUpdateBuffer<?>>> view2Buffers;
27
28 public ModelUpdateListener(Set<AnyRelationView> relationViews) {
29 this.relation2View = new HashMap<>();
30 this.view2Buffers = new HashMap<>();
31
32 for (var relationView : relationViews) {
33 registerView(relationView);
34 }
35 }
36
37 private void registerView(AnyRelationView view) {
38 AnyRelation relation = view.getRepresentation();
39
40 // 1. register views to relations, if necessary
41 var views = relation2View.computeIfAbsent(relation, x -> new HashSet<>());
42 views.add(view);
43
44 // 2. register notifier map to views, if necessary
45 view2Buffers.computeIfAbsent(view, x -> new HashSet<>());
46 }
47
48 public boolean containsRelationView(AnyRelationView relationalKey) {
49 return view2Buffers.containsKey(relationalKey);
50 }
51
52 public <D> void addListener(IInputKey key, RelationView<D> relationView, ITuple seed,
53 IQueryRuntimeContextListener listener) {
54 if (view2Buffers.containsKey(relationView)) {
55 ViewUpdateTranslator<D> updateListener = new ViewUpdateTranslator<>(key, relationView, seed, listener);
56 ViewUpdateBuffer<D> updateBuffer = new ViewUpdateBuffer<>(updateListener);
57 view2Buffers.get(relationView).add(updateBuffer);
58 } else {
59 throw new IllegalArgumentException();
60 }
61 }
62
63 public void removeListener(IInputKey key, AnyRelationView relationView, ITuple seed,
64 IQueryRuntimeContextListener listener) {
65 if (view2Buffers.containsKey(relationView)) {
66 Set<ViewUpdateBuffer<?>> buffers = this.view2Buffers.get(relationView);
67 for (var buffer : buffers) {
68 if (buffer.getUpdateListener().equals(key, relationView, seed, listener)) {
69 // remove buffer and terminate immediately, or it will break iterator.
70 buffers.remove(buffer);
71 return;
72 }
73 }
74 } else {
75 throw new IllegalArgumentException("Relation view is not registered for updates");
76 }
77 }
78
79 public <D> void addUpdate(Relation<D> relation, Tuple key, D oldValue, D newValue) {
80 var views = this.relation2View.get(relation);
81 if (views == null) {
82 return;
83 }
84 for (var view : views) {
85 var buffers = this.view2Buffers.get(view);
86 for (var buffer : buffers) {
87 @SuppressWarnings("unchecked")
88 var typedBuffer = (ViewUpdateBuffer<D>) buffer;
89 typedBuffer.addChange(key, oldValue, newValue);
90 }
91 }
92 }
93
94 public boolean hasChanges() {
95 for (var bufferCollection : this.view2Buffers.values()) {
96 for (ViewUpdateBuffer<?> buffer : bufferCollection) {
97 if (buffer.hasChanges()) {
98 return true;
99 }
100 }
101 }
102 return false;
103 }
104
105 public void flush() {
106 for (var bufferCollection : this.view2Buffers.values()) {
107 for (ViewUpdateBuffer<?> buffer : bufferCollection) {
108 buffer.flush();
109 }
110 }
111 }
112}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java
deleted file mode 100644
index b9406018..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java
+++ /dev/null
@@ -1,32 +0,0 @@
1package tools.refinery.store.query.viatra.internal.viewupdate;
2
3import java.util.Arrays;
4import java.util.Objects;
5
6record ViewUpdate(Object[] tuple, boolean isInsertion) {
7 @Override
8 public int hashCode() {
9 final int prime = 31;
10 int result = 1;
11 result = prime * result + Arrays.deepHashCode(tuple);
12 result = prime * result + Objects.hash(isInsertion);
13 return result;
14 }
15
16 @Override
17 public boolean equals(Object obj) {
18 if (this == obj)
19 return true;
20 if (obj == null)
21 return false;
22 if (getClass() != obj.getClass())
23 return false;
24 ViewUpdate other = (ViewUpdate) obj;
25 return isInsertion == other.isInsertion && Arrays.deepEquals(tuple, other.tuple);
26 }
27
28 @Override
29 public String toString() {
30 return "ViewUpdate [" + Arrays.toString(tuple) + "insertion= " + this.isInsertion + "]";
31 }
32}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java
deleted file mode 100644
index 49f4c501..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java
+++ /dev/null
@@ -1,47 +0,0 @@
1package tools.refinery.store.query.viatra.internal.viewupdate;
2
3import tools.refinery.store.tuple.Tuple;
4
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.List;
8
9public class ViewUpdateBuffer<D> {
10 protected final ViewUpdateTranslator<D> updateListener;
11
12 protected final List<ViewUpdate> buffer = new ArrayList<>();
13
14 public ViewUpdateBuffer(ViewUpdateTranslator<D> updateListener) {
15 this.updateListener = updateListener;
16 }
17
18 public ViewUpdateTranslator<D> getUpdateListener() {
19 return updateListener;
20 }
21
22 public boolean hasChanges() {
23 return !buffer.isEmpty();
24 }
25
26 public void addChange(Tuple tuple, D oldValue, D newValue) {
27 if (oldValue != newValue) {
28 Object[] oldTuple = updateListener.isMatching(tuple, oldValue);
29 Object[] newTuple = updateListener.isMatching(tuple, newValue);
30 if (!Arrays.equals(oldTuple, newTuple)) {
31 if (oldTuple != null) {
32 buffer.add(new ViewUpdate(oldTuple, false));
33 }
34 if (newTuple != null) {
35 buffer.add(new ViewUpdate(newTuple, true));
36 }
37 }
38 }
39 }
40
41 public void flush() {
42 for (ViewUpdate viewChange : buffer) {
43 updateListener.processChange(viewChange);
44 }
45 buffer.clear();
46 }
47}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java
deleted file mode 100644
index c324c84a..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java
+++ /dev/null
@@ -1,73 +0,0 @@
1package tools.refinery.store.query.viatra.internal.viewupdate;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
7import tools.refinery.store.query.view.AnyRelationView;
8import tools.refinery.store.query.view.RelationView;
9import tools.refinery.store.tuple.Tuple;
10
11import java.util.Objects;
12
13public class ViewUpdateTranslator<D> {
14 private final IInputKey wrappedKey;
15
16 private final RelationView<D> key;
17
18 private final ITuple filter;
19
20 private final IQueryRuntimeContextListener listener;
21
22 public ViewUpdateTranslator(IInputKey wrappedKey, RelationView<D> key, ITuple filter,
23 IQueryRuntimeContextListener listener) {
24 super();
25 this.wrappedKey = wrappedKey;
26 this.key = key;
27 this.filter = filter;
28 this.listener = listener;
29 }
30
31 public boolean equals(IInputKey wrappedKey, AnyRelationView relationView, ITuple seed,
32 IQueryRuntimeContextListener listener) {
33 return this.wrappedKey == wrappedKey && key == relationView && filter.equals(seed) && this.listener == listener;
34 }
35
36 public void processChange(ViewUpdate change) {
37 listener.update(wrappedKey, Tuples.flatTupleOf(change.tuple()), change.isInsertion());
38 }
39
40 @SuppressWarnings("squid:S1168")
41 public Object[] isMatching(Tuple tuple, D value) {
42 if (!key.filter(tuple, value)) {
43 return null;
44 }
45 return isMatching(key.forwardMap(tuple, value), filter);
46 }
47
48 @SuppressWarnings("squid:S1168")
49 private Object[] isMatching(Object[] tuple, ITuple filter) {
50 for (int i = 0; i < filter.getSize(); i++) {
51 final Object filterObject = filter.get(i);
52 if (filterObject != null && !filterObject.equals(tuple[i])) {
53 return null;
54 }
55 }
56 return tuple;
57 }
58
59 @Override
60 public int hashCode() {
61 return Objects.hash(filter, key, listener);
62 }
63
64 @Override
65 public boolean equals(Object obj) {
66 if (this == obj)
67 return true;
68 if (!(obj instanceof ViewUpdateTranslator<?> other))
69 return false;
70 return Objects.equals(filter, other.filter) && Objects.equals(key, other.key)
71 && Objects.equals(listener, other.listener);
72 }
73}
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 e82e006c..72e8d7e5 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,17 +1,20 @@
1package tools.refinery.store.query.viatra; 1package tools.refinery.store.query.viatra;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.representation.Relation; 4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.model.representation.TruthValue; 5import tools.refinery.store.query.DNF;
6import tools.refinery.store.query.*; 6import tools.refinery.store.query.ModelQuery;
7import tools.refinery.store.query.Variable;
7import tools.refinery.store.query.atom.*; 8import tools.refinery.store.query.atom.*;
8import tools.refinery.store.query.view.FilteredRelationView; 9import tools.refinery.store.query.view.FilteredRelationView;
9import tools.refinery.store.query.view.KeyOnlyRelationView; 10import tools.refinery.store.query.view.KeyOnlyRelationView;
10import tools.refinery.store.query.view.RelationView; 11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.representation.TruthValue;
11import tools.refinery.store.tuple.Tuple; 13import tools.refinery.store.tuple.Tuple;
12import tools.refinery.store.tuple.TupleLike; 14import tools.refinery.store.tuple.TupleLike;
13 15
14import java.util.*; 16import java.util.HashSet;
17import java.util.Set;
15import java.util.stream.Stream; 18import java.util.stream.Stream;
16 19
17import static org.junit.jupiter.api.Assertions.assertEquals; 20import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -19,41 +22,49 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
19class QueryTest { 22class QueryTest {
20 @Test 23 @Test
21 void typeConstraintTest() { 24 void typeConstraintTest() {
22 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 25 var person = new Symbol<>("Person", 1, Boolean.class, false);
23 Relation<Boolean> asset = new Relation<>("Asset", 1, Boolean.class, false); 26 var asset = new Symbol<>("Asset", 1, Boolean.class, false);
24 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 27 var personView = new KeyOnlyRelationView<>(person);
25 28
26 var p1 = new Variable("p1"); 29 var p1 = new Variable("p1");
27 DNF predicate = DNF.builder("TypeConstraint") 30 var predicate = DNF.builder("TypeConstraint")
28 .parameters(p1) 31 .parameters(p1)
29 .clause(new RelationViewAtom(personView, p1)) 32 .clause(new RelationViewAtom(personView, p1))
30 .build(); 33 .build();
31 34
32 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, asset), Set.of(personView), 35 var store = ModelStore.builder()
33 Set.of(predicate)); 36 .symbols(person, asset)
34 QueryableModel model = store.createModel(); 37 .with(ViatraModelQuery.ADAPTER)
38 .queries(predicate)
39 .build();
40
41 var model = store.createModel();
42 var personInterpretation = model.getInterpretation(person);
43 var assetInterpretation = model.getInterpretation(asset);
44 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
45 var predicateResultSet = queryEngine.getResultSet(predicate);
35 46
36 model.put(person, Tuple.of(0), true); 47 personInterpretation.put(Tuple.of(0), true);
37 model.put(person, Tuple.of(1), true); 48 personInterpretation.put(Tuple.of(1), true);
38 model.put(asset, Tuple.of(1), true);
39 model.put(asset, Tuple.of(2), true);
40 49
41 model.flushChanges(); 50 assetInterpretation.put(Tuple.of(1), true);
42 assertEquals(2, model.countResults(predicate)); 51 assetInterpretation.put(Tuple.of(2), true);
43 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0), Tuple.of(1))); 52
53 queryEngine.flushChanges();
54 assertEquals(2, predicateResultSet.countResults());
55 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1)));
44 } 56 }
45 57
46 @Test 58 @Test
47 void relationConstraintTest() { 59 void relationConstraintTest() {
48 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 60 var person = new Symbol<>("Person", 1, Boolean.class, false);
49 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 61 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
50 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 62 var personView = new KeyOnlyRelationView<>(person);
51 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 63 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
52 TruthValue::must); 64
53 65 var p1 = new Variable("p1");
54 Variable p1 = new Variable("p1"); 66 var p2 = new Variable("p2");
55 Variable p2 = new Variable("p2"); 67 var predicate = DNF.builder("RelationConstraint")
56 DNF predicate = DNF.builder("RelationConstraint")
57 .parameters(p1, p2) 68 .parameters(p1, p2)
58 .clause( 69 .clause(
59 new RelationViewAtom(personView, p1), 70 new RelationViewAtom(personView, p1),
@@ -62,37 +73,45 @@ class QueryTest {
62 ) 73 )
63 .build(); 74 .build();
64 75
65 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 76 var store = ModelStore.builder()
66 Set.of(personView, friendMustView), Set.of(predicate)); 77 .symbols(person, friend)
67 QueryableModel model = store.createModel(); 78 .with(ViatraModelQuery.ADAPTER)
79 .queries(predicate)
80 .build();
81
82 var model = store.createModel();
83 var personInterpretation = model.getInterpretation(person);
84 var friendInterpretation = model.getInterpretation(friend);
85 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
86 var predicateResultSet = queryEngine.getResultSet(predicate);
68 87
69 assertEquals(0, model.countResults(predicate)); 88 assertEquals(0, predicateResultSet.countResults());
70 89
71 model.put(person, Tuple.of(0), true); 90 personInterpretation.put(Tuple.of(0), true);
72 model.put(person, Tuple.of(1), true); 91 personInterpretation.put(Tuple.of(1), true);
73 model.put(person, Tuple.of(2), true); 92 personInterpretation.put(Tuple.of(2), true);
74 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
75 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
76 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
77 93
78 assertEquals(0, model.countResults(predicate)); 94 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
95 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
96 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
79 97
80 model.flushChanges(); 98 assertEquals(0, predicateResultSet.countResults());
81 assertEquals(3, model.countResults(predicate)); 99
82 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); 100 queryEngine.flushChanges();
101 assertEquals(3, predicateResultSet.countResults());
102 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2)));
83 } 103 }
84 104
85 @Test 105 @Test
86 void andTest() { 106 void andTest() {
87 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 107 var person = new Symbol<>("Person", 1, Boolean.class, false);
88 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 108 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
89 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 109 var personView = new KeyOnlyRelationView<>(person);
90 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 110 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
91 TruthValue::must); 111
92 112 var p1 = new Variable("p1");
93 Variable p1 = new Variable("p1"); 113 var p2 = new Variable("p2");
94 Variable p2 = new Variable("p2"); 114 var predicate = DNF.builder("RelationConstraint")
95 DNF predicate = DNF.builder("RelationConstraint")
96 .parameters(p1, p2) 115 .parameters(p1, p2)
97 .clause( 116 .clause(
98 new RelationViewAtom(personView, p1), 117 new RelationViewAtom(personView, p1),
@@ -102,45 +121,52 @@ class QueryTest {
102 ) 121 )
103 .build(); 122 .build();
104 123
105 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 124 var store = ModelStore.builder()
106 Set.of(personView, friendMustView), Set.of(predicate)); 125 .symbols(person, friend)
107 QueryableModel model = store.createModel(); 126 .with(ViatraModelQuery.ADAPTER)
127 .queries(predicate)
128 .build();
129
130 var model = store.createModel();
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);
108 135
109 assertEquals(0, model.countResults(predicate)); 136 assertEquals(0, predicateResultSet.countResults());
110 137
111 model.put(person, Tuple.of(0), true); 138 personInterpretation.put(Tuple.of(0), true);
112 model.put(person, Tuple.of(1), true); 139 personInterpretation.put(Tuple.of(1), true);
113 model.put(person, Tuple.of(2), true); 140 personInterpretation.put(Tuple.of(2), true);
114 141
115 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); 142 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
116 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); 143 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
117 144
118 model.flushChanges(); 145 queryEngine.flushChanges();
119 assertEquals(0, model.countResults(predicate)); 146 assertEquals(0, predicateResultSet.countResults());
120 147
121 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); 148 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
122 model.flushChanges(); 149 queryEngine.flushChanges();
123 assertEquals(2, model.countResults(predicate)); 150 assertEquals(2, predicateResultSet.countResults());
124 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0))); 151 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0)));
125 152
126 model.put(friend, Tuple.of(2, 0), TruthValue.TRUE); 153 friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE);
127 model.flushChanges(); 154 queryEngine.flushChanges();
128 assertEquals(4, model.countResults(predicate)); 155 assertEquals(4, predicateResultSet.countResults());
129 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2), 156 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2),
130 Tuple.of(2, 0))); 157 Tuple.of(2, 0)));
131 } 158 }
132 159
133 @Test 160 @Test
134 void existTest() { 161 void existTest() {
135 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 162 var person = new Symbol<>("Person", 1, Boolean.class, false);
136 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 163 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
137 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 164 var personView = new KeyOnlyRelationView<>(person);
138 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 165 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
139 TruthValue::must); 166
140 167 var p1 = new Variable("p1");
141 Variable p1 = new Variable("p1"); 168 var p2 = new Variable("p2");
142 Variable p2 = new Variable("p2"); 169 var predicate = DNF.builder("RelationConstraint")
143 DNF predicate = DNF.builder("RelationConstraint")
144 .parameters(p1) 170 .parameters(p1)
145 .clause( 171 .clause(
146 new RelationViewAtom(personView, p1), 172 new RelationViewAtom(personView, p1),
@@ -149,39 +175,45 @@ class QueryTest {
149 ) 175 )
150 .build(); 176 .build();
151 177
152 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 178 var store = ModelStore.builder()
153 Set.of(personView, friendMustView), Set.of(predicate)); 179 .symbols(person, friend)
154 QueryableModel model = store.createModel(); 180 .with(ViatraModelQuery.ADAPTER)
181 .queries(predicate)
182 .build();
183
184 var model = store.createModel();
185 var personInterpretation = model.getInterpretation(person);
186 var friendInterpretation = model.getInterpretation(friend);
187 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
188 var predicateResultSet = queryEngine.getResultSet(predicate);
155 189
156 assertEquals(0, model.countResults(predicate)); 190 personInterpretation.put(Tuple.of(0), true);
191 personInterpretation.put(Tuple.of(1), true);
192 personInterpretation.put(Tuple.of(2), true);
157 193
158 model.put(person, Tuple.of(0), true); 194 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
159 model.put(person, Tuple.of(1), true); 195 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
160 model.put(person, Tuple.of(2), true); 196 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
161 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
162 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
163 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
164 197
165 assertEquals(0, model.countResults(predicate)); 198 assertEquals(0, predicateResultSet.countResults());
166 199
167 model.flushChanges(); 200 queryEngine.flushChanges();
168 assertEquals(2, model.countResults(predicate)); 201 assertEquals(2, predicateResultSet.countResults());
169 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0), Tuple.of(1))); 202 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1)));
170 } 203 }
171 204
172 @Test 205 @Test
173 void orTest() { 206 void orTest() {
174 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 207 var person = new Symbol<>("Person", 1, Boolean.class, false);
175 Relation<Boolean> animal = new Relation<>("Animal", 1, Boolean.class, false); 208 var animal = new Symbol<>("Animal", 1, Boolean.class, false);
176 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 209 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
177 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 210 var personView = new KeyOnlyRelationView<>(person);
178 RelationView<Boolean> animalView = new KeyOnlyRelationView(animal); 211 var animalView = new KeyOnlyRelationView<>(animal);
179 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 212 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
180 TruthValue::must); 213
181 214 var p1 = new Variable("p1");
182 Variable p1 = new Variable("p1"); 215 var p2 = new Variable("p2");
183 Variable p2 = new Variable("p2"); 216 var predicate = DNF.builder("Or")
184 DNF predicate = DNF.builder("Or")
185 .parameters(p1, p2) 217 .parameters(p1, p2)
186 .clause( 218 .clause(
187 new RelationViewAtom(personView, p1), 219 new RelationViewAtom(personView, p1),
@@ -195,32 +227,43 @@ class QueryTest {
195 ) 227 )
196 .build(); 228 .build();
197 229
198 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, animal, friend), 230 var store = ModelStore.builder()
199 Set.of(personView, animalView, friendMustView), Set.of(predicate)); 231 .symbols(person, animal, friend)
200 QueryableModel model = store.createModel(); 232 .with(ViatraModelQuery.ADAPTER)
201 233 .queries(predicate)
202 model.put(person, Tuple.of(0), true); 234 .build();
203 model.put(person, Tuple.of(1), true); 235
204 model.put(animal, Tuple.of(2), true); 236 var model = store.createModel();
205 model.put(animal, Tuple.of(3), true); 237 var personInterpretation = model.getInterpretation(person);
206 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); 238 var animalInterpretation = model.getInterpretation(animal);
207 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); 239 var friendInterpretation = model.getInterpretation(friend);
208 model.put(friend, Tuple.of(2, 3), TruthValue.TRUE); 240 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
209 model.put(friend, Tuple.of(3, 0), TruthValue.TRUE); 241 var predicateResultSet = queryEngine.getResultSet(predicate);
210 242
211 model.flushChanges(); 243 personInterpretation.put(Tuple.of(0), true);
212 assertEquals(2, model.countResults(predicate)); 244 personInterpretation.put(Tuple.of(1), true);
213 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(2, 3))); 245
246 animalInterpretation.put(Tuple.of(2), true);
247 animalInterpretation.put(Tuple.of(3), true);
248
249 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
250 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
251 friendInterpretation.put(Tuple.of(2, 3), TruthValue.TRUE);
252 friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE);
253
254 queryEngine.flushChanges();
255 assertEquals(2, predicateResultSet.countResults());
256 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(2, 3)));
214 } 257 }
215 258
216 @Test 259 @Test
217 void equalityTest() { 260 void equalityTest() {
218 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 261 var person = new Symbol<>("Person", 1, Boolean.class, false);
219 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 262 var personView = new KeyOnlyRelationView<>(person);
220 263
221 Variable p1 = new Variable("p1"); 264 var p1 = new Variable("p1");
222 Variable p2 = new Variable("p2"); 265 var p2 = new Variable("p2");
223 DNF predicate = DNF.builder("Equality") 266 var predicate = DNF.builder("Equality")
224 .parameters(p1, p2) 267 .parameters(p1, p2)
225 .clause( 268 .clause(
226 new RelationViewAtom(personView, p1), 269 new RelationViewAtom(personView, p1),
@@ -229,30 +272,37 @@ class QueryTest {
229 ) 272 )
230 .build(); 273 .build();
231 274
232 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person), Set.of(personView), Set.of(predicate)); 275 var store = ModelStore.builder()
233 QueryableModel model = store.createModel(); 276 .symbols(person)
277 .with(ViatraModelQuery.ADAPTER)
278 .queries(predicate)
279 .build();
280
281 var model = store.createModel();
282 var personInterpretation = model.getInterpretation(person);
283 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
284 var predicateResultSet = queryEngine.getResultSet(predicate);
234 285
235 model.put(person, Tuple.of(0), true); 286 personInterpretation.put(Tuple.of(0), true);
236 model.put(person, Tuple.of(1), true); 287 personInterpretation.put(Tuple.of(1), true);
237 model.put(person, Tuple.of(2), true); 288 personInterpretation.put(Tuple.of(2), true);
238 289
239 model.flushChanges(); 290 queryEngine.flushChanges();
240 assertEquals(3, model.countResults(predicate)); 291 assertEquals(3, predicateResultSet.countResults());
241 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2))); 292 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2)));
242 } 293 }
243 294
244 @Test 295 @Test
245 void inequalityTest() { 296 void inequalityTest() {
246 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 297 var person = new Symbol<>("Person", 1, Boolean.class, false);
247 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 298 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
248 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 299 var personView = new KeyOnlyRelationView<>(person);
249 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 300 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
250 TruthValue::must); 301
251 302 var p1 = new Variable("p1");
252 Variable p1 = new Variable("p1"); 303 var p2 = new Variable("p2");
253 Variable p2 = new Variable("p2"); 304 var p3 = new Variable("p3");
254 Variable p3 = new Variable("p3"); 305 var predicate = DNF.builder("Inequality")
255 DNF predicate = DNF.builder("Inequality")
256 .parameters(p1, p2, p3) 306 .parameters(p1, p2, p3)
257 .clause( 307 .clause(
258 new RelationViewAtom(personView, p1), 308 new RelationViewAtom(personView, p1),
@@ -263,32 +313,40 @@ class QueryTest {
263 ) 313 )
264 .build(); 314 .build();
265 315
266 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 316 var store = ModelStore.builder()
267 Set.of(personView, friendMustView), Set.of(predicate)); 317 .symbols(person, friend)
268 QueryableModel model = store.createModel(); 318 .with(ViatraModelQuery.ADAPTER)
319 .queries(predicate)
320 .build();
321
322 var model = store.createModel();
323 var personInterpretation = model.getInterpretation(person);
324 var friendInterpretation = model.getInterpretation(friend);
325 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
326 var predicateResultSet = queryEngine.getResultSet(predicate);
327
328 personInterpretation.put(Tuple.of(0), true);
329 personInterpretation.put(Tuple.of(1), true);
330 personInterpretation.put(Tuple.of(2), true);
269 331
270 model.put(person, Tuple.of(0), true); 332 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
271 model.put(person, Tuple.of(1), true); 333 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
272 model.put(person, Tuple.of(2), true);
273 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
274 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
275 334
276 model.flushChanges(); 335 queryEngine.flushChanges();
277 assertEquals(2, model.countResults(predicate)); 336 assertEquals(2, predicateResultSet.countResults());
278 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2))); 337 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2)));
279 } 338 }
280 339
281 @Test 340 @Test
282 void patternCallTest() { 341 void patternCallTest() {
283 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 342 var person = new Symbol<>("Person", 1, Boolean.class, false);
284 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 343 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
285 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 344 var personView = new KeyOnlyRelationView<>(person);
286 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 345 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
287 TruthValue::must); 346
288 347 var p1 = new Variable("p1");
289 Variable p1 = new Variable("p1"); 348 var p2 = new Variable("p2");
290 Variable p2 = new Variable("p2"); 349 var friendPredicate = DNF.builder("RelationConstraint")
291 DNF friendPredicate = DNF.builder("RelationConstraint")
292 .parameters(p1, p2) 350 .parameters(p1, p2)
293 .clause( 351 .clause(
294 new RelationViewAtom(personView, p1), 352 new RelationViewAtom(personView, p1),
@@ -297,44 +355,51 @@ class QueryTest {
297 ) 355 )
298 .build(); 356 .build();
299 357
300 Variable p3 = new Variable("p3"); 358 var p3 = new Variable("p3");
301 Variable p4 = new Variable("p4"); 359 var p4 = new Variable("p4");
302 DNF predicate = DNF.builder("PositivePatternCall") 360 var predicate = DNF.builder("PositivePatternCall")
303 .parameters(p3, p4) 361 .parameters(p3, p4)
304 .clause( 362 .clause(
305 new RelationViewAtom(personView, p3), 363 new RelationViewAtom(personView, p3),
306 new RelationViewAtom(personView, p4), 364 new RelationViewAtom(personView, p4),
307 new CallAtom<>(friendPredicate, p3, p4) 365 new DNFCallAtom(friendPredicate, p3, p4)
308 ) 366 )
309 .build(); 367 .build();
310 368
311 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 369 var store = ModelStore.builder()
312 Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); 370 .symbols(person, friend)
313 QueryableModel model = store.createModel(); 371 .with(ViatraModelQuery.ADAPTER)
372 .queries(predicate)
373 .build();
374
375 var model = store.createModel();
376 var personInterpretation = model.getInterpretation(person);
377 var friendInterpretation = model.getInterpretation(friend);
378 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
379 var predicateResultSet = queryEngine.getResultSet(predicate);
314 380
315 model.put(person, Tuple.of(0), true); 381 personInterpretation.put(Tuple.of(0), true);
316 model.put(person, Tuple.of(1), true); 382 personInterpretation.put(Tuple.of(1), true);
317 model.put(person, Tuple.of(2), true); 383 personInterpretation.put(Tuple.of(2), true);
318 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
319 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
320 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
321 384
322 model.flushChanges(); 385 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
386 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
387 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
323 388
324 assertEquals(3, model.countResults(friendPredicate)); 389 queryEngine.flushChanges();
390 assertEquals(3, predicateResultSet.countResults());
325 } 391 }
326 392
327 @Test 393 @Test
328 void negativePatternCallTest() { 394 void negativePatternCallTest() {
329 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 395 var person = new Symbol<>("Person", 1, Boolean.class, false);
330 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 396 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
331 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 397 var personView = new KeyOnlyRelationView<>(person);
332 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 398 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
333 TruthValue::must); 399
334 400 var p1 = new Variable("p1");
335 Variable p1 = new Variable("p1"); 401 var p2 = new Variable("p2");
336 Variable p2 = new Variable("p2"); 402 var friendPredicate = DNF.builder("RelationConstraint")
337 DNF friendPredicate = DNF.builder("RelationConstraint")
338 .parameters(p1, p2) 403 .parameters(p1, p2)
339 .clause( 404 .clause(
340 new RelationViewAtom(personView, p1), 405 new RelationViewAtom(personView, p1),
@@ -343,44 +408,52 @@ class QueryTest {
343 ) 408 )
344 .build(); 409 .build();
345 410
346 Variable p3 = new Variable("p3"); 411 var p3 = new Variable("p3");
347 Variable p4 = new Variable("p4"); 412 var p4 = new Variable("p4");
348 DNF predicate = DNF.builder("NegativePatternCall") 413 var predicate = DNF.builder("NegativePatternCall")
349 .parameters(p3, p4) 414 .parameters(p3, p4)
350 .clause( 415 .clause(
351 new RelationViewAtom(personView, p3), 416 new RelationViewAtom(personView, p3),
352 new RelationViewAtom(personView, p4), 417 new RelationViewAtom(personView, p4),
353 new CallAtom<>(false, friendPredicate, p3, p4) 418 new DNFCallAtom(false, friendPredicate, p3, p4)
354 ) 419 )
355 .build(); 420 .build();
356 421
357 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 422 var store = ModelStore.builder()
358 Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); 423 .symbols(person, friend)
359 QueryableModel model = store.createModel(); 424 .with(ViatraModelQuery.ADAPTER)
425 .queries(predicate)
426 .build();
427
428 var model = store.createModel();
429 var personInterpretation = model.getInterpretation(person);
430 var friendInterpretation = model.getInterpretation(friend);
431 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
432 var predicateResultSet = queryEngine.getResultSet(predicate);
433
434 personInterpretation.put(Tuple.of(0), true);
435 personInterpretation.put(Tuple.of(1), true);
436 personInterpretation.put(Tuple.of(2), true);
360 437
361 model.put(person, Tuple.of(0), true); 438 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
362 model.put(person, Tuple.of(1), true); 439 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
363 model.put(person, Tuple.of(2), true); 440 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
364 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
365 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
366 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
367 441
368 model.flushChanges(); 442 queryEngine.flushChanges();
369 assertEquals(6, model.countResults(predicate)); 443 assertEquals(6, predicateResultSet.countResults());
370 } 444 }
371 445
372 @Test 446 @Test
373 void negativeWithQuantificationTest() { 447 void negativeWithQuantificationTest() {
374 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 448 var person = new Symbol<>("Person", 1, Boolean.class, false);
375 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 449 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
376 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 450 var personView = new KeyOnlyRelationView<>(person);
377 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 451 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
378 TruthValue::must);
379 452
380 Variable p1 = new Variable("p1"); 453 var p1 = new Variable("p1");
381 Variable p2 = new Variable("p2"); 454 var p2 = new Variable("p2");
382 455
383 DNF called = DNF.builder("Called") 456 var called = DNF.builder("Called")
384 .parameters(p1, p2) 457 .parameters(p1, p2)
385 .clause( 458 .clause(
386 new RelationViewAtom(personView, p1), 459 new RelationViewAtom(personView, p1),
@@ -389,39 +462,47 @@ class QueryTest {
389 ) 462 )
390 .build(); 463 .build();
391 464
392 DNF predicate = DNF.builder("Count") 465 var predicate = DNF.builder("Count")
393 .parameters(p1) 466 .parameters(p1)
394 .clause( 467 .clause(
395 new RelationViewAtom(personView, p1), 468 new RelationViewAtom(personView, p1),
396 new CallAtom<>(false, called, p1, p2) 469 new DNFCallAtom(false, called, p1, p2)
397 ) 470 )
398 .build(); 471 .build();
399 472
400 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 473 var store = ModelStore.builder()
401 Set.of(personView, friendMustView), Set.of(called, predicate)); 474 .symbols(person, friend)
402 QueryableModel model = store.createModel(); 475 .with(ViatraModelQuery.ADAPTER)
476 .queries(predicate)
477 .build();
478
479 var model = store.createModel();
480 var personInterpretation = model.getInterpretation(person);
481 var friendInterpretation = model.getInterpretation(friend);
482 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
483 var predicateResultSet = queryEngine.getResultSet(predicate);
403 484
404 model.put(person, Tuple.of(0), true); 485 personInterpretation.put(Tuple.of(0), true);
405 model.put(person, Tuple.of(1), true); 486 personInterpretation.put(Tuple.of(1), true);
406 model.put(person, Tuple.of(2), true); 487 personInterpretation.put(Tuple.of(2), true);
407 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
408 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
409 488
410 model.flushChanges(); 489 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
411 assertEquals(2, model.countResults(predicate)); 490 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
491
492 queryEngine.flushChanges();
493 assertEquals(2, predicateResultSet.countResults());
412 } 494 }
413 495
414 @Test 496 @Test
415 void transitivePatternCallTest() { 497 void transitivePatternCallTest() {
416 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 498 var person = new Symbol<>("Person", 1, Boolean.class, false);
417 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 499 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
418 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 500 var personView = new KeyOnlyRelationView<>(person);
419 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 501 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
420 TruthValue::must); 502
421 503 var p1 = new Variable("p1");
422 Variable p1 = new Variable("p1"); 504 var p2 = new Variable("p2");
423 Variable p2 = new Variable("p2"); 505 var friendPredicate = DNF.builder("RelationConstraint")
424 DNF friendPredicate = DNF.builder("RelationConstraint")
425 .parameters(p1, p2) 506 .parameters(p1, p2)
426 .clause( 507 .clause(
427 new RelationViewAtom(personView, p1), 508 new RelationViewAtom(personView, p1),
@@ -430,29 +511,38 @@ class QueryTest {
430 ) 511 )
431 .build(); 512 .build();
432 513
433 Variable p3 = new Variable("p3"); 514 var p3 = new Variable("p3");
434 Variable p4 = new Variable("p4"); 515 var p4 = new Variable("p4");
435 DNF predicate = DNF.builder("TransitivePatternCall") 516 var predicate = DNF.builder("TransitivePatternCall")
436 .parameters(p3, p4) 517 .parameters(p3, p4)
437 .clause( 518 .clause(
438 new RelationViewAtom(personView, p3), 519 new RelationViewAtom(personView, p3),
439 new RelationViewAtom(personView, p4), 520 new RelationViewAtom(personView, p4),
440 new CallAtom<>(CallPolarity.TRANSITIVE, friendPredicate, p3, p4) 521 new DNFCallAtom(CallPolarity.TRANSITIVE, friendPredicate, p3, p4)
441 ) 522 )
442 .build(); 523 .build();
443 524
444 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 525 var store = ModelStore.builder()
445 Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); 526 .symbols(person, friend)
446 QueryableModel model = store.createModel(); 527 .with(ViatraModelQuery.ADAPTER)
528 .queries(predicate)
529 .build();
530
531 var model = store.createModel();
532 var personInterpretation = model.getInterpretation(person);
533 var friendInterpretation = model.getInterpretation(friend);
534 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
535 var predicateResultSet = queryEngine.getResultSet(predicate);
536
537 personInterpretation.put(Tuple.of(0), true);
538 personInterpretation.put(Tuple.of(1), true);
539 personInterpretation.put(Tuple.of(2), true);
447 540
448 model.put(person, Tuple.of(0), true); 541 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
449 model.put(person, Tuple.of(1), true); 542 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
450 model.put(person, Tuple.of(2), true);
451 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
452 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
453 543
454 model.flushChanges(); 544 queryEngine.flushChanges();
455 assertEquals(3, model.countResults(predicate)); 545 assertEquals(3, predicateResultSet.countResults());
456 } 546 }
457 547
458 static void compareMatchSets(Stream<TupleLike> matchSet, Set<Tuple> expected) { 548 static void compareMatchSets(Stream<TupleLike> matchSet, Set<Tuple> expected) {
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 e8fa6ed1..49087a8d 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,54 +1,59 @@
1package tools.refinery.store.query.viatra; 1package tools.refinery.store.query.viatra;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.representation.Relation; 4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.DNF; 5import tools.refinery.store.query.DNF;
6import tools.refinery.store.query.QueryableModel; 6import tools.refinery.store.query.ModelQuery;
7import tools.refinery.store.query.QueryableModelStore;
8import tools.refinery.store.query.Variable; 7import tools.refinery.store.query.Variable;
9import tools.refinery.store.query.atom.RelationViewAtom; 8import tools.refinery.store.query.atom.RelationViewAtom;
10import tools.refinery.store.query.viatra.ViatraQueryableModelStore;
11import tools.refinery.store.query.view.KeyOnlyRelationView; 9import tools.refinery.store.query.view.KeyOnlyRelationView;
12import tools.refinery.store.query.view.RelationView; 10import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.tuple.Tuple; 11import tools.refinery.store.tuple.Tuple;
14 12
15import java.util.Set;
16
17import static org.junit.jupiter.api.Assertions.assertEquals; 13import static org.junit.jupiter.api.Assertions.assertEquals;
18 14
19class QueryTransactionTest { 15class QueryTransactionTest {
20 @Test 16 @Test
21 void flushTest() { 17 void flushTest() {
22 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 18 var person = new Symbol<>("Person", 1, Boolean.class, false);
23 Relation<Boolean> asset = new Relation<>("Asset", 1, Boolean.class, false); 19 var asset = new Symbol<>("Asset", 1, Boolean.class, false);
24 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 20 var personView = new KeyOnlyRelationView<>(person);
25 21
26 var p1 = new Variable("p1"); 22 var p1 = new Variable("p1");
27 DNF predicate = DNF.builder("TypeConstraint") 23 var predicate = DNF.builder("TypeConstraint")
28 .parameters(p1) 24 .parameters(p1)
29 .clause(new RelationViewAtom(personView, p1)) 25 .clause(new RelationViewAtom(personView, p1))
30 .build(); 26 .build();
31 27
32 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, asset), Set.of(personView), 28 var store = ModelStore.builder()
33 Set.of(predicate)); 29 .symbols(person, asset)
34 QueryableModel model = store.createModel(); 30 .with(ViatraModelQuery.ADAPTER)
31 .queries(predicate)
32 .build();
33
34 var model = store.createModel();
35 var personInterpretation = model.getInterpretation(person);
36 var assetInterpretation = model.getInterpretation(asset);
37 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
38 var predicateResultSet = queryEngine.getResultSet(predicate);
39
40 assertEquals(0, predicateResultSet.countResults());
35 41
36 assertEquals(0, model.countResults(predicate)); 42 personInterpretation.put(Tuple.of(0), true);
43 personInterpretation.put(Tuple.of(1), true);
37 44
38 model.put(person, Tuple.of(0), true); 45 assetInterpretation.put(Tuple.of(1), true);
39 model.put(person, Tuple.of(1), true); 46 assetInterpretation.put(Tuple.of(2), true);
40 model.put(asset, Tuple.of(1), true);
41 model.put(asset, Tuple.of(2), true);
42 47
43 assertEquals(0, model.countResults(predicate)); 48 assertEquals(0, predicateResultSet.countResults());
44 49
45 model.flushChanges(); 50 queryEngine.flushChanges();
46 assertEquals(2, model.countResults(predicate)); 51 assertEquals(2, predicateResultSet.countResults());
47 52
48 model.put(person, Tuple.of(4), true); 53 personInterpretation.put(Tuple.of(4), true);
49 assertEquals(2, model.countResults(predicate)); 54 assertEquals(2, predicateResultSet.countResults());
50 55
51 model.flushChanges(); 56 queryEngine.flushChanges();
52 assertEquals(3, model.countResults(predicate)); 57 assertEquals(3, predicateResultSet.countResults());
53 } 58 }
54} 59}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java
index 07869050..69491fda 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java
@@ -3,8 +3,8 @@ package tools.refinery.store.query.viatra.internal.cardinality;
3import org.junit.jupiter.params.ParameterizedTest; 3import org.junit.jupiter.params.ParameterizedTest;
4import org.junit.jupiter.params.provider.Arguments; 4import org.junit.jupiter.params.provider.Arguments;
5import org.junit.jupiter.params.provider.MethodSource; 5import org.junit.jupiter.params.provider.MethodSource;
6import tools.refinery.store.model.representation.cardinality.UpperCardinalities; 6import tools.refinery.store.representation.cardinality.UpperCardinalities;
7import tools.refinery.store.model.representation.cardinality.UpperCardinality; 7import tools.refinery.store.representation.cardinality.UpperCardinality;
8 8
9import java.util.stream.Stream; 9import java.util.stream.Stream;
10 10
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java
index afc4a2f3..20dad543 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java
@@ -2,8 +2,8 @@ package tools.refinery.store.query.viatra.internal.cardinality;
2 2
3import org.junit.jupiter.api.BeforeEach; 3import org.junit.jupiter.api.BeforeEach;
4import org.junit.jupiter.api.Test; 4import org.junit.jupiter.api.Test;
5import tools.refinery.store.model.representation.cardinality.UpperCardinalities; 5import tools.refinery.store.representation.cardinality.UpperCardinalities;
6import tools.refinery.store.model.representation.cardinality.UpperCardinality; 6import tools.refinery.store.representation.cardinality.UpperCardinality;
7 7
8import static org.hamcrest.MatcherAssert.assertThat; 8import static org.hamcrest.MatcherAssert.assertThat;
9import static org.hamcrest.Matchers.equalTo; 9import static org.hamcrest.Matchers.equalTo;