Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/main/java/fr/inria/corese/core/next/query/api/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
import fr.inria.corese.core.next.query.api.result.TupleQueryResult;

/**
* A query on a repository that can be formulated in one of the supported query languages (for example SPARQL).
* It should hold kgram.core.Query + ASTQuery
* A prepared SPARQL query that can be evaluated against a repository.
*
* <p>Concrete subtypes are {@link TupleQuery} (SELECT), {@link BooleanQuery} (ASK),
* and {@link GraphQuery} (CONSTRUCT / DESCRIBE).
* All evaluation state (bindings, dataset, timeout) is carried by the
* {@link Operation} supertype and propagated on each {@link #evaluate()} call.</p>
*/

public interface Query<T> extends Operation {
Expand Down Expand Up @@ -42,10 +46,14 @@ enum QueryType {
*/
QueryLanguage getLanguage();

// Execution options
/**
* Set the execution timeout for the query regarding remote operations (i.e. for SERVICE clauses)
* @param timeoutMillis time in milliseconds
* Sets a fine-grained execution timeout for this specific query, expressed in milliseconds.
*
* <p>When both this value and {@link Operation#setMaxExecutionTime(int)} are set,
* the shorter of the two limits is enforced. A value of {@code 0} disables this
* query-level timeout.</p>
*
* @param timeoutMillis maximum evaluation time in milliseconds; 0 means no limit
* @return this
*/
Query<T> setTimeout(long timeoutMillis);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
/**
* Query-facing contracts, result types, validation entry points, and I/O
* abstractions.
* Public SPARQL query API for Corese.
*
* <p>The final public SPARQL request API is not defined yet. Parser, AST,
* bridge, and execution wiring remain outside this package so they cannot be
* mistaken for that future contract.</p>
* <p>Entry point: obtain a {@link fr.inria.corese.core.next.query.api.repository.RepositoryConnection}
* from a {@link fr.inria.corese.core.next.query.api.repository.Repository}, then prepare
* one of the four query types:</p>
*
* <ul>
* <li>{@link fr.inria.corese.core.next.query.api.TupleQuery} — SPARQL SELECT</li>
* <li>{@link fr.inria.corese.core.next.query.api.BooleanQuery} — SPARQL ASK</li>
* <li>{@link fr.inria.corese.core.next.query.api.GraphQuery} — SPARQL CONSTRUCT / DESCRIBE</li>
* <li>{@link fr.inria.corese.core.next.query.api.Update} — SPARQL 1.1 UPDATE</li>
* </ul>
*
* <p>All types implement {@link fr.inria.corese.core.next.query.api.Operation}, which provides
* initial bindings ({@code setBinding}), dataset override ({@code setDataset}),
* and execution-time limit ({@code setMaxExecutionTime}).
* Query types additionally expose {@code setTimeout(long millis)} for millisecond precision.</p>
*
* <p>No internal types (parser, AST, bridge, KGRAM) appear in this package or its sub-packages.
* All errors are reported via the exception hierarchy rooted at
* {@link fr.inria.corese.core.next.query.api.exception.QueryException}.</p>
*/
package fr.inria.corese.core.next.query.api;
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,12 @@ Update prepareUpdate(QueryLanguage queryLanguage, String updateString)
* @throws IllegalStateException if the connection is closed
*/
void rollback() throws RepositoryException;

/**
* Closes this connection and releases any resources it holds.
*
* @throws RepositoryException if closing the connection fails
*/
@Override
void close() throws RepositoryException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package fr.inria.corese.core.next.query.impl.dataset;

import fr.inria.corese.core.next.query.api.dataset.Dataset;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

/**
* Mutable implementation of {@link Dataset}.
*/
public final class CoreseDataset implements Dataset {

private final Set<String> defaultGraphs = new LinkedHashSet<>();
private final Set<String> namedGraphs = new LinkedHashSet<>();

@Override
public Set<String> getDefaultGraphs() {
return Collections.unmodifiableSet(defaultGraphs);
}

@Override
public Set<String> getNamedGraphs() {
return Collections.unmodifiableSet(namedGraphs);
}

@Override
public Dataset addDefaultGraph(String uri) {
defaultGraphs.add(uri);
return this;
}

@Override
public Dataset addNamedGraph(String uri) {
namedGraphs.add(uri);
return this;
}

@Override
public Dataset clear() {
defaultGraphs.clear();
namedGraphs.clear();
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Mutable implementation of the {@link fr.inria.corese.core.next.query.api.dataset.Dataset} API.
*
* <p>Only {@link fr.inria.corese.core.next.query.impl.dataset.CoreseDataset} lives here.
* Users who need a {@code Dataset} instance should import
* {@code CoreseDataset} directly or use a factory in the public API.</p>
*/
package fr.inria.corese.core.next.query.impl.dataset;
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package fr.inria.corese.core.next.query.impl.query;

import fr.inria.corese.core.next.data.api.Value;
import fr.inria.corese.core.next.query.api.Operation;
import fr.inria.corese.core.next.query.api.QueryLanguage;
import fr.inria.corese.core.next.query.api.dataset.Dataset;
import fr.inria.corese.core.next.query.api.result.Binding;
import fr.inria.corese.core.next.query.api.result.BindingSet;
import fr.inria.corese.core.next.query.impl.result.CoreseBinding;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
* Base class for prepared SPARQL operations.
*
* <p>Manages initial bindings, dataset override, inference flag, and timeout.
* Subclasses implement query-type-specific evaluation.</p>
*/
abstract class AbstractCoreseOperation implements Operation {

private final String queryString;
private final QueryLanguage language;
private final LinkedHashMap<String, Value> bindings = new LinkedHashMap<>();
private Dataset dataset;
private boolean includeInferred = true;
private int maxExecutionTime = 0;

protected AbstractCoreseOperation(String queryString, QueryLanguage language) {
this.queryString = queryString;
this.language = language;
}

public String getQueryString() {
return queryString;
}

public QueryLanguage getLanguage() {
return language;
}

@Override
public Operation setBinding(String name, Value value) {
bindings.put(name, value);
return this;
}

@Override
public Operation removeBinding(String name) {
bindings.remove(name);
return this;
}

@Override
public Operation clearBindings() {
bindings.clear();
return this;
}

@Override
public BindingSet getBindings() {
return new MapBackedBindingSet(Map.copyOf(bindings));
}

@Override
public Operation setDataset(Dataset dataset) {
this.dataset = dataset;
return this;
}

@Override
public Dataset getDataset() {
return dataset;
}

@Override
public Operation setIncludeInferred(boolean includeInferred) {
this.includeInferred = includeInferred;
return this;
}

@Override
public boolean getIncludeInferred() {
return includeInferred;
}

@Override
public Operation setMaxExecutionTime(int maxExecutionTimeSeconds) {
this.maxExecutionTime = maxExecutionTimeSeconds;
return this;
}

@Override
public int getMaxExecutionTime() {
return maxExecutionTime;
}

private static final class MapBackedBindingSet implements BindingSet {

private final Map<String, Value> map;

MapBackedBindingSet(Map<String, Value> map) {
this.map = map;
}

@Override
public Set<String> getBindingNames() {
return Collections.unmodifiableSet(map.keySet());
}

@Override
public boolean hasBinding(String name) {
return map.containsKey(name);
}

@Override
public Value getValue(String name) {
return map.get(name);
}

@Override
public Iterator<Binding> iterator() {
return map.entrySet().stream()
.<Binding>map(e -> new CoreseBinding(e.getKey(), e.getValue()))
.iterator();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package fr.inria.corese.core.next.query.impl.query;

import fr.inria.corese.core.next.query.api.BooleanQuery;
import fr.inria.corese.core.next.query.api.Query;
import fr.inria.corese.core.next.query.api.QueryLanguage;
import fr.inria.corese.core.next.query.api.exception.QueryEvaluationException;
import fr.inria.corese.core.next.query.impl.sparql.execution.NextSparqlPipelineExecutor;

/**
* Prepared SPARQL ASK query.
*
* <p>Delegates evaluation to {@link NextSparqlPipelineExecutor}.</p>
*/
public final class CoreseBooleanQuery extends AbstractCoreseOperation implements BooleanQuery {

private final NextSparqlPipelineExecutor executor;
private long timeoutMillis = 0;

public CoreseBooleanQuery(String queryString, QueryLanguage language, NextSparqlPipelineExecutor executor) {
super(queryString, language);
this.executor = executor;
}

@Override
public Query<Boolean> setTimeout(long timeoutMillis) {
this.timeoutMillis = timeoutMillis;
return this;
}

@Override
public QueryType getQueryType() {
return QueryType.BOOLEAN;
}

@Override
public Boolean evaluate() throws QueryEvaluationException {
return executor.evaluateBoolean(getQueryString(), getBindings(), getDataset(), effectiveTimeoutMillis());
}

private long effectiveTimeoutMillis() {
long fromQuery = this.timeoutMillis;
long fromOperation = (long) getMaxExecutionTime() * 1000L;
if (fromQuery > 0 && fromOperation > 0) {
return Math.min(fromQuery, fromOperation);
}
return fromQuery > 0 ? fromQuery : fromOperation;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package fr.inria.corese.core.next.query.impl.query;

import fr.inria.corese.core.next.query.api.GraphQuery;
import fr.inria.corese.core.next.query.api.Query;
import fr.inria.corese.core.next.query.api.QueryLanguage;
import fr.inria.corese.core.next.query.api.exception.QueryEvaluationException;
import fr.inria.corese.core.next.query.api.result.GraphQueryResult;
import fr.inria.corese.core.next.query.impl.sparql.execution.NextSparqlPipelineExecutor;

/**
* Prepared SPARQL CONSTRUCT or DESCRIBE query.
*
* <p>Delegates evaluation to {@link NextSparqlPipelineExecutor}. Initial bindings,
* dataset override, and timeout are propagated into the KGRAM evaluation layer
* on each {@link #evaluate()} call. The CONSTRUCT template is applied to each
* WHERE-clause result mapping to materialise the output statements.</p>
*/
public final class CoreseGraphQuery extends AbstractCoreseOperation implements GraphQuery {

private final NextSparqlPipelineExecutor executor;
private long timeoutMillis = 0;

public CoreseGraphQuery(String queryString, QueryLanguage language, NextSparqlPipelineExecutor executor) {
super(queryString, language);
this.executor = executor;
}

@Override
public Query<GraphQueryResult> setTimeout(long timeoutMillis) {
this.timeoutMillis = timeoutMillis;
return this;
}

@Override
public QueryType getQueryType() {
return QueryType.GRAPH;
}

@Override
public GraphQueryResult evaluate() throws QueryEvaluationException {
return executor.evaluateGraph(getQueryString(), getBindings(), getDataset(), effectiveTimeoutMillis());
}

private long effectiveTimeoutMillis() {
long fromQuery = this.timeoutMillis;
long fromOperation = (long) getMaxExecutionTime() * 1000L;
if (fromQuery > 0 && fromOperation > 0) {
return Math.min(fromQuery, fromOperation);
}
return fromQuery > 0 ? fromQuery : fromOperation;
}
}
Loading
Loading