/* * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors * * SPDX-License-Identifier: EPL-2.0 */ package tools.refinery.store.query.interpreter.internal; import tools.refinery.store.model.Model; import tools.refinery.store.model.ModelListener; import tools.refinery.store.query.dnf.AnyQuery; import tools.refinery.store.query.dnf.FunctionalQuery; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.dnf.RelationalQuery; import tools.refinery.store.query.resultset.AnyResultSet; import tools.refinery.store.query.resultset.EmptyResultSet; import tools.refinery.store.query.resultset.ResultSet; import tools.refinery.store.query.interpreter.QueryInterpreterAdapter; import tools.refinery.store.query.interpreter.internal.matcher.InterpretedFunctionalMatcher; import tools.refinery.store.query.interpreter.internal.matcher.RawPatternMatcher; import tools.refinery.store.query.interpreter.internal.matcher.InterpretedRelationalMatcher; import tools.refinery.interpreter.CancellationToken; import tools.refinery.interpreter.api.AdvancedInterpreterEngine; import tools.refinery.interpreter.api.GenericQueryGroup; import tools.refinery.interpreter.api.IQuerySpecification; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; public class QueryInterpreterAdapterImpl implements QueryInterpreterAdapter, ModelListener { private final Model model; private final QueryInterpreterStoreAdapterImpl storeAdapter; private final AdvancedInterpreterEngine queryEngine; private final Map resultSets; private boolean pendingChanges; QueryInterpreterAdapterImpl(Model model, QueryInterpreterStoreAdapterImpl storeAdapter) { this.model = model; this.storeAdapter = storeAdapter; var scope = new RelationalScope(this); queryEngine = AdvancedInterpreterEngine.createUnmanagedEngine(scope, storeAdapter.getEngineOptions()); var querySpecifications = storeAdapter.getQuerySpecifications(); GenericQueryGroup.of( Collections.>unmodifiableCollection(querySpecifications.values()).stream() ).prepare(queryEngine); queryEngine.flushChanges(); var vacuousQueries = storeAdapter.getVacuousQueries(); resultSets = new LinkedHashMap<>(querySpecifications.size() + vacuousQueries.size()); for (var entry : querySpecifications.entrySet()) { var rawPatternMatcher = queryEngine.getMatcher(entry.getValue()); var query = entry.getKey(); resultSets.put(query, createResultSet((Query) query, rawPatternMatcher)); } for (var vacuousQuery : vacuousQueries) { resultSets.put(vacuousQuery, new EmptyResultSet<>(this, (Query) vacuousQuery)); } model.addListener(this); } private ResultSet createResultSet(Query query, RawPatternMatcher matcher) { if (query instanceof RelationalQuery relationalQuery) { @SuppressWarnings("unchecked") var resultSet = (ResultSet) new InterpretedRelationalMatcher(this, relationalQuery, matcher); return resultSet; } else if (query instanceof FunctionalQuery functionalQuery) { return new InterpretedFunctionalMatcher<>(this, functionalQuery, matcher); } else { throw new IllegalArgumentException("Unknown query: " + query); } } @Override public Model getModel() { return model; } @Override public QueryInterpreterStoreAdapterImpl getStoreAdapter() { return storeAdapter; } public CancellationToken getCancellationToken() { return storeAdapter.getCancellationToken(); } @Override public ResultSet getResultSet(Query query) { var canonicalQuery = storeAdapter.getCanonicalQuery(query); var resultSet = resultSets.get(canonicalQuery); if (resultSet == null) { throw new IllegalArgumentException("No matcher for query %s in model".formatted(query.name())); } @SuppressWarnings("unchecked") var typedResultSet = (ResultSet) resultSet; return typedResultSet; } @Override public boolean hasPendingChanges() { return pendingChanges; } public void markAsPending() { if (!pendingChanges) { pendingChanges = true; } } @Override public void flushChanges() { queryEngine.flushChanges(); pendingChanges = false; } @Override public void afterRestore() { flushChanges(); } }