Skip to content

Commit aa68bf5

Browse files
committed
docs(sql-orm): retire stale includeMany references; align include docs with correlated lowering
`includeMany` is no longer a method on any surface — the ORM exposes `.include(...)` and the SQL builder has no include method. Clean up the references this leaves behind, and align the adapter docs with the correlated-only include lowering this branch introduces: - Delete the obsolete `include-many-patterns.mdc` rulecard (it documented a removed `SelectBuilderImpl.includeMany()` API) and its index entry. - Remove the dead `HasIncludeManyCapabilities` type (zero usages; it encoded the now-defunct lateral+jsonAgg include gate). - Postgres README: includes now lower to a correlated subquery, not `LEFT JOIN LATERAL`; note LATERAL emission is retained only for the public `lateralJoin()` DSL. - SQLite README: rename includeMany -> include; correlated is the strategy, not a fallback. - AGENTS.md (capability-gating example), the queries skill gotcha, and a stale e2e describe label: includeMany -> include / a real capability. - Remove the broken `### Queries with includeMany` SQL-builder example from query-patterns.md (it called a nonexistent `.includeMany()`). ADRs and the Query Lanes subsystem doc are left as-is (historical / architecture docs handled separately). Refs: TML-2729 Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
1 parent ea025e8 commit aa68bf5

9 files changed

Lines changed: 24 additions & 174 deletions

File tree

.agents/rules/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ Rules below are listed by bare filename; the canonical file is `.agents/rules/<n
9090
## SQL & Query Patterns
9191
- `query-patterns.mdc` — Query DSL patterns
9292
- `postgres-lateral-patterns.mdc` — LATERAL/json_agg patterns
93-
- `include-many-patterns.mdc` — includeMany type inference
9493
- `sql-types-imports.mdc` — SQL types import path (use @prisma-next/sql-contract/types)
9594

9695
## TypeScript & Typing

.agents/rules/include-many-patterns.mdc

Lines changed: 0 additions & 95 deletions
This file was deleted.

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pnpm fixtures:check # Use this rather than ad-hoc emit-and-diff
9292
- **ExecutionContext**: Encapsulates contract, codecs, operations, and types. Pass to `schema()`, `sql()`, `orm()`.
9393
- **Interface + factory pattern for stateful services**: Stateful services (registries, runtimes, adapters, drivers) are exposed through an interface plus a `createX()` factory; the implementing class stays package-private. Consumers depend on the interface, never the implementation. Pattern reference: [`docs/architecture docs/patterns/interface-plus-factory.md`](docs/architecture%20docs/patterns/interface-plus-factory.md).
9494
- **Three-layer polymorphic IR for AST/IR class hierarchies**: AST/IR nodes (Contract IR, Schema IR, migration ops) are organised as framework interface → family abstract base → target concrete classes. Concrete classes are publicly exported as the target's IR alphabet; `freezeNode(this)` is called in the constructor. Target packs contribute new entity kinds via `AuthoringContributions.entities` (see [`docs/reference/typescript-patterns.md`](docs/reference/typescript-patterns.md) § "AST/IR class hierarchies"). Pattern references: [`three-layer-polymorphic-ir.md`](docs/architecture%20docs/patterns/three-layer-polymorphic-ir.md), [`frozen-class-ast.md`](docs/architecture%20docs/patterns/frozen-class-ast.md), [`json-canonical-class-in-memory.md`](docs/architecture%20docs/patterns/json-canonical-class-in-memory.md).
95-
- **Capability Gating**: Features like `includeMany` and `returning()` require capabilities in the contract; gating is enforced at authoring time.
95+
- **Capability Gating**: Features like `returning()` require capabilities in the contract; gating is enforced at authoring time.
9696
- **Builder chaining**: Methods return new instances — always chain calls.
9797
- **Column access**: Use `table.columns.fieldName` to avoid conflicts with table properties.
9898

docs/reference/query-patterns.md

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -152,39 +152,6 @@ const plan = db.sql
152152
type JoinedRow = ResultType<typeof plan>;
153153
```
154154

155-
### Queries with includeMany
156-
157-
```typescript
158-
import { db } from '../prisma/db';
159-
import type { ResultType } from '@prisma-next/sql-query/types';
160-
161-
const userTable = db.schema.tables.user;
162-
const postTable = db.schema.tables.post;
163-
164-
const plan = db.sql
165-
.from(userTable)
166-
.includeMany(
167-
postTable,
168-
(on) => on.eqCol(userTable.columns.id, postTable.columns.userId),
169-
(child) =>
170-
child
171-
.select({
172-
id: postTable.columns.id,
173-
title: postTable.columns.title,
174-
})
175-
.orderBy(postTable.columns.createdAt.desc()),
176-
{ alias: 'posts' },
177-
)
178-
.select({
179-
id: userTable.columns.id,
180-
email: userTable.columns.email,
181-
posts: true,
182-
})
183-
.build();
184-
185-
type UserWithPosts = ResultType<typeof plan>;
186-
```
187-
188155
## Anti-Patterns
189156

190157
**❌ WRONG: Don't create extra aliases for one-off usage**

packages/2-sql/4-lanes/relational-core/src/types.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -151,26 +151,6 @@ export type ComputeColumnJsType<
151151
: never
152152
: never;
153153

154-
/**
155-
* Utility type to check if a contract has the required capabilities for includeMany.
156-
* Requires both `lateral` and `jsonAgg` to be `true` in the contract's capabilities for the target.
157-
* Capabilities are nested by target: `{ [target]: { lateral: true, jsonAgg: true } }`
158-
*/
159-
export type HasIncludeManyCapabilities<TContract extends Contract<SqlStorage>> = TContract extends {
160-
capabilities: infer C;
161-
target: infer T;
162-
}
163-
? T extends string
164-
? C extends Record<string, Record<string, boolean>>
165-
? C extends { [K in T]: infer TargetCaps }
166-
? TargetCaps extends { lateral: true; jsonAgg: true }
167-
? true
168-
: false
169-
: false
170-
: false
171-
: false
172-
: false;
173-
174154
/**
175155
* Alias for the SQL-domain executable plan, exposed under the legacy
176156
* `SqlPlan` name for compatibility with SQL builder/utility call sites.

packages/3-targets/6-adapters/postgres/README.md

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Provide PostgreSQL-specific adapter implementation, codecs, and capabilities. En
2020

2121
- **Adapter Implementation**: Implement `Adapter` SPI for PostgreSQL
2222
- Lower SQL ASTs to PostgreSQL dialect SQL
23-
- Render `includeMany` as `LEFT JOIN LATERAL` with `json_agg` for nested array includes
23+
- Render `.include(...)` as a correlated subquery with `json_agg` for nested array includes
2424
- Advertise PostgreSQL capabilities (`lateral`, `jsonAgg`)
2525
- Normalize PostgreSQL EXPLAIN output
2626
- Map PostgreSQL errors to `RuntimeError` envelope
@@ -90,7 +90,7 @@ flowchart TD
9090
- Main adapter implementation
9191
- Lowers SQL ASTs to PostgreSQL SQL
9292
- Renders joins (INNER, LEFT, RIGHT, FULL) with ON conditions
93-
- Renders `includeMany` as `LEFT JOIN LATERAL` with `json_agg` for nested array includes
93+
- Renders `.include(...)` as a correlated subquery with `json_agg` for nested array includes
9494
- Renders DML operations (INSERT, UPDATE, DELETE) with RETURNING clauses
9595
- Advertises PostgreSQL capabilities (`lateral`, `jsonAgg`, `returning`)
9696
- Maps PostgreSQL errors to `RuntimeError`
@@ -191,8 +191,8 @@ The adapter declares the following PostgreSQL capabilities:
191191

192192
- **`orderBy: true`** - Supports ORDER BY clauses
193193
- **`limit: true`** - Supports LIMIT clauses
194-
- **`lateral: true`** - Supports LATERAL joins for `includeMany` nested array includes
195-
- **`jsonAgg: true`** - Supports JSON aggregation functions (`json_agg`) for `includeMany`
194+
- **`lateral: true`** - Supports LATERAL joins (used by the SQL-builder `lateralJoin()` DSL)
195+
- **`jsonAgg: true`** - Supports JSON aggregation functions (`json_agg`) used to lower `.include(...)` to correlated subqueries
196196
- **`returning: true`** - Supports RETURNING clauses for DML operations (INSERT, UPDATE, DELETE)
197197
- **`sql.enums: true`** - Supports contract-defined enum storage types
198198

@@ -205,31 +205,30 @@ The capabilities on the descriptor must match the capabilities in code. If they
205205

206206
See `docs/reference/capabilities.md` and `docs/architecture docs/subsystems/5. Adapters & Targets.md` for details.
207207

208-
## includeMany Support
208+
## Include Support
209209

210-
The adapter supports `includeMany` for nested array includes using PostgreSQL's `LATERAL` joins and `json_agg`:
210+
The adapter lowers `.include(...)` for nested array includes to a correlated subquery in the SELECT list, using `json_agg`:
211211

212212
**Lowering Strategy:**
213-
- Renders `includeMany` as `LEFT JOIN LATERAL` with a subquery that uses `json_agg(json_build_object(...))` to aggregate child rows into a JSON array
214-
- The ON condition from the include is moved into the WHERE clause of the lateral subquery
215-
- When both `ORDER BY` and `LIMIT` are present, wraps the query in an inner SELECT that projects individual columns with aliases, then uses `json_agg(row_to_json(sub.*))` on the result
216-
- Uses different aliases for the table (`{alias}_lateral`) and column (`{alias}`) to avoid ambiguity
213+
- Renders each `.include(...)` as a correlated subquery that uses `json_agg(json_build_object(...))` to aggregate child rows into a JSON array
214+
- The ON condition from the include becomes the WHERE clause of the correlated subquery, referencing the outer row
215+
- When both `ORDER BY` and `LIMIT` are present, wraps the child query in an inner SELECT that projects individual columns with aliases, then uses `json_agg(row_to_json(sub.*))` on the result
217216

218217
**Capabilities Required:**
219-
- `lateral: true` - Enables LATERAL join support
220218
- `jsonAgg: true` - Enables `json_agg` function support
221219

222220
**Example SQL Output:**
223221
```sql
224-
SELECT "user"."id" AS "id", "posts_lateral"."posts" AS "posts"
225-
FROM "user"
226-
LEFT JOIN LATERAL (
222+
SELECT "user"."id" AS "id", (
227223
SELECT json_agg(json_build_object('id', "post"."id", 'title', "post"."title")) AS "posts"
228224
FROM "post"
229225
WHERE "user"."id" = "post"."userId"
230-
) AS "posts_lateral" ON true
226+
) AS "posts"
227+
FROM "user"
231228
```
232229

230+
> LATERAL emission is retained in the renderer (and the `lateral` capability stays advertised) for the public SQL-builder `lateralJoin()` DSL; the ORM include path no longer uses it.
231+
233232
## DML Operations with RETURNING
234233

235234
The adapter supports RETURNING clauses for DML operations (INSERT, UPDATE, DELETE), allowing you to return affected rows:

packages/3-targets/6-adapters/sqlite/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Provide SQLite-specific adapter implementation, codecs, and capabilities. Enable
2020

2121
- **Adapter Implementation**: Implement `Adapter` SPI for SQLite
2222
- Lower SQL ASTs to SQLite dialect SQL
23-
- Render `includeMany` as correlated subquery with `json_group_array(json_object(...))` for nested array includes
23+
- Render `.include(...)` as correlated subquery with `json_group_array(json_object(...))` for nested array includes
2424
- Advertise SQLite capabilities (`jsonAgg`, `returning`; no `lateral`, no `enums`)
2525
- Provide target-specific marker SQL via `readMarkerStatement()` on `AdapterProfile`
2626
- Map SQLite errors to `RuntimeError` envelope
@@ -91,7 +91,7 @@ flowchart TD
9191
- Main adapter implementation
9292
- Lowers SQL ASTs to SQLite SQL with `?` positional parameters
9393
- Renders joins (INNER, LEFT, RIGHT, FULL) with ON conditions
94-
- Renders `includeMany` as correlated subquery with `json_group_array(json_object(...))` for nested array includes
94+
- Renders `.include(...)` as correlated subquery with `json_group_array(json_object(...))` for nested array includes
9595
- Renders DML operations (INSERT, UPDATE, DELETE) with RETURNING clauses
9696
- Renders ON CONFLICT (DO NOTHING / DO UPDATE SET) for upserts
9797
- Uses `CAST(expr AS type)` instead of Postgres `::type` syntax
@@ -148,17 +148,17 @@ The adapter declares the following SQLite capabilities:
148148

149149
- **`sql.orderBy: true`** -- Supports ORDER BY clauses
150150
- **`sql.limit: true`** -- Supports LIMIT clauses
151-
- **`sql.lateral: false`** -- No LATERAL join support; `includeMany` uses correlated subquery fallback
152-
- **`sql.jsonAgg: true`** -- Supports JSON aggregation via `json_group_array()` for `includeMany`
151+
- **`sql.lateral: false`** -- No LATERAL join support; `.include(...)` uses correlated subqueries
152+
- **`sql.jsonAgg: true`** -- Supports JSON aggregation via `json_group_array()` for `.include(...)`
153153
- **`sql.returning: true`** -- Supports RETURNING clauses for DML operations (SQLite 3.35+)
154154
- **`sql.enums: false`** -- No native enum support
155155

156-
## includeMany Support
156+
## Include Support
157157

158-
The adapter supports `includeMany` for nested array includes using SQLite's `json_group_array()` and `json_object()`:
158+
The adapter lowers `.include(...)` for nested array includes using SQLite's `json_group_array()` and `json_object()`:
159159

160160
**Lowering Strategy:**
161-
- Renders `includeMany` as a correlated subquery with `json_group_array(json_object(...))` to aggregate child rows into a JSON array
161+
- Renders `.include(...)` as a correlated subquery with `json_group_array(json_object(...))` to aggregate child rows into a JSON array
162162
- Uses `COALESCE(..., '[]')` to handle empty results
163163

164164
**Example SQL Output:**

skills/prisma-next-queries/postgres.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ The callback's return value passes through `db.transaction(...)`. Capture insert
314314
5. **Importing `and` / `or` / `not` from a Postgres façade subpath.** The combinators currently live in `@prisma-next/sql-orm-client` — an internal package. See *What Prisma Next doesn't do yet* in [`SKILL.md`](./SKILL.md).
315315
6. **Trying to `db.sql.from(tables.user)`.** That surface does not exist. The builder is table-shaped: `db.sql.<tableName>.select(...)`. There is no `db.schema.tables` either.
316316
7. **Trying to `db.execute(plan)` directly.** Plans execute through the runtime: `db.runtime().execute(plan)`. Inside a transaction, use `tx.execute(plan)`.
317-
8. **Setting `capabilities: { includeMany: true }` in `prisma-next.config.ts`.** `defineConfig` does not take `capabilities`. Capabilities are declared by the active adapter and become part of the emitted contract; the Postgres adapter advertises `lateral`, `jsonAgg`, and `returning` out of the box. Enable extension capabilities through `extensions: [...]` in the config (see `prisma-next-contract`).
317+
8. **Setting `capabilities: { lateral: true }` in `prisma-next.config.ts`.** `defineConfig` does not take `capabilities`. Capabilities are declared by the active adapter and become part of the emitted contract; the Postgres adapter advertises `lateral`, `jsonAgg`, and `returning` out of the box. Enable extension capabilities through `extensions: [...]` in the config (see `prisma-next-contract`).
318318
9. **Confabulating a `db.sql.raw(...)`, TypedSQL, or `.stream()` surface.** None of those exist today. See *What Prisma Next doesn't do yet* in [`SKILL.md`](./SKILL.md).
319319
10. **Mixing the ORM mutation return with `runtime.execute(plan)`.** ORM terminals issue the query themselves and return rows. `runtime.execute` is for SQL-builder plans.
320320
11. **Top-N grouped queries written as `groupBy(...).aggregate(...).sort().slice()` in JS.** That's a fallback because the grouped collection doesn't expose `.orderBy(...)` / `.take(...)`. Fine at small cardinalities; for large grouped result sets, drop to `db.sql.<table>`.

test/e2e/framework/test/sqlite/orm.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ describe('e2e: ORM on SQLite', { timeout: timeouts.databaseOperation }, () => {
171171
});
172172
});
173173

174-
describe('includeMany', () => {
174+
describe('include', () => {
175175
it('loads 1:N relation via json_group_array', async () => {
176176
await withSqliteTestRuntime<Contract>(contractJsonPath, async ({ ormClient }) => {
177177
const users = await ormClient.User.where((u) => u.id.eq(1))

0 commit comments

Comments
 (0)