From 1be64083c2c38eedeffc7cea9f51afbed4d46d28 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Mon, 26 Sep 2022 01:42:58 +0200 Subject: refactor: remove viatra dependency from store --- .../query/viatra/ViatraQueryableModelStore.java | 31 +++++---- .../internal/context/RelationalEngineContext.java | 1 - .../context/RelationalQueryMetaContext.java | 11 +-- .../internal/context/RelationalRuntimeContext.java | 10 +-- .../query/viatra/internal/pquery/DNF2PQuery.java | 78 ++++++++++++++-------- .../internal/pquery/RelationViewWrapper.java | 30 +++++++++ .../internal/viewupdate/ModelUpdateListener.java | 14 ++-- .../viatra/internal/viewupdate/ViewUpdate.java | 6 +- .../internal/viewupdate/ViewUpdateBuffer.java | 1 + .../internal/viewupdate/ViewUpdateTranslator.java | 20 ++++-- 10 files changed, 136 insertions(+), 66 deletions(-) create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java (limited to 'subprojects/store-query-viatra/src') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java index 5a02ca08..a63abc3a 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java @@ -8,10 +8,9 @@ import tools.refinery.store.model.representation.DataRepresentation; import tools.refinery.store.query.QueryableModel; import tools.refinery.store.query.QueryableModelStore; import tools.refinery.store.query.building.*; +import tools.refinery.store.query.viatra.internal.RawPatternMatcher; import tools.refinery.store.query.viatra.internal.ViatraQueryableModel; import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery; -import tools.refinery.store.query.viatra.internal.RawPatternMatcher; -import tools.refinery.store.query.viatra.internal.pquery.SimplePQuery; import tools.refinery.store.query.view.RelationView; import java.util.Collections; @@ -21,7 +20,9 @@ import java.util.Set; public class ViatraQueryableModelStore implements QueryableModelStore { protected final ModelStore store; + protected final Set> relationViews; + protected final Map> predicates; public ViatraQueryableModelStore(ModelStore store, Set> relationViews, @@ -41,9 +42,9 @@ public class ViatraQueryableModelStore implements QueryableModelStore { private void validateViews(Set> dataRepresentations, Set> relationViews) { for (RelationView relationView : relationViews) { if (!dataRepresentations.contains(relationView.getRepresentation())) { - throw new IllegalArgumentException( - DataRepresentation.class.getSimpleName() + " " + relationView.getStringID() + " added to " - + QueryableModelStore.class.getSimpleName() + " without a referred representation."); + throw new IllegalArgumentException("%s %s added to %s without a referred representation.".formatted( + DataRepresentation.class.getSimpleName(), relationView.getName(), + QueryableModelStore.class.getSimpleName())); } } } @@ -65,10 +66,10 @@ public class ViatraQueryableModelStore implements QueryableModelStore { private void validateRelationAtom(Set> relationViews, DNFPredicate dnfPredicate, RelationAtom relationAtom) { if (!relationViews.contains(relationAtom.view())) { - throw new IllegalArgumentException(DNFPredicate.class.getSimpleName() + " " - + dnfPredicate.getUniqueName() + " contains reference to a view of " - + relationAtom.view().getRepresentation().getName() - + " that is not in the model."); + throw new IllegalArgumentException( + "%s %s contains reference to a view %s that is not in the model.".formatted( + DNFPredicate.class.getSimpleName(), dnfPredicate.getUniqueName(), + relationAtom.view().getName())); } } @@ -76,19 +77,17 @@ public class ViatraQueryableModelStore implements QueryableModelStore { PredicateAtom predicateAtom) { if (!predicates.contains(predicateAtom.getReferred())) { throw new IllegalArgumentException( - DNFPredicate.class.getSimpleName() + " " + dnfPredicate.getUniqueName() - + " contains reference to a predicate " - + predicateAtom.getReferred().getName() - + "that is not in the model."); + "%s %s contains reference to a predicate %s that is not in the model.".formatted( + DNFPredicate.class.getSimpleName(), dnfPredicate.getUniqueName(), + predicateAtom.getReferred().getName())); } } private Map> initPredicates(Set predicates) { Map> result = new HashMap<>(); - Map dnf2PQueryMap = new HashMap<>(); + var dnf2PQuery = new DNF2PQuery(); for (DNFPredicate dnfPredicate : predicates) { - GenericQuerySpecification query = - DNF2PQuery.translate(dnfPredicate, dnf2PQueryMap).build(); + GenericQuerySpecification query = dnf2PQuery.translate(dnfPredicate).build(); result.put(dnfPredicate, query); } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java index 882734cb..d32d49ba 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java @@ -29,5 +29,4 @@ public class RelationalEngineContext implements IEngineContext { public IQueryRuntimeContext getQueryRuntimeContext() { return runtimeContext; } - } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java index 64c23c61..eb3c6fbd 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java @@ -3,9 +3,11 @@ package tools.refinery.store.query.viatra.internal.context; import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContext; import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication; -import tools.refinery.store.query.view.RelationView; +import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; -import java.util.*; +import java.util.Collection; +import java.util.Map; +import java.util.Set; /** * The meta context information for String scopes. @@ -36,9 +38,8 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext { } public void ensureValidKey(IInputKey key) { - if (key instanceof RelationView) { - return; + if (!(key instanceof RelationViewWrapper)) { + throw new IllegalArgumentException("The input key %s is not a valid input key.".formatted(key)); } - throw new IllegalArgumentException("The input key %s is not a valid input key.".formatted(key)); } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java index 0bd1b807..c007d630 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java @@ -7,6 +7,7 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; import tools.refinery.store.model.Model; +import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; import tools.refinery.store.query.view.RelationView; @@ -67,7 +68,8 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { @SuppressWarnings("squid:S1452") RelationView checkKey(IInputKey key) { - if (key instanceof RelationView relationViewKey) { + if (key instanceof RelationViewWrapper wrappedKey) { + var relationViewKey = wrappedKey.getWrappedKey(); if (modelUpdateListener.containsRelationalView(relationViewKey)) { return relationViewKey; } else { @@ -117,7 +119,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { } @Override - public Iterable enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) { + public Iterable enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) { return enumerateTuples(key, seedMask, seed); } @@ -130,14 +132,14 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { @Override public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { RelationView relationalKey = checkKey(key); - this.modelUpdateListener.addListener(relationalKey, seed, listener); + this.modelUpdateListener.addListener(key, relationalKey, seed, listener); } @Override public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { RelationView relationalKey = checkKey(key); - this.modelUpdateListener.removeListener(relationalKey, seed, listener); + this.modelUpdateListener.removeListener(key, relationalKey, seed, listener); } @Override diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java index c093be47..b6468e76 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java @@ -12,28 +12,53 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeCo import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import tools.refinery.store.query.building.*; +import tools.refinery.store.query.view.RelationView; import java.util.*; +import java.util.stream.Collectors; public class DNF2PQuery { - private DNF2PQuery() { - throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); - } + private final Set translating = new LinkedHashSet<>(); + + private final Map dnf2PQueryMap = new HashMap<>(); - public static SimplePQuery translate(DNFPredicate predicate, Map dnf2PQueryMap) { - SimplePQuery query = dnf2PQueryMap.get(predicate); - if (query != null) { - return query; + private final Map, RelationViewWrapper> view2WrapperMap = new HashMap<>(); + + public SimplePQuery translate(DNFPredicate predicate) { + if (translating.contains(predicate)) { + var path = translating.stream().map(DNFPredicate::getName).collect(Collectors.joining(" -> ")); + throw new IllegalStateException("Circular reference %s -> %s detected".formatted(path, + predicate.getName())); } - query = new SimplePQuery(predicate.getName()); + // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant + // way, which would cause a ConcurrentModificationException with computeIfAbsent. + var pQuery = dnf2PQueryMap.get(predicate); + if (pQuery == null) { + translating.add(predicate); + try { + pQuery = doTranslate(predicate); + dnf2PQueryMap.put(predicate, pQuery); + } finally { + translating.remove(predicate); + } + } + return pQuery; + } + + private SimplePQuery doTranslate(DNFPredicate predicate) { + var query = new SimplePQuery(predicate.getName()); + Map parameters = new HashMap<>(); + for (Variable variable : predicate.getVariables()) { + parameters.put(variable, new PParameter(variable.getName())); + } - predicate.getVariables().forEach(variable -> parameters.put(variable, new PParameter(variable.getName()))); List parameterList = new ArrayList<>(); for (var param : predicate.getVariables()) { parameterList.add(parameters.get(param)); } query.setParameters(parameterList); + for (DNFAnd clause : predicate.getClauses()) { PBody body = new PBody(query); List symbolicParameters = new ArrayList<>(); @@ -44,15 +69,14 @@ public class DNF2PQuery { body.setSymbolicParameters(symbolicParameters); query.addBody(body); for (DNFAtom constraint : clause.getConstraints()) { - translateDNFAtom(constraint, body, dnf2PQueryMap); + translateDNFAtom(constraint, body); } } - dnf2PQueryMap.put(predicate, query); + return query; } - private static void translateDNFAtom(DNFAtom constraint, PBody body, - Map dnf2PQueryMap) { + private void translateDNFAtom(DNFAtom constraint, PBody body) { if (constraint instanceof EquivalenceAtom equivalence) { translateEquivalenceAtom(equivalence, body); } @@ -60,11 +84,11 @@ public class DNF2PQuery { translateRelationAtom(relation, body); } if (constraint instanceof PredicateAtom predicate) { - translatePredicateAtom(predicate, body, dnf2PQueryMap); + translatePredicateAtom(predicate, body); } } - private static void translateEquivalenceAtom(EquivalenceAtom equivalence, PBody body) { + private void translateEquivalenceAtom(EquivalenceAtom equivalence, PBody body) { PVariable varSource = body.getOrCreateVariableByName(equivalence.getLeft().getName()); PVariable varTarget = body.getOrCreateVariableByName(equivalence.getRight().getName()); if (equivalence.isPositive()) @@ -73,7 +97,7 @@ public class DNF2PQuery { new Inequality(body, varSource, varTarget); } - private static void translateRelationAtom(RelationAtom relation, PBody body) { + private void translateRelationAtom(RelationAtom relation, PBody body) { if (relation.substitution().size() != relation.view().getArity()) { throw new IllegalArgumentException("Arity (%d) does not match parameter numbers (%d)".formatted( relation.view().getArity(), relation.substitution().size())); @@ -82,32 +106,34 @@ public class DNF2PQuery { for (int i = 0; i < relation.substitution().size(); i++) { variables[i] = body.getOrCreateVariableByName(relation.substitution().get(i).getName()); } - new TypeConstraint(body, Tuples.flatTupleOf(variables), relation.view()); + new TypeConstraint(body, Tuples.flatTupleOf(variables), wrapView(relation.view())); + } + + private RelationViewWrapper wrapView(RelationView relationView) { + return view2WrapperMap.computeIfAbsent(relationView, RelationViewWrapper::new); } - private static void translatePredicateAtom(PredicateAtom predicate, PBody body, - Map dnf2PQueryMap) { + private void translatePredicateAtom(PredicateAtom predicate, PBody body) { Object[] variables = new Object[predicate.getSubstitution().size()]; for (int i = 0; i < predicate.getSubstitution().size(); i++) { variables[i] = body.getOrCreateVariableByName(predicate.getSubstitution().get(i).getName()); } + var variablesTuple = Tuples.flatTupleOf(variables); + var translatedReferred = translate(predicate.getReferred()); if (predicate.isPositive()) { if (predicate.isTransitive()) { if (predicate.getSubstitution().size() != 2) { throw new IllegalArgumentException("Transitive Predicate Atoms must be binary."); } - new BinaryTransitiveClosure(body, Tuples.flatTupleOf(variables), - DNF2PQuery.translate(predicate.getReferred(), dnf2PQueryMap)); + new BinaryTransitiveClosure(body, variablesTuple, translatedReferred); } else { - new PositivePatternCall(body, Tuples.flatTupleOf(variables), - DNF2PQuery.translate(predicate.getReferred(), dnf2PQueryMap)); + new PositivePatternCall(body, variablesTuple, translatedReferred); } } else { if (predicate.isTransitive()) { - throw new InputMismatchException("Transitive Predicate Atoms cannot be negative."); + throw new IllegalArgumentException("Transitive Predicate Atoms cannot be negative."); } else { - new NegativePatternCall(body, Tuples.flatTupleOf(variables), - DNF2PQuery.translate(predicate.getReferred(), dnf2PQueryMap)); + new NegativePatternCall(body, variablesTuple, translatedReferred); } } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java new file mode 100644 index 00000000..2a4148dc --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java @@ -0,0 +1,30 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.context.common.BaseInputKeyWrapper; +import tools.refinery.store.query.view.RelationView; + +public class RelationViewWrapper extends BaseInputKeyWrapper> { + public RelationViewWrapper(RelationView wrappedKey) { + super(wrappedKey); + } + + @Override + public String getPrettyPrintableName() { + return wrappedKey.getName(); + } + + @Override + public String getStringID() { + return getPrettyPrintableName(); + } + + @Override + public int getArity() { + return wrappedKey.getArity(); + } + + @Override + public boolean isEnumerable() { + return true; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java index 25919888..5a0da315 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java @@ -1,5 +1,6 @@ package tools.refinery.store.query.viatra.internal.viewupdate; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; import tools.refinery.store.model.Tuple; @@ -46,20 +47,23 @@ public class ModelUpdateListener { return view2Buffers.containsKey(relationalKey); } - public void addListener(RelationView relationView, ITuple seed, IQueryRuntimeContextListener listener) { + public void addListener(IInputKey key, RelationView relationView, ITuple seed, + IQueryRuntimeContextListener listener) { if (view2Buffers.containsKey(relationView)) { - ViewUpdateTranslator updateListener = new ViewUpdateTranslator<>(relationView, seed, listener); + ViewUpdateTranslator updateListener = new ViewUpdateTranslator<>(key, relationView, seed, listener); ViewUpdateBuffer updateBuffer = new ViewUpdateBuffer<>(updateListener); view2Buffers.get(relationView).add(updateBuffer); - } else + } else { throw new IllegalArgumentException(); + } } - public void removeListener(RelationView relationView, ITuple seed, IQueryRuntimeContextListener listener) { + public void removeListener(IInputKey key, RelationView relationView, ITuple seed, + IQueryRuntimeContextListener listener) { if (view2Buffers.containsKey(relationView)) { Set> buffers = this.view2Buffers.get(relationView); for (var buffer : buffers) { - if (buffer.getUpdateListener().equals(relationView, seed, listener)) { + if (buffer.getUpdateListener().equals(key, relationView, seed, listener)) { // remove buffer and terminate immediately, or it will break iterator. buffers.remove(buffer); return; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java index c727f046..b9406018 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java @@ -3,8 +3,7 @@ package tools.refinery.store.query.viatra.internal.viewupdate; import java.util.Arrays; import java.util.Objects; -record ViewUpdate (Object[] tuple, boolean isInsertion) { - +record ViewUpdate(Object[] tuple, boolean isInsertion) { @Override public int hashCode() { final int prime = 31; @@ -28,7 +27,6 @@ record ViewUpdate (Object[] tuple, boolean isInsertion) { @Override public String toString() { - return "ViewUpdate [" + Arrays.toString(tuple) + "insertion= "+this.isInsertion+"]"; + return "ViewUpdate [" + Arrays.toString(tuple) + "insertion= " + this.isInsertion + "]"; } - } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java index 5a4243f2..e13a9cb8 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java @@ -8,6 +8,7 @@ import java.util.List; public class ViewUpdateBuffer { protected final ViewUpdateTranslator updateListener; + protected final List buffer = new ArrayList<>(); public ViewUpdateBuffer(ViewUpdateTranslator updateListener) { diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java index 2f7f9a9c..62a10e45 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java @@ -1,5 +1,6 @@ package tools.refinery.store.query.viatra.internal.viewupdate; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; @@ -9,29 +10,38 @@ import tools.refinery.store.query.view.RelationView; import java.util.Objects; public class ViewUpdateTranslator { + private final IInputKey wrappedKey; + private final RelationView key; private final ITuple filter; private final IQueryRuntimeContextListener listener; - public ViewUpdateTranslator(RelationView key, ITuple filter, IQueryRuntimeContextListener listener) { + public ViewUpdateTranslator(IInputKey wrappedKey, RelationView key, ITuple filter, + IQueryRuntimeContextListener listener) { super(); + this.wrappedKey = wrappedKey; this.key = key; this.filter = filter; this.listener = listener; } - public boolean equals(RelationView relationView, ITuple seed, IQueryRuntimeContextListener listener) { - return key == relationView && filter.equals(seed) && this.listener == listener; + public boolean equals(IInputKey wrappedKey, RelationView relationView, ITuple seed, + IQueryRuntimeContextListener listener) { + return this.wrappedKey == wrappedKey && key == relationView && filter.equals(seed) && this.listener == listener; } public void processChange(ViewUpdate change) { - listener.update(key, Tuples.flatTupleOf(change.tuple()), change.isInsertion()); + listener.update(wrappedKey, Tuples.flatTupleOf(change.tuple()), change.isInsertion()); } + @SuppressWarnings("squid:S1168") public Object[] isMatching(Tuple tuple, D value) { - return isMatching(key.getWrappedKey().transform(tuple, value), filter); + if (!key.filter(tuple, value)) { + return null; + } + return isMatching(key.forwardMap(tuple, value), filter); } @SuppressWarnings("squid:S1168") -- cgit v1.2.3-70-g09d2