8000 test(spec): hold the examples and every inferred type to the format by colinhacks · Pull Request #188 · colinhacks/reylo · GitHub
[go: up one dir, main page]

Skip to content

test(spec): hold the examples and every inferred type to the format - #188

Open
colinhacks wants to merge 4 commits into
mainfrom
spec-held-to-engine
Open

colinhacks wants to merge 4 commits into
mainfrom
spec-held-to-engine

Conversation

@colinhacks
@colinhacks colinhacks commented Nov 5, 2026 •
Copy link
Copy Markdown
Owner

This makes the tests fail whenever the type descriptor spec promises something the engine does not print.

For example, the spec's MySQL example promised that a varchar(100) column prints size: { max: 100 }. Nothing checked that, and the engine printed no size at all. Now a test runs each example's DDL and statement through the engine and fails if the result differs from the example. Its first run found 12 such differences, listed below.

Two smaller changes go with it: the soundness oracle checks every type it infers against the format's own rules, and the Rust tests read the same examples instead of keeping a hand-copied subset.

What is now checked

  • Examples held to the engine (tests/spec-examples.test.ts). Each example in spec/examples.ts now carries its schema and statement beside its descriptor. For Postgres, MySQL, SQLite and DuckDB, the test runs them on an empty database of the example's own through the root module's compile and compares every field the example shows, all but the server's version, and holds the whole descriptor to the JSON Schema with no diagnostic. SQL Server's and Oracle's stay hand-written, and the file says so. Compared rather than generated, so the file keeps its shared constants and its prose.
  • Every inferred type checked (oracle/src/validity.rs). Every parameter's and column's type of every analysis the oracle makes, in its cases and its replays, must be a Type of spec/typedefs.schema.json, read and write back as the same JSON, and pass rule 7 (Type::check). A violation fails the case, or counts as a contradiction in a replay.
  • One shared copy (spec/examples.json). nub run typedefs writes it from spec/examples.ts and --check holds it current. Core's tests read it, round-trip and check every type in it, and keep literal JSON only for what no example shows.

Other changes this brings

  • CI's test job runs pgvector/pgvector:pg18, Postgres 18 with the extension installed, since CI fails on a skip and the vector example needs it. It is its own example, so everything else runs on any Postgres, and it skips where the extension is missing.
  • The oracle gains one dependency, boon, a JSON Schema 2020-12 validator, and eight crates under it. The oracle is not published and the reylo binary does not link them.
  • A change to spec/typedefs.schema.json or spec/examples.json now runs every engine check, since the engine's tests and the oracle read them.

Examples changed, where the engine is right

Example The spec said The engine prints, and why it is right
first_example, sql select id, email, bio from users where id = $1 The same with its leading -- One user, by id. line: the field is the statement as the database runs it
mysql_columns, next (:n + 1) The union's members unnamed bigint, double and decimal: a type's name is the database's name for it
sqlite_columns, price (price numeric) name: "NUMERIC" name: "numeric": SQLite reports a declared type as written, but for its own words (INT, INTEGER, REAL, TEXT, BLOB)
structured_param, its statement rows(kind varchar(32), at timestamptz?), which is a syntax error and leaves kind nullable rows(kind varchar(32) not null, at timestamptz); the descriptor it shows is unchanged

Examples changed, where the engine is less precise

Each example now says what the engine writes today, with a note where the gap is. None is unsound: each type holds every value the column can.

Column DDL The spec said The engine prints
Postgres e email, a domain: varchar(255) check (value like '%@%') size: {max: 255}, pattern: {dialect: "like", source: "%@%"}, name: "public.email" size: {max: 255}, name: "varchar": the server describes a domain's column by its base type, and no engine writes pattern
MySQL at timestamp(3) tick: "1/1000", max: "2038-01-19T03:14:07.999Z" tick: "1/1000000", max: "2038-01-19T03:14:07.999999Z"
MySQL status enum('b','a') enum: ["b", "a"] No enum
MySQL name varchar(100) size: {max: 100} No size
MySQL body text size: {unit: "byte", encoding: "UTF-8", max: 65535} No size
MySQL tags set('a','b') size: {max: 2}, element enum: ["a", "b"] No size, element plain text
SQLite x Declared with no type The union of integer, float, text and bytes {kind: "unknown"}
SQLite n integer in a STRICT table integer alone The union of integer, float, text and bytes, named INTEGER

#186 makes n integer alone, and whichever of the two lands second updates the example.

What the oracle found

Every type passed in the 170 cases. The replays found one limitation: --replay postgres reports 8 contradictions, because the engine writes a Postgres range over an array, a composite or a varbit as it is, and the schema's OrderedType refused those subtypes. It is settled: #177 lets subtype on range and multirange be any Type, so the 8 go away when it lands. No case in oracle/cases has such a type, so CI's oracle passes without it.

What ran

  • cargo build --workspace --all-targets, no warning, and cargo test of every engine crate and the oracle.
  • nub run typecheck; nub run test on Postgres 18.6 and MySQL 8.4.11: 365 passed, none skipped.
  • The whole oracle with --strict-coverage, on Postgres 18.6 with pgvector, PostGIS and the five validators, MySQL 8.4.11, SQLite and DuckDB (--features duckdb): 170 cases, none failed and no violation.
  • The replays, beyond what CI runs: SQLite's suite (31,539 statements) and MySQL's (42,952) with no contradiction; Postgres's (24,990) with the 8 above. DuckDB's aborted about 35 minutes in, in a debug build, with Rust cannot catch foreign exceptions, before its report, and printed no violation up to there.
  • By hand: a wrong example fails the examples test, and an invalid type given through --analyses fails its case under all three rules.

@vercel
vercel Bot commented Nov 5, 2026 •
Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
reylo Ready Ready Preview Nov 5, 2026 5:29pm UTC

Request Review

Copilot AI balanced review requested due to automatic review settings November 5, 2026 15:30
Copilot AI left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@pullfrog pullfrog Bot left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No critical issues — one small coverage gap inline.

Reviewed changes

Reviewed the whole PR at 814cf10: the spec's examples now run on each engine, the oracle checks every type it infers, and core's tests read one shared copy of the examples.

  • Examples carry their SQL: each export of spec/examples.ts is now an Example with its setup and statement. tests/spec-examples.test.ts runs the Postgres, MySQL, SQLite and DuckDB ones through reylo/rtd's analyze and compares every field each example shows. Several examples were corrected to what the engine actually prints.
  • spec/examples.json generated: spec/generate.ts writes it from the module's exports, and --check (in tests/typedefs.test.ts) keeps it current. Core's types.rs tests round-trip it and run check on every type in it.
  • Oracle validity check: the new oracle/src/validity.rs (built on boon) holds each parameter's and column's type to $defs/Type, a serde round trip and Type::check. A violation fails the case, and in a replay it counts as a contradiction.
  • CI: the test job's Postgres is now pgvector/pgvector:pg18. A change to spec/typedefs.schema.json or spec/examples.json now runs every engine check.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using claude-opus-5-5 | 𝕏

Comment thread engine/core/src/types.rs Resolved
@pullfrog pullfrog Bot left a comment
Copy link
Copy Markdown
Contributor

Choose a re 8000 ason for hiding this comment

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

✅ No new issues found. The earlier coverage gap is closed.

Reviewed changes

Reviewed ca0015e, the one commit added since the review at 814cf10.

  • Restored literal round trips for kinds no example shows: core's types.rs tests now round-trip uuid again, and also datetime (with its required tick), multirange and any. No export of spec/examples.ts holds these four kinds, so now an example or a literal line reads every kind in the schema.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

Each example now carries its schema and statement. A test runs them on the
database and compares every field the example shows with what the engine
writes, so an example can no longer promise what the engine does not write.
spec/examples.json, which the spec's generator writes, replaces the subset
core's tests copied by hand.
Each parameter's and column's type must be a Type of the JSON Schema, read
and write back as the same JSON, and pass rule 7. Nested JSON shapes, unions
and structured parameters are built per statement, so no table of built-in
types covers them.

This branch has not been deployed

No deployments
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

0