Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ab0b854
docs(projects): scaffold unify-query-operations project and self-any-…
SevInf May 21, 2026
8605a3b
feat(operations): add `any: true` arm to SelfSpec and QueryOperationS…
SevInf May 21, 2026
61b8c75
feat(sql-orm-client): wire `any: true` arm through model-accessor + O…
SevInf May 21, 2026
6161cce
docs(projects): scaffold family-ops-factory slice for unify-query-ope…
SevInf May 21, 2026
fe91b46
feat(family-sql): publish type twin for QueryOperationTypes<CT>
SevInf May 21, 2026
8a77dfd
feat(family-sql): wire sqlFamilyOperations factory and descriptor-met…
SevInf May 21, 2026
073aa73
feat(sql-runtime): wire SQL family descriptor into createExecutionCon…
SevInf May 21, 2026
b8b17da
docs(projects): split unify-query-operations slice 3 \`collapse-consu…
SevInf May 21, 2026
aac9a5c
docs(projects): scaffold collapse-consumers slice for unify-query-ope…
SevInf May 21, 2026
da0b020
refactor(sql-builder): delete BuiltinFunctions, rename fns.ne to fns.neq
SevInf Jun 2, 2026
6372e33
refactor(sql-orm-client): collapse ORM accessor to registry loop; del…
SevInf May 28, 2026
8b699f9
refactor(sql-orm-client): delete ComparisonMethods<T, Traits>; derive…
SevInf May 28, 2026
2003625
fix(family-sql): CodecIdsWithTrait gates on tuple but ExtractCodecTyp…
SevInf May 28, 2026
5075077
fix(sql-orm-client): re-emit fixtures with SqlFamilyQueryOperationTypes
SevInf May 28, 2026
8a6e74c
fix(sql-orm-client): migrate hand-rolled test fixtures to registry-de…
SevInf May 28, 2026
8745b37
fix(fixtures): re-emit stale contract.d.ts files with SqlFamilyQueryO…
SevInf May 28, 2026
602dffb
fix(fixtures): re-emit extension contract-spaces + e2e fixtures with …
SevInf May 28, 2026
996fe39
fix(test/e2e): re-emit sqlite fixture with SqlFamilyQueryOperationTypes
SevInf May 28, 2026
85d692d
docs(unify-query-operations): manual-QA script for collapse-consumers…
SevInf May 28, 2026
aa06cde
docs(unify-query-operations): manual-QA run report 2026-05-28
SevInf May 28, 2026
646bbe5
refactor(family-sql,sql-runtime): break workspace build cycle; make f…
SevInf May 29, 2026
ab63767
fix(fixtures): re-emit after rebase onto origin/main
SevInf May 29, 2026
a1adf5f
fix(fixtures,family-sql): post-rebase fixups for 0.12.0 main
SevInf Jun 2, 2026
2898b04
fix(tests): post-rebase test adaptations for 0.12.0 main
SevInf Jun 2, 2026
7a76491
fix(sql-orm-client): preserve predicate-return surface on non-Postgre…
SevInf Jun 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/telemetry-backend/src/prisma/contract.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion examples/bundle-size/src/postgres/generated/contract.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion examples/multi-extension-monorepo/app/src/contract.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion examples/paradedb-demo/src/prisma/contract.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion examples/prisma-next-demo-sqlite/src/prisma/contract.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions examples/prisma-next-demo/src/prisma-no-emit/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import postgresAdapter from '@prisma-next/adapter-postgres/runtime';
import postgresDriver from '@prisma-next/driver-postgres/runtime';
import pgvector from '@prisma-next/extension-pgvector/runtime';
import { SqlContractSerializer } from '@prisma-next/family-sql/ir';
import sqlRuntimeFamilyDescriptor from '@prisma-next/family-sql/runtime';
import { sql as sqlBuilder } from '@prisma-next/sql-builder/runtime';
import { orm } from '@prisma-next/sql-orm-client';
import type { Runtime } from '@prisma-next/sql-runtime';
Expand All @@ -11,6 +12,7 @@ import { contract } from '../../prisma/contract';
import { PostCollection, UserCollection } from '../orm-client/collections';

export const stack = createSqlExecutionStack({
family: sqlRuntimeFamilyDescriptor,
target: postgresTarget,
adapter: postgresAdapter,
driver: postgresDriver,
Expand Down
4 changes: 3 additions & 1 deletion examples/prisma-next-demo/src/prisma/contract.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ import { db } from '../prisma/db';
*
* Features exercised:
* 1. Self-join via `.as()` aliasing of the same table (`post` aliased as `p1` and `p2`).
* 2. INNER JOIN with a non-equality predicate (`ne(p1.userId, p2.userId)`).
* 2. INNER JOIN with a non-equality predicate (`neq(p1.userId, p2.userId)`).
* 3. pgvector `cosineDistance` called with two column references from two aliases — in the
* SELECT projection and in the ORDER BY.
* 4. Typed result row inferred from the SELECT projection, mixing columns from both aliases.
*/
export async function crossAuthorSimilarity(limit = 10, runtime?: Runtime) {
const plan = db.sql.post
.as('p1')
.innerJoin(db.sql.post.as('p2'), (f, fns) => fns.ne(f.p1.userId, f.p2.userId))
.innerJoin(db.sql.post.as('p2'), (f, fns) => fns.neq(f.p1.userId, f.p2.userId))
.select((f, fns) => ({
postAId: f.p1.id,
postATitle: f.p1.title,
Expand All @@ -51,7 +51,7 @@ export async function crossAuthorSimilarity(limit = 10, runtime?: Runtime) {
postBUserId: f.p2.userId,
distance: fns.cosineDistance(f.p1.embedding, f.p2.embedding),
}))
.where((f, fns) => fns.and(fns.ne(f.p1.embedding, null), fns.ne(f.p2.embedding, null)))
.where((f, fns) => fns.and(fns.neq(f.p1.embedding, null), fns.neq(f.p2.embedding, null)))
.orderBy((f, fns) => fns.cosineDistance(f.p1.embedding, f.p2.embedding), {
direction: 'asc',
})
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion examples/react-router-demo/src/prisma/contract.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 10 additions & 5 deletions packages/1-framework/1-core/operations/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ export interface ReturnSpec {
}

export type SelfSpec =
| { readonly codecId: string; readonly traits?: never }
| { readonly traits: readonly string[]; readonly codecId?: never };
| { readonly codecId: string; readonly traits?: never; readonly any?: never }
| { readonly traits: readonly string[]; readonly codecId?: never; readonly any?: never }
| { readonly any: true; readonly codecId?: never; readonly traits?: never };

export interface OperationEntry {
readonly self?: SelfSpec;
Expand Down Expand Up @@ -42,11 +43,15 @@ export function createOperationRegistry<
if (descriptor.self) {
const hasCodecId = descriptor.self.codecId !== undefined;
const hasTraits = descriptor.self.traits !== undefined && descriptor.self.traits.length > 0;
if (!hasCodecId && !hasTraits) {
throw new Error(`Operation "${name}" self has neither codecId nor traits`);
const hasAny = descriptor.self.any === true;
if (!hasCodecId && !hasTraits && !hasAny) {
throw new Error(`Operation "${name}" self has none of codecId, traits, or any`);
}
if (hasCodecId && hasTraits) {
throw new Error(`Operation "${name}" self has both codecId and traits`);
throw new Error(`Operation "${name}" self combines codecId and traits`);
}
if (hasAny && (hasCodecId || hasTraits)) {
throw new Error(`Operation "${name}" self combines any with codecId or traits`);
}
}
operations[name] = descriptor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ describe('OperationRegistry', () => {
);
});

it('throws when self has neither codecId nor traits', () => {
it('throws when self has none of codecId, traits, or any', () => {
const registry = createOperationRegistry();

expect(() =>
registry.register('bad', {
// @ts-expect-error — SelfSpec requires codecId or traits
// @ts-expect-error — SelfSpec requires codecId, traits, or any
self: {},
impl: noopImpl,
}),
).toThrow('Operation "bad" self has neither codecId nor traits');
).toThrow('Operation "bad" self has none of codecId, traits, or any');
});

it('throws when self has an empty traits array', () => {
Expand All @@ -68,19 +68,56 @@ describe('OperationRegistry', () => {
self: { traits: [] },
impl: noopImpl,
}),
).toThrow('Operation "bad" self has neither codecId nor traits');
).toThrow('Operation "bad" self has none of codecId, traits, or any');
});

it('throws when self has both codecId and traits', () => {
it('throws when self combines codecId and traits', () => {
const registry = createOperationRegistry();

expect(() =>
registry.register('bad', {
// @ts-expect-error — SelfSpec disallows both codecId and traits
// @ts-expect-error — SelfSpec disallows combining codecId and traits
self: { codecId: 'pg/text@1', traits: ['textual'] },
impl: noopImpl,
}),
).toThrow('Operation "bad" self has both codecId and traits');
).toThrow('Operation "bad" self combines codecId and traits');
});

it('accepts self with any: true', () => {
const registry = createOperationRegistry();

expect(() =>
registry.register(
'fine',
descriptor({
self: { any: true },
}),
),
).not.toThrow();
});

it('throws when self combines any with codecId', () => {
const registry = createOperationRegistry();

expect(() =>
registry.register('bad', {
// @ts-expect-error — SelfSpec disallows combining any with codecId
self: { any: true, codecId: 'pg/text@1' },
impl: noopImpl,
}),
).toThrow('Operation "bad" self combines any with codecId or traits');
});

it('throws when self combines any with traits', () => {
const registry = createOperationRegistry();

expect(() =>
registry.register('bad', {
// @ts-expect-error — SelfSpec disallows combining any with traits
self: { any: true, traits: ['textual'] },
impl: noopImpl,
}),
).toThrow('Operation "bad" self combines any with codecId or traits');
});

it('accepts trait-only self', () => {
Expand Down
14 changes: 10 additions & 4 deletions packages/2-sql/1-core/contract/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,18 @@ export type CodecTypesOf<T> = [T] extends [never]
* Dispatch hint identifying the first-argument target of an operation.
*
* Used by ORM column helpers to decide whether an operation is reachable on a
* field. Either names a concrete codec identity or a set of capability traits
* that the field's codec must carry.
* field. Either names a concrete codec identity, a set of capability traits
* that the field's codec must carry, or `any: true` meaning the operation
* applies to every codec irrespective of traits.
*
* Keep arms in lock-step with `SelfSpec` in `@prisma-next/operations` (same
* arms, same order). The runtime registry validates the same exactly-one-set
* invariant the type-level discriminated union encodes.
*/
export type QueryOperationSelfSpec =
| { readonly codecId: string; readonly traits?: never }
| { readonly traits: readonly CodecTrait[]; readonly codecId?: never };
| { readonly codecId: string; readonly traits?: never; readonly any?: never }
| { readonly traits: readonly CodecTrait[]; readonly codecId?: never; readonly any?: never }
| { readonly any: true; readonly codecId?: never; readonly traits?: never };

/**
* Structural shape an operation's impl must return: any value carrying a
Expand Down
Loading
Loading