diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cb1419f31..d86bcd84e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,16 +8,23 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Development] + +## [0.61.0] - 2026-10-18 + ### Added - **GFQL relationship-type adjacency sidecars** (#2184): `gfql_index_edges(..., type_column=..., type_values=...)` explicitly builds forward and reverse adjacency indexes for selected string or integer relationship values. Matching queries can narrow candidate edge rows while retaining the full edge predicate and canonical results; queries without a live sidecar use ordinary adjacency. Sidecars are built at graph setup, share neighbor arrays with ordinary indexes, and appear as `typed:` rows with incremental CSR bytes in `show_indexes()`. Typed options are keyword-only. cuDF builds may add overhead on dense-community shapes, and sidecars must be rebuilt after rebinding or changing edges. -- **GFQL node-type wavefront segments**: `gfql_index_node_types(..., type_column=..., type_values=...)` builds node row-position segments for selected scalar types or Boolean labels. Matching seeded wavefront hops can narrow source and destination candidates while retaining canonical node filters and results; queries without a live segment use the ordinary paths. Node segments are built at graph setup and appear as `typed_node:` `node_type_segment` rows in `show_indexes()`; selective drop supports all segments, one column, or one segment. - +- **GFQL Cypher backtick identifiers**: property names, aliases, labels, relationship types, and map keys can preserve spaces, dots, hyphens, escaped backticks, and reserved words through parsing, binding, lowering, and rendering. Unterminated backticks remain syntax errors, and unquoted dotted-property semantics are unchanged (#2198). +- **GFQL node-type segments and indexed destination filtering** (#2192, #2193): `gfql_index_node_types(..., type_column=..., type_values=...)` explicitly builds node row-position segments for selected scalar types or Boolean labels. Matching seeded wavefront hops can narrow source and destination candidates while retaining canonical node filters and results; queries without a live segment use the ordinary paths. A simple Polars plain-chain destination node predicate may additionally lower into an indexed direct hop; this narrow lowering is separate from general node-segment support. Segments are built at graph setup, appear as `typed_node:` `node_type_segment` rows in `show_indexes()`, and selective drop supports all segments, one column, or one segment. - **GFQL Cypher aggregates over relationship rows**: in a single required `MATCH`, aggregates such as `MATCH (a)-[r]->(b) RETURN a, count(*), sum(r.w), collect(b.id)` run on per-path binding rows, so group keys and arguments can reference any node or relationship alias, including `DISTINCT`, post-aggregate arithmetic (`count(b) + 1`) and multi-alias keys. These shapes previously raised unsupported-query errors. +- **GFQL `DateTimeValue.from_epoch`** (#2197): construct an explicit UTC instant from epoch seconds or milliseconds with `unit="s"|"ms"`; typed wire datetime values accept the equivalent `{"type": "datetime", "value": ..., "unit": "s"|"ms"}` form. ### Fixed +- **GFQL comparison predicates and typed wire inputs reject numeric-versus-datetime comparisons**: a bare integer no longer silently compares as an opaque unitless value against a datetime column. Use a typed ISO datetime value or explicit `DateTimeValue.from_epoch` UTC epoch units. There is no default epoch unit, and `epoch_ms` predicate flags are rejected (#2197). This boundary does not change all mixed-type Cypher `EQ`/`NE` semantics. +- **GFQL Call runtime failures use structured `E306`**: exceptions from safelisted handlers are wrapped as `GFQLCallExecutionError` with the handler name, requested engine, original exception type, and original exception as `__cause__`; input/reference validation retains its existing structured codes (#2199). +- **GFQL index byte reporting is engine-aware** (#2201): `show_indexes()` reports Polars and cuDF sidecar/segment bytes without assuming a pandas-only Series interface. - **GFQL Polars indexed connected bindings**: the default planner gate now admits moderately sized key frontiers and edge gathers. Measured on LDBC SF1 IC4; other families showed no regression, and the relaxation is not claimed to generalize. Explicit cost-gate overrides still take precedence; other index paths and engines retain their defaults. - **GFQL indexed traversal uses faster sorted uniqueness**: integer index arrays with at least 128 entries and Boolean arrays with more than one entry use sorted deduplication, avoiding the slower `numpy.unique` path. Measured on NumPy 2.4; applies on all versions. Tiny integer arrays retain native `unique` because the extra sort/mask setup can cost more there; tiny Boolean arrays favor sorting. Other dtypes and cuPy retain their existing uniqueness semantics. IC4 benchmark evidence and follow-up are tracked in graphistry/pyg-bench#303.