Skip to content

CLI: Rename Prisma 2 to Prisma Framework - #940

Merged
janpio merged 1 commit into
masterfrom
cli/rename-prisma2
Nov 21, 2019
Merged

CLI: Rename Prisma 2 to Prisma Framework#940
janpio merged 1 commit into
masterfrom
cli/rename-prisma2

Conversation

@nikolasburk

Copy link
Copy Markdown
Contributor

I've adjusted the wording in the prisma2 CLI commands to reference the "Prisma Framework" instead of "Prisma 2".

@schickling

Copy link
Copy Markdown
Member

LGTM

@janpio

janpio commented Nov 16, 2019

Copy link
Copy Markdown
Contributor

(I still think we should have a definitive decision if it should be Prisma Framework or the Prisma Framework)

@williamluke4

Copy link
Copy Markdown
  • Prisma Framework = 🚀
  • The Prisma Framework = 🎉

@janpio janpio added this to the Preview 17 milestone Nov 19, 2019
@janpio janpio changed the title rename Prisma 2 to Prisma Framework in the CLI CLI: Rename Prisma 2 to Prisma Framework Nov 21, 2019
@janpio
janpio merged commit 12ff423 into master Nov 21, 2019
@janpio
janpio deleted the cli/rename-prisma2 branch November 21, 2019 10:15
@jednano

jednano commented Nov 25, 2019

Copy link
Copy Markdown

It used to be TheFacebook... used to be.

tensordreams added a commit that referenced this pull request Jul 28, 2026
## Linked issue

Refs
[TML-2979](https://linear.app/prisma-company/issue/TML-2979/sql-orm-updatecountdeletecount-compile-mti-variant-table-predicates)

## Summary

`updateCount`, `deleteCount`, and the include-backed `deleteAll` path
now compile MTI variant-narrowed predicates through a correlated joined
subquery instead of placing variant-table references directly in the
outer write. The matching count read also keeps variant context so it
counts the same joined row set that the write targets.

## At a glance

```ts
const count = await mixedPoly
  .variant('Feature')
  .where((task) => task.priority.gt(1))
  .updateCount({ title: 'Queued' });
```

Before this change, the accepted predicate could compile into a bare
`UPDATE ... WHERE features.priority > ...` without `features` in scope.

## Decision

This PR ships correlated-subquery planning for MTI variant-narrowed
`updateCount`, `deleteCount`, and the internal count delete used by
`deleteAll()` with includes.

The count read propagates `variantName` and `modelName` into
`compileSelect`, so the existing read planner joins the selected MTI
table. The count write detects MTI variant narrowing and wraps the
original filters in `WHERE EXISTS (...)`, where the inner query aliases
the base table, joins the variant table, and correlates back to the
outer write by primary key.

## Reviewer notes

- The important behavior lives in `compileUpdateCount` /
`compileDeleteCount`; non-variant and STI paths intentionally keep the
old plain-filter shape.
- The include-backed `deleteAll()` path threads `variantName` and
`modelName` into `compileDeleteCount`, keeping its snapshot read and
delete mutation aligned.
- The write plan uses one SQL statement and avoids materialising
matching primary keys in JS.
- The new tests avoid adding bare `as` casts; the package lint still
prints existing no-bare-cast infos from older production files, but it
exits successfully.

## How it fits together

1. `Collection.updateCount` and `Collection.deleteCount` build a
matching primary-key read before the write. That read now carries
`variantName` and `modelName` into `compileSelect`, allowing the normal
MTI join machinery to join `features`.
2. `query-plan-mutations` adds `buildCountMutationWhere`, which only
switches behavior when both a selected variant and model name identify
an MTI variant.
3. The MTI write filter creates an inner base-table alias, rewrites
base-table references in the original filters to that alias, joins the
selected variant table, and correlates the inner row to the outer write
target on the primary key.
4. Scalar variant fields and variant-declared relation predicates both
work because their `features.*` references now live inside the joined
subquery scope.
5. `deleteAll()` with includes passes its collection variant context
into the internal count delete, so that path also routes through the
MTI-aware predicate builder.

## Behavior changes & evidence

- **MTI scalar predicates in count writes are executable**:
`.variant('Feature').where((task) =>
task.priority.gt(1)).updateCount(...)` now scopes `features.priority`
through a joined subquery.
- Implementation:
[packages/3-extensions/sql-orm-client/src/query-plan-mutations.ts](packages/3-extensions/sql-orm-client/src/query-plan-mutations.ts),
[packages/3-extensions/sql-orm-client/src/collection.ts](packages/3-extensions/sql-orm-client/src/collection.ts)
- Evidence:
[packages/3-extensions/sql-orm-client/test/collection-variant.test.ts](packages/3-extensions/sql-orm-client/test/collection-variant.test.ts)

- **Variant-declared relation predicates in count writes are
executable**: `.variant('Feature').where((task) =>
task.assignee.some()).deleteCount()` now scopes `features.assignee_id`
through the same joined subquery.
- Implementation:
[packages/3-extensions/sql-orm-client/src/query-plan-mutations.ts](packages/3-extensions/sql-orm-client/src/query-plan-mutations.ts)
- Evidence:
[packages/3-extensions/sql-orm-client/test/collection-variant.test.ts](packages/3-extensions/sql-orm-client/test/collection-variant.test.ts)

- **Include-backed MTI deletes keep variant predicates scoped**:
`.variant('Feature').where(...).include('assignee').deleteAll()` now
threads variant context into the delete mutation instead of emitting the
original outer predicate.
- Implementation:
[packages/3-extensions/sql-orm-client/src/collection.ts](packages/3-extensions/sql-orm-client/src/collection.ts)
- Evidence:
[packages/3-extensions/sql-orm-client/test/collection-variant.test.ts](packages/3-extensions/sql-orm-client/test/collection-variant.test.ts)

## Compatibility / migration / risk

No public API or extension-author migration change. The SQL shape
changes only for MTI variant-narrowed count writes, including the
internal count delete used by `deleteAll()` with includes; plain,
non-variant, and STI count writes keep the existing direct WHERE shape.

## Testing performed

- `pnpm --filter @prisma-next/sql-orm-client typecheck`
- `pnpm --filter @prisma-next/sql-orm-client test --
collection-variant.test.ts`
- `pnpm --filter @prisma-next/sql-orm-client test --
query-plan-mutations.test.ts`
- `pnpm --filter @prisma-next/sql-orm-client lint`
- `pnpm --filter @prisma-next/sql-orm-client build`
- `pnpm lint:casts`
- `pnpm check:upgrade-coverage --mode pr`
- `git diff --check`

## Skill update

n/a — internal bug fix; no user-facing commands, flags, public
TypeScript API, error codes, or glossary terms changed.

## Alternatives considered

- **Materialise matching primary keys before writing**: this would reuse
the joined read path directly, but it changes bulk count writes into a
read-then-write-by-key workflow and can move an unbounded matching set
through JS.
- **Add `UPDATE ... FROM` / joined delete support to the mutation AST**:
this would make the join explicit in the write AST, but it broadens the
shared mutation AST and renderer surface for a narrow bug fix. The
correlated subquery fits the existing AST.

## Checklist

- [x] All commits are signed off (`git commit -s`) per the
[DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). The DCO
status check will block merge if any commit is missing a
`Signed-off-by:` trailer.
- [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is
scoped to one logical concern.
- [x] Tests are updated (or `n/a` if the change is doc-only / refactor
with no behavioural delta).
- [x] The PR title is in `TML-NNNN: <sentence-case title>` form (Linear
ticket prefix + concise title naming the concrete deliverable). See
`.claude/skills/create-pr/SKILL.md` for the full convention.
- [x] The **Skill update** section above is filled in (or stated `n/a —
internal only`).

## Notes for the reviewer

The branch records an incidental `changes: []` declaration in
`skills/extension-author/prisma-next-extension-upgrade/upgrades/0.15-to-0.16/instructions.md`;
no extension-author action is required for this internal planner bug
fix.

---------

Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
SevInf added a commit that referenced this pull request Aug 6, 2026
Shaping artifacts for the **affected-row-counts** project — spec and
three-slice plan, per the project lifecycle in `projects/README.md`.

## What this project does

`updateAndCount` and `deleteAndCount` run two statements: a `SELECT` of
every matching primary key, then the write — returning the *read's* row
count and discarding whatever the write reported. That is not atomic
(outside a transaction a concurrent insert is updated but not counted),
it evaluates the filter twice and materialises every matching key in JS
purely to call `.length` on it, and it builds the two `WHERE` clauses
through different code paths that already drifted once for MTI variants
(#940).

The count already exists and is thrown away — Postgres reports it in the
`CommandComplete` tag, SQLite in `sqlite3_changes64()` via
`StatementSync.run()`. The gap is structural: `RuntimeScope.execute()`
returns a row stream with nowhere for statement metadata to live.

After this project the driver SPI splits along the question being asked,
named the way every prior art names it (JDBC, ADO.NET, Go):

    query<Row>(req): AsyncIterable<Row>          // rows
    execute(req):    Promise<SqlStatementStats>  // { affectedRows: number }

`affectedRows` is not optional — absence is not a state either engine has
for the statements `execute()` exists to serve. Statistics never travel
through a row stream, so the seven `for await` re-wrap sites between
driver and caller stop being a hazard. Prepared-ness rides on the request
rather than doubling the method surface, so four driver methods become
two.

## Scope boundaries

Streaming write terminals, `createAndCount`, and new targets are out.
Count semantics are deliberately *not* unified across targets —
Postgres's command tag, SQLite's `sqlite3_changes64()`, and Mongo's
`modifiedCount` each mean something different, and the project documents
the difference rather than reconciling it.

## Decision provenance

Three questions were settled with the operator at spec time and moved
into the spec body: the execution shape (an earlier single-`execute()`
frame-yielding design was considered and reversed), the naming falling
out of that shape, and per-driver count semantics. Spec § Open Questions
records the reversal.

The project amends ADR 210 — Prepared Statements rather than adding a new
ADR: every principle it states survives, only the shape they were
expressed through changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Steven McClankerton <tatarintsev@prisma.io>
SevInf added a commit that referenced this pull request Aug 6, 2026
Shaping artifacts for the **affected-row-counts** project — spec and
three-slice plan, per the project lifecycle in `projects/README.md`.

## What this project does

`updateAndCount` and `deleteAndCount` run two statements: a `SELECT` of
every matching primary key, then the write — returning the *read's* row
count and discarding whatever the write reported. That is not atomic
(outside a transaction a concurrent insert is updated but not counted),
it evaluates the filter twice and materialises every matching key in JS
purely to call `.length` on it, and it builds the two `WHERE` clauses
through different code paths that already drifted once for MTI variants
(#940).

The count already exists and is thrown away — Postgres reports it in the
`CommandComplete` tag, SQLite in `sqlite3_changes64()` via
`StatementSync.run()`. The gap is structural: `RuntimeScope.execute()`
returns a row stream with nowhere for statement metadata to live.

After this project the driver SPI splits along the question being asked,
named the way every prior art names it (JDBC, ADO.NET, Go):

    query<Row>(req): AsyncIterable<Row>          // rows
    execute(req):    Promise<SqlStatementStats>  // { affectedRows: number }

`affectedRows` is not optional — absence is not a state either engine has
for the statements `execute()` exists to serve. Statistics never travel
through a row stream, so the seven `for await` re-wrap sites between
driver and caller stop being a hazard. Prepared-ness rides on the request
rather than doubling the method surface, so four driver methods become
two.

## Scope boundaries

Streaming write terminals, `createAndCount`, and new targets are out.
Count semantics are deliberately *not* unified across targets —
Postgres's command tag, SQLite's `sqlite3_changes64()`, and Mongo's
`modifiedCount` each mean something different, and the project documents
the difference rather than reconciling it.

## Decision provenance

Three questions were settled with the operator at spec time and moved
into the spec body: the execution shape (an earlier single-`execute()`
frame-yielding design was considered and reversed), the naming falling
out of that shape, and per-driver count semantics. Spec § Open Questions
records the reversal.

The project amends ADR 210 — Prepared Statements rather than adding a new
ADR: every principle it states survives, only the shape they were
expressed through changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Steven McClankerton <tatarintsev@prisma.io>
SevInf added a commit that referenced this pull request Aug 6, 2026
Shaping artifacts for the **affected-row-counts** project — spec and
three-slice plan, per the project lifecycle in `projects/README.md`.

## What this project does

`updateAndCount` and `deleteAndCount` run two statements: a `SELECT` of
every matching primary key, then the write — returning the *read's* row
count and discarding whatever the write reported. That is not atomic
(outside a transaction a concurrent insert is updated but not counted),
it evaluates the filter twice and materialises every matching key in JS
purely to call `.length` on it, and it builds the two `WHERE` clauses
through different code paths that already drifted once for MTI variants
(#940).

The count already exists and is thrown away — Postgres reports it in the
`CommandComplete` tag, SQLite in `sqlite3_changes64()` via
`StatementSync.run()`. The gap is structural: `RuntimeScope.execute()`
returns a row stream with nowhere for statement metadata to live.

After this project the driver SPI splits along the question being asked,
named the way every prior art names it (JDBC, ADO.NET, Go):

    query<Row>(req): AsyncIterable<Row>          // rows
    execute(req):    Promise<SqlStatementStats>  // { affectedRows: number }

`affectedRows` is not optional — absence is not a state either engine has
for the statements `execute()` exists to serve. Statistics never travel
through a row stream, so the seven `for await` re-wrap sites between
driver and caller stop being a hazard. Prepared-ness rides on the request
rather than doubling the method surface, so four driver methods become
two.

## Scope boundaries

Streaming write terminals, `createAndCount`, and new targets are out.
Count semantics are deliberately *not* unified across targets —
Postgres's command tag, SQLite's `sqlite3_changes64()`, and Mongo's
`modifiedCount` each mean something different, and the project documents
the difference rather than reconciling it.

## Decision provenance

Three questions were settled with the operator at spec time and moved
into the spec body: the execution shape (an earlier single-`execute()`
frame-yielding design was considered and reversed), the naming falling
out of that shape, and per-driver count semantics. Spec § Open Questions
records the reversal.

The project amends ADR 210 — Prepared Statements rather than adding a new
ADR: every principle it states survives, only the shape they were
expressed through changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Steven McClankerton <tatarintsev@prisma.io>
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.

5 participants