neo4j/cypher-dsl

[Parser] Validate and collect all properties from a clause

Opened this issue · 3 comments

snj07 commented

I want to collect all the properties used for filtering the data and do some validation on them. For example:

String query = "MATCH (start {name: 'v1'}) RETURN count(*) AS COUNT";
var statement = CypherParser.parse(query, options)

In the above query I want to collect vertex property "name". Similarly, I want to collect the properties used in other clauses like WHERE, WITH etc. Is there any possible way to access Clause list of Statement without using reflection so I can collect the properties?
Is it possible to convert org.neo4j.cypherdsl.core.Clause to org.neo4j.cypher.internal.ast.Clause so I can modify the parsed clauses and use Neo4jASTFactory class to create a new Statement?

For retrieving the property filters, you can make use of the recent Catalog feature -> https://neo4j-contrib.github.io/cypher-dsl/2023.3.0/#catalog-support

Here is a simple example and the output

    @Test
    void catalog_usage() {
        parseQuery("MATCH (start {name: 'v1'}) RETURN count(*) AS COUNT");

        parseQuery("MATCH (n:Person {name: 'bob'}) WITH n WHERE n.age > 20 RETURN bob");
    }

    private void parseQuery(String query) {
        Statement statement = CypherParser.parse(query);
        var catalog = statement.getCatalog();
        System.out.println("----");
        catalog.getAllPropertyFilters().forEach((key, value) -> {
            var labels = key.owningToken().stream().toList();
            var label = labels.size() > 0 ? labels.get(0) : "NONE";
            var propertyKey = key.name();
            value.forEach(propertyFilter -> {
                var clause = propertyFilter.clause().name();
                var operator = propertyFilter.operator().name();
                var left = propertyFilter.left().toString();
                var right = propertyFilter.right().toString();

                System.out.println("detected property filter on token `%s` for property `%s` during `%s` clause , operator is `%s`, left is `%s` and right is `%s`".formatted(
//                        owningType,
                        label,
                        propertyKey,
                        clause,
                        operator,
                        left,
                        right
                ));
            });
        });
    }
----
detected property filter on token `NONE` for property `name` during `MATCH` clause , operator is `EQUALITY`, left is `InternalPropertyImpl{cypher=start.name}` and right is `StringLiteral{cypher='v1'}`
----
detected property filter on token `Token[type=NODE_LABEL, value=Person]` for property `name` during `MATCH` clause , operator is `EQUALITY`, left is `InternalPropertyImpl{cypher=n.name}` and right is `StringLiteral{cypher='bob'}`
detected property filter on token `Token[type=NODE_LABEL, value=Person]` for property `age` during `WITH` clause , operator is `GREATER_THAN`, left is `InternalPropertyImpl{cypher=n.age}` and right is `NumberLiteral{cypher=20}`
snj07 commented

I cannot use 2023.3.0, as I'm using Java 11 and it requires Java 17. Is there any other possible way? Could you also suggest a way to add additional clause/filter in parsed dsl?

We don't have plans to backport the catalog feature to Java 8. And in addition, the recent Neo4j parser itself requires JDK 17, so we are bounded on that side anyway.