Skip to content

Commit 112857e

Browse files
Merge branch 'neo4j-cypher-query-parser' into feature/cql-query-parser
2 parents 5257564 + 2e7d1d8 commit 112857e

33 files changed

Lines changed: 6368 additions & 0 deletions

client-java/controller/src/main/antlr4/org/evomaster/client/java/controller/neo4j/cypher25/Cypher25Lexer.g4

Lines changed: 1402 additions & 0 deletions
Large diffs are not rendered by default.

client-java/controller/src/main/antlr4/org/evomaster/client/java/controller/neo4j/cypher25/Cypher25Parser.g4

Lines changed: 2024 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.evomaster.client.java.controller.neo4j.conditions;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.List;
6+
7+
/**
8+
* Represents a logical AND of multiple conditions.
9+
*/
10+
public class AndCondition implements CypherCondition {
11+
12+
private final List<CypherCondition> conditions;
13+
14+
public AndCondition(List<CypherCondition> conditions) {
15+
this.conditions = conditions != null ? new ArrayList<>(conditions) : new ArrayList<>();
16+
}
17+
18+
public List<CypherCondition> getConditions() {
19+
return Collections.unmodifiableList(conditions);
20+
}
21+
22+
@Override
23+
public String toString() {
24+
StringBuilder sb = new StringBuilder("(");
25+
for (int i = 0; i < conditions.size(); i++) {
26+
if (i > 0) sb.append(" AND ");
27+
sb.append(conditions.get(i));
28+
}
29+
sb.append(")");
30+
return sb.toString();
31+
}
32+
33+
@Override
34+
public boolean equals(Object o) {
35+
if (this == o) return true;
36+
if (o == null || getClass() != o.getClass()) return false;
37+
AndCondition that = (AndCondition) o;
38+
return conditions.equals(that.conditions);
39+
}
40+
41+
@Override
42+
public int hashCode() {
43+
return conditions.hashCode();
44+
}
45+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.evomaster.client.java.controller.neo4j.conditions;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* The any-label wildcard % in a label expression, e.g. (n:%). Satisfied when the element
7+
* bound to the variable has a non-empty label set.
8+
*/
9+
public class AnyLabelCondition implements CypherCondition {
10+
11+
private final String variableName;
12+
13+
public AnyLabelCondition(String variableName) {
14+
this.variableName = variableName;
15+
}
16+
17+
public String getVariableName() {
18+
return variableName;
19+
}
20+
21+
@Override
22+
public String toString() {
23+
return variableName + ":%";
24+
}
25+
26+
@Override
27+
public boolean equals(Object o) {
28+
if (this == o) return true;
29+
if (o == null || getClass() != o.getClass()) return false;
30+
return Objects.equals(variableName, ((AnyLabelCondition) o).variableName);
31+
}
32+
33+
@Override
34+
public int hashCode() {
35+
return variableName != null ? variableName.hashCode() : 0;
36+
}
37+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package org.evomaster.client.java.controller.neo4j.conditions;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* An operand that is an arithmetic expression over other operands, e.g. {@code p.age + 5} or
7+
* {@code -n.weight}. Keeps the structure (operator + sub-operands) instead of the original text,
8+
* so the inner {@link PropertyOperand}s stay resolvable per mapping and the heuristics calculator
9+
* can valuate {@code v(x op y) = apply(op, v(left), v(right))}.
10+
*
11+
* <p>Fully-literal subtrees are folded to a {@link LiteralOperand} at parse time, so this class only
12+
* ever holds an expression that still depends on the graph (at least one property reference).
13+
*
14+
* <p>For {@link ArithmeticOperator#NEGATE} (unary minus) the operand is {@link #getLeft()} and
15+
* {@link #getRight()} is {@code null}.
16+
*/
17+
public final class ArithmeticOperand implements Operand {
18+
19+
private final ArithmeticOperator operator;
20+
private final Operand left;
21+
private final Operand right;
22+
23+
public ArithmeticOperand(ArithmeticOperator operator, Operand left, Operand right) {
24+
this.operator = operator;
25+
this.left = left;
26+
this.right = right;
27+
}
28+
29+
public ArithmeticOperator getOperator() {
30+
return operator;
31+
}
32+
33+
public Operand getLeft() {
34+
return left;
35+
}
36+
37+
public Operand getRight() {
38+
return right;
39+
}
40+
41+
@Override
42+
public String toString() {
43+
if (operator == ArithmeticOperator.NEGATE) {
44+
return "-" + left;
45+
}
46+
return "(" + left + " " + symbol() + " " + right + ")";
47+
}
48+
49+
private String symbol() {
50+
switch (operator) {
51+
case PLUS: return "+";
52+
case MINUS: return "-";
53+
case TIMES: return "*";
54+
case DIVIDE: return "/";
55+
case MODULO: return "%";
56+
case POWER: return "^";
57+
default: return "?";
58+
}
59+
}
60+
61+
@Override
62+
public boolean equals(Object o) {
63+
if (this == o) return true;
64+
if (o == null || getClass() != o.getClass()) return false;
65+
ArithmeticOperand that = (ArithmeticOperand) o;
66+
return operator == that.operator
67+
&& Objects.equals(left, that.left)
68+
&& Objects.equals(right, that.right);
69+
}
70+
71+
@Override
72+
public int hashCode() {
73+
int result = operator != null ? operator.hashCode() : 0;
74+
result = 31 * result + (left != null ? left.hashCode() : 0);
75+
result = 31 * result + (right != null ? right.hashCode() : 0);
76+
return result;
77+
}
78+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.evomaster.client.java.controller.neo4j.conditions;
2+
3+
/**
4+
* The arithmetic connectives an {@link ArithmeticOperand} can carry. Binary operators map to the
5+
* Cypher tokens {@code + - * / % ^}; {@link #NEGATE} is unary minus (its operand is the left side).
6+
*/
7+
public enum ArithmeticOperator {
8+
PLUS,
9+
MINUS,
10+
TIMES,
11+
DIVIDE,
12+
MODULO,
13+
POWER,
14+
NEGATE
15+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.evomaster.client.java.controller.neo4j.conditions;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* A comparison from a WHERE clause: left OP right.
7+
* Both sides are typed {@link Operand}s so each can be valuated against the graph
8+
* independently. The right operand is null for the unary IS NULL / IS NOT NULL operators.
9+
*/
10+
public class ComparisonCondition implements CypherCondition {
11+
12+
private final Operand left;
13+
private final ComparisonOperator operator;
14+
private final Operand right;
15+
16+
public ComparisonCondition(Operand left, ComparisonOperator operator, Operand right) {
17+
this.left = left;
18+
this.operator = operator;
19+
this.right = right;
20+
}
21+
22+
public Operand getLeft() {
23+
return left;
24+
}
25+
26+
public ComparisonOperator getOperator() {
27+
return operator;
28+
}
29+
30+
public Operand getRight() {
31+
return right;
32+
}
33+
34+
@Override
35+
public String toString() {
36+
if (right == null) {
37+
return left + " " + operator.getSymbol();
38+
}
39+
return left + " " + operator.getSymbol() + " " + right;
40+
}
41+
42+
@Override
43+
public boolean equals(Object o) {
44+
if (this == o) return true;
45+
if (o == null || getClass() != o.getClass()) return false;
46+
ComparisonCondition that = (ComparisonCondition) o;
47+
return operator == that.operator
48+
&& Objects.equals(left, that.left)
49+
&& Objects.equals(right, that.right);
50+
}
51+
52+
@Override
53+
public int hashCode() {
54+
int result = left != null ? left.hashCode() : 0;
55+
result = 31 * result + (operator != null ? operator.hashCode() : 0);
56+
result = 31 * result + (right != null ? right.hashCode() : 0);
57+
return result;
58+
}
59+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.evomaster.client.java.controller.neo4j.conditions;
2+
3+
/**
4+
* Comparison operators used in Cypher WHERE clauses.
5+
*/
6+
public enum ComparisonOperator {
7+
EQUALS("="),
8+
NOT_EQUALS("<>"),
9+
LESS_THAN("<"),
10+
LESS_THAN_OR_EQUALS("<="),
11+
GREATER_THAN(">"),
12+
GREATER_THAN_OR_EQUALS(">="),
13+
STARTS_WITH("STARTS WITH"),
14+
ENDS_WITH("ENDS WITH"),
15+
CONTAINS("CONTAINS"),
16+
IN("IN"),
17+
IS_NULL("IS NULL"),
18+
IS_NOT_NULL("IS NOT NULL");
19+
20+
private final String symbol;
21+
22+
ComparisonOperator(String symbol) {
23+
this.symbol = symbol;
24+
}
25+
26+
public String getSymbol() {
27+
return symbol;
28+
}
29+
30+
public static ComparisonOperator fromSymbol(String symbol) {
31+
for (ComparisonOperator op : values()) {
32+
if (op.symbol.equalsIgnoreCase(symbol)) {
33+
return op;
34+
}
35+
}
36+
return null;
37+
}
38+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.evomaster.client.java.controller.neo4j.conditions;
2+
3+
/**
4+
* Represents a condition extracted from a Cypher query.
5+
* Conditions can come from:
6+
* - Node labels: (n:Person) → LabelCondition
7+
* - Node properties: (n {name: "Alice"}) → PropertyCondition
8+
* - Edge types: -[:KNOWS]-> → TypeCondition
9+
* - Edge properties: -[:KNOWS {since: 2020}]-> → PropertyCondition
10+
* - WHERE clause: WHERE n.age > 25 → ComparisonCondition
11+
* - Logical operators: AND, OR, NOT
12+
*/
13+
public interface CypherCondition {
14+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.evomaster.client.java.controller.neo4j.conditions;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* Represents a label condition: n:Label
7+
* Extracted from patterns like (n:Person) or (n:Person:Employee)
8+
*/
9+
public class LabelCondition implements CypherCondition {
10+
11+
private final String variableName;
12+
private final String label;
13+
14+
public LabelCondition(String variableName, String label) {
15+
this.variableName = variableName;
16+
this.label = label;
17+
}
18+
19+
public String getVariableName() {
20+
return variableName;
21+
}
22+
23+
public String getLabel() {
24+
return label;
25+
}
26+
27+
@Override
28+
public String toString() {
29+
return variableName + ":" + label;
30+
}
31+
32+
@Override
33+
public boolean equals(Object o) {
34+
if (this == o) return true;
35+
if (o == null || getClass() != o.getClass()) return false;
36+
LabelCondition that = (LabelCondition) o;
37+
if (!Objects.equals(variableName, that.variableName)) return false;
38+
return Objects.equals(label, that.label);
39+
}
40+
41+
@Override
42+
public int hashCode() {
43+
int result = variableName != null ? variableName.hashCode() : 0;
44+
result = 31 * result + (label != null ? label.hashCode() : 0);
45+
return result;
46+
}
47+
}

0 commit comments

Comments
 (0)