Skip to content

EQL v3 JSON on Supabase: encrypted containment + JSONPath selector querying #650

Description

@coderdan

Follow-up to #623 (which added the JSONPath selector-with-constraint to the Drizzle v3 integration).

Problem

The Supabase v3 adapter has no encrypted-JSON querying at all — not even the #621 containment (that lives only in Drizzle). searchableJson / query_jsonb / ste_vec / selector have zero references in packages/stack-supabase/src/. Encrypted eql_v3_json columns round-trip through select/insert, but they are non-queryable on this surface, and the typed key sets actively exclude them (a JSON column resolves to never in QueryTypesForColumn).

So Supabase needs BOTH:

  1. Encrypted-JSON containment (@>), the Drizzle feat(stack): EQL v3 JSON support — types.Json + containment #621 equivalent.
  2. JSONPath selector-with-constraint (col->'path' <op> value), the EQL v3 JSON: implement JSONPath selector-with-constraint querying (->, ->>) #623 equivalent.

The hard part: PostgREST can't cast a filter value

The Drizzle path works because it emits raw SQL with the casts the overloads require (::eql_v3.query_jsonb for containment, ::public.eql_v3_jsonb_entry for the selector comparison). PostgREST has no syntax to cast a filter value, and an uncast literal is ambiguous across the @> / comparison overloads (42725 "operator is not unique"). This is the same wall the scalar v3 filters hit — they escape it by sending the full storage envelope to a no-cast overload, but a JSON query needle can't be a full storage envelope.

Required investigation (do this first)

A live-PostgREST probe to find a filter form that reaches an overload needing no value cast — mirroring how ordering already works (order=col->op.asc needs no operand/cast; see query-builder-v3.ts:282-320). If no such form exists for the encrypted-JSON overloads, this needs an EQL-bundle change (a no-cast-friendly overload) — coordinate with the EQL project.

Plumbing (once the wire form is settled)

  • Core: add a searchableJson arm to QueryTypesForColumn (packages/stack/src/eql/v3/columns.ts:770) so JSON columns stop resolving to never.
  • packages/stack-supabase/src/types.ts: a V3SearchableJsonKeys key set (sibling to V3EncryptedFreeTextKeys), remove JSON columns from NonQueryableV3Keys erasure, add a FilterOp member + builder method.
  • packages/stack-supabase/src/query-builder-v3.ts: widen V3ColumnLike.getQueryCapabilities, add searchableJson arms to queryTypeForRawOp/queryTypeForOrOp/assertTermQueryable, and a new applier seam beside applyContainsFilter.
  • Reference impl: packages/stack-drizzle/src/v3/operators.ts (containment containsJsonOp; selector selectorCompare) and sql-dialect.ts.
  • Live tests in packages/stack-supabase/integration/wire.integration.test.ts (add an eql_v3_json fixture column).

Context

Split out of #623 during the Stack 1.0 push: the Drizzle selector was clean and unblocked, but the Supabase path needs genuine PostgREST design work that shouldn't gate the Drizzle capability for launch.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions