Skip to content

TML-2782: thread variant name through orderBy for MTI variant fields#740

Open
tensordreams wants to merge 4 commits into
mainfrom
tml-2782-sql-orm-orderby-on-a-variant-narrowed-collection-drops-mti
Open

TML-2782: thread variant name through orderBy for MTI variant fields#740
tensordreams wants to merge 4 commits into
mainfrom
tml-2782-sql-orm-orderby-on-a-variant-narrowed-collection-drops-mti

Conversation

@tensordreams

@tensordreams tensordreams commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

What

Fixes TML-2782: orderBy on a variant-narrowed collection couldn't reference an MTI variant-specific column — db.orm.Task.variant('Feature').orderBy(o => o.priority.desc()) threw Cannot read properties of undefined, because orderBy built its accessor without the selected variantName, resolving fields against the base table only.

How

The variant-aware machinery already exists (TML-2683's where/first fix): createModelAccessor takes an optional variantName and resolves variant-owned fields to a ColumnRef on the joined variant table. This PR threads state.variantName through orderBy's accessor construction and gives the selector callback the same VariantAwareModelAccessor<…, State['variantName']> type treatment — an exact mirror of the where path, including the justified boundary cast (net bare-cast delta: −1). The include-refinement orderBy (r => r.variant('X').orderBy(…)) shares the same call site and is fixed by the same change; no query-lowering changes were needed (the variant join was already emitted).

The no-variant path is byte-for-byte unchanged (optional param, truthiness-keyed) and pinned by a regression test.

Verification

Tests-first (RED→GREEN evidenced): 3 unit tests (variant column resolves to ColumnRef.of('features','priority'); base fields stay base-qualified; no-variant unchanged), 4 type tests (accept under variant('Feature') at root + include refinement; reject under variant('Bug') and with no variant), 2 PGlite integration tests asserting the actual priority-descending order whole-shape under default selection. Gates: package typecheck + 521 tests, integration 8/8, lint:deps, lint:casts −1, DCO. Independently reviewed (pattern fidelity vs where/first, regression guard, non-tautological tests): no findings.

Scope: 1 src file + 3 test files. Adjacent known issues deliberately untouched: TML-2783 (select-leak), TML-2828 (variant relations on accessor).

Summary by CodeRabbit

  • Bug Fixes

    • Fixed orderBy() on variant-narrowed collections to correctly resolve variant-specific fields instead of throwing an error.
  • Tests

    • Added comprehensive test coverage for ordering with variant-narrowed collections, including polymorphic query pipelines and integration scenarios.
  • Documentation

    • Updated upgrade notes documenting the orderBy() variant-narrowing fix.

@tensordreams tensordreams requested a review from a team as a code owner June 5, 2026 14:34
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: da076029-4137-4240-8c77-bcbcaf2bac75

📥 Commits

Reviewing files that changed from the base of the PR and between ad553a8 and f3a6796.

📒 Files selected for processing (5)
  • packages/3-extensions/sql-orm-client/src/collection.ts
  • packages/3-extensions/sql-orm-client/test/collection-variant.test.ts
  • packages/3-extensions/sql-orm-client/test/polymorphism.test-d.ts
  • skills/extension-author/prisma-next-extension-upgrade/upgrades/0.12-to-0.13/instructions.md
  • test/integration/test/sql-orm-client/polymorphism-include.test.ts

📝 Walkthrough

Walkthrough

This PR extends Collection.orderBy() to be variant-aware: the method now accepts callbacks typed as VariantAwareModelAccessor that respect the variant state, enabling variant-narrowed MTI collections to resolve variant-owned fields instead of throwing. Implementation mirrors the existing where() variant scoping pattern, with comprehensive type-level and runtime tests validating the behavior.

Changes

Variant-aware orderBy for MTI polymorphic collections

Layer / File(s) Summary
Core implementation and type cleanup
packages/3-extensions/sql-orm-client/src/collection.ts
Collection.orderBy(...) signature updated to accept VariantAwareModelAccessor parameterized by State['variantName']. Implementation constructs variant-scoped accessor via createModelAccessor(..., this.state.variantName) and uses blindCast for type alignment. ModelAccessor import removed.
Type-level contract tests
packages/3-extensions/sql-orm-client/test/polymorphism.test-d.ts
New tests assert that orderBy() selector callbacks expose variant-specific fields (Feature/Bug variants), reject non-matching variant fields via @ts-expect-error, expose only base fields when unrefined, and preserve variant-aware typing through include(...) refinements.
Runtime variant-aware ordering tests
packages/3-extensions/sql-orm-client/test/collection-variant.test.ts
Three new tests validate AST generation: variant-owned field (priority) resolves to features.priority with sort direction, base fields remain qualified to base table (tasks.title), and non-variant orderBy resolves base fields to base table. Tests inspect runtime.executions[0].plan.ast and verify column references.
Integration tests and test infrastructure
test/integration/test/sql-orm-client/polymorphism-include.test.ts
OrderBy type scaffolding expanded with desc() method; ScalarFilter now extends OrderBy. New RootTaskCollection interface and createTaskCollection(runtime) helper enable testing .variant(name).orderBy(...). Two integration cases validate Feature-narrowed root-level ordering and variant-specific ordering within Project include refinements.
Upgrade documentation
skills/extension-author/prisma-next-extension-upgrade/upgrades/0.12-to-0.13/instructions.md
Changelog note documents the orderBy bug fix: variant-narrowed collections now correctly resolve MTI variant-owned fields instead of throwing. Clarifies no extension API changes or codemods required.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • wmadden
  • aqrln

Poem

🐰 A rabbit's ode to variant ordering

Order the variants, sorted just right,
Feature and Bug fields now in sight!
Type-safe and tested, through every include,
The orderBy spell is now in the mood. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'TML-2782: thread variant name through orderBy for MTI variant fields' clearly and specifically describes the main technical change: threading the variant name parameter through the orderBy implementation to fix MTI variant field resolution.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2782-sql-orm-orderby-on-a-variant-narrowed-collection-drops-mti
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch tml-2782-sql-orm-orderby-on-a-variant-narrowed-collection-drops-mti

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.

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
postgres / no-emit 149.32 KB (0%)
postgres / emit 118.4 KB (0%)
mongo / no-emit 76.67 KB (0%)
mongo / emit 70.96 KB (0%)
cf-worker / no-emit 179.38 KB (0%)
cf-worker / emit 145.16 KB (0%)

@pkg-pr-new

pkg-pr-new Bot commented Jun 5, 2026

Copy link
Copy Markdown

Open in StackBlitz

@prisma-next/extension-author-tools

npm i https://pkg.pr.new/@prisma-next/extension-author-tools@740

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/@prisma-next/mongo-runtime@740

@prisma-next/family-mongo

npm i https://pkg.pr.new/@prisma-next/family-mongo@740

@prisma-next/sql-runtime

npm i https://pkg.pr.new/@prisma-next/sql-runtime@740

@prisma-next/family-sql

npm i https://pkg.pr.new/@prisma-next/family-sql@740

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/@prisma-next/extension-arktype-json@740

@prisma-next/middleware-cache

npm i https://pkg.pr.new/@prisma-next/middleware-cache@740

@prisma-next/mongo

npm i https://pkg.pr.new/@prisma-next/mongo@740

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/@prisma-next/extension-paradedb@740

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/@prisma-next/extension-pgvector@740

@prisma-next/extension-postgis

npm i https://pkg.pr.new/@prisma-next/extension-postgis@740

@prisma-next/postgres

npm i https://pkg.pr.new/@prisma-next/postgres@740

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/@prisma-next/sql-orm-client@740

@prisma-next/sqlite

npm i https://pkg.pr.new/@prisma-next/sqlite@740

@prisma-next/extension-supabase

npm i https://pkg.pr.new/@prisma-next/extension-supabase@740

@prisma-next/target-mongo

npm i https://pkg.pr.new/@prisma-next/target-mongo@740

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/@prisma-next/adapter-mongo@740

@prisma-next/driver-mongo

npm i https://pkg.pr.new/@prisma-next/driver-mongo@740

@prisma-next/contract

npm i https://pkg.pr.new/@prisma-next/contract@740

@prisma-next/utils

npm i https://pkg.pr.new/@prisma-next/utils@740

@prisma-next/config

npm i https://pkg.pr.new/@prisma-next/config@740

@prisma-next/errors

npm i https://pkg.pr.new/@prisma-next/errors@740

@prisma-next/framework-components

npm i https://pkg.pr.new/@prisma-next/framework-components@740

@prisma-next/operations

npm i https://pkg.pr.new/@prisma-next/operations@740

@prisma-next/ts-render

npm i https://pkg.pr.new/@prisma-next/ts-render@740

@prisma-next/contract-authoring

npm i https://pkg.pr.new/@prisma-next/contract-authoring@740

@prisma-next/ids

npm i https://pkg.pr.new/@prisma-next/ids@740

@prisma-next/psl-parser

npm i https://pkg.pr.new/@prisma-next/psl-parser@740

@prisma-next/psl-printer

npm i https://pkg.pr.new/@prisma-next/psl-printer@740

@prisma-next/cli

npm i https://pkg.pr.new/@prisma-next/cli@740

@prisma-next/cli-telemetry

npm i https://pkg.pr.new/@prisma-next/cli-telemetry@740

@prisma-next/emitter

npm i https://pkg.pr.new/@prisma-next/emitter@740

@prisma-next/migration-tools

npm i https://pkg.pr.new/@prisma-next/migration-tools@740

prisma-next

npm i https://pkg.pr.new/prisma-next@740

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/@prisma-next/vite-plugin-contract-emit@740

@prisma-next/mongo-codec

npm i https://pkg.pr.new/@prisma-next/mongo-codec@740

@prisma-next/mongo-contract

npm i https://pkg.pr.new/@prisma-next/mongo-contract@740

@prisma-next/mongo-value

npm i https://pkg.pr.new/@prisma-next/mongo-value@740

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/@prisma-next/mongo-contract-psl@740

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/@prisma-next/mongo-contract-ts@740

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/@prisma-next/mongo-emitter@740

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/@prisma-next/mongo-schema-ir@740

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/@prisma-next/mongo-query-ast@740

@prisma-next/mongo-orm

npm i https://pkg.pr.new/@prisma-next/mongo-orm@740

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/@prisma-next/mongo-query-builder@740

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/@prisma-next/mongo-lowering@740

@prisma-next/mongo-wire

npm i https://pkg.pr.new/@prisma-next/mongo-wire@740

@prisma-next/sql-contract

npm i https://pkg.pr.new/@prisma-next/sql-contract@740

@prisma-next/sql-errors

npm i https://pkg.pr.new/@prisma-next/sql-errors@740

@prisma-next/sql-operations

npm i https://pkg.pr.new/@prisma-next/sql-operations@740

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/@prisma-next/sql-schema-ir@740

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/@prisma-next/sql-contract-psl@740

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/@prisma-next/sql-contract-ts@740

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/@prisma-next/sql-contract-emitter@740

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/@prisma-next/sql-lane-query-builder@740

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/@prisma-next/sql-relational-core@740

@prisma-next/sql-builder

npm i https://pkg.pr.new/@prisma-next/sql-builder@740

@prisma-next/target-postgres

npm i https://pkg.pr.new/@prisma-next/target-postgres@740

@prisma-next/target-sqlite

npm i https://pkg.pr.new/@prisma-next/target-sqlite@740

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/@prisma-next/adapter-postgres@740

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/@prisma-next/adapter-sqlite@740

@prisma-next/driver-postgres

npm i https://pkg.pr.new/@prisma-next/driver-postgres@740

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/@prisma-next/driver-sqlite@740

commit: fea89b5

Comment thread packages/3-extensions/sql-orm-client/src/collection.ts
Comment thread packages/3-extensions/sql-orm-client/src/collection.ts
Comment thread packages/3-extensions/sql-orm-client/test/collection-variant.test.ts Outdated
@aqrln aqrln enabled auto-merge (rebase) June 8, 2026 14:33
@tensordreams tensordreams force-pushed the tml-2782-sql-orm-orderby-on-a-variant-narrowed-collection-drops-mti branch from f3a6796 to 0b3dff4 Compare June 8, 2026 14:37
…ant fields

orderBy() called createModelAccessor without the selected variantName, so
the accessor resolved every selector field against the base table only. For
an MTI variant a variant-owned column (e.g. priority on the joined variant
table) was unreachable, dropping the column and breaking the sort.

Mirror the where()/first() pattern: thread this.state.variantName through
createModelAccessor and make the selector callback param
VariantAwareModelAccessor, bridged at the accessor boundary with the same
justified blindCast. The no-variant path is byte-for-byte unchanged. The
include-refinement orderBy shares this call site, so
r.variant(X).orderBy(...) inside an include is fixed too.

Tests: unit (variant-aware ColumnRef resolution + no-variant regression
guard), type tests (priority type-checks under variant(Feature), rejected
without a variant), and PGlite integration (root + include-refinement
variant orderBy, whole-shape toEqual asserting the order).

Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
…By variant tests

AsyncIterableResult#then already collects, so awaiting the orderBy
terminal yields the array directly. Removes the trailing .toArray()
from the three orderBy variant tests added by this PR. API-wide
removal is tracked in TML-2848.

Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
@tensordreams tensordreams force-pushed the tml-2782-sql-orm-orderby-on-a-variant-narrowed-collection-drops-mti branch from 0b3dff4 to fea89b5 Compare June 8, 2026 16:41
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.

2 participants