diff options
Diffstat (limited to 'subprojects/store')
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 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import java.util.Collections; | ||
4 | import java.util.HashMap; | ||
5 | import java.util.Map; | ||
6 | import java.util.Set; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | ||
9 | |||
10 | import tools.refinery.store.model.ModelDiffCursor; | ||
11 | import tools.refinery.store.model.ModelStore; | ||
12 | import tools.refinery.store.model.ModelStoreImpl; | ||
13 | import tools.refinery.store.model.representation.DataRepresentation; | ||
14 | import tools.refinery.store.query.building.DNFAnd; | ||
15 | import tools.refinery.store.query.building.DNFAtom; | ||
16 | import tools.refinery.store.query.building.DNFPredicate; | ||
17 | import tools.refinery.store.query.building.PredicateAtom; | ||
18 | import tools.refinery.store.query.building.RelationAtom; | ||
19 | import tools.refinery.store.query.internal.DNF2PQuery; | ||
20 | import tools.refinery.store.query.internal.QueriableModelImpl; | ||
21 | import tools.refinery.store.query.internal.RawPatternMatcher; | ||
22 | import tools.refinery.store.query.internal.DNF2PQuery.SimplePQuery; | ||
23 | import tools.refinery.store.query.view.RelationView; | ||
24 | |||
25 | public 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 @@ | |||
1 | package tools.refinery.store.query; | 1 | package tools.refinery.store.query; |
2 | 2 | ||
3 | import tools.refinery.store.model.Model; | ||
4 | import tools.refinery.store.query.building.DNFPredicate; | ||
5 | |||
3 | import java.util.Optional; | 6 | import java.util.Optional; |
4 | import java.util.Set; | 7 | import java.util.Set; |
5 | import java.util.stream.Stream; | 8 | import java.util.stream.Stream; |
6 | 9 | ||
7 | import tools.refinery.store.model.Model; | 10 | public interface QueryableModel extends Model{ |
8 | import tools.refinery.store.query.building.DNFPredicate; | ||
9 | |||
10 | public 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 @@ | |||
1 | package tools.refinery.store.query; | 1 | package tools.refinery.store.query; |
2 | 2 | ||
3 | import java.util.Set; | ||
4 | |||
5 | import tools.refinery.store.model.ModelDiffCursor; | 3 | import tools.refinery.store.model.ModelDiffCursor; |
6 | import tools.refinery.store.model.ModelStore; | 4 | import tools.refinery.store.model.ModelStore; |
7 | import tools.refinery.store.model.representation.DataRepresentation; | 5 | import tools.refinery.store.model.representation.DataRepresentation; |
8 | import tools.refinery.store.query.building.DNFPredicate; | 6 | import tools.refinery.store.query.building.DNFPredicate; |
9 | import tools.refinery.store.query.view.RelationView; | 7 | import tools.refinery.store.query.view.RelationView; |
10 | 8 | ||
11 | public interface QueriableModelStore extends ModelStore{ | 9 | import java.util.Set; |
10 | |||
11 | public 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 @@ | |||
1 | package tools.refinery.store.query.building; | 1 | package tools.refinery.store.query.building; |
2 | 2 | ||
3 | import tools.refinery.store.query.view.RelationView; | ||
4 | |||
5 | import java.util.ArrayList; | ||
3 | import java.util.List; | 6 | import java.util.List; |
4 | import java.util.Map; | 7 | import java.util.Map; |
5 | import java.util.Set; | 8 | import java.util.Set; |
6 | 9 | ||
7 | import tools.refinery.store.query.view.FilteredRelationView; | 10 | public record RelationAtom(RelationView<?> view, List<Variable> substitution) implements DNFAtom { |
8 | import tools.refinery.store.query.view.RelationView; | ||
9 | |||
10 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.ArrayList; | ||
4 | import java.util.HashMap; | ||
5 | import java.util.InputMismatchException; | ||
6 | import java.util.LinkedHashSet; | ||
7 | import java.util.List; | ||
8 | import java.util.Map; | ||
9 | import java.util.Set; | ||
10 | |||
11 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | ||
12 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
13 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; | ||
14 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
15 | import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; | ||
16 | import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; | ||
17 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; | ||
18 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExportedParameter; | ||
19 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Inequality; | ||
20 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.NegativePatternCall; | ||
21 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure; | ||
22 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; | ||
23 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; | ||
24 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery; | ||
25 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; | ||
26 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; | ||
27 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
28 | |||
29 | import tools.refinery.store.query.building.DNFAnd; | ||
30 | import tools.refinery.store.query.building.DNFAtom; | ||
31 | import tools.refinery.store.query.building.DNFPredicate; | ||
32 | import tools.refinery.store.query.building.EquivalenceAtom; | ||
33 | import tools.refinery.store.query.building.PredicateAtom; | ||
34 | import tools.refinery.store.query.building.RelationAtom; | ||
35 | import tools.refinery.store.query.building.Variable; | ||
36 | |||
37 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.lang.reflect.InvocationTargetException; | ||
4 | import java.util.concurrent.Callable; | ||
5 | |||
6 | import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; | ||
7 | import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; | ||
8 | import org.eclipse.viatra.query.runtime.api.scope.IInstanceObserver; | ||
9 | import org.eclipse.viatra.query.runtime.api.scope.ViatraBaseIndexChangeListener; | ||
10 | |||
11 | /** | ||
12 | * copied from org.eclipse.viatra.query.runtime.tabular.TabularEngineContext; | ||
13 | */ | ||
14 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.HashSet; | ||
5 | import java.util.Map; | ||
6 | import java.util.Set; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
9 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
10 | |||
11 | import tools.refinery.store.model.Tuple; | ||
12 | import tools.refinery.store.model.representation.Relation; | ||
13 | import tools.refinery.store.query.view.RelationView; | ||
14 | |||
15 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.Optional; | ||
4 | import java.util.stream.Stream; | ||
5 | |||
6 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.Map; | ||
5 | import java.util.Optional; | ||
6 | import java.util.Set; | ||
7 | import java.util.stream.Stream; | ||
8 | |||
9 | import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; | ||
10 | import org.eclipse.viatra.query.runtime.api.GenericQueryGroup; | ||
11 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | ||
12 | import org.eclipse.viatra.query.runtime.api.IQueryGroup; | ||
13 | |||
14 | import tools.refinery.store.map.Cursor; | ||
15 | import tools.refinery.store.map.DiffCursor; | ||
16 | import tools.refinery.store.model.Model; | ||
17 | import tools.refinery.store.model.ModelDiffCursor; | ||
18 | import tools.refinery.store.model.Tuple; | ||
19 | import tools.refinery.store.model.representation.DataRepresentation; | ||
20 | import tools.refinery.store.model.representation.Relation; | ||
21 | import tools.refinery.store.query.QueriableModel; | ||
22 | import tools.refinery.store.query.QueriableModelStore; | ||
23 | import tools.refinery.store.query.building.DNFPredicate; | ||
24 | |||
25 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.Optional; | ||
4 | import java.util.stream.Stream; | ||
5 | |||
6 | import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; | ||
7 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | ||
8 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; | ||
9 | import org.eclipse.viatra.query.runtime.matchers.tuple.AbstractTuple; | ||
10 | |||
11 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; | ||
4 | import org.eclipse.viatra.query.runtime.api.scope.IEngineContext; | ||
5 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; | ||
6 | |||
7 | import tools.refinery.store.model.Model; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.Collection; | ||
4 | import java.util.Collections; | ||
5 | import java.util.HashMap; | ||
6 | import java.util.HashSet; | ||
7 | import java.util.Map; | ||
8 | import java.util.Set; | ||
9 | |||
10 | import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContext; | ||
11 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
12 | import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication; | ||
13 | |||
14 | import tools.refinery.store.query.view.RelationView; | ||
15 | |||
16 | /** | ||
17 | * The meta context information for String scopes. | ||
18 | */ | ||
19 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import static tools.refinery.store.util.CollectionsUtil.filter; | ||
4 | import static tools.refinery.store.util.CollectionsUtil.map; | ||
5 | |||
6 | import java.lang.reflect.InvocationTargetException; | ||
7 | import java.util.Iterator; | ||
8 | import java.util.Optional; | ||
9 | import java.util.concurrent.Callable; | ||
10 | |||
11 | import org.eclipse.viatra.query.runtime.base.core.NavigationHelperImpl; | ||
12 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
13 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryMetaContext; | ||
14 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; | ||
15 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
16 | import org.eclipse.viatra.query.runtime.matchers.context.IndexingService; | ||
17 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
18 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; | ||
19 | import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; | ||
20 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
21 | import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; | ||
22 | |||
23 | import tools.refinery.store.model.Model; | ||
24 | import tools.refinery.store.query.view.RelationView; | ||
25 | |||
26 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.Set; | ||
4 | |||
5 | import org.apache.log4j.Logger; | ||
6 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
7 | import org.eclipse.viatra.query.runtime.api.scope.IEngineContext; | ||
8 | import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; | ||
9 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; | ||
10 | |||
11 | import tools.refinery.store.model.Model; | ||
12 | import tools.refinery.store.model.Tuple; | ||
13 | import tools.refinery.store.model.representation.Relation; | ||
14 | import tools.refinery.store.query.view.RelationView; | ||
15 | |||
16 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.Arrays; | ||
4 | import java.util.Objects; | ||
5 | |||
6 | record 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.ArrayList; | ||
4 | import java.util.Arrays; | ||
5 | import java.util.List; | ||
6 | |||
7 | import tools.refinery.store.model.Tuple; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.Objects; | ||
4 | |||
5 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
6 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
7 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
8 | |||
9 | import tools.refinery.store.model.Tuple; | ||
10 | import tools.refinery.store.query.view.RelationView; | ||
11 | |||
12 | public 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 @@ | |||
1 | package tools.refinery.store.query.test; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | |||
5 | import java.util.ArrayList; | ||
6 | import java.util.Arrays; | ||
7 | import java.util.Collections; | ||
8 | import java.util.HashSet; | ||
9 | import java.util.List; | ||
10 | import java.util.Set; | ||
11 | import java.util.stream.Stream; | ||
12 | |||
13 | import org.junit.jupiter.api.Test; | ||
14 | |||
15 | import tools.refinery.store.model.Tuple; | ||
16 | import tools.refinery.store.model.representation.Relation; | ||
17 | import tools.refinery.store.model.representation.TruthValue; | ||
18 | import tools.refinery.store.query.QueriableModel; | ||
19 | import tools.refinery.store.query.QueriableModelStore; | ||
20 | import tools.refinery.store.query.QueriableModelStoreImpl; | ||
21 | import tools.refinery.store.query.building.DNFAnd; | ||
22 | import tools.refinery.store.query.building.DNFPredicate; | ||
23 | import tools.refinery.store.query.building.EquivalenceAtom; | ||
24 | import tools.refinery.store.query.building.PredicateAtom; | ||
25 | import tools.refinery.store.query.building.RelationAtom; | ||
26 | import tools.refinery.store.query.building.Variable; | ||
27 | import tools.refinery.store.query.view.FilteredRelationView; | ||
28 | import tools.refinery.store.query.view.KeyOnlyRelationView; | ||
29 | import tools.refinery.store.query.view.RelationView; | ||
30 | |||
31 | class 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 @@ | |||
1 | package tools.refinery.store.query.test; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | |||
5 | import java.util.Arrays; | ||
6 | import java.util.Collections; | ||
7 | import java.util.List; | ||
8 | import java.util.Set; | ||
9 | |||
10 | import org.junit.jupiter.api.Test; | ||
11 | |||
12 | import tools.refinery.store.model.Tuple; | ||
13 | import tools.refinery.store.model.representation.Relation; | ||
14 | import tools.refinery.store.query.QueriableModel; | ||
15 | import tools.refinery.store.query.QueriableModelStore; | ||
16 | import tools.refinery.store.query.QueriableModelStoreImpl; | ||
17 | import tools.refinery.store.query.building.DNFAnd; | ||
18 | import tools.refinery.store.query.building.DNFPredicate; | ||
19 | import tools.refinery.store.query.building.RelationAtom; | ||
20 | import tools.refinery.store.query.building.Variable; | ||
21 | import tools.refinery.store.query.view.KeyOnlyRelationView; | ||
22 | import tools.refinery.store.query.view.RelationView; | ||
23 | |||
24 | class 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 | } | ||