Skip to content

Commit 0871a59

Browse files
Merge pull request #432 from corese-stack/feature/359-sparql-11-parser-and-ast-regex
feat(#359): SPARQL 1.1 - Parser and AST : REGEX
2 parents e95f2de + 507385b commit 0871a59

1 file changed

Lines changed: 137 additions & 0 deletions

File tree

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package fr.inria.corese.core.next.query.impl.parser;
2+
3+
import fr.inria.corese.core.next.query.api.exception.QueryValidationException;
4+
import fr.inria.corese.core.next.query.impl.sparql.ast.BindAst;
5+
import fr.inria.corese.core.next.query.impl.sparql.ast.FilterAst;
6+
import fr.inria.corese.core.next.query.impl.sparql.ast.LiteralAst;
7+
import fr.inria.corese.core.next.query.impl.sparql.ast.QueryAst;
8+
import fr.inria.corese.core.next.query.impl.sparql.ast.SelectQueryAst;
9+
import fr.inria.corese.core.next.query.impl.sparql.ast.VarAst;
10+
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.BinaryRegexAst;
11+
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.TrinaryRegexAst;
12+
import org.junit.jupiter.api.DisplayName;
13+
import org.junit.jupiter.api.Test;
14+
15+
import static org.junit.jupiter.api.Assertions.assertEquals;
16+
import static org.junit.jupiter.api.Assertions.assertFalse;
17+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
18+
import static org.junit.jupiter.api.Assertions.assertNotNull;
19+
import static org.junit.jupiter.api.Assertions.assertThrows;
20+
21+
@DisplayName("SPARQL 1.1 - Parser and AST : REGEX")
22+
class SparqlParserRegexTest extends AbstractSparqlParserFeatureTest {
23+
24+
@Test
25+
@DisplayName("FILTER(REGEX(?label, \"test\"))")
26+
void shouldParseBinaryRegexInFilter() {
27+
SparqlParser parser = newParserDefault();
28+
29+
QueryAst ast = parser.parse("""
30+
SELECT * WHERE {
31+
?s ?p ?label .
32+
FILTER(REGEX(?label, "test"))
33+
}
34+
""");
35+
36+
assertNotNull(ast);
37+
FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast());
38+
BinaryRegexAst regex = assertInstanceOf(BinaryRegexAst.class, filter.operator());
39+
assertEquals("label", assertInstanceOf(VarAst.class, regex.getString()).name());
40+
assertEquals("\"test\"", assertInstanceOf(LiteralAst.class, regex.getPattern()).lexical());
41+
}
42+
43+
@Test
44+
@DisplayName("BIND(REGEX(?label, \"test\") AS ?matches)")
45+
void shouldParseBinaryRegexInBind() {
46+
SparqlParser parser = newParserDefault();
47+
48+
QueryAst ast = parser.parse("""
49+
SELECT * WHERE {
50+
?s ?p ?label .
51+
BIND(REGEX(?label, "test") AS ?matches)
52+
}
53+
""");
54+
55+
assertNotNull(ast);
56+
BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast());
57+
BinaryRegexAst regex = assertInstanceOf(BinaryRegexAst.class, bind.expression());
58+
assertEquals("label", assertInstanceOf(VarAst.class, regex.getString()).name());
59+
assertEquals("\"test\"", assertInstanceOf(LiteralAst.class, regex.getPattern()).lexical());
60+
assertEquals("matches", bind.variable().name());
61+
}
62+
63+
@Test
64+
@DisplayName("FILTER(REGEX(?label, \"test\", \"i\"))")
65+
void shouldParseTrinaryRegexInFilter() {
66+
SparqlParser parser = newParserDefault();
67+
68+
QueryAst ast = parser.parse("""
69+
SELECT * WHERE {
70+
?s ?p ?label .
71+
FILTER(REGEX(?label, "test", "i"))
72+
}
73+
""");
74+
75+
assertNotNull(ast);
76+
FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast());
77+
TrinaryRegexAst regex = assertInstanceOf(TrinaryRegexAst.class, filter.operator());
78+
assertEquals("label", assertInstanceOf(VarAst.class, regex.getString()).name());
79+
assertEquals("\"test\"", assertInstanceOf(LiteralAst.class, regex.getPattern()).lexical());
80+
assertEquals("\"i\"", assertInstanceOf(LiteralAst.class, regex.getFlags()).lexical());
81+
}
82+
83+
@Test
84+
@DisplayName("BIND(REGEX(?label, \"^hello\", \"i\") AS ?matches)")
85+
void shouldParseTrinaryRegexInBind() {
86+
SparqlParser parser = newParserDefault();
87+
88+
QueryAst ast = parser.parse("""
89+
SELECT * WHERE {
90+
?s ?p ?label .
91+
BIND(REGEX(?label, "^hello", "i") AS ?matches)
92+
}
93+
""");
94+
95+
assertNotNull(ast);
96+
BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast());
97+
TrinaryRegexAst regex = assertInstanceOf(TrinaryRegexAst.class, bind.expression());
98+
assertEquals("label", assertInstanceOf(VarAst.class, regex.getString()).name());
99+
assertEquals("\"^hello\"", assertInstanceOf(LiteralAst.class, regex.getPattern()).lexical());
100+
assertEquals("\"i\"", assertInstanceOf(LiteralAst.class, regex.getFlags()).lexical());
101+
assertEquals("matches", bind.variable().name());
102+
}
103+
104+
@Test
105+
@DisplayName("ORDER BY REGEX(?label, ?pattern)")
106+
void shouldParseOrderByRegexAndValidateVariableScope() {
107+
SparqlParser parser = newParserDefault();
108+
109+
QueryAst ast = parser.parse("""
110+
SELECT ?label WHERE {
111+
?s ?p ?label .
112+
?s <http://example.com/pattern> ?pattern .
113+
} ORDER BY REGEX(?label, ?pattern)
114+
""");
115+
116+
assertNotNull(ast);
117+
SelectQueryAst select = assertInstanceOf(SelectQueryAst.class, ast);
118+
assertFalse(select.solutionModifier().orderBy().isEmpty());
119+
BinaryRegexAst regex = assertInstanceOf(BinaryRegexAst.class, select.solutionModifier().orderBy().getFirst().expression());
120+
assertEquals("label", assertInstanceOf(VarAst.class, regex.getString()).name());
121+
assertEquals("pattern", assertInstanceOf(VarAst.class, regex.getPattern()).name());
122+
}
123+
124+
@Test
125+
@DisplayName("ORDER BY REGEX(?label, ?missing) — should reject variable not visible in WHERE")
126+
void shouldRejectOrderByRegexWhenVariableNotVisibleInWhere() {
127+
SparqlParser parser = newParserDefault();
128+
129+
QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse("""
130+
SELECT ?label WHERE {
131+
?s ?p ?label .
132+
} ORDER BY REGEX(?label, ?missing)
133+
"""));
134+
135+
assertEquals("Variable ?missing used in ORDER BY is not visible in WHERE clause", exception.getMessage());
136+
}
137+
}

0 commit comments

Comments
 (0)