diff --git a/src/main/java/fr/inria/corese/core/next/query/api/exception/UnsupportedQueryFeatureException.java b/src/main/java/fr/inria/corese/core/next/query/api/exception/UnsupportedQueryFeatureException.java new file mode 100644 index 000000000..70a9de447 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/api/exception/UnsupportedQueryFeatureException.java @@ -0,0 +1,27 @@ +package fr.inria.corese.core.next.query.api.exception; + +/** + * Thrown when a syntactically valid query uses a feature not implemented by the current next pipeline. + */ +@SuppressWarnings("java:S110") +public class UnsupportedQueryFeatureException extends QueryException { + + /** + * Constructs an UnsupportedQueryFeatureException with a detail message. + * + * @param message the detail message explaining which query feature is not supported + */ + public UnsupportedQueryFeatureException(String message) { + super(message); + } + + /** + * Constructs an UnsupportedQueryFeatureException with a detail message and cause. + * + * @param message the detail message explaining which query feature is not supported + * @param cause the underlying cause that exposed the unsupported feature + */ + public UnsupportedQueryFeatureException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java index dec830c56..3029681f1 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilder.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.bridge; +import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException; import fr.inria.corese.core.next.query.impl.sparql.ast.*; import fr.inria.corese.core.next.query.impl.sparql.ast.path.PathAst; import fr.inria.corese.core.next.query.impl.sparql.ast.path.PredicatePathAst; @@ -191,20 +192,20 @@ static TermAst simplePredicate(PathAst path) { if (path instanceof PredicatePathAst(TermAst predicate)) { return predicate; } - throw new UnsupportedOperationException( - "Property path bridge compilation is not supported yet for: " + throw new UnsupportedQueryFeatureException( + "Property path bridge compilation is not supported yet by the next pipeline for: " + path.getClass().getSimpleName()); } private static void rejectUnsupportedAskClauses(AskQueryAst askQueryAst) { if (!askQueryAst.valuesClause().mappings().isEmpty()) { - throw new UnsupportedOperationException( - "Inline VALUES is not supported yet for ASK (values handling is a follow-up)"); + throw new UnsupportedQueryFeatureException( + "Inline VALUES is not supported yet by the next pipeline for ASK"); } SolutionModifierAst mod = askQueryAst.solutionModifier(); if (mod.hasGroupBy() || mod.hasHaving() || mod.distinct() || mod.reduced()) { - throw new UnsupportedOperationException( - "Solution modifiers (GROUP BY, HAVING, DISTINCT, REDUCED) are not supported for ASK"); + throw new UnsupportedQueryFeatureException( + "GROUP BY, HAVING, DISTINCT and REDUCED are not supported yet by the next pipeline for ASK"); } // TODO(#388): inline VALUES needs a dedicated runtime mapping. // TODO(#388): GROUP BY / HAVING would require aggregate-aware ASK semantics, not just field copying. @@ -213,22 +214,23 @@ private static void rejectUnsupportedAskClauses(AskQueryAst askQueryAst) { private static void rejectUnsupportedSelectClauses(SelectQueryAst selectQueryAst) { if (!selectQueryAst.valuesClause().mappings().isEmpty()) { - throw new UnsupportedOperationException("VALUES is not supported yet when building a next Query"); + throw new UnsupportedQueryFeatureException( + "Inline VALUES is not supported yet by the next pipeline for SELECT"); } ProjectionAst projection = selectQueryAst.projection(); if (!projection.expressionTerms().isEmpty() || !projection.expressionBoundVariables().isEmpty()) { - throw new UnsupportedOperationException( - "SELECT expressions are not supported yet when building a next Query"); + throw new UnsupportedQueryFeatureException( + "SELECT expressions and aliases are not supported yet by the next pipeline"); } SolutionModifierAst solutionModifier = selectQueryAst.solutionModifier(); if (solutionModifier.reduced()) { - throw new UnsupportedOperationException("REDUCED is not supported yet when building a next Query"); + throw new UnsupportedQueryFeatureException("REDUCED is not supported yet by the next pipeline for SELECT"); } if (solutionModifier.hasGroupBy()) { - throw new UnsupportedOperationException("GROUP BY is not supported yet when building a next Query"); + throw new UnsupportedQueryFeatureException("GROUP BY is not supported yet by the next pipeline for SELECT"); } if (solutionModifier.hasHaving()) { - throw new UnsupportedOperationException("HAVING is not supported yet when building a next Query"); + throw new UnsupportedQueryFeatureException("HAVING is not supported yet by the next pipeline for SELECT"); } // TODO(#387): inline VALUES needs a dedicated runtime mapping. // TODO(#387): SELECT expressions need a clear runtime story for aliases and reuse in later clauses. @@ -238,13 +240,13 @@ private static void rejectUnsupportedSelectClauses(SelectQueryAst selectQueryAst private static void rejectUnsupportedDescribeClauses(DescribeQueryAst describeQueryAst) { if (!describeQueryAst.valuesClause().mappings().isEmpty()) { - throw new UnsupportedOperationException( - "Inline VALUES is not supported yet for DESCRIBE (values handling is a follow-up)"); + throw new UnsupportedQueryFeatureException( + "Inline VALUES is not supported yet by the next pipeline for DESCRIBE"); } SolutionModifierAst mod = describeQueryAst.solutionModifier(); if (mod.hasGroupBy() || mod.hasHaving() || mod.distinct() || mod.reduced()) { - throw new UnsupportedOperationException( - "Solution modifiers (GROUP BY, HAVING, DISTINCT, REDUCED) are not supported for DESCRIBE"); + throw new UnsupportedQueryFeatureException( + "GROUP BY, HAVING, DISTINCT and REDUCED are not supported yet by the next pipeline for DESCRIBE"); } // TODO(#390): inline VALUES needs a dedicated runtime mapping. // TODO(#390): GROUP BY / HAVING would require aggregate-aware DESCRIBE semantics, not just field copying. @@ -465,13 +467,13 @@ private void applyLimitOffset(Query query, SolutionModifierAst solutionModifier) private static void rejectUnsupportedConstructClauses(ConstructQueryAst constructQueryAst) { if (!constructQueryAst.valuesClause().mappings().isEmpty()) { - throw new UnsupportedOperationException( - "Inline VALUES is not supported yet for CONSTRUCT (values handling is a follow-up)"); + throw new UnsupportedQueryFeatureException( + "Inline VALUES is not supported yet by the next pipeline for CONSTRUCT"); } SolutionModifierAst mod = constructQueryAst.solutionModifier(); if (mod.hasGroupBy() || mod.hasHaving() || mod.distinct() || mod.reduced()) { - throw new UnsupportedOperationException( - "Solution modifiers (GROUP BY, HAVING, DISTINCT, REDUCED) are not supported for CONSTRUCT"); + throw new UnsupportedQueryFeatureException( + "GROUP BY, HAVING, DISTINCT and REDUCED are not supported yet by the next pipeline for CONSTRUCT"); } // TODO(#389): inline VALUES needs a dedicated runtime mapping. // TODO(#389): GROUP BY / HAVING would require aggregate-aware CONSTRUCT semantics, not just field copying. diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpression.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpression.java index b2c7aaf80..f47dcc51f 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpression.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpression.java @@ -1,7 +1,8 @@ -package fr.inria.corese.core.next.query.impl.sparql.bridge; - -import fr.inria.corese.core.next.data.impl.io.common.IOConstants; -import fr.inria.corese.core.next.query.impl.sparql.ast.*; +package fr.inria.corese.core.next.query.impl.sparql.bridge; + +import fr.inria.corese.core.next.data.impl.io.common.IOConstants; +import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException; +import fr.inria.corese.core.next.query.impl.sparql.ast.*; import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.*; import fr.inria.corese.core.next.query.kgram.api.core.Filter; import fr.inria.corese.core.next.util.StringUtils; @@ -211,14 +212,15 @@ private static Expression constraintToExpression(ConstraintAst constraint) { case Sha512Ast sha512Ast -> functionTerm("sha512", convert(sha512Ast.argument())); case ExistsAst existsAst -> - throw new UnsupportedOperationException( - "EXISTS { ... } conversion requires GroupGraphPatternAst → Exp (see CoreseAstQueryBuilder)"); - case NotExistsAst notExistsAst -> - throw new UnsupportedOperationException( - "NOT EXISTS { ... } conversion requires GroupGraphPatternAst → Exp (see CoreseAstQueryBuilder)"); - default -> - throw new UnsupportedOperationException( - "Unsupported constraint AST: " + constraint.getClass().getName()); + throw new UnsupportedQueryFeatureException( + "EXISTS filters are not supported yet by the next pipeline"); + case NotExistsAst notExistsAst -> + throw new UnsupportedQueryFeatureException( + "NOT EXISTS filters are not supported yet by the next pipeline"); + default -> + throw new UnsupportedQueryFeatureException( + "Filter expression is not supported yet by the next pipeline: " + + constraint.getClass().getSimpleName()); }; } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java index d5ba13f19..9d304e573 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompiler.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.bridge; +import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException; import fr.inria.corese.core.next.query.impl.sparql.ast.BgpAst; import fr.inria.corese.core.next.query.impl.sparql.ast.BindAst; import fr.inria.corese.core.next.query.impl.sparql.ast.FilterAst; @@ -57,8 +58,9 @@ Exp compile(PatternAst pattern) { case BindAst bind -> compileBind(bind); case ServiceAst service -> compileService(service); case GroupGraphPatternAst group -> compileGroup(group); - default -> throw new UnsupportedOperationException( - "WHERE compilation not yet supported for: " + pattern.getClass().getSimpleName()); + default -> throw new UnsupportedQueryFeatureException( + "WHERE pattern is not supported yet by the next pipeline: " + + pattern.getClass().getSimpleName()); }; } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderAskTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderAskTest.java index 603320a88..7e838d10f 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderAskTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderAskTest.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.bridge; +import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException; import fr.inria.corese.core.next.query.impl.parser.AbstractSparqlParserFeatureTest; import fr.inria.corese.core.next.query.impl.parser.SparqlParser; import fr.inria.corese.core.next.query.impl.sparql.ast.AskQueryAst; @@ -112,14 +113,14 @@ void appliesFromNamedClause() { } @Test - @DisplayName("Inline VALUES is not supported yet → UnsupportedOperationException") + @DisplayName("Inline VALUES is not supported yet -> UnsupportedQueryFeatureException") void rejectsValuesClause() { ValuesAst values = new ValuesAst(List.of( new ValueMappingAst(Map.of(new VarAst("s"), new IriAst("http://example.org/x"))))); AskQueryAst ask = new AskQueryAst( DatasetClauseAst.none(), whereOneTriple(), null, null, values); - assertThrows(UnsupportedOperationException.class, () -> builder.toNextQuery(ask)); + assertThrows(UnsupportedQueryFeatureException.class, () -> builder.toNextQuery(ask)); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderConstructTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderConstructTest.java index 038512d41..41eb7e2ff 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderConstructTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderConstructTest.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.bridge; +import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException; import fr.inria.corese.core.next.query.impl.parser.AbstractSparqlParserFeatureTest; import fr.inria.corese.core.next.query.impl.parser.SparqlParser; import fr.inria.corese.core.next.query.impl.sparql.ast.*; @@ -156,12 +157,12 @@ void appliesOrderBy() { } @Test - @DisplayName("Inline VALUES is not supported yet -> UnsupportedOperationException") + @DisplayName("Inline VALUES is not supported yet -> UnsupportedQueryFeatureException") void rejectsValuesClause() { ValuesAst values = new ValuesAst(List.of(new ValueMappingAst(Map.of(new VarAst("x"), new IriAst("http://example.org/v"))))); ConstructQueryAst construct = new ConstructQueryAst(template(new TriplePatternAst(new VarAst("x"), new VarAst("p"), new VarAst("o"))), DatasetClauseAst.none(), whereSPO(), null, null, values); - assertThrows(UnsupportedOperationException.class, () -> builder.toNextQuery(construct)); + assertThrows(UnsupportedQueryFeatureException.class, () -> builder.toNextQuery(construct)); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderDescribeTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderDescribeTest.java index 96cd4ef93..9400bab37 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderDescribeTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/CoreseAstQueryBuilderDescribeTest.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.bridge; +import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException; import fr.inria.corese.core.next.query.impl.parser.SparqlParser; import fr.inria.corese.core.next.query.impl.sparql.ast.*; import fr.inria.corese.core.next.query.kgram.api.core.Node; @@ -160,25 +161,25 @@ void appliesOrderBy() { } @Test - @DisplayName("Inline VALUES is not supported yet → UnsupportedOperationException") + @DisplayName("Inline VALUES is not supported yet -> UnsupportedQueryFeatureException") void rejectsValuesClause() { ValuesAst values = new ValuesAst(List.of( new ValueMappingAst(Map.of(new VarAst("x"), new IriAst("http://example.org/v"))))); DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new VarAst("x")), whereBindingX(), null, null, values); - assertThrows(UnsupportedOperationException.class, () -> builder.toNextQuery(describe)); + assertThrows(UnsupportedQueryFeatureException.class, () -> builder.toNextQuery(describe)); } @Test - @DisplayName("Unsupported solution modifier (e.g. DISTINCT) → UnsupportedOperationException") + @DisplayName("Unsupported solution modifier (e.g. DISTINCT) -> UnsupportedQueryFeatureException") void rejectsUnsupportedModifier() { SolutionModifierAst mod = SolutionModifierAst.withoutGroupBy( true, false, List.of(), null, null); DescribeQueryAst describe = new DescribeQueryAst( DatasetClauseAst.none(), List.of(new VarAst("x")), whereBindingX(), mod); - assertThrows(UnsupportedOperationException.class, () -> builder.toNextQuery(describe)); + assertThrows(UnsupportedQueryFeatureException.class, () -> builder.toNextQuery(describe)); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpressionTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpressionTest.java index 3233c90b0..bbb853039 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpressionTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpressionTest.java @@ -1,22 +1,21 @@ package fr.inria.corese.core.next.query.impl.sparql.bridge; -import fr.inria.corese.core.kgram.api.core.Edge; +import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException; +import fr.inria.corese.core.next.query.impl.sparql.ast.GroupGraphPatternAst; import fr.inria.corese.core.next.query.impl.sparql.ast.IriAst; import fr.inria.corese.core.next.query.impl.sparql.ast.LiteralAst; -import fr.inria.corese.core.next.query.impl.sparql.ast.TriplePatternAst; import fr.inria.corese.core.next.query.impl.sparql.ast.VarAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.ExistsAst; import fr.inria.corese.core.sparql.triple.parser.Constant; import fr.inria.corese.core.sparql.triple.parser.Expression; import fr.inria.corese.core.sparql.triple.parser.Variable; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import java.util.List; -public class SparqlAstToExpressionTest { +import static org.junit.jupiter.api.Assertions.*; - @Test - void queryAstToQuery() { - } +class SparqlAstToExpressionTest { @Test void iriAstToExpression() { @@ -48,91 +47,14 @@ void varAstToExpression() { assertEquals("var1", varNode.getLabel()); } -// @Test -// void triplePatternAstIriIriIriToEdge() { -// IriAst iri = new IriAst(""); -// -// TriplePatternAst iriiriiri = new TriplePatternAst(iri, iri, iri); -// Edge iriiriiriEdge = SparqlAstToExpression.convert(iriiriiri); -// assertNotNull(iriiriiriEdge); -// assertInstanceOf(Edge.class, iriiriiriEdge); -// assertInstanceOf(Constant.class, iriiriiriEdge.getSubjectNode()); -// assertInstanceOf(Constant.class, iriiriiriEdge.getPropertyNode()); -// assertInstanceOf(Constant.class, iriiriiriEdge.getObjectNode()); -// } -// -// @Test -// void triplePatternAstIriIriLitToEdge() { -// IriAst iri = new IriAst(""); -// LiteralAst lit = new LiteralAst("1234", "fr", null); -// VarAst var = new VarAst("var1"); -// -// TriplePatternAst iriirilit = new TriplePatternAst(iri, iri, lit); -// Edge iriirilitEdge = SparqlAstToExpression.convert(iriirilit); -// assertNotNull(iriirilitEdge); -// assertInstanceOf(Edge.class, iriirilitEdge); -// assertInstanceOf(Constant.class, iriirilitEdge.getSubjectNode()); -// assertInstanceOf(Constant.class, iriirilitEdge.getPropertyNode()); -// assertInstanceOf(Constant.class, iriirilitEdge.getObjectNode()); -// } -// -// @Test -// void triplePatternAstVarIriLitToEdge() { -// IriAst iri = new IriAst(""); -// LiteralAst lit = new LiteralAst("1234", "fr", null); -// VarAst var = new VarAst("var1"); -// -// TriplePatternAst varirilit = new TriplePatternAst(var, iri, lit); -// Edge varirilitEdge = SparqlAstToExpression.convert(varirilit); -// assertNotNull(varirilitEdge); -// assertInstanceOf(Edge.class, varirilitEdge); -// assertInstanceOf(Variable.class, varirilitEdge.getSubjectNode()); -// assertInstanceOf(Constant.class, varirilitEdge.getPropertyNode()); -// assertInstanceOf(Constant.class, varirilitEdge.getObjectNode()); -// } -// -// @Test -// void triplePatternAstIriVarLitToEdge() { -// IriAst iri = new IriAst(""); -// LiteralAst lit = new LiteralAst("1234", "fr", null); -// VarAst var = new VarAst("var1"); -// -// TriplePatternAst irivarlit = new TriplePatternAst(iri, var, lit); -// Edge irivarlitEdge = SparqlAstToExpression.convert(irivarlit); -// assertNotNull(irivarlitEdge); -// assertInstanceOf(Edge.class, irivarlitEdge); -// assertInstanceOf(Constant.class, irivarlitEdge.getSubjectNode()); -// assertInstanceOf(Variable.class, irivarlitEdge.getPropertyNode()); -// assertInstanceOf(Constant.class, irivarlitEdge.getObjectNode()); -// } -// -// @Test -// void triplePatternAstVarIriVarToEdge() { -// IriAst iri = new IriAst(""); -// VarAst var1 = new VarAst("var1"); -// VarAst var2 = new VarAst("var2"); -// -// TriplePatternAst varirivar = new TriplePatternAst(var1, iri, var2); -// Edge varirivarEdge = SparqlAstToExpression.convert(varirivar); -// assertNotNull(varirivarEdge); -// assertInstanceOf(Edge.class, varirivarEdge); -// assertInstanceOf(Variable.class, varirivarEdge.getSubjectNode()); -// assertInstanceOf(Constant.class, varirivarEdge.getPropertyNode()); -// assertInstanceOf(Variable.class, varirivarEdge.getObjectNode()); -// } -// -// @Test -// void triplePatternAstVarVarVarToEdge() { -// VarAst var1 = new VarAst("var1"); -// VarAst var2 = new VarAst("var2"); -// VarAst var3 = new VarAst("var3"); -// -// TriplePatternAst varirivar = new TriplePatternAst(var1, var2, var3); -// Edge varirivarEdge = SparqlAstToExpression.convert(varirivar); -// assertNotNull(varirivarEdge); -// assertInstanceOf(Edge.class, varirivarEdge); -// assertInstanceOf(Variable.class, varirivarEdge.getSubjectNode()); -// assertInstanceOf(Variable.class, varirivarEdge.getPropertyNode()); -// assertInstanceOf(Variable.class, varirivarEdge.getObjectNode()); -// } + @Test + void existsFilterFailsWithUnsupportedQueryFeatureException() { + ExistsAst exists = new ExistsAst(new GroupGraphPatternAst(List.of())); + + UnsupportedQueryFeatureException error = assertThrows( + UnsupportedQueryFeatureException.class, + () -> SparqlAstToExpression.convert(exists)); + + assertTrue(error.getMessage().contains("EXISTS filters")); + } } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompilerTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompilerTest.java index 495165013..003cce741 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompilerTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/sparql/bridge/WhereCompilerTest.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.bridge; +import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException; import fr.inria.corese.core.next.query.impl.parser.AbstractSparqlParserFeatureTest; import fr.inria.corese.core.next.query.impl.sparql.ast.*; import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.FunctionCallAst; @@ -186,6 +187,18 @@ void bindShouldPropagateFunctionalFlag() { assertTrue(bindExp.isFunctional(), "BIND exp should propagate functional flag"); } + @Test + @DisplayName("Unsupported WHERE pattern kinds fail with UnsupportedQueryFeatureException") + void unsupportedPatternFailsWithTypedException() { + SubQueryAst subQuery = new SubQueryAst(new SelectQueryAst(group(bgp("s", "p", "o")))); + + UnsupportedQueryFeatureException error = assertThrows( + UnsupportedQueryFeatureException.class, + () -> compiler.compile(subQuery)); + + assertTrue(error.getMessage().contains("WHERE pattern")); + } + @Test @DisplayName("SERVICE SILENT sets the isSilent flag") void compilesServiceSilent() {