Skip to content

feat(query-spec): shared query language spec package; wire codegen + query-builder#1392

Merged
pyramation merged 1 commit into
mainfrom
feat/query-spec
Jul 18, 2026
Merged

feat(query-spec): shared query language spec package; wire codegen + query-builder#1392
pyramation merged 1 commit into
mainfrom
feat/query-spec

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

New zero-dependency leaf package packages/query-spec (unscoped npm name query-spec) defining the Constructive query language grammar — the single source of truth for filter, ordering, and pagination shapes shared by the GraphQL SDK/ORM layer and the SQL query builder.

query-spec exports:

  • Operator groups as const arrays + derived unions: NULL/COMPARISON/DISTINCT/LIST/LIKE/PATTERN/INSENSITIVE/ARRAY/POSTGIS_FILTER_OPERATORS, FILTER_OPERATORS, LOGICAL_OPERATORS, with runtime guards isFilterOperator() / isLogicalOperator().
  • Generic grammar: FieldFilter<TOperand>, RelationalFilter<TOperand> (every/some/none), Filter<TOperand> — generic over the operand type so each layer constrains what fields compare against (JSON values in the SDK; values/exprs/subqueries in SQL).
  • OrderByItem/OrderDirection, PageInfo, ConnectionResult<T>.

Wiring (no breaking changes):

  • graphql/codegen src/types/query.ts: the previously inlined FilterOperator/FieldFilter/RelationalFilter/Filter/OrderByItem/PageInfo/ConnectionResult definitions are deleted and re-exported from query-spec, so all existing @constructive-io/graphql-codegen type consumers are unaffected.
  • postgres/query-builder: FieldFilter is now composed from the spec's operator-group unions via mapped types, preserving its per-group operand precision:
    export type FieldFilter =
      { isNull?: boolean } &
      { [K in ComparisonFilterOperator]?: Operand | QueryBuilder } &
      { [K in DistinctFilterOperator]?: Operand } &
      { [K in ListFilterOperator]?: Operand[] | QueryBuilder } &
      { [K in LikeFilterOperator]?: Operand } &
      { [K in PatternFilterOperator]?: string };
    so operator names can never drift from the SDK grammar (type-only import; adds only the tiny query-spec dep).

One subtlety: Filter is an interface (not an intersection type) because TS's excess-property check mishandles recursive generic intersections of an index signature + named combinators (not: { field: ... } failed to compile as an intersection).

Tests: new query-spec suite; query-builder 111 passing; codegen 358 passing.

Link to Devin session: https://app.devin.ai/sessions/3766c470681e402680eae001e9679801
Requested by: @pyramation

@pyramation pyramation self-assigned this Jul 18, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@pyramation
pyramation merged commit cab4290 into main Jul 18, 2026
39 checks passed
@pyramation
pyramation deleted the feat/query-spec branch July 18, 2026 06:26
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