Skip to content

Make @CompileQuery query rewriting strict and part of the build - #11

Open
zijian-yi wants to merge 5 commits into
EngineeringSoftware:query-rewriting-cifrom
zijian-yi:query-rewriting-hardening
Open

zijian-yi wants to merge 5 commits into
EngineeringSoftware:query-rewriting-cifrom
zijian-yi:query-rewriting-hardening

Conversation

@zijian-yi

@zijian-yi zijian-yi commented Oct 19, 2026 •

Copy link
Copy Markdown

Problem

Before this PR, @CompileQuery rewriting could fail without anyone noticing. A query the compiler couldn't handle fell back to the interpreter, or had parts dropped (WHERE, DISTINCT, WITH, …), and the tests still passed. Some code paths called System.exit. The plugin had no tests.

Changes

  • One strict rewriter. The new QueryRewriter replaces the duplicated logic in CodegenMojo and ImplCodeGen; ImplCodeGen is removed. Unsupported Cypher, syntax errors and non-literal query arguments now fail the build, naming the file and line. All System.exit calls are gone.
  • Build integration. A compile-queries profile runs the codegen, and a new compiled-queries-ci.yml workflow runs the rewritten tests. Generated tests go to target/generated-test-sources/compiled-queries instead of src/test. @CompileQuery is documented as test-only.
  • Tests.
    • QueryRewriterTest covers rewriting and error cases.
    • CodegenMojoTest adds the plugin's first tests.
    • CompiledQueryTest checks that compiled results match the interpreter for 12 query shapes.
  • Dependencies. The plugin adds JUnit 5 at test scope for its new tests and drops antlr/javaparser, which the rewritten Mojo no longer uses. The scoping fix is in Scope junit-jupiter-engine to test and drop unused plugin test deps #12.

Testing

Ran each workflow's steps locally:

  • Compiled Queries CI: plugin 7 tests pass, and the 29 rewritten tests pass.
  • Test and Coverage CI: 241 tests pass, with line coverage at 81.7% (gate is 70%).
  • Spotless is clean.

🤖 Generated with Claude Code using Claude Opus 5.5 (claude-opus-5-5)

- Merge the duplicated rewriters (CodegenMojo and ImplCodeGen) into
  org.estore.compiler.QueryRewriter; both entry points now delegate to it.
- Fail instead of silently falling back: Cypher syntax errors, non-literal
  query arguments, annotated methods without a query, and unparseable
  generated code raise QueryCompileException, which the Mojo reports as a
  MojoExecutionException naming the file.
- CodeGenBuilder rejects constructs it used to drop or crash on (WHERE,
  OPTIONAL MATCH, DISTINCT, ORDER BY/SKIP/LIMIT, WITH, UNION, UNWIND, SET,
  multi-variable DELETE) and replaces System.exit calls with exceptions.
  Remove the never-implemented compiler NodePropScan.
- Add a compile-queries profile in estore/pom.xml and use it in CI instead
  of invoking the plugin goal by hand.
- Tests: QueryRewriterTest, CodegenMojoTest (first plugin tests), and
  CompiledQueryTest, which checks compiled results against the interpreter
  for each supported query shape.
- Scope junit-jupiter-engine to test in estore so it no longer leaks into
  consumers; drop unused plugin dependencies.
The codegen Mojo now writes Transformed*Test.java into
target/generated-test-sources/compiled-queries (same package layout) and
registers that directory as a test source root, instead of writing next to
the original sources in src/test. Stale output is cleared on each run, and
mvn clean removes it.

Drop the .gitignore rule for in-tree Transformed*Test.java so leftover
copies from the old layout show up in git status rather than causing
duplicate-class compile errors.
ImplCodeGen was the original standalone rewriter, reachable only through
an exec:java@compile entry; the codegen plugin replaces it. Removing it
lets QueryRewriter drop its lenient rewrite-everything mode, so it now
has a single strict path with one place that adds error context.

Also drop per-file timing from the Mojo, remove tests that duplicated
coverage elsewhere, and share one helper across CompiledQueryTest's
mutation cases.
The Mojo deletes outputDir on every run, and outputDir can be overridden
with -DoutputDir, so a mistaken path such as src/test/java would wipe the
test sources. Fail with a clear message instead.
@zijian-yi
zijian-yi changed the base branch from main to query-rewriting-ci October 19, 2026 18:44
<artifactId>estore</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a good catch, but can we have this in a separate PR
the entire dependency change

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #11

Comment thread README.md Outdated

#### Run Tests with Compiled Queries

Test methods annotated with `@CompileQuery` can also run with their Cypher queries compiled

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If CompileQuery can only be used on tests, let's make that explicit (or be specific about locations)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, will potentially support non-test case in a future PR.

Comment thread estore/pom.xml Outdated
target/generated-test-sources/compiled-queries before the tests compile. The plugin
depends on this module, so it cannot be in the same reactor (even with -pl): install it
first, then build this module's POM directly, e.g.
mvn -pl estore -am install -DskipTests && mvn -pl estore-maven-plugin install

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel we are repeating this too many times; can we remove from here; we have in README and in one action; that should be good enough

import org.estore.compiler.QueryRewriter;

/**
* Rewrites the queries in every {@code @CompileQuery} method under {@code sourceDir} into Java

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this answers the other question


@Test
void writesTransformedFileIntoOutputPackage() throws Exception {
writeSource("ATest", " @CompileQuery void m() { db.query(\"MATCH (n) RETURN n\"); }\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we use diff names in case tests end up running in parallel? Maybe we based it on the name of the test itself

"FTest",
" @CompileQuery void m() { db.query(\"MATCH (n) RETURN n\"); }\n");
runMojo();
Files.delete(source);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we assert after this that it was deleted and before that it exists

@gliga gliga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a separate CI action for rewrite tests

- Move the dependency scoping fix to its own PR. This PR keeps only the
  plugin's test-scoped JUnit 5 for its new tests and drops antlr and
  javaparser, which the rewritten Mojo no longer imports.
- Run the rewritten tests in a separate Compiled Queries CI workflow;
  restore test-ci and coverage-ci to their main versions.
- State in the README and the @CompileQuery javadoc that the annotation
  is for test methods only.
- Remove the build instructions from the estore POM; the README and the
  workflow cover them.
- CodegenMojoTest: derive class names from each test's method name, and
  check that generated output exists before the source is deleted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants