Skip to content

docs(skills): prisma-next-queries — Postgres surface is always namespace-qualified#917

Open
ankur-arch wants to merge 3 commits into
mainfrom
docs/queries-skill-qualified-orm-surface
Open

docs(skills): prisma-next-queries — Postgres surface is always namespace-qualified#917
ankur-arch wants to merge 3 commits into
mainfrom
docs/queries-skill-qualified-orm-surface

Conversation

@ankur-arch

@ankur-arch ankur-arch commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What this fixes

The prisma-next-queries skill teaches agents (and people) how to query Prisma Next. Three things it teaches no longer match how the released packages behave. Anyone following the skill on a Postgres project today writes code that crashes on its first query.

This PR updates the skill to the tested behavior. Every correction was verified by running real queries against @prisma-next 0.14.0 on a live Postgres database, and cross-checked against the source on main.

The major change: Postgres access is always namespace-qualified

Since #778, the ORM and SQL builder resolve models through the schema namespace only:

// What the skill taught          // What actually works
db.orm.User.where(...)            db.orm.public.User.where(...)
db.sql.user.select(...)           db.sql.public.user.select(...)

The flat form does not error helpfully. db.orm.User is undefined, so the first chained call throws Cannot read properties of undefined (reading 'where'). The skill said the flat form "still works for single-namespace contracts", which is exactly the setup every new project has, so the guidance broke the most common case.

Impact: every Postgres example in the skill produced crashing code. This also affects the create-prisma scaffold templates (seed.ts, index.ts, users.ts still use the flat form, so npm run db:seed crashes on a fresh scaffold). That template fix is separate from this PR and still needed.

Two smaller corrections

  1. .count() is not a query terminal. Calling it throws count() is only available inside include() refinement callbacks. Counting goes through .aggregate((a) => ({ n: a.count() })), which the skill's aggregate section already documents. The terminal list now reads .all() / .first() / .aggregate(...).

  2. SQL builder inserts need the array form. .insert({ email }) fails inside result decoding on 0.14.0 (this[#rows].map is not a function). .insert([{ email }]) works, including .returning(...) and generated-id defaults. The example now uses the array form and notes the constraint.

How this was verified

db.orm.User                                          -> undefined
db.orm.public.User.where({...}).all()                -> rows ✓
db.orm.public.Post.where({...}).count()              -> throws
db.orm.public.Post.aggregate((a) => ({n: a.count()})) -> { n: number } ✓
db.sql.public.user.insert({ email })                 -> execute throws
db.sql.public.user.insert([{ email }]).returning(...) -> [{ id, email }] ✓

The same validation run surfaced a few adjacent issues that are out of scope here but worth tracking: the scaffold templates above, MongoDB @default(now()) not being applied at create time, and pipeline .match on ObjectId fields matching nothing. Happy to file them separately.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Updated Postgres query guidance to use namespace-qualified accessors throughout.
    • Clarified that flat Postgres access forms no longer apply and may resolve to undefined.
    • Refreshed examples for reads, writes, joins, aggregates, and scripts to match the current Postgres patterns.
    • Added clearer notes on common pitfalls and how to choose the right query path.

…s namespace-qualified

Corrections verified against @prisma-next 0.14.0 and current main while
writing the Prisma Next Fundamentals docs (prisma/web#8011):

- The flat `db.orm.User` / `db.sql.user` form does not exist on Postgres.
  #778 removed the flat fallback; the orm() proxy resolves only namespace
  keys, so bare model access returns `undefined` at runtime. All Postgres
  examples now use `db.orm.public.<Model>` / `db.sql.public.<table>`, and
  the "flat form still works for single-namespace contracts" claim is
  replaced with the tested behavior.
- `.count()` is not a collection terminal (it throws "count() is only
  available inside include() refinement callbacks"). Counting goes through
  `.aggregate((a) => ({ n: a.count() }))`; the terminal list is corrected.
- SQL-builder inserts must pass rows as an array. The single-object
  `.insert({...})` form fails at result decoding on 0.14.0; the example
  now uses `.insert([{...}])` and notes the constraint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ankur-arch
ankur-arch requested a review from a team as a code owner July 6, 2026 09:26
@coderabbitai

coderabbitai Bot commented Jul 6, 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: af10b4be-f5fd-40de-b336-2cb59d9d5820

📥 Commits

Reviewing files that changed from the base of the PR and between a047147 and c9cf152.

📒 Files selected for processing (2)
  • skills/prisma-next-queries/SKILL.md
  • skills/prisma-next-queries/postgres.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • skills/prisma-next-queries/SKILL.md
  • skills/prisma-next-queries/postgres.md

📝 Walkthrough

Walkthrough

Documentation updates across skills/prisma-next-queries/SKILL.md and skills/prisma-next-queries/postgres.md replace flat Postgres accessor forms with namespace-qualified db.orm.<ns>.<Model> and db.sql.<ns>.<table> usage, and state that flat Postgres access resolves to undefined.

Changes

Namespace-qualified accessor documentation

Layer / File(s) Summary
SKILL.md overview and accessor guidance
skills/prisma-next-queries/SKILL.md
Frontmatter, target-picking guidance, and checklist updated to describe namespace-qualified accessors and note that flat Postgres forms resolve to undefined.
SKILL.md consumption and script examples
skills/prisma-next-queries/SKILL.md
Consumption examples, single-consumption buffering, short-script seeding, and the N:M include workaround updated to namespace-qualified form.
postgres.md lane overview and read/query examples
skills/prisma-next-queries/postgres.md
Lane definitions, ORM reads, predicates, pagination, eager-loading, and read-side aggregate examples updated to namespace-qualified accessors.
postgres.md SQL builder and namespace behavior notes
skills/prisma-next-queries/postgres.md
SQL builder examples, DML returning examples, computed projection, self-join, namespace behavior notes, and grouped top-N guidance updated to namespace-qualified form.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • prisma/prisma-next#564: Both PRs update the same db.orm accessor addressing docs, one for Postgres namespace-qualified paths and one for MongoDB storage-name-keyed paths.
  • prisma/prisma-next#548: Related docs update in the same prisma-next-queries skill covering script teardown behavior alongside these accessor changes.

Suggested reviewers: wmadden

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main documentation change: Postgres access is now namespace-qualified throughout.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/queries-skill-qualified-orm-surface

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/prisma-next-queries/postgres.md`:
- Around line 111-117: The pagination example builds the next cursor from
page1[page1.length - 1] in the Post query flow, which will fail when the first
page is empty. Update the Post pagination snippet to guard the empty result from
db.orm.public.Post.orderBy(...).take(20).all() before deriving last or
constructing page2, and only continue to the next page when page1 has at least
one item.

In `@skills/prisma-next-queries/SKILL.md`:
- Around line 124-126: The Postgres short-script example is not self-contained
because the `users` iterable is missing, so the snippet cannot be copied and run
as shown. Update the example around the `for (const u of users)` and
`db.orm.public.User.create` usage by adding a concrete `users` binding or an
inline seed source in the same snippet so the loop has defined input.
- Around line 79-84: The buffered query example uses the projected shape from
User.select('id', 'email'), so the type annotation should match the returned row
shape instead of the full entity type. Update the Promise<User[]> annotation in
the buffered example to Promise<Row[]> and keep the surrounding prose/examples
consistent with the Row[] terminology used by
db.orm.public.User.select(...).all().toArray().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 18448aa6-cceb-44ae-a59f-adc5980ca23e

📥 Commits

Reviewing files that changed from the base of the PR and between a2791c5 and a047147.

📒 Files selected for processing (2)
  • skills/prisma-next-queries/SKILL.md
  • skills/prisma-next-queries/postgres.md

Comment thread skills/prisma-next-queries/postgres.md Outdated
Comment thread skills/prisma-next-queries/SKILL.md Outdated
Comment thread skills/prisma-next-queries/SKILL.md
Comment thread skills/prisma-next-queries/postgres.md Outdated
```

The flat `db.sql.users` / `db.orm.User` form still works when bare names are unique across all namespaces. When the same bare name appears in more than one namespace, use the coordinate form — both the type system and the runtime require it to resolve to the right table.
There is no flat `db.sql.users` / `db.orm.User` form: the namespace coordinate is always required on Postgres. The runtime proxy resolves only namespace keys, so a bare model access returns `undefined` (verified against 0.14.0 and current `main`; the flat fallback was removed in #778).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this historical fun fact in the skill?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, dropped. It now states the rule plainly: the namespace coordinate is always required on Postgres, and a bare model access returns undefined so the first chained call throws. Same cleanup applied to the equivalent sentence in SKILL.md. Fixed in c9cf152.


- **`db.orm.<Model>`** — ORM, PascalCase model name (`db.orm.User`). Fluent `.where(...).select(...).orderBy(...).all()`, fully typed against `Contract`. Default lane for CRUD with relations.
- **`db.sql.<table>`** — SQL builder, lowercase storage name (`db.sql.user`). Produces a *plan* executed via `db.runtime().execute(plan)`. Use when the ORM is too high-level — explicit `JOIN`, computed projections, set operations, window functions.
- **`db.orm.<ns>.<Model>`** — ORM, namespace-qualified PascalCase model name (`db.orm.public.User`). Fluent `.where(...).select(...).orderBy(...).all()`, fully typed against `Contract`. Default lane for CRUD with relations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to mention a bit on how ns relates to PSL and contract. We always use either public or placeholder <ns> throughout the doc. We should mention somewhere that public is default (for the models declarated outside of namespace block in PSL) and <ns> stand for a namespace model have been explicitly defined in.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Added a paragraph to the Key Concepts section (and mirrored it in SKILL.md's namespace section): models declared at the top level of the PSL live in the default public namespace, and models declared inside a namespace <name> { ... } block are addressed by that namespace; the examples use public and readers substitute their own. Fixed in c9cf152.

@SevInf SevInf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preemtively approve, but there are few things I'd like to change before we merge it

ankur-arch and others added 2 commits July 7, 2026 12:52
- Explain where the namespace coordinate comes from: top-level PSL
  models live in the default public namespace, models inside a
  namespace <name> { } block are addressed by that namespace (SevInf).
- Drop the historical note about the flat fallback's removal; state
  the rule plainly (SevInf).
- Guard the empty first page before deriving the cursor in the
  pagination example (CodeRabbit).
- Promise<User[]> -> Promise<Row[]> for consistency with the
  surrounding Row[] text (CodeRabbit).
- Make the short-script seed example self-contained by defining the
  users array it iterates (CodeRabbit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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