Skip to content

feat(scalars): add eql_v3.text encrypted-domain family (eq / match / ord)#260

Open
tobyhede wants to merge 21 commits into
eql_v3from
v3-domain-type-text
Open

feat(scalars): add eql_v3.text encrypted-domain family (eq / match / ord)#260
tobyhede wants to merge 21 commits into
eql_v3from
v3-domain-type-text

Conversation

@tobyhede
Copy link
Copy Markdown
Contributor

@tobyhede tobyhede commented Jun 5, 2026

Adds the eql_v3.text scalar encrypted-domain family at parity with EQL v2 encrypted text: equality (HMAC), match (a new self-contained eql_v3.bloom_filter SEM index term), and ORE ordering. First scalar to add a new index Term (Bloom) and the first non-integer, unbounded ordered kind.

Supported text domains

Domain Operators Index term
eql_v3.text — (storage only)
eql_v3.text_eq = <> HMAC (hm)
eql_v3.text_match @> <@ Bloom filter (bf)
eql_v3.text_ord = <> < <= > >=, min/max ORE block (ob)
eql_v3.text_ord_ore same as text_ord ORE block (ob)

A real encrypted text payload carries hm + bf + ob; callers cast per predicate. Match is bloom-filter containment on text_match — deliberately not SQL LIKE — and never backs equality (that always routes through Hm).

Notes

  • @>/<@ flip from blocker → inlinable wrappers only on Bloom domains, so the int4 golden is byte-identical (codegen:parity green).
  • New eql_v3.bloom_filter SEM type is self-contained (no eql_v2 dependency; test:self_contained_v3 green).
  • SQLx matrix generalised for non-Copy (String) plaintext (CopyClone, to_sql_literal(&Self)); [text] harness marker mirrors [temporal].

Stacked on eql_v3.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a30b3254-8131-40c6-9fdb-707c39db0b81

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v3-domain-type-text

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

tobyhede added 4 commits June 5, 2026 15:12
…t wired-kinds comments

Addresses CodeRabbit review on #260:
- Fixture::Zero now resolves to None for non-integer kinds, matching Min/Max and
  the function's documented contract (test-guaranteed never hit, but consistent).
- cast_for_kind/plaintext_sql_type_for_kind doc comments now list Text as wired.
…ven test, match coverage

- bloom_filter(jsonb): LANGUAGE sql (inlinable), drop the redundant RAISE. The
  match capability is tied to the text_match domain CHECK (which guarantees bf),
  so a missing key can only occur on raw jsonb — return NULL there, mirroring
  hmac_256. Add the pin_search_path inline-critical clause + splinter allowlist
  row so it stays unpinned/inlinable. has_bloom_filter unchanged (matches
  has_hmac_256). SEM test now asserts NULL instead of a raise.
- context.rs: table-driven operator-metadata test — a new term's metadata is one
  table row, not another hand-rolled assertion block.
- eql-tests-macros: document the is_temporal -> is_hand_written rename (the
  predicate gates "diverges from the generated integer path", not "is a date").
- text_match: add a bare-operator (`col @> needle`) GIN index-engagement test;
  document the probabilistic / ngram-disjoint basis of the disjoint assertion.
- text_smoke: add empty-bloom set-semantics test (everything contains the empty
  filter; the empty filter contains nothing).
- rename string_to_plaintext_is_utf8 -> string_to_plaintext_is_text.
tobyhede added 2 commits June 5, 2026 20:02
…x text "" pivot (#262)

The scalar matrix's third pivot was hardwired to `Default::default()` — `0` for
int, the epoch for date, but `""` for text, which encrypts to an empty ORE term
and broke ordering/aggregates/counts (83 CI failures on #260).

Introduce the real taxonomy as traits:
- ScalarType (base) — identity, fixtures, literal rendering.
- OrderedScalar: ScalarType — min_pivot/max_pivot + an overridable interior
  mid_pivot (default Self::default()). int/date inherit (0/epoch); text overrides
  to a real median ("frank"), never the degenerate "".
- SignedScalar: OrderedScalar — origin() (numeric zero / sign boundary). int and
  date only; text is NOT SignedScalar (lexicographic order has no origin).

The pivot SWEEP stays uniform (min/mid/max) across every ordered type, so the
single canonical matrix snapshot is preserved — only a `_pivot_zero_` ->
`_pivot_mid_` rename. The signed-only sign-boundary test (asserts ORE ordering is
monotonic across the origin) is generic over `SignedScalar` and lives outside the
`scalars::` namespace (like text_match), so a `text` instantiation is a compile
error and it never enters the inventory snapshot — no per-capability snapshot,
inventory, or macro branching.

Also: drop "" from TEXT_FIXTURES (text has no numeric origin — #262); the proc
macro emits OrderedScalar+SignedScalar for the generated integer impls; harden
text_match::match_uses_functional_index to force enable_seqscan=off.

Verified: 640 text/int4/date/signed/text_match tests pass (prior 83 "" failures
gone); matrix inventory matches the regenerated snapshot (5 types, no signed
leak); codegen:parity unchanged. Empty-string behavioural decision tracked in #262.
…(STRICT)

The extractor is declared STRICT, so PostgreSQL returns NULL for a NULL
argument without entering the body — the explicit guard was dead code.
Matches the inlined bloom_filter extractor; behaviour unchanged (verified:
ore_block(NULL::jsonb) IS NULL, missing-ob still RAISEs).
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.

1 participant