Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .metis/initiatives/GQLITE-I-0049/initiative.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,34 @@ sub-steps once started (human check-in before decomposing, per Metis HITL).

- 2026-05-30: Initiative created. Structure approved (initiative + task-per-cluster).
Starting with Temporal (T-A).
- 2026-06-02: **WithOrderBy (T-D) cluster CLOSED (+10, PR #91).** `WithOrderBy1`
[45] (all 10 type examples). Two root causes: (1) a non-aggregating WITH's
ORDER BY over a *kept* input variable was only applied on the outer SELECT, so a
downstream aggregating WITH (`collect`) never saw sorted rows — now also pushed
into the CTE body via `order_expr_all_live_input` gate in `transform_with.c`
(SQLite preserves an ordered subquery's order through `json_group_array`);
(2) `gql_order_cmp_func`'s temporal compare used `parse_temporal_ns` whose
`epoch*1e9` overflows int64 ~year 2262, so year-9999 datetimes sorted *smallest*
— new overflow-safe `cmp_temporal_strings()` compares `(epoch_seconds, sub_ns)`.
Verified zero regressions, 3776→3786, unit 944/944, functional clean.
- 2026-06-02: **Merge (T-C) — deep architectural blockers identified, deferred.**
Investigated the undirected MATCH+MERGE+RETURN cluster (Merge5 [12]/[13]).
Root cause of row-doubling: the RETURN-after-MERGE re-query builds a synthetic
combined MATCH (original MATCH pattern + MERGE pattern). For undirected
`(a)-[r]-(b)` whose endpoints reuse MATCH variables, the transform re-emits the
shared endpoints into a *reset* FROM and drops the MATCH nodes' property
constraints, so the undirected OR matches each edge twice. A property-transplant
fix (copy MATCH node props onto MERGE endpoints, drop redundant standalone nodes)
was prototyped but blocked by a *second* transform bug: a fresh-fresh undirected
connected pattern in the re-query drops endpoint property joins entirely (the
parsed-equivalent query emits them fine — the re-query path resets the builder
mid-emission). Reverted (no commit). Additional Merge blockers: (a) MERGE
processes only the FIRST match row (`break` in `executor_merge.c` ~line 1088), so
multi-row MATCH+MERGE can't bind/return per-row (Merge8 [1] expects +3 rels);
(b) `handle_create_return` is a hand-rolled projection that doesn't handle
aggregate RETURN items (`count(*)`/`count(a)` → `?column?`/null) — gates
Merge5 [4], Merge9 [3]. These need transform/executor rework, not a contained
fix; left for a dedicated effort.
- 2026-06-02: Comparison2 [3] confirmed blocked by boolean-type-preservation
(`WHERE <bool-var>` and `WHERE b = true` both filter all rows). List12 [1] is the
entity-in-list property access deep item (`x.name` on collected nodes → null).
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,58 @@ All notable changes to GraphQLite are documented here. Format loosely follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
[Semantic Versioning](https://semver.org/).

## [0.6.0] — 2026-06-03

A large openCypher conformance release. TCK pass rate moves from **91.5%**
(3549 executable scenarios) to **97.7%** (3788 / 3876), **+239 scenarios** with
zero regressions among previously-passing scenarios. 944/944 unit tests pass;
functional tests clean.

### Added — openCypher coverage

- **Pattern & path matching completeness** — variable-length path hydration,
`relationships()` / `nodes()` on varlen and null paths, path-wide relationship
uniqueness, multi-rel OPTIONAL MATCH with full-pattern (all-or-none) semantics,
bidirectional bracketed relationship patterns, and four-label conjunctions in
expression context.
- **Temporal** — closed the non-DST temporal cluster: duration arithmetic and
ISO round-trip normalization (months not normalized across days; 1 month =
30.436875 days), `duration.between`, component accessors, `date`/`time`/
`datetime`/`localdatetime` construction and selection, named-zone handling, and
UTC-instant ordering. Cross-type ordering now uses an orderability comparator
with a NaN sentinel and an overflow-safe `(seconds, nanoseconds)` temporal
comparison (far-future years no longer wrap int64 epoch-nanoseconds).
- **Quantifiers** — `all` / `any` / `none` / `single` over list pipelines now
evaluate consistently; non-deterministic CTEs (`rand()`/`RANDOM()` in WITH
projections) are emitted `AS MATERIALIZED` so a multiply-referenced list is
evaluated once, fixing algebraic-identity scenarios.
- **WITH / ORDER BY / aggregation** — `ORDER BY` on a non-aggregating WITH now
flows to a downstream aggregating WITH (`… ORDER BY x WITH collect(y)` collects
in sorted order); computed (non-aggregate) WITH keys (e.g. `a.n % 3 AS m`) are
now GROUP BY keys; `LIMIT`/`OFFSET` inline into the WITH CTE body.
- **Existential subqueries** — `EXISTS { pattern }` brace form.
- **Validation** — compile-time `SyntaxError` diagnostics (pattern expressions in
`SET` RHS, relationship-uniqueness, label/type 3-valued-logic predicates, and
more).

### Fixed

- Multi-row `MATCH … CREATE` / `MATCH … DELETE … CREATE` runs the write per
matched row; inter-pattern variable references in `CREATE` (`{x: a.id}`)
resolve against earlier patterns; `RETURN` is pre-captured before `DELETE`.
- `REMOVE` on a null/unbound variable is a no-op; `RETURN *` excludes synthetic
anonymous aliases.
- General-expression projection in `CREATE … RETURN` and `SET` (list/JSON props).

### Notes

Remaining gaps (~2.3%) concentrate in DST-aware timezone arithmetic, nested
existential subqueries, multi-row MERGE binding, and boolean subtype preservation
(SQLite has no native boolean type). See
[`docs/testing/semantic-coverage-matrix.md`](docs/testing/semantic-coverage-matrix.md).
Windows extension tests (`test_*_timestamp*`) remain non-blocking pending an
MSYS2/MinGW `julianday('now')` regression (GQLITE-T-0205).

## [0.5.0] — 2026-05-22

Significant TCK conformance release plus the first-time Windows extension
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ g.dijkstra("alice", "bob")
- **Zero configuration** — Works with any SQLite database, no server required
- **Multiple bindings** — Python, Rust, and raw SQL interfaces

## openCypher Conformance

GraphQLite is validated against the official [openCypher Technology Compatibility
Kit (TCK)](https://github.com/opencypher/openCypher) — the canonical conformance
suite for the Cypher query language. Current coverage:

| Area | Scenarios | Passing |
|------|-----------|---------|
| **Overall** | **3,876** | **97.7%** |
| Expressions (temporal, lists, maps, comparison, literals, …) | 2,599 | 98.0% |
| Clauses (MATCH, WITH, MERGE, CREATE, SET, DELETE, UNWIND, …) | 1,247 | 97.2% |
| Use cases (triadic selection, subgraph counting) | 30 | 100% |

Run it yourself with `angreal test tck`. The remaining gaps are tracked in
[`docs/testing/semantic-coverage-matrix.md`](docs/testing/semantic-coverage-matrix.md)
and concentrate in a few deep areas (DST-aware timezone arithmetic, nested
existential subqueries, multi-row MERGE). Booleans, strings, null handling,
CREATE/SET/DELETE/REMOVE, UNION, and SKIP/LIMIT are at 100%.

## Documentation

**[Full Documentation](https://colliery-io.github.io/graphqlite/)** — Tutorials, how-to guides, and API reference
Expand Down
2 changes: 1 addition & 1 deletion bindings/python/src/graphqlite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .utils import escape_string, sanitize_rel_type, CYPHER_RESERVED
from ._platform import get_loadable_path

__version__ = "0.5.0"
__version__ = "0.6.0"
__all__ = [
"BulkInsertResult",
"Connection", "connect", "wrap", "load", "loadable_path",
Expand Down
2 changes: 1 addition & 1 deletion bindings/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bindings/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "graphqlite"
version = "0.5.0"
version = "0.6.0"
edition = "2021"
description = "SQLite extension for graph queries using Cypher"
license = "MIT"
Expand Down
Loading