Skip to content

Order two lists item by item with <, <=, > and >= on Postgres and Oracle, and refuse toString() of a list or a map - #248

Merged
jasperblues merged 3 commits into
mainfrom
list-order
Oct 28, 2026
Merged

jasperblues merged 3 commits into
mainfrom
list-order

Conversation

@jasperblues

Copy link
Copy Markdown
Member

Port of liberation-data/drivine4j#349 (drivine4j PR #361, merged as 3c5c4e5).

The SQL stores gave null for <, <=, > and >= of two lists. Where the statement makes either side a list, the two are now ordered item by item, as Cypher orders them. The first pair that is not equal decides, and a list that starts the other comes first. A pair with a null, of two kinds, or of two maps that differ is not ordered, so the comparison is null.

SQL: every v0.6.18 spec statement, 998 of them, compiles byte for byte as before on both Postgres and Oracle. The 33 statements new in v0.6.19 compile to the same SQL as Drivine for TypeScript's, once each library's driver wrapper is normalised.

Tests beyond the spec, ported from drivine4j:

  • tests/integration/test_cypher_compiled.py, and its sync copy, cover:
    • [[]] < [[], 1];
    • integers past 2^53;
    • nested and null-bearing temporal lists;
    • [] < [duration('P1D')];
    • list compare in an aggregate's argument;
    • list compare beside a walk;
    • a comparison against a 150-item literal;
    • lists read out of an unwound map.
  • tests/unit/test_cypher_compiled_size.py checks that Oracle declares the function once and calls it.
  • tests/unit/test_cypher_refusals.py checks the toString() refusal and the two Oracle refusals.

Known limits, kept as they are:

  • two parameters whose kind is left open give null (drivine4j#385);
  • maps inside lists (drivine4j#386);
  • Oracle floats outside NUMBER (drivine4j#383).

Fixes #215

…cle, and refuse toString() of a list or a map

Port of liberation-data/drivine4j#349 (drivine4j PR #361). The SQL stores gave null for <, <=, >
and >= of two lists. Where the statement makes either side a list, the two are now ordered item by
item, as Cypher orders them: the first pair that is not equal decides, a list that starts the other
comes first, and a pair with a null, of two kinds, or of two maps that differ is not ordered.

- SqlCypherCompiler.list_order gives -1, 0 or 1, or null. Postgres walks the two lists with a
  recursive query by place; Oracle declares cy_list_order, a PL/SQL function over JSON_ELEMENT_T.
  It is declared through declare() each time it is called, with no flag of its own: declare()
  keeps one copy, and #244's trial compile gives back what it declared. A statement that writes, and a reduce() step, call no
  function the query declares, so there Oracle refuses the comparison with the spec's messages.
- _compared_items gives temporal items as the comparison needs them: zoned values as their
  moments, durations and values of two kinds as maps of their kind (equal or not ordered), and a
  temporal list beside a text list as maps too, so the comparison is null.
- toString() of a list or a map the statement makes is refused, as Neo4j (Cypher 5) refuses it.
- The Cypher spec runs at v0.6.19.

Every v0.6.18 statement compiles to the same SQL as before on Postgres and Oracle.

Fixes #215
# Conflicts:
#	tests/integration/test_cypher_compiled.py
#	tests/sync_integration/test_cypher_compiled.py
@jasperblues
jasperblues merged commit efcecd8 into main Oct 28, 2026
6 checks passed
@jasperblues jasperblues mentioned this pull request Oct 28, 2026
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.

Port of liberation-data/drivine4j#349

1 participant