aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-09-26 00:39:23 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-10-03 20:06:52 +0200
commitaac386f0d8c4e4585026b11bfeca20f378f7f261 (patch)
treecad56fc2c88a1abd56258d64b5ce3a16baaff011 /subprojects/store
parentchore: fix some warnings (diff)
downloadrefinery-aac386f0d8c4e4585026b11bfeca20f378f7f261.tar.gz
refinery-aac386f0d8c4e4585026b11bfeca20f378f7f261.tar.zst
refinery-aac386f0d8c4e4585026b11bfeca20f378f7f261.zip
refactor: move viatra into a separate subproject
Diffstat (limited to 'subprojects/store')
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/QueriableModelStoreImpl.java127
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java (renamed from subprojects/store/src/main/java/tools/refinery/store/query/QueriableModel.java)12
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java (renamed from subprojects/store/src/main/java/tools/refinery/store/query/QueriableModelStore.java)14
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/building/RelationAtom.java30
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/DNF2PQuery.java189
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/DummyBaseIndexer.java59
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java103
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/PredicateResult.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/QueriableModelImpl.java212
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/RawPatternMatcher.java57
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java33
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalQueryMetaContext.java58
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java178
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalScope.java43
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java34
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java46
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java57
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTest.java445
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTransactionTest.java58
19 files changed, 20 insertions, 1759 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/QueriableModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/query/QueriableModelStoreImpl.java
deleted file mode 100644
index 653783dd..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/QueriableModelStoreImpl.java
+++ /dev/null
@@ -1,127 +0,0 @@
1package tools.refinery.store.query;
2
3import java.util.Collections;
4import java.util.HashMap;
5import java.util.Map;
6import java.util.Set;
7
8import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
9
10import tools.refinery.store.model.ModelDiffCursor;
11import tools.refinery.store.model.ModelStore;
12import tools.refinery.store.model.ModelStoreImpl;
13import tools.refinery.store.model.representation.DataRepresentation;
14import tools.refinery.store.query.building.DNFAnd;
15import tools.refinery.store.query.building.DNFAtom;
16import tools.refinery.store.query.building.DNFPredicate;
17import tools.refinery.store.query.building.PredicateAtom;
18import tools.refinery.store.query.building.RelationAtom;
19import tools.refinery.store.query.internal.DNF2PQuery;
20import tools.refinery.store.query.internal.QueriableModelImpl;
21import tools.refinery.store.query.internal.RawPatternMatcher;
22import tools.refinery.store.query.internal.DNF2PQuery.SimplePQuery;
23import tools.refinery.store.query.view.RelationView;
24
25public class QueriableModelStoreImpl implements QueriableModelStore {
26 protected final ModelStore store;
27 protected final Set<RelationView<?>> relationViews;
28 protected final Map<DNFPredicate, GenericQuerySpecification<RawPatternMatcher>> predicates;
29
30 public QueriableModelStoreImpl(Set<DataRepresentation<?, ?>> dataRepresentations,
31 Set<RelationView<?>> relationViews, Set<DNFPredicate> predicates) {
32 this.store = new ModelStoreImpl(dataRepresentations);
33 validateViews(dataRepresentations, relationViews);
34 this.relationViews = Collections.unmodifiableSet(relationViews);
35 validatePredicates(relationViews, predicates);
36 this.predicates = initPredicates(predicates);
37 }
38
39 private void validateViews(Set<DataRepresentation<?, ?>> dataRepresentations, Set<RelationView<?>> relationViews) {
40 for (RelationView<?> relationView : relationViews) {
41 // TODO: make it work for non-relation representation?
42 if (!dataRepresentations.contains(relationView.getRepresentation())) {
43 throw new IllegalArgumentException(
44 DataRepresentation.class.getSimpleName() + " " + relationView.getStringID() + " added to "
45 + QueriableModelStore.class.getSimpleName() + " without a referred representation.");
46 }
47 }
48 }
49
50 private void validatePredicates(Set<RelationView<?>> relationViews, Set<DNFPredicate> predicates) {
51 for (DNFPredicate dnfPredicate : predicates) {
52 for (DNFAnd clause : dnfPredicate.getClauses()) {
53 for (DNFAtom atom : clause.getConstraints()) {
54 if (atom instanceof RelationAtom relationAtom) {
55 validateRelationAtom(relationViews, dnfPredicate, relationAtom);
56 } else if (atom instanceof PredicateAtom predicateAtom) {
57 validatePredicateAtom(predicates, dnfPredicate, predicateAtom);
58 }
59 }
60 }
61 }
62 }
63
64 private void validateRelationAtom(Set<RelationView<?>> relationViews, DNFPredicate dnfPredicate,
65 RelationAtom relationAtom) {
66 if (!relationViews.contains(relationAtom.getView())) {
67 throw new IllegalArgumentException(DNFPredicate.class.getSimpleName() + " "
68 + dnfPredicate.getUniqueName() + " contains reference to a view of "
69 + relationAtom.getView().getRepresentation().getName()
70 + " that is not in the model.");
71 }
72 }
73 private void validatePredicateAtom(Set<DNFPredicate> predicates, DNFPredicate dnfPredicate,
74 PredicateAtom predicateAtom) {
75 if (!predicates.contains(predicateAtom.getReferred())) {
76 throw new IllegalArgumentException(
77 DNFPredicate.class.getSimpleName() + " " + dnfPredicate.getUniqueName()
78 + " contains reference to a predicate "
79 + predicateAtom.getReferred().getName()
80 + "that is not in the model.");
81 }
82 }
83
84 private Map<DNFPredicate, GenericQuerySpecification<RawPatternMatcher>> initPredicates(Set<DNFPredicate> predicates) {
85 Map<DNFPredicate, GenericQuerySpecification<RawPatternMatcher>> result = new HashMap<>();
86 Map<DNFPredicate, SimplePQuery> dnf2PQueryMap = new HashMap<>();
87 for (DNFPredicate dnfPredicate : predicates) {
88 GenericQuerySpecification<RawPatternMatcher> query = DNF2PQuery.translate(dnfPredicate,dnf2PQueryMap).build();
89 result.put(dnfPredicate, query);
90 }
91
92 return result;
93 }
94
95 @Override
96 public Set<DataRepresentation<?, ?>> getDataRepresentations() {
97 return store.getDataRepresentations();
98 }
99 @Override
100 public Set<RelationView<?>> getViews() {
101 return this.relationViews;
102 }
103 @Override
104 public Set<DNFPredicate> getPredicates() {
105 return predicates.keySet();
106 }
107
108 @Override
109 public QueriableModel createModel() {
110 return new QueriableModelImpl(this, this.store.createModel(), predicates);
111 }
112
113 @Override
114 public QueriableModel createModel(long state) {
115 return new QueriableModelImpl(this, this.store.createModel(state), predicates);
116 }
117
118 @Override
119 public synchronized Set<Long> getStates() {
120 return this.store.getStates();
121 }
122
123 @Override
124 public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
125 return this.store.getDiffCursor(from, to);
126 }
127}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/QueriableModel.java b/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java
index f669b3ed..187abbc2 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/QueriableModel.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java
@@ -1,15 +1,17 @@
1package tools.refinery.store.query; 1package tools.refinery.store.query;
2 2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.query.building.DNFPredicate;
5
3import java.util.Optional; 6import java.util.Optional;
4import java.util.Set; 7import java.util.Set;
5import java.util.stream.Stream; 8import java.util.stream.Stream;
6 9
7import tools.refinery.store.model.Model; 10public interface QueryableModel extends Model{
8import tools.refinery.store.query.building.DNFPredicate;
9
10public interface QueriableModel extends Model{
11 Set<DNFPredicate> getPredicates(); 11 Set<DNFPredicate> getPredicates();
12 12
13 boolean hasChanges();
14
13 void flushChanges(); 15 void flushChanges();
14 16
15 boolean hasResult(DNFPredicate predicate); 17 boolean hasResult(DNFPredicate predicate);
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/QueriableModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java
index 3a5b51ff..08efe17c 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/QueriableModelStore.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java
@@ -1,23 +1,23 @@
1package tools.refinery.store.query; 1package tools.refinery.store.query;
2 2
3import java.util.Set;
4
5import tools.refinery.store.model.ModelDiffCursor; 3import tools.refinery.store.model.ModelDiffCursor;
6import tools.refinery.store.model.ModelStore; 4import tools.refinery.store.model.ModelStore;
7import tools.refinery.store.model.representation.DataRepresentation; 5import tools.refinery.store.model.representation.DataRepresentation;
8import tools.refinery.store.query.building.DNFPredicate; 6import tools.refinery.store.query.building.DNFPredicate;
9import tools.refinery.store.query.view.RelationView; 7import tools.refinery.store.query.view.RelationView;
10 8
11public interface QueriableModelStore extends ModelStore{ 9import java.util.Set;
10
11public interface QueryableModelStore extends ModelStore{
12 @SuppressWarnings("squid:S1452") 12 @SuppressWarnings("squid:S1452")
13 Set<DataRepresentation<?, ?>> getDataRepresentations(); 13 Set<DataRepresentation<?, ?>> getDataRepresentations();
14 @SuppressWarnings("squid:S1452") 14 @SuppressWarnings("squid:S1452")
15 Set<RelationView<?>> getViews(); 15 Set<RelationView<?>> getViews();
16 Set<DNFPredicate> getPredicates(); 16 Set<DNFPredicate> getPredicates();
17 17
18 QueriableModel createModel(); 18 QueryableModel createModel();
19 QueriableModel createModel(long state); 19 QueryableModel createModel(long state);
20 20
21 Set<Long> getStates(); 21 Set<Long> getStates();
22 ModelDiffCursor getDiffCursor(long from, long to); 22 ModelDiffCursor getDiffCursor(long from, long to);
23} 23}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/building/RelationAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/building/RelationAtom.java
index 1238f1d7..f66245fc 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/building/RelationAtom.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/building/RelationAtom.java
@@ -1,35 +1,17 @@
1package tools.refinery.store.query.building; 1package tools.refinery.store.query.building;
2 2
3import tools.refinery.store.query.view.RelationView;
4
5import java.util.ArrayList;
3import java.util.List; 6import java.util.List;
4import java.util.Map; 7import java.util.Map;
5import java.util.Set; 8import java.util.Set;
6 9
7import tools.refinery.store.query.view.FilteredRelationView; 10public record RelationAtom(RelationView<?> view, List<Variable> substitution) implements DNFAtom {
8import tools.refinery.store.query.view.RelationView;
9
10public class RelationAtom implements DNFAtom {
11 RelationView<?> view;
12 List<Variable> substitution;
13
14 public RelationAtom(RelationView<?> view, List<Variable> substitution) { 11 public RelationAtom(RelationView<?> view, List<Variable> substitution) {
15 this.view = view; 12 this.view = view;
16 this.substitution = substitution; 13 // Create a mutable copy of substitution so that unifyVariables can change it.
17 } 14 this.substitution = new ArrayList<>(substitution);
18
19 public RelationView<?> getView() {
20 return view;
21 }
22
23 public void setView(FilteredRelationView<?> view) {
24 this.view = view;
25 }
26
27 public List<Variable> getSubstitution() {
28 return substitution;
29 }
30
31 public void setSubstitution(List<Variable> substitution) {
32 this.substitution = substitution;
33 } 15 }
34 16
35 @Override 17 @Override
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/DNF2PQuery.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/DNF2PQuery.java
deleted file mode 100644
index bcc03fb4..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/DNF2PQuery.java
+++ /dev/null
@@ -1,189 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.InputMismatchException;
6import java.util.LinkedHashSet;
7import java.util.List;
8import java.util.Map;
9import java.util.Set;
10
11import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
12import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
13import org.eclipse.viatra.query.runtime.api.scope.QueryScope;
14import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
15import org.eclipse.viatra.query.runtime.matchers.psystem.PBody;
16import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable;
17import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality;
18import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExportedParameter;
19import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Inequality;
20import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.NegativePatternCall;
21import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure;
22import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
23import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint;
24import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery;
25import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter;
26import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility;
27import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
28
29import tools.refinery.store.query.building.DNFAnd;
30import tools.refinery.store.query.building.DNFAtom;
31import tools.refinery.store.query.building.DNFPredicate;
32import tools.refinery.store.query.building.EquivalenceAtom;
33import tools.refinery.store.query.building.PredicateAtom;
34import tools.refinery.store.query.building.RelationAtom;
35import tools.refinery.store.query.building.Variable;
36
37public class DNF2PQuery {
38
39 public static SimplePQuery translate(DNFPredicate predicate, Map<DNFPredicate, SimplePQuery> dnf2PQueryMap) {
40 SimplePQuery query = dnf2PQueryMap.get(predicate);
41 if (query != null) {
42 return query;
43 }
44 query = new DNF2PQuery().new SimplePQuery(predicate.getName());
45 Map<Variable, PParameter> parameters = new HashMap<>();
46
47 predicate.getVariables().forEach(variable -> parameters.put(variable, new PParameter(variable.getName())));
48 List<PParameter> parameterList = new ArrayList<>();
49 for(var param : predicate.getVariables()) {
50 parameterList.add(parameters.get(param));
51 }
52 query.setParameter(parameterList);
53 for (DNFAnd clause : predicate.getClauses()) {
54 PBody body = new PBody(query);
55 List<ExportedParameter> symbolicParameters = new ArrayList<>();
56 for(var param : predicate.getVariables()) {
57 PVariable pVar = body.getOrCreateVariableByName(param.getName());
58 symbolicParameters.add(new ExportedParameter(body, pVar, parameters.get(param)));
59 }
60 body.setSymbolicParameters(symbolicParameters);
61 query.addBody(body);
62 for (DNFAtom constraint : clause.getConstraints()) {
63 translateDNFAtom(constraint, body, dnf2PQueryMap);
64 }
65 }
66 dnf2PQueryMap.put(predicate, query);
67 return query;
68 }
69
70 private static void translateDNFAtom(DNFAtom constraint, PBody body, Map<DNFPredicate, SimplePQuery> dnf2PQueryMap) {
71 if (constraint instanceof EquivalenceAtom equivalence) {
72 translateEquivalenceAtom(equivalence, body);
73 }
74 if (constraint instanceof RelationAtom relation) {
75 translateRelationAtom(relation, body);
76 }
77 if (constraint instanceof PredicateAtom predicate) {
78 translatePredicateAtom(predicate, body, dnf2PQueryMap);
79 }
80 }
81
82 private static void translateEquivalenceAtom(EquivalenceAtom equivalence, PBody body) {
83 PVariable varSource = body.getOrCreateVariableByName(equivalence.getLeft().getName());
84 PVariable varTarget = body.getOrCreateVariableByName(equivalence.getRight().getName());
85 if (equivalence.isPositive())
86 new Equality(body, varSource, varTarget);
87 else
88 new Inequality(body, varSource, varTarget);
89 }
90
91 private static void translateRelationAtom(RelationAtom relation, PBody body) {
92 if (relation.getSubstitution().size() != relation.getView().getArity()) {
93 throw new IllegalArgumentException("Arity (" + relation.getView().getArity()
94 + ") does not match parameter numbers (" + relation.getSubstitution().size() + ")");
95 }
96 Object[] variables = new Object[relation.getSubstitution().size()];
97 for (int i = 0; i < relation.getSubstitution().size(); i++) {
98 variables[i] = body.getOrCreateVariableByName(relation.getSubstitution().get(i).getName());
99 }
100 new TypeConstraint(body, Tuples.flatTupleOf(variables), relation.getView());
101 }
102
103 private static void translatePredicateAtom(PredicateAtom predicate, PBody body, Map<DNFPredicate, SimplePQuery> dnf2PQueryMap) {
104 Object[] variables = new Object[predicate.getSubstitution().size()];
105 for (int i = 0; i < predicate.getSubstitution().size(); i++) {
106 variables[i] = body.getOrCreateVariableByName(predicate.getSubstitution().get(i).getName());
107 }
108 if (predicate.isPositive()) {
109 if (predicate.isTransitive()) {
110 if (predicate.getSubstitution().size() != 2) {
111 throw new IllegalArgumentException("Transitive Predicate Atoms must be binary.");
112 }
113 new BinaryTransitiveClosure(body, Tuples.flatTupleOf(variables),
114 DNF2PQuery.translate(predicate.getReferred(), dnf2PQueryMap));
115 } else {
116 new PositivePatternCall(body, Tuples.flatTupleOf(variables),
117 DNF2PQuery.translate(predicate.getReferred(), dnf2PQueryMap));
118 }
119 } else {
120 if (predicate.isTransitive()) {
121 throw new InputMismatchException("Transitive Predicate Atoms cannot be negative.");
122 } else {
123 new NegativePatternCall(body, Tuples.flatTupleOf(variables),
124 DNF2PQuery.translate(predicate.getReferred(), dnf2PQueryMap));
125 }
126 }
127 }
128
129 public class SimplePQuery extends BasePQuery {
130
131 private String fullyQualifiedName;
132 private List<PParameter> parameters;
133 private LinkedHashSet<PBody> bodies = new LinkedHashSet<>();
134
135 public SimplePQuery(String name) {
136 super(PVisibility.PUBLIC);
137 fullyQualifiedName = name;
138 }
139
140 @Override
141 public String getFullyQualifiedName() {
142 return fullyQualifiedName;
143 }
144
145 public void setParameter(List<PParameter> parameters) {
146 this.parameters = parameters;
147 }
148
149 @Override
150 public List<PParameter> getParameters() {
151 return parameters;
152 }
153
154 public void addBody(PBody body) {
155 bodies.add(body);
156 }
157
158 @Override
159 protected Set<PBody> doGetContainedBodies() {
160 setEvaluationHints(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.UNSPECIFIED));
161 return bodies;
162 }
163
164 public GenericQuerySpecification<RawPatternMatcher> build() {
165 return new GenericQuerySpecification<RawPatternMatcher>(this) {
166
167 @Override
168 public Class<? extends QueryScope> getPreferredScopeClass() {
169 return RelationalScope.class;
170 }
171
172 @Override
173 protected RawPatternMatcher instantiate(ViatraQueryEngine engine) {
174 RawPatternMatcher matcher = engine.getExistingMatcher(this);
175 if (matcher == null) {
176 matcher = engine.getMatcher(this);
177 }
178 return matcher;
179 }
180
181 @Override
182 public RawPatternMatcher instantiate() {
183 return new RawPatternMatcher(this);
184 }
185
186 };
187 }
188 }
189} \ No newline at end of file
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/DummyBaseIndexer.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/DummyBaseIndexer.java
deleted file mode 100644
index 49637071..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/DummyBaseIndexer.java
+++ /dev/null
@@ -1,59 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.lang.reflect.InvocationTargetException;
4import java.util.concurrent.Callable;
5
6import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex;
7import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener;
8import org.eclipse.viatra.query.runtime.api.scope.IInstanceObserver;
9import org.eclipse.viatra.query.runtime.api.scope.ViatraBaseIndexChangeListener;
10
11/**
12 * copied from org.eclipse.viatra.query.runtime.tabular.TabularEngineContext;
13 */
14public class DummyBaseIndexer implements IBaseIndex{
15
16 @Override
17 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
18 try {
19 return callable.call();
20 } catch (Exception e) {
21 throw new InvocationTargetException(e);
22 }
23 }
24
25 @Override
26 public void addBaseIndexChangeListener(ViatraBaseIndexChangeListener listener) {
27 // no notification support
28 }
29
30 @Override
31 public void removeBaseIndexChangeListener(ViatraBaseIndexChangeListener listener) {
32 // no notification support
33 }
34
35 @Override
36 public void resampleDerivedFeatures() {
37 throw new UnsupportedOperationException();
38 }
39
40 @Override
41 public boolean addIndexingErrorListener(IIndexingErrorListener listener) {
42 return true;
43 }
44
45 @Override
46 public boolean removeIndexingErrorListener(IIndexingErrorListener listener) {
47 return true;
48 }
49
50 @Override
51 public boolean addInstanceObserver(IInstanceObserver observer, Object observedObject) {
52 return true;
53 }
54
55 @Override
56 public boolean removeInstanceObserver(IInstanceObserver observer, Object observedObject) {
57 return true;
58 }
59}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java
deleted file mode 100644
index aa80985f..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java
+++ /dev/null
@@ -1,103 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.HashMap;
4import java.util.HashSet;
5import java.util.Map;
6import java.util.Set;
7
8import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
9import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
10
11import tools.refinery.store.model.Tuple;
12import tools.refinery.store.model.representation.Relation;
13import tools.refinery.store.query.view.RelationView;
14
15public class ModelUpdateListener {
16 /**
17 * Collections of Relations and their Views.
18 */
19 private final Map<Relation<?>, Set<RelationView<?>>> relation2View;
20 /**
21 * Collection of Views and their buffers.
22 */
23 private final Map<RelationView<?>, Set<ViewUpdateBuffer<?>>> view2Buffers;
24
25 public ModelUpdateListener(Set<RelationView<?>> relationViews) {
26 this.relation2View = new HashMap<>();
27 this.view2Buffers = new HashMap<>();
28
29 for (RelationView<?> relationView : relationViews) {
30 registerView(relationView);
31 }
32 }
33
34 private void registerView(RelationView<?> view) {
35 Relation<?> relation = view.getRepresentation();
36
37 // 1. register views to relations, if necessary
38 var views = relation2View.computeIfAbsent(relation, x->new HashSet<>());
39 views.add(view);
40
41 // 2. register notifier map to views, if necessary
42 view2Buffers.computeIfAbsent(view, x->new HashSet<>());
43 }
44
45 boolean containsRelationalView(RelationView<?> relationalKey) {
46 return view2Buffers.containsKey(relationalKey);
47 }
48
49 <D> void addListener(RelationView<D> relationView, ITuple seed, IQueryRuntimeContextListener listener) {
50 if (view2Buffers.containsKey(relationView)) {
51 ViewUpdateTranslator<D> updateListener = new ViewUpdateTranslator<>(relationView, seed, listener);
52 ViewUpdateBuffer<D> updateBuffer = new ViewUpdateBuffer<>(updateListener);
53 view2Buffers.get(relationView).add(updateBuffer);
54 } else
55 throw new IllegalArgumentException();
56 }
57
58 void removeListener(RelationView<?> relationView, ITuple seed, IQueryRuntimeContextListener listener) {
59 if (view2Buffers.containsKey(relationView)) {
60 Set<ViewUpdateBuffer<?>> buffers = this.view2Buffers.get(relationView);
61 for(var buffer : buffers) {
62 if(buffer.getUpdateListener().key == seed && buffer.getUpdateListener().listener == listener) {
63 // remove buffer and terminate immediately, or it will break iterator.
64 buffers.remove(buffer);
65 return;
66 }
67 }
68 } else
69 throw new IllegalArgumentException();
70 }
71
72 public <D> void addUpdate(Relation<D> relation, Tuple key, D oldValue, D newValue) {
73 var views = this.relation2View.get(relation);
74 if (views != null) {
75 for (var view : views) {
76 var buffers = this.view2Buffers.get(view);
77 for (var buffer : buffers) {
78 @SuppressWarnings("unchecked")
79 var typedBuffer = (ViewUpdateBuffer<D>) buffer;
80 typedBuffer.addChange(key, oldValue, newValue);
81 }
82 }
83 }
84 }
85
86 public boolean hasChange() {
87 for (var bufferCollection : this.view2Buffers.values()) {
88 for (ViewUpdateBuffer<?> buffer : bufferCollection) {
89 if (buffer.hasChange())
90 return true;
91 }
92 }
93 return false;
94 }
95
96 public void flush() {
97 for (var bufferCollection : this.view2Buffers.values()) {
98 for (ViewUpdateBuffer<?> buffer : bufferCollection) {
99 buffer.flush();
100 }
101 }
102 }
103}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/PredicateResult.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/PredicateResult.java
deleted file mode 100644
index 65d23eb6..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/PredicateResult.java
+++ /dev/null
@@ -1,24 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.Optional;
4import java.util.stream.Stream;
5
6public interface PredicateResult {
7
8 boolean hasResult();
9
10 boolean hasResult(Object[] parameters);
11
12 Optional<Object[]> oneResult();
13
14 Optional<Object[]> oneResult(Object[] parameters);
15
16 Stream<Object[]> allResults();
17
18 Stream<Object[]> allResults(Object[] parameters);
19
20 int countResults();
21
22 int countResults(Object[] parameters);
23
24} \ No newline at end of file
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/QueriableModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/QueriableModelImpl.java
deleted file mode 100644
index 0f4d609f..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/QueriableModelImpl.java
+++ /dev/null
@@ -1,212 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.HashMap;
4import java.util.Map;
5import java.util.Optional;
6import java.util.Set;
7import java.util.stream.Stream;
8
9import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
10import org.eclipse.viatra.query.runtime.api.GenericQueryGroup;
11import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
12import org.eclipse.viatra.query.runtime.api.IQueryGroup;
13
14import tools.refinery.store.map.Cursor;
15import tools.refinery.store.map.DiffCursor;
16import tools.refinery.store.model.Model;
17import tools.refinery.store.model.ModelDiffCursor;
18import tools.refinery.store.model.Tuple;
19import tools.refinery.store.model.representation.DataRepresentation;
20import tools.refinery.store.model.representation.Relation;
21import tools.refinery.store.query.QueriableModel;
22import tools.refinery.store.query.QueriableModelStore;
23import tools.refinery.store.query.building.DNFPredicate;
24
25public class QueriableModelImpl implements QueriableModel {
26 protected final QueriableModelStore store;
27 protected final Model model;
28 protected final Map<DNFPredicate, GenericQuerySpecification<RawPatternMatcher>> predicates2PQuery;
29
30 protected RelationalScope scope;
31 protected AdvancedViatraQueryEngine engine;
32 protected Map<DNFPredicate, RawPatternMatcher> predicate2Matcher;
33
34 public QueriableModelImpl(QueriableModelStore store, Model model,
35 Map<DNFPredicate, GenericQuerySpecification<RawPatternMatcher>> predicates2PQuery) {
36 this.store = store;
37 this.model = model;
38 this.predicates2PQuery = predicates2PQuery;
39 initEngine();
40 }
41
42 private void initEngine() {
43 this.scope = new RelationalScope(this.model, this.store.getViews());
44 this.engine = AdvancedViatraQueryEngine.createUnmanagedEngine(this.scope);
45 this.predicate2Matcher = initMatchers(this.engine, this.predicates2PQuery);
46 }
47
48 private Map<DNFPredicate, RawPatternMatcher> initMatchers(AdvancedViatraQueryEngine engine,
49 Map<DNFPredicate, GenericQuerySpecification<RawPatternMatcher>> predicates2pQuery) {
50 // 1. prepare group
51 IQueryGroup queryGroup = GenericQueryGroup.of(Set.copyOf(predicates2pQuery.values()));
52 engine.prepareGroup(queryGroup, null);
53
54 // 2. then get all matchers
55 Map<DNFPredicate, RawPatternMatcher> result = new HashMap<>();
56 for (var entry : predicates2pQuery.entrySet()) {
57 var matcher = engine.getMatcher(entry.getValue());
58 result.put(entry.getKey(), matcher);
59 }
60 return result;
61 }
62
63 @Override
64 public Set<DataRepresentation<?, ?>> getDataRepresentations() {
65 return model.getDataRepresentations();
66 }
67
68 @Override
69 public Set<DNFPredicate> getPredicates() {
70 return store.getPredicates();
71 }
72
73 @Override
74 public <K, V> V get(DataRepresentation<K, V> representation, K key) {
75 return model.get(representation, key);
76 }
77
78 @Override
79 public <K, V> Cursor<K, V> getAll(DataRepresentation<K, V> representation) {
80 return model.getAll(representation);
81 }
82
83 @SuppressWarnings("unchecked")
84 @Override
85 public <K, V> V put(DataRepresentation<K, V> representation, K key, V value) {
86 V oldValue = this.model.put(representation, key, value);
87 if(representation instanceof Relation<?> relation) {
88 this.scope.processUpdate((Relation<V>)relation, (Tuple)key, oldValue, value);
89 }
90 return oldValue;
91 }
92
93 @Override
94 public <K, V> void putAll(DataRepresentation<K, V> representation, Cursor<K, V> cursor) {
95 if(representation instanceof Relation<?>) {
96 @SuppressWarnings("unchecked")
97 Relation<V> relation = (Relation<V>) representation;
98 while(cursor.move()) {
99 Tuple key = (Tuple) cursor.getKey();
100 V newValue = cursor.getValue();
101 V oldValue = this.model.put(relation, key, newValue);
102 this.scope.processUpdate(relation, key, oldValue, newValue);
103 }
104 } else {
105 this.model.putAll(representation, cursor);
106 }
107 }
108
109 @Override
110 public <K, V> long getSize(DataRepresentation<K, V> representation) {
111 return model.getSize(representation);
112 }
113
114 protected PredicateResult getPredicateResult(DNFPredicate predicate) {
115 var result = this.predicate2Matcher.get(predicate);
116 if (result == null) {
117 throw new IllegalArgumentException("Model does not contain predicate " + predicate.getName() + "!");
118 } else
119 return result;
120 }
121
122 protected void validateParameters(DNFPredicate predicate, Object[] parameters) {
123 int predicateArity = predicate.getVariables().size();
124 int parameterArity = parameters.length;
125 if (parameterArity != predicateArity) {
126 throw new IllegalArgumentException("Predicate " + predicate.getName() + " with " + predicateArity
127 + " arity called with different number of parameters (" + parameterArity + ")!");
128 }
129 }
130
131 @Override
132 public boolean hasResult(DNFPredicate predicate) {
133 return getPredicateResult(predicate).hasResult();
134 }
135
136 @Override
137 public boolean hasResult(DNFPredicate predicate, Object[] parameters) {
138 validateParameters(predicate, parameters);
139 return getPredicateResult(predicate).hasResult(parameters);
140 }
141
142 @Override
143 public Optional<Object[]> oneResult(DNFPredicate predicate){
144 return getPredicateResult(predicate).oneResult();
145 }
146
147 @Override
148 public Optional<Object[]> oneResult(DNFPredicate predicate, Object[] parameters){
149 validateParameters(predicate, parameters);
150 return getPredicateResult(predicate).oneResult(parameters);
151 }
152
153 @Override
154 public Stream<Object[]> allResults(DNFPredicate predicate){
155 return getPredicateResult(predicate).allResults();
156 }
157
158 @Override
159 public Stream<Object[]> allResults(DNFPredicate predicate, Object[] parameters){
160 validateParameters(predicate, parameters);
161 return getPredicateResult(predicate).allResults(parameters);
162 }
163
164 @Override
165 public int countResults(DNFPredicate predicate){
166 return getPredicateResult(predicate).countResults();
167 }
168
169 @Override
170 public int countResults(DNFPredicate predicate, Object[] parameters){
171 validateParameters(predicate, parameters);
172 return getPredicateResult(predicate).countResults(parameters);
173
174 }
175 @Override
176 public void flushChanges() {
177 this.scope.flush();
178 }
179
180 @Override
181 public ModelDiffCursor getDiffCursor(long to) {
182 return model.getDiffCursor(to);
183 }
184
185 @Override
186 public long commit() {
187 return this.model.commit();
188 }
189
190 @Override
191 public void restore(long state) {
192 restoreWithDiffReplay(state);
193 }
194
195 public void restoreWithDiffReplay(long state) {
196 var modelDiffCursor = getDiffCursor(state);
197 for(DataRepresentation<?,?> dataRepresentation : this.getDataRepresentations()) {
198 restoreRepresentationWithDiffReplay(modelDiffCursor, dataRepresentation);
199 }
200 }
201
202 private <K,V> void restoreRepresentationWithDiffReplay(ModelDiffCursor modelDiffCursor,
203 DataRepresentation<K, V> dataRepresentation) {
204 DiffCursor<K,V> diffCursor = modelDiffCursor.getCursor(dataRepresentation);
205 this.putAll(dataRepresentation, diffCursor);
206 }
207
208 public void restoreWithReinit(long state) {
209 model.restore(state);
210 this.initEngine();
211 }
212}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RawPatternMatcher.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/RawPatternMatcher.java
deleted file mode 100644
index c6d6353c..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RawPatternMatcher.java
+++ /dev/null
@@ -1,57 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.Optional;
4import java.util.stream.Stream;
5
6import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher;
7import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
8import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
9import org.eclipse.viatra.query.runtime.matchers.tuple.AbstractTuple;
10
11public class RawPatternMatcher extends GenericPatternMatcher implements PredicateResult{
12
13 protected final Object[] empty;
14
15 public RawPatternMatcher(GenericQuerySpecification<? extends GenericPatternMatcher> specification) {
16 super(specification);
17 this.empty = new Object[specification.getParameterNames().size()];
18 }
19
20 @Override
21 public boolean hasResult() {
22 return hasResult(empty);
23 }
24 @Override
25 public boolean hasResult(Object[] parameters) {
26 return this.backend.hasMatch(parameters);
27 }
28 @Override
29 public Optional<Object[]> oneResult() {
30 return oneResult(empty);
31 }
32 @Override
33 public Optional<Object[]> oneResult(Object[] parameters) {
34 Optional<Tuple> tuple = this.backend.getOneArbitraryMatch(parameters);
35 if(tuple.isPresent()) {
36 return Optional.of(tuple.get().getElements());
37 } else {
38 return Optional.empty();
39 }
40 }
41 @Override
42 public Stream<Object[]> allResults() {
43 return allResults(empty);
44 }
45 @Override
46 public Stream<Object[]> allResults(Object[] parameters) {
47 return this.backend.getAllMatches(parameters).map(AbstractTuple::getElements);
48 }
49 @Override
50 public int countResults() {
51 return countResults(empty);
52 }
53 @Override
54 public int countResults(Object[] parameters) {
55 return backend.countMatches(parameters);
56 }
57}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java
deleted file mode 100644
index dfbd8545..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java
+++ /dev/null
@@ -1,33 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex;
4import org.eclipse.viatra.query.runtime.api.scope.IEngineContext;
5import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext;
6
7import tools.refinery.store.model.Model;
8
9public class RelationalEngineContext implements IEngineContext{
10 private final IBaseIndex baseIndex = new DummyBaseIndexer();
11 private final RelationalRuntimeContext runtimeContext;
12
13
14 public RelationalEngineContext(Model model, ModelUpdateListener updateListener) {
15 runtimeContext = new RelationalRuntimeContext(model, updateListener);
16 }
17
18 @Override
19 public IBaseIndex getBaseIndex() {
20 return this.baseIndex;
21 }
22
23 @Override
24 public void dispose() {
25 //lifecycle not controlled by engine
26 }
27
28 @Override
29 public IQueryRuntimeContext getQueryRuntimeContext() {
30 return runtimeContext;
31 }
32
33}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalQueryMetaContext.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalQueryMetaContext.java
deleted file mode 100644
index 05fb0904..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalQueryMetaContext.java
+++ /dev/null
@@ -1,58 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.Collection;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.HashSet;
7import java.util.Map;
8import java.util.Set;
9
10import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContext;
11import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
12import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication;
13
14import tools.refinery.store.query.view.RelationView;
15
16/**
17 * The meta context information for String scopes.
18 */
19public final class RelationalQueryMetaContext extends AbstractQueryMetaContext {
20
21 @Override
22 public boolean isEnumerable(IInputKey key) {
23 ensureValidKey(key);
24 return key.isEnumerable();
25 }
26
27 @Override
28 public boolean isStateless(IInputKey key) {
29 ensureValidKey(key);
30 return key instanceof RelationView<?>;
31 }
32
33 @Override
34 public Collection<InputKeyImplication> getImplications(IInputKey implyingKey) {
35 ensureValidKey(implyingKey);
36 return new HashSet<InputKeyImplication>();
37 }
38
39 @Override
40 public Map<Set<Integer>, Set<Integer>> getFunctionalDependencies(IInputKey key) {
41 ensureValidKey(key);
42 if (key instanceof RelationView) {
43 return new HashMap<Set<Integer>, Set<Integer>>();
44 } else {
45 return Collections.emptyMap();
46 }
47 }
48
49 public void ensureValidKey(IInputKey key) {
50 if (! (key instanceof RelationView<?>))
51 illegalInputKey(key);
52 }
53
54 public void illegalInputKey(IInputKey key) {
55 throw new IllegalArgumentException("The input key " + key + " is not a valid input key.");
56 }
57
58}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java
deleted file mode 100644
index a186b5dd..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java
+++ /dev/null
@@ -1,178 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import static tools.refinery.store.util.CollectionsUtil.filter;
4import static tools.refinery.store.util.CollectionsUtil.map;
5
6import java.lang.reflect.InvocationTargetException;
7import java.util.Iterator;
8import java.util.Optional;
9import java.util.concurrent.Callable;
10
11import org.eclipse.viatra.query.runtime.base.core.NavigationHelperImpl;
12import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
13import org.eclipse.viatra.query.runtime.matchers.context.IQueryMetaContext;
14import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext;
15import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
16import org.eclipse.viatra.query.runtime.matchers.context.IndexingService;
17import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
18import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
19import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask;
20import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
21import org.eclipse.viatra.query.runtime.matchers.util.Accuracy;
22
23import tools.refinery.store.model.Model;
24import tools.refinery.store.query.view.RelationView;
25
26public class RelationalRuntimeContext implements IQueryRuntimeContext {
27 private final RelationalQueryMetaContext metaContext = new RelationalQueryMetaContext();
28 private final ModelUpdateListener modelUpdateListener;
29 private final Model model;
30
31 public RelationalRuntimeContext(Model model, ModelUpdateListener relationUpdateListener) {
32 this.model = model;
33 this.modelUpdateListener = relationUpdateListener;
34 }
35
36 @Override
37 public IQueryMetaContext getMetaContext() {
38 return metaContext;
39 }
40
41 /**
42 * TODO: check {@link NavigationHelperImpl#coalesceTraversals(Callable)}
43 */
44 @Override
45 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
46 try {
47 return callable.call();
48 } catch (Exception e) {
49 throw new InvocationTargetException(e);
50 }
51 }
52
53 @Override
54 public boolean isCoalescing() {
55 return true;
56 }
57
58 @Override
59 public boolean isIndexed(IInputKey key, IndexingService service) {
60 if(key instanceof RelationView<?> relationalKey) {
61 return this.modelUpdateListener.containsRelationalView(relationalKey);
62 } else {
63 return false;
64 }
65 }
66
67 @Override
68 public void ensureIndexed(IInputKey key, IndexingService service) {
69 if(!isIndexed(key, service)) {
70 throw new IllegalStateException("Engine tries to index a new key " +key);
71 }
72 }
73 @SuppressWarnings("squid:S1452")
74 RelationView<?> checkKey(IInputKey key) {
75 if(key instanceof RelationView) {
76 RelationView<?> relationViewKey = (RelationView<?>) key;
77 if(modelUpdateListener.containsRelationalView(relationViewKey)) {
78 return relationViewKey;
79 } else {
80 throw new IllegalStateException("Query is asking for non-indexed key");
81 }
82 } else {
83 throw new IllegalStateException("Query is asking for non-relational key");
84 }
85 }
86
87 @Override
88 public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
89 RelationView<?> relationalViewKey = checkKey(key);
90 Iterable<Object[]> allObjects = relationalViewKey.getAll(model);
91 Iterable<Object[]> filteredBySeed = filter(allObjects,objectArray -> isMatching(objectArray,seedMask,seed));
92 Iterator<Object[]> iterator = filteredBySeed.iterator();
93 int result = 0;
94 while(iterator.hasNext()) {
95 iterator.next();
96 result++;
97 }
98 return result;
99 }
100
101 @Override
102 public Optional<Long> estimateCardinality(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) {
103 return Optional.empty();
104 }
105
106 @Override
107 public Iterable<Tuple> enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
108 RelationView<?> relationalViewKey = checkKey(key);
109 Iterable<Object[]> allObjects = relationalViewKey.getAll(model);
110 Iterable<Object[]> filteredBySeed = filter(allObjects,objectArray -> isMatching(objectArray,seedMask,seed));
111 return map(filteredBySeed,Tuples::flatTupleOf);
112 }
113
114 private boolean isMatching(Object[] tuple, TupleMask seedMask, ITuple seed) {
115 for(int i=0; i<seedMask.indices.length; i++) {
116 final Object seedElement = seed.get(i);
117 final Object tupleElement = tuple[seedMask.indices[i]];
118 if(!tupleElement.equals(seedElement)) {
119 return false;
120 }
121 }
122 return true;
123 }
124
125 @Override
126 public Iterable<? extends Object> enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) {
127 return enumerateTuples(key, seedMask, seed);
128 }
129
130 @Override
131 public boolean containsTuple(IInputKey key, ITuple seed) {
132 RelationView<?> relationalViewKey = checkKey(key);
133 return relationalViewKey.get(model,seed.getElements());
134 }
135
136 @Override
137 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
138 RelationView<?> relationalKey = checkKey(key);
139 this.modelUpdateListener.addListener(relationalKey, seed, listener);
140
141 }
142
143 @Override
144 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
145 RelationView<?> relationalKey = checkKey(key);
146 this.modelUpdateListener.removeListener(relationalKey, seed, listener);
147 }
148
149 @Override
150 public Object wrapElement(Object externalElement) {
151 return externalElement;
152 }
153
154 @Override
155 public Object unwrapElement(Object internalElement) {
156 return internalElement;
157 }
158
159 @Override
160 public Tuple wrapTuple(Tuple externalElements) {
161 return externalElements;
162 }
163
164 @Override
165 public Tuple unwrapTuple(Tuple internalElements) {
166 return internalElements;
167 }
168
169 @Override
170 public void ensureWildcardIndexing(IndexingService service) {
171 throw new UnsupportedOperationException();
172 }
173
174 @Override
175 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException {
176 runnable.run();
177 }
178}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalScope.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalScope.java
deleted file mode 100644
index e8d45356..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/RelationalScope.java
+++ /dev/null
@@ -1,43 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.Set;
4
5import org.apache.log4j.Logger;
6import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
7import org.eclipse.viatra.query.runtime.api.scope.IEngineContext;
8import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener;
9import org.eclipse.viatra.query.runtime.api.scope.QueryScope;
10
11import tools.refinery.store.model.Model;
12import tools.refinery.store.model.Tuple;
13import tools.refinery.store.model.representation.Relation;
14import tools.refinery.store.query.view.RelationView;
15
16public class RelationalScope extends QueryScope{
17 private final Model model;
18 private final ModelUpdateListener updateListener;
19
20 public RelationalScope(Model model, Set<RelationView<?>> relationViews) {
21 this.model = model;
22 this.updateListener = new ModelUpdateListener(relationViews);
23 //this.changeListener = new
24 }
25
26 public <D> void processUpdate(Relation<D> relation, Tuple key, D oldValue, D newValue) {
27 updateListener.addUpdate(relation, key, oldValue, newValue);
28 }
29
30 public boolean hasChange() {
31 return updateListener.hasChange();
32 }
33
34 public void flush() {
35 updateListener.flush();
36 }
37
38 @Override
39 protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener,
40 Logger logger) {
41 return new RelationalEngineContext(model, updateListener);
42 }
43}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java
deleted file mode 100644
index 7d1a4c05..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java
+++ /dev/null
@@ -1,34 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.Arrays;
4import java.util.Objects;
5
6record ViewUpdate (Object[] tuple, boolean isInsertion) {
7
8 @Override
9 public int hashCode() {
10 final int prime = 31;
11 int result = 1;
12 result = prime * result + Arrays.deepHashCode(tuple);
13 result = prime * result + Objects.hash(isInsertion);
14 return result;
15 }
16
17 @Override
18 public boolean equals(Object obj) {
19 if (this == obj)
20 return true;
21 if (obj == null)
22 return false;
23 if (getClass() != obj.getClass())
24 return false;
25 ViewUpdate other = (ViewUpdate) obj;
26 return isInsertion == other.isInsertion && Arrays.deepEquals(tuple, other.tuple);
27 }
28
29 @Override
30 public String toString() {
31 return "ViewUpdate [" + Arrays.toString(tuple) + "insertion= "+this.isInsertion+"]";
32 }
33
34}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java
deleted file mode 100644
index 6bc4c96a..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java
+++ /dev/null
@@ -1,46 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.ArrayList;
4import java.util.Arrays;
5import java.util.List;
6
7import tools.refinery.store.model.Tuple;
8
9public class ViewUpdateBuffer<D> {
10 protected final ViewUpdateTranslator<D> updateListener;
11 protected final List<ViewUpdate> buffer = new ArrayList<>();
12
13 public ViewUpdateBuffer(ViewUpdateTranslator<D> updateListener) {
14 this.updateListener = updateListener;
15 }
16
17 public ViewUpdateTranslator<D> getUpdateListener() {
18 return updateListener;
19 }
20
21 public boolean hasChange() {
22 return ! buffer.isEmpty();
23 }
24
25 public void addChange(Tuple tuple, D oldValue, D newValue) {
26 if(oldValue != newValue) {
27 Object[] oldTuple = updateListener.isMatching(tuple, oldValue);
28 Object[] newTuple = updateListener.isMatching(tuple, newValue);
29 if(!Arrays.equals(oldTuple, newTuple)) {
30 if(oldTuple != null) {
31 buffer.add(new ViewUpdate(oldTuple, false));
32 }
33 if(newTuple != null) {
34 buffer.add(new ViewUpdate(newTuple, true));
35 }
36 }
37 }
38 }
39
40 public void flush() {
41 for (ViewUpdate viewChange : buffer) {
42 updateListener.processChange(viewChange);
43 }
44 buffer.clear();
45 }
46}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java b/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java
deleted file mode 100644
index 1c210c5f..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java
+++ /dev/null
@@ -1,57 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.Objects;
4
5import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
6import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
7import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
8
9import tools.refinery.store.model.Tuple;
10import tools.refinery.store.query.view.RelationView;
11
12public class ViewUpdateTranslator<D> {
13 final RelationView<D> key;
14 final ITuple filter;
15 final IQueryRuntimeContextListener listener;
16
17 public ViewUpdateTranslator(RelationView<D> key, ITuple filter, IQueryRuntimeContextListener listener) {
18 super();
19 this.key = key;
20 this.filter = filter;
21 this.listener = listener;
22 }
23
24 public void processChange(ViewUpdate change) {
25 listener.update(key, Tuples.flatTupleOf(change.tuple()), change.isInsertion());
26 }
27
28 public Object[] isMatching(Tuple tuple, D value){
29 return isMatching(key.getWrappedKey().transform(tuple, value), filter);
30 }
31 @SuppressWarnings("squid:S1168")
32 private Object[] isMatching(Object[] tuple, ITuple filter) {
33 for(int i = 0; i<filter.getSize(); i++) {
34 final Object filterObject = filter.get(i);
35 if(filterObject != null && !filterObject.equals(tuple[i])) {
36 return null;
37 }
38 }
39 return tuple;
40 }
41
42 @Override
43 public int hashCode() {
44 return Objects.hash(filter, key, listener);
45 }
46
47 @Override
48 public boolean equals(Object obj) {
49 if (this == obj)
50 return true;
51 if (!(obj instanceof ViewUpdateTranslator))
52 return false;
53 ViewUpdateTranslator<?> other = (ViewUpdateTranslator<?>) obj;
54 return Objects.equals(filter, other.filter) && Objects.equals(key, other.key)
55 && Objects.equals(listener, other.listener);
56 }
57}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTest.java b/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTest.java
deleted file mode 100644
index 02381bcd..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTest.java
+++ /dev/null
@@ -1,445 +0,0 @@
1package tools.refinery.store.query.test;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.Collections;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Set;
11import java.util.stream.Stream;
12
13import org.junit.jupiter.api.Test;
14
15import tools.refinery.store.model.Tuple;
16import tools.refinery.store.model.representation.Relation;
17import tools.refinery.store.model.representation.TruthValue;
18import tools.refinery.store.query.QueriableModel;
19import tools.refinery.store.query.QueriableModelStore;
20import tools.refinery.store.query.QueriableModelStoreImpl;
21import tools.refinery.store.query.building.DNFAnd;
22import tools.refinery.store.query.building.DNFPredicate;
23import tools.refinery.store.query.building.EquivalenceAtom;
24import tools.refinery.store.query.building.PredicateAtom;
25import tools.refinery.store.query.building.RelationAtom;
26import tools.refinery.store.query.building.Variable;
27import tools.refinery.store.query.view.FilteredRelationView;
28import tools.refinery.store.query.view.KeyOnlyRelationView;
29import tools.refinery.store.query.view.RelationView;
30
31class QueryTest {
32
33 static void compareMatchSets(Stream<Object[]> matchSet, Set<List<Tuple>> expected) {
34 Set<List<Tuple>> translatedMatchSet = new HashSet<>();
35 var interator = matchSet.iterator();
36 while (interator.hasNext()) {
37 var element = interator.next();
38 List<Tuple> elementToTranslatedMatchSet = new ArrayList<>();
39 for (int i = 0; i < element.length; i++) {
40 elementToTranslatedMatchSet.add((Tuple) element[i]);
41 }
42 translatedMatchSet.add(elementToTranslatedMatchSet);
43 }
44
45 assertEquals(expected, translatedMatchSet);
46 }
47
48 @Test
49 void typeConstraintTest() {
50 Relation<Boolean> person = new Relation<>("Person", 1, false);
51 Relation<Boolean> asset = new Relation<>("Asset", 1, false);
52 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
53
54 List<Variable> parameters = Arrays.asList(new Variable("p1"));
55 RelationAtom personRelationAtom = new RelationAtom(persionView, parameters);
56 DNFAnd clause = new DNFAnd(Collections.emptySet(), Arrays.asList(personRelationAtom));
57 DNFPredicate predicate = new DNFPredicate("TypeConstraint", parameters, Arrays.asList(clause));
58
59 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, asset), Set.of(persionView),
60 Set.of(predicate));
61 QueriableModel model = store.createModel();
62
63 model.put(person, Tuple.of(0), true);
64 model.put(person, Tuple.of(1), true);
65 model.put(asset, Tuple.of(1), true);
66 model.put(asset, Tuple.of(2), true);
67
68 model.flushChanges();
69 assertEquals(2, model.countResults(predicate));
70 compareMatchSets(model.allResults(predicate), Set.of(List.of(Tuple.of(0)), List.of(Tuple.of(1))));
71 }
72
73 @Test
74 void relationConstraintTest() {
75 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
76 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
77 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
78 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
79
80 Variable p1 = new Variable("p1");
81 Variable p2 = new Variable("p2");
82 List<Variable> parameters = Arrays.asList(p1, p2);
83
84 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
85 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
86 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
87 DNFAnd clause = new DNFAnd(Collections.emptySet(),
88 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
89 DNFPredicate predicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
90
91 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
92 Set.of(persionView, friendMustView), Set.of(predicate));
93 QueriableModel model = store.createModel();
94
95 assertEquals(0, model.countResults(predicate));
96
97 model.put(person, Tuple.of(0), true);
98 model.put(person, Tuple.of(1), true);
99 model.put(person, Tuple.of(2), true);
100 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
101 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
102 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
103
104 assertEquals(0, model.countResults(predicate));
105
106 model.flushChanges();
107 assertEquals(3, model.countResults(predicate));
108 compareMatchSets(model.allResults(predicate), Set.of(List.of(Tuple.of(0), Tuple.of(1)),
109 List.of(Tuple.of(1), Tuple.of(0)), List.of(Tuple.of(1), Tuple.of(2))));
110 }
111
112 @Test
113 void andTest() {
114 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
115 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
116 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
117 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
118
119 Variable p1 = new Variable("p1");
120 Variable p2 = new Variable("p2");
121 List<Variable> parameters = Arrays.asList(p1, p2);
122
123 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
124 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
125 RelationAtom friendRelationAtom1 = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
126 RelationAtom friendRelationAtom2 = new RelationAtom(friendMustView, Arrays.asList(p2, p1));
127 DNFAnd clause = new DNFAnd(Collections.emptySet(),
128 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom1, friendRelationAtom2));
129 DNFPredicate predicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
130
131 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
132 Set.of(persionView, friendMustView), Set.of(predicate));
133 QueriableModel model = store.createModel();
134
135 assertEquals(0, model.countResults(predicate));
136
137 model.put(person, Tuple.of(0), true);
138 model.put(person, Tuple.of(1), true);
139 model.put(person, Tuple.of(2), true);
140
141 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
142 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
143
144 model.flushChanges();
145 assertEquals(0, model.countResults(predicate));
146
147 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
148 model.flushChanges();
149 assertEquals(2, model.countResults(predicate));
150 compareMatchSets(model.allResults(predicate),
151 Set.of(List.of(Tuple.of(0), Tuple.of(1)), List.of(Tuple.of(1), Tuple.of(0))));
152
153 model.put(friend, Tuple.of(2, 0), TruthValue.TRUE);
154 model.flushChanges();
155 assertEquals(4, model.countResults(predicate));
156 compareMatchSets(model.allResults(predicate),
157 Set.of(List.of(Tuple.of(0), Tuple.of(1)), List.of(Tuple.of(1), Tuple.of(0)),
158 List.of(Tuple.of(0), Tuple.of(2)), List.of(Tuple.of(2), Tuple.of(0))));
159 }
160
161 @Test
162 void existTest() {
163 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
164 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
165 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
166 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
167
168 Variable p1 = new Variable("p1");
169 Variable p2 = new Variable("p2");
170 List<Variable> parameters = Arrays.asList(p1);
171
172 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
173 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
174 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
175 DNFAnd clause = new DNFAnd(Set.of(p2),
176 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
177 DNFPredicate predicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
178
179 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
180 Set.of(persionView, friendMustView), Set.of(predicate));
181 QueriableModel model = store.createModel();
182
183 assertEquals(0, model.countResults(predicate));
184
185 model.put(person, Tuple.of(0), true);
186 model.put(person, Tuple.of(1), true);
187 model.put(person, Tuple.of(2), true);
188 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
189 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
190 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
191
192 assertEquals(0, model.countResults(predicate));
193
194 model.flushChanges();
195 assertEquals(2, model.countResults(predicate));
196 compareMatchSets(model.allResults(predicate), Set.of(List.of(Tuple.of(0)), List.of(Tuple.of(1))));
197 }
198
199 @Test
200 void orTest() {
201 Relation<Boolean> person = new Relation<>("Person", 1, false);
202 Relation<Boolean> animal = new Relation<>("Animal", 1, false);
203 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
204 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
205 RelationView<Boolean> animalView = new KeyOnlyRelationView(animal);
206 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
207
208 Variable p1 = new Variable("p1");
209 Variable p2 = new Variable("p2");
210 List<Variable> parameters = Arrays.asList(p1, p2);
211
212 // Person-Person friendship
213 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
214 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
215 RelationAtom friendRelationAtom1 = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
216 DNFAnd clause1 = new DNFAnd(Collections.emptySet(),
217 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom1));
218
219 // Animal-Animal friendship
220 RelationAtom animalRelationAtom1 = new RelationAtom(animalView, Arrays.asList(p1));
221 RelationAtom animalRelationAtom2 = new RelationAtom(animalView, Arrays.asList(p2));
222 RelationAtom friendRelationAtom2 = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
223 DNFAnd clause2 = new DNFAnd(Collections.emptySet(),
224 Arrays.asList(animalRelationAtom1, animalRelationAtom2, friendRelationAtom2));
225
226 // No inter-species friendship
227
228 DNFPredicate predicate = new DNFPredicate("Or", parameters, Arrays.asList(clause1, clause2));
229
230 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, animal, friend),
231 Set.of(persionView, animalView, friendMustView), Set.of(predicate));
232 QueriableModel model = store.createModel();
233
234 model.put(person, Tuple.of(0), true);
235 model.put(person, Tuple.of(1), true);
236 model.put(animal, Tuple.of(2), true);
237 model.put(animal, Tuple.of(3), true);
238 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
239 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
240 model.put(friend, Tuple.of(2, 3), TruthValue.TRUE);
241 model.put(friend, Tuple.of(3, 0), TruthValue.TRUE);
242
243 model.flushChanges();
244 assertEquals(2, model.countResults(predicate));
245 compareMatchSets(model.allResults(predicate),
246 Set.of(List.of(Tuple.of(0), Tuple.of(1)), List.of(Tuple.of(2), Tuple.of(3))));
247 }
248
249 @Test
250 void equalityTest() {
251 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
252 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
253
254 Variable p1 = new Variable("p1");
255 Variable p2 = new Variable("p2");
256 List<Variable> parameters = Arrays.asList(p1, p2);
257
258 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
259 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
260 EquivalenceAtom equivalenceAtom = new EquivalenceAtom(true, p1, p2);
261 DNFAnd clause = new DNFAnd(Collections.emptySet(),
262 Arrays.asList(personRelationAtom1, personRelationAtom2, equivalenceAtom));
263 DNFPredicate predicate = new DNFPredicate("Equality", parameters, Arrays.asList(clause));
264
265 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person), Set.of(persionView), Set.of(predicate));
266 QueriableModel model = store.createModel();
267
268 model.put(person, Tuple.of(0), true);
269 model.put(person, Tuple.of(1), true);
270 model.put(person, Tuple.of(2), true);
271
272 model.flushChanges();
273 assertEquals(3, model.countResults(predicate));
274 compareMatchSets(model.allResults(predicate), Set.of(List.of(Tuple.of(0), Tuple.of(0)),
275 List.of(Tuple.of(1), Tuple.of(1)), List.of(Tuple.of(2), Tuple.of(2))));
276 }
277
278 @Test
279 void inequalityTest() {
280 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
281 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
282 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
283 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
284
285 Variable p1 = new Variable("p1");
286 Variable p2 = new Variable("p2");
287 Variable p3 = new Variable("p3");
288 List<Variable> parameters = Arrays.asList(p1, p2, p3);
289
290 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
291 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
292 RelationAtom friendRelationAtom1 = new RelationAtom(friendMustView, Arrays.asList(p1, p3));
293 RelationAtom friendRelationAtom2 = new RelationAtom(friendMustView, Arrays.asList(p2, p3));
294 EquivalenceAtom inequivalenceAtom = new EquivalenceAtom(false, p1, p2);
295 DNFAnd clause = new DNFAnd(Collections.emptySet(), Arrays.asList(personRelationAtom1, personRelationAtom2,
296 friendRelationAtom1, friendRelationAtom2, inequivalenceAtom));
297 DNFPredicate predicate = new DNFPredicate("Inequality", parameters, Arrays.asList(clause));
298
299 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
300 Set.of(persionView, friendMustView), Set.of(predicate));
301 QueriableModel model = store.createModel();
302
303 model.put(person, Tuple.of(0), true);
304 model.put(person, Tuple.of(1), true);
305 model.put(person, Tuple.of(2), true);
306 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
307 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
308
309 model.flushChanges();
310 assertEquals(2, model.countResults(predicate));
311 compareMatchSets(model.allResults(predicate),
312 Set.of(List.of(Tuple.of(0), Tuple.of(1), Tuple.of(2)), List.of(Tuple.of(1), Tuple.of(0), Tuple.of(2))));
313 }
314
315 @Test
316 void patternCallTest() {
317 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
318 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
319 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
320 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
321
322 Variable p1 = new Variable("p1");
323 Variable p2 = new Variable("p2");
324 List<Variable> parameters = Arrays.asList(p1, p2);
325
326 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
327 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
328 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
329 DNFAnd clause = new DNFAnd(Collections.emptySet(),
330 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
331 DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
332
333 Variable p3 = new Variable("p3");
334 Variable p4 = new Variable("p4");
335 List<Variable> substitution = Arrays.asList(p3, p4);
336 RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3));
337 RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4));
338 PredicateAtom friendPredicateAtom = new PredicateAtom(true, false, friendPredicate, substitution);
339 DNFAnd patternCallClause = new DNFAnd(Collections.emptySet(),
340 Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom));
341 DNFPredicate predicate = new DNFPredicate("PatternCall", substitution, Arrays.asList(patternCallClause));
342
343 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
344 Set.of(persionView, friendMustView), Set.of(friendPredicate, predicate));
345 QueriableModel model = store.createModel();
346
347 model.put(person, Tuple.of(0), true);
348 model.put(person, Tuple.of(1), true);
349 model.put(person, Tuple.of(2), true);
350 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
351 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
352 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
353
354 model.flushChanges();
355
356 assertEquals(3, model.countResults(friendPredicate));
357 }
358
359 @Test
360 void negativePatternCallTest() {
361 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
362 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
363 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
364 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
365
366 Variable p1 = new Variable("p1");
367 Variable p2 = new Variable("p2");
368 List<Variable> parameters = Arrays.asList(p1, p2);
369
370 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
371 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
372 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
373 DNFAnd clause = new DNFAnd(Collections.emptySet(),
374 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
375 DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
376
377 Variable p3 = new Variable("p3");
378 Variable p4 = new Variable("p4");
379 List<Variable> substitution = Arrays.asList(p3, p4);
380 RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3));
381 RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4));
382 PredicateAtom friendPredicateAtom = new PredicateAtom(false, false, friendPredicate, substitution);
383 DNFAnd negativePatternCallClause = new DNFAnd(Collections.emptySet(),
384 Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom));
385 DNFPredicate predicate = new DNFPredicate("NegativePatternCall", substitution,
386 Arrays.asList(negativePatternCallClause));
387
388 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
389 Set.of(persionView, friendMustView), Set.of(friendPredicate, predicate));
390 QueriableModel model = store.createModel();
391
392 model.put(person, Tuple.of(0), true);
393 model.put(person, Tuple.of(1), true);
394 model.put(person, Tuple.of(2), true);
395 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
396 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
397 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
398
399 model.flushChanges();
400 assertEquals(6, model.countResults(predicate));
401 }
402
403 @Test
404 void transitivePatternCallTest() {
405 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
406 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
407 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
408 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
409
410 Variable p1 = new Variable("p1");
411 Variable p2 = new Variable("p2");
412 List<Variable> parameters = Arrays.asList(p1, p2);
413
414 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
415 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
416 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
417 DNFAnd clause = new DNFAnd(Collections.emptySet(),
418 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
419 DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
420
421 Variable p3 = new Variable("p3");
422 Variable p4 = new Variable("p4");
423 List<Variable> substitution = Arrays.asList(p3, p4);
424 RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3));
425 RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4));
426 PredicateAtom friendPredicateAtom = new PredicateAtom(true, true, friendPredicate, substitution);
427 DNFAnd patternCallClause = new DNFAnd(Collections.emptySet(),
428 Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom));
429 DNFPredicate predicate = new DNFPredicate("TransitivePatternCall", substitution,
430 Arrays.asList(patternCallClause));
431
432 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
433 Set.of(persionView, friendMustView), Set.of(friendPredicate, predicate));
434 QueriableModel model = store.createModel();
435
436 model.put(person, Tuple.of(0), true);
437 model.put(person, Tuple.of(1), true);
438 model.put(person, Tuple.of(2), true);
439 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
440 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
441
442 model.flushChanges();
443 assertEquals(3, model.countResults(predicate));
444 }
445} \ No newline at end of file
diff --git a/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTransactionTest.java b/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTransactionTest.java
deleted file mode 100644
index e72186b9..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTransactionTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
1package tools.refinery.store.query.test;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import java.util.Arrays;
6import java.util.Collections;
7import java.util.List;
8import java.util.Set;
9
10import org.junit.jupiter.api.Test;
11
12import tools.refinery.store.model.Tuple;
13import tools.refinery.store.model.representation.Relation;
14import tools.refinery.store.query.QueriableModel;
15import tools.refinery.store.query.QueriableModelStore;
16import tools.refinery.store.query.QueriableModelStoreImpl;
17import tools.refinery.store.query.building.DNFAnd;
18import tools.refinery.store.query.building.DNFPredicate;
19import tools.refinery.store.query.building.RelationAtom;
20import tools.refinery.store.query.building.Variable;
21import tools.refinery.store.query.view.KeyOnlyRelationView;
22import tools.refinery.store.query.view.RelationView;
23
24class QueryTransactionTest {
25 @Test
26 void flushTest() {
27 Relation<Boolean> person = new Relation<>("Person", 1, false);
28 Relation<Boolean> asset = new Relation<>("Asset", 1, false);
29 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
30
31 List<Variable> parameters = Arrays.asList(new Variable("p1"));
32 RelationAtom personRelationAtom = new RelationAtom(persionView, parameters);
33 DNFAnd clause = new DNFAnd(Collections.emptySet(), Arrays.asList(personRelationAtom));
34 DNFPredicate predicate = new DNFPredicate("TypeConstraint", parameters, Arrays.asList(clause));
35
36 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, asset), Set.of(persionView),
37 Set.of(predicate));
38 QueriableModel model = store.createModel();
39
40 assertEquals(0, model.countResults(predicate));
41
42 model.put(person, Tuple.of(0), true);
43 model.put(person, Tuple.of(1), true);
44 model.put(asset, Tuple.of(1), true);
45 model.put(asset, Tuple.of(2), true);
46
47 assertEquals(0, model.countResults(predicate));
48
49 model.flushChanges();
50 assertEquals(2, model.countResults(predicate));
51
52 model.put(person, Tuple.of(4), true);
53 assertEquals(2, model.countResults(predicate));
54
55 model.flushChanges();
56 assertEquals(3, model.countResults(predicate));
57 }
58}