---
url: /unthrown/api/prisma.md
---
**@unthrown/prisma**

***

# @unthrown/prisma

## Classes

### ForeignKeyViolation

Defined in: [packages/prisma/src/index.ts:84](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L84)

A foreign key constraint was violated (Prisma error `P2003`).

#### Extends

* `TaggedErrorInstance`<`"ForeignKeyViolation"`, {
  `cause`: `unknown`;
  }>

#### Constructors

##### Constructor

```ts
new ForeignKeyViolation(fields): ForeignKeyViolation;
```

Defined in: [packages/prisma/src/index.ts:85](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L85)

###### Parameters

| Parameter | Type |
| ------ | ------ |
| `fields` | { `cause`: `unknown`; } |
| `fields.cause` | `unknown` |

###### Returns

[`ForeignKeyViolation`](#foreignkeyviolation)

###### Overrides

```ts
TaggedError("ForeignKeyViolation")<{ cause: unknown }>.constructor
```

#### Properties

| Property | Modifier | Type | Inherited from | Defined in |
| ------ | ------ | ------ | ------ | ------ |
|  `_tag` | `readonly` | `"ForeignKeyViolation"` | `TaggedError("ForeignKeyViolation")._tag` | packages/core/dist/index.d.mts:2360 |
|  `cause` | `public` | `unknown` | `TaggedError("ForeignKeyViolation").cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 |
|  `message` | `public` | `string` | `TaggedError("ForeignKeyViolation").message` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1075 |
|  `name` | `public` | `string` | `TaggedError("ForeignKeyViolation").name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 |
|  `stack?` | `public` | `string` | `TaggedError("ForeignKeyViolation").stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |

***

### InvalidCursor

Defined in: [packages/prisma/src/index.ts:121](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L121)

The cursor handed to `withCursor` could not be used — the caller's
`parseCursor` rejected it, or the query it produced was one Prisma refuses.

#### Remarks

The one anticipated failure of pagination, and the reason it is modeled at
all: a cursor is an **opaque string from the outside world** (a query
parameter), so a client sending garbage is input you answer with a 400 — not
a bug in your code. Every other pagination failure is a defect, like any other
query.

#### Extends

* `TaggedErrorInstance`<`"InvalidCursor"`, {
  `cause`: `unknown`;
  }>

#### Constructors

##### Constructor

```ts
new InvalidCursor(fields): InvalidCursor;
```

Defined in: [packages/prisma/src/index.ts:122](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L122)

###### Parameters

| Parameter | Type |
| ------ | ------ |
| `fields` | { `cause`: `unknown`; } |
| `fields.cause` | `unknown` |

###### Returns

[`InvalidCursor`](#invalidcursor)

###### Overrides

```ts
TaggedError("InvalidCursor")<{ cause: unknown }>.constructor
```

#### Properties

| Property | Modifier | Type | Inherited from | Defined in |
| ------ | ------ | ------ | ------ | ------ |
|  `_tag` | `readonly` | `"InvalidCursor"` | `TaggedError("InvalidCursor")._tag` | packages/core/dist/index.d.mts:2360 |
|  `cause` | `public` | `unknown` | `TaggedError("InvalidCursor").cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 |
|  `message` | `public` | `string` | `TaggedError("InvalidCursor").message` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1075 |
|  `name` | `public` | `string` | `TaggedError("InvalidCursor").name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 |
|  `stack?` | `public` | `string` | `TaggedError("InvalidCursor").stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |

***

### RecordNotFound

Defined in: [packages/prisma/src/index.ts:103](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L103)

A record required by the operation does not exist (Prisma errors `P2025` and
`P2018`) — the missing row of a `findUniqueOrThrow`, `update`, or `delete`,
**or** the missing target of a nested `connect`.

#### Remarks

The nested-`connect` case is why `tryCreate` and `tryUpsert` carry this error
despite never "missing" a row of their own: `create({ data: { author: {
connect: { id } } } })` raises `P2025` when that author does not exist (and
`P2018` for the to-many side of the same mistake). Both codes say the same
thing — a record the write depended on was not found — so both map here.

#### Extends

* `TaggedErrorInstance`<`"RecordNotFound"`, {
  `cause`: `unknown`;
  }>

#### Constructors

##### Constructor

```ts
new RecordNotFound(fields): RecordNotFound;
```

Defined in: [packages/prisma/src/index.ts:104](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L104)

###### Parameters

| Parameter | Type |
| ------ | ------ |
| `fields` | { `cause`: `unknown`; } |
| `fields.cause` | `unknown` |

###### Returns

[`RecordNotFound`](#recordnotfound)

###### Overrides

```ts
TaggedError("RecordNotFound")<{ cause: unknown }>.constructor
```

#### Properties

| Property | Modifier | Type | Inherited from | Defined in |
| ------ | ------ | ------ | ------ | ------ |
|  `_tag` | `readonly` | `"RecordNotFound"` | `TaggedError("RecordNotFound")._tag` | packages/core/dist/index.d.mts:2360 |
|  `cause` | `public` | `unknown` | `TaggedError("RecordNotFound").cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 |
|  `message` | `public` | `string` | `TaggedError("RecordNotFound").message` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1075 |
|  `name` | `public` | `string` | `TaggedError("RecordNotFound").name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 |
|  `stack?` | `public` | `string` | `TaggedError("RecordNotFound").stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |

***

### UniqueConstraintViolation

Defined in: [packages/prisma/src/index.ts:73](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L73)

A unique constraint was violated (Prisma error `P2002`).

#### Remarks

`fields` carries the offending column set from the error's `meta.target`
(empty when the driver does not report it).

#### Extends

* `TaggedErrorInstance`<`"UniqueConstraintViolation"`, {
  `cause`: `unknown`;
  `fields`: readonly `string`\[];
  }>

#### Constructors

##### Constructor

```ts
new UniqueConstraintViolation(fields): UniqueConstraintViolation;
```

Defined in: [packages/prisma/src/index.ts:77](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L77)

###### Parameters

| Parameter | Type |
| ------ | ------ |
| `fields` | { `cause`: `unknown`; `fields`: readonly `string`\[]; } |
| `fields.cause` | `unknown` |
| `fields.fields` | readonly `string`\[] |

###### Returns

[`UniqueConstraintViolation`](#uniqueconstraintviolation)

###### Overrides

```ts
TaggedError("UniqueConstraintViolation")<{
  fields: readonly string[];
  cause: unknown;
}>.constructor
```

#### Properties

| Property | Modifier | Type | Inherited from | Defined in |
| ------ | ------ | ------ | ------ | ------ |
|  `_tag` | `readonly` | `"UniqueConstraintViolation"` | `TaggedError("UniqueConstraintViolation")._tag` | packages/core/dist/index.d.mts:2360 |
|  `cause` | `public` | `unknown` | `TaggedError("UniqueConstraintViolation").cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 |
|  `fields` | `readonly` | readonly `string`\[] | `TaggedError("UniqueConstraintViolation").fields` | [packages/prisma/src/index.ts:74](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L74) |
|  `message` | `public` | `string` | `TaggedError("UniqueConstraintViolation").message` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1075 |
|  `name` | `public` | `string` | `TaggedError("UniqueConstraintViolation").name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 |
|  `stack?` | `public` | `string` | `TaggedError("UniqueConstraintViolation").stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |

## Type Aliases

### CreateError

```ts
type CreateError = 
  | UniqueConstraintViolation
  | ForeignKeyViolation
  | RecordNotFound;
```

Defined in: [packages/prisma/src/index.ts:250](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L250)

What `tryCreate` can fail with.

***

### CreateManyError

```ts
type CreateManyError = 
  | UniqueConstraintViolation
  | ForeignKeyViolation;
```

Defined in: [packages/prisma/src/index.ts:252](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L252)

What `tryCreateMany` / `tryCreateManyAndReturn` can fail with.

***

### CursorPaginationMeta

```ts
type CursorPaginationMeta = object & 
  | {
  endCursor: string;
  startCursor: string;
}
  | {
  endCursor: null;
  startCursor: null;
};
```

Defined in: [packages/prisma/src/pagination.ts:20](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/pagination.ts#L20)

The page metadata of `withCursor`.

#### Type Declaration

| Name | Type | Defined in |
| ------ | ------ | ------ |
| `hasNextPage` | `boolean` | [packages/prisma/src/pagination.ts:22](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/pagination.ts#L22) |
| `hasPreviousPage` | `boolean` | [packages/prisma/src/pagination.ts:21](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/pagination.ts#L21) |

#### Remarks

`startCursor` / `endCursor` are the cursors of the page's boundary rows, so
they are `null` together exactly when the page is empty — checking one
narrows the other. They are deliberately NOT coupled to the flags: the last
page has `hasNextPage: false` with a non-null `endCursor`, and an empty page
past the end has `hasPreviousPage: true` with a null `startCursor`.

***

### CursorPaginationOptions

```ts
type CursorPaginationOptions<Row, Cursor> = object & 
  | {
  after?: string;
  before?: never;
  limit: number;
}
  | {
  after?: never;
  before?: string;
  limit: number;
}
  | {
  after?: string;
  before?: never;
  limit: null;
};
```

Defined in: [packages/prisma/src/pagination.ts:49](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/pagination.ts#L49)

Options of `withCursor`, in the style of `prisma-extension-pagination`.

#### Type Declaration

| Name | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `getCursor()?` | (`row`) => `string` | Serialize a row into an opaque cursor. Defaults to `row.id`, as described above. | [packages/prisma/src/pagination.ts:51](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/pagination.ts#L51) |
| `parseCursor()?` | (`cursor`) => `Cursor` | Parse an opaque cursor back into the model's `cursor` input. | [packages/prisma/src/pagination.ts:53](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/pagination.ts#L53) |

#### Type Parameters

| Type Parameter | Description |
| ------ | ------ |
| `Row` | the (selection-narrowed) result row type. |
| `Cursor` | the model's `cursor` input (its unique-where shape). |

#### Remarks

`after` and `before` are mutually exclusive — a page runs in one direction,
and passing both used to silently drop `after`. Pick a direction.

`limit: null` returns everything (from the `after` cursor when given).
Combining `limit: null` with `before` is a compile error — "everything
before the cursor, backwards, unbounded" is not something Prisma's negative
`take` can express.

The default cursor is the record's `id` field, serialized with `String` and
parsed back to a number when it is all digits (autoincrement ids) — a bigint
once it exceeds `Number.MAX_SAFE_INTEGER`, so `BigInt` ids never lose
precision — or kept as a string otherwise (uuid / cuid ids). A **string** id
that is itself all digits is serialized with a leading `~` (`"~123"`), so it
parses back to the string rather than to a number. Provide
`getCursor` / `parseCursor` for composite keys, or when the selection omits
`id`.

***

### CursorPaginator

```ts
type CursorPaginator<Results, Cursor> = object;
```

Defined in: [packages/prisma/src/index.ts:352](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L352)

What `tryPaginate` returns: a builder holding the query, consumed by
`withCursor`.

#### Type Parameters

| Type Parameter | Description |
| ------ | ------ |
| `Results` *extends* readonly `unknown`\[] | the (selection-narrowed) `findMany` payload. |
| `Cursor` | the model's `cursor` input (its unique-where shape). |

#### Properties

| Property | Modifier | Type | Description | Defined in |
| ------ | ------ | ------ | ------ | ------ |
|  `withCursor` | `readonly` | (`options`) => `AsyncResult`<\[`Results`, [`CursorPaginationMeta`](#cursorpaginationmeta)], [`InvalidCursor`](#invalidcursor)> | Run the paginated query: the page and its metadata, or an [InvalidCursor](#invalidcursor) — the only modeled failure, since the cursor is the only part of the query that came from outside. | [packages/prisma/src/index.ts:358](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L358) |

***

### DeleteError

```ts
type DeleteError = 
  | RecordNotFound
  | UniqueConstraintViolation
  | ForeignKeyViolation;
```

Defined in: [packages/prisma/src/index.ts:260](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L260)

What `tryDelete` can fail with — `UniqueConstraintViolation` included, raised
when an `onDelete: SetDefault` / `SetNull` rewrite of the referencing rows
collides with a unique index.

***

### DeleteManyError

```ts
type DeleteManyError = 
  | UniqueConstraintViolation
  | ForeignKeyViolation;
```

Defined in: [packages/prisma/src/index.ts:266](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L266)

What `tryDeleteMany` can fail with — see [DeleteError](#deleteerror).

***

### PrismaQueryError

```ts
type PrismaQueryError = 
  | UniqueConstraintViolation
  | ForeignKeyViolation
  | RecordNotFound;
```

Defined in: [packages/prisma/src/index.ts:140](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L140)

The full union of domain errors a Prisma **query** can surface.

#### Remarks

This is the RUNTIME-side union: [qualifyPrismaError](#qualifyprismaerror) maps into it. Each
`try*` method narrows the static type to the codes its operation can actually
hit — a read hits none of them, so it is typed `never`.

Infrastructure failures are deliberately absent: they are defects, not values
(see [qualifyPrismaError](#qualifyprismaerror)). [InvalidCursor](#invalidcursor) is absent too — it
belongs to pagination, not to a query.

***

### TransactionClient

```ts
type TransactionClient<C> = Omit<C, TxDenyList>;
```

Defined in: [packages/prisma/src/index.ts:405](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L405)

The client an interactive `$tryTransaction` callback receives — the extended
client minus what a transaction cannot do.

#### Type Parameters

| Type Parameter | Description |
| ------ | ------ |
| `C` | the extended client, usually `typeof db`. |

#### Remarks

Name the `tx` parameter of a helper factored out of a callback with this,
rather than restating the deny list: `$tryTransaction` uses the very same
alias, so the two cannot drift. Restating it by hand does drift silently —
`Omit` of a key that does not exist is not an error, so a hand-copied list
keeps compiling after the library's own list changes.

Not to be confused with Prisma's own generated `Prisma.TransactionClient` —
that one is non-generic and, notably, does not remove `$tryTransaction`.

#### Example

```ts
type Tx = TransactionClient<typeof db>;

const chargeFees = (tx: Tx, id: number) =>
  tx.invoice.tryUpdate({ where: { id }, data: { charged: true } });

db.$tryTransaction((tx) => chargeFees(tx, 1));
```

***

### TransactionIsolationLevel

```ts
type TransactionIsolationLevel = 
  | "ReadUncommitted"
  | "ReadCommitted"
  | "RepeatableRead"
  | "Snapshot"
  | "Serializable";
```

Defined in: [packages/prisma/src/index.ts:338](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L338)

The isolation levels Prisma accepts across databases, as a closed union.

#### Remarks

The schema-derived `Prisma.TransactionIsolationLevel` of a generated client
is narrower (it lists only what YOUR database supports), but a shareable
extension cannot name a generated type — this union at least rejects typos
at compile time; a level your database does not support still fails at
runtime as a defect (an unsupported level is a bug, not an outcome).

***

### TryTransaction

```ts
type TryTransaction = {
<C, T, E>  (this, fn, options?): AsyncResult<T, PrismaQueryError | E>;
<C, P>  (this, operations, options?): AsyncResult<UnwrapPrismaTuple<P>, PrismaQueryError>;
};
```

Defined in: [packages/prisma/src/index.ts:425](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L425)

The type of `$tryTransaction`: overloaded exactly as Prisma's own
`$transaction` is — an interactive callback, or a batch of raw operations.

#### Call Signature

```ts
<C, T, E>(
   this, 
   fn, 
   options?
): AsyncResult<T, PrismaQueryError | E>;
```

An interactive transaction whose callback speaks `AsyncResult`: an `Err`
triggers a ROLLBACK and comes out as the same typed `Err`.

##### Type Parameters

| Type Parameter |
| ------ |
| `C` |
| `T` |
| `E` |

##### Parameters

| Parameter | Type |
| ------ | ------ |
| `this` | `C` |
| `fn` | (`tx`) => `AsyncResult`<`T`, `E`> |
| `options?` | { `isolationLevel?`: [`TransactionIsolationLevel`](#transactionisolationlevel); `maxWait?`: `number`; `timeout?`: `number`; } |
| `options.isolationLevel?` | [`TransactionIsolationLevel`](#transactionisolationlevel) |
| `options.maxWait?` | `number` |
| `options.timeout?` | `number` |

##### Returns

`AsyncResult`<`T`, [`PrismaQueryError`](#prismaqueryerror) | `E`>

##### Remarks

The callback's `Err` is thrown internally as a sentinel so Prisma aborts the
transaction, then unwrapped back into the typed error channel —
`AsyncResult<T, E | PrismaQueryError>`. A defect inside the callback also
rolls back and stays a defect — including a callback that *throws* instead
of returning an `AsyncResult` (a bug, never downgraded to a modeled error).
The `try*` methods are available on `tx` (extensions propagate into the
interactive transaction); the deny list additionally removes
`$tryTransaction` itself — no nesting. Name a helper's `tx` parameter with
[TransactionClient](#transactionclient).

The `| PrismaQueryError` is not merely defensive: a deferred constraint
surfaces its violation at COMMIT rather than at the statement, so the
transaction boundary itself can produce one. Prisma's own machinery failing
any other way (a `maxWait` / `timeout` expiry, a lost connection) is
infrastructure, and so a defect like everywhere else.

##### Example

```ts
const moved = db.$tryTransaction((tx) =>
  tx.account
    .tryUpdate({ where: { id: from }, data: { balance: { decrement: amount } } })
    .flatMap(() =>
      tx.account.tryUpdate({
        where: { id: to },
        data: { balance: { increment: amount } },
      }),
    ),
);
// Err anywhere → both updates rolled back, and the Err is in `moved`.
```

#### Call Signature

```ts
<C, P>(
   this, 
   operations, 
   options?
): AsyncResult<UnwrapPrismaTuple<P>, PrismaQueryError>;
```

A batch transaction: the operations run in one round trip, all or nothing,
with no application code held open in between.

##### Type Parameters

| Type Parameter |
| ------ |
| `C` |
| `P` *extends* readonly `PrismaPromise`<`unknown`>\[] |

##### Parameters

| Parameter | Type |
| ------ | ------ |
| `this` | `C` |
| `operations` | readonly \[`P`] |
| `options?` | { `isolationLevel?`: [`TransactionIsolationLevel`](#transactionisolationlevel); } |
| `options.isolationLevel?` | [`TransactionIsolationLevel`](#transactionisolationlevel) |

##### Returns

`AsyncResult`<[`UnwrapPrismaTuple`](#unwrapprismatuple)<`P`>, [`PrismaQueryError`](#prismaqueryerror)>

##### Remarks

Two things follow from Prisma's batch form taking **unexecuted**
`PrismaPromise`s, and both are deliberate:

* The array holds the **raw** delegate methods — `db.user.create(...)`, not
  `tryCreate`. A `try*` method has already executed and returns an
  `AsyncResult`, so passing one is a compile error.
* `E` is the whole [PrismaQueryError](#prismaqueryerror) union rather than the
  per-operation narrowing the `try*` methods give: a raw `PrismaPromise`
  carries no error-type information. Every infrastructure failure is still
  a defect, exactly as everywhere else.

A fixed tuple keeps positional types; a dynamic array (a `.map(...)`)
collapses to `AsyncResult<T[], PrismaQueryError>`.

`maxWait` and `timeout` are absent by design — they govern an interactive
transaction's open window, which a single-round-trip batch does not have.

##### Example

```ts
const rows = db.$tryTransaction(
  inputs.map((data) => db.user.create({ data })),
);
//    ^? AsyncResult<User[], PrismaQueryError>
// Any constraint violation → nothing is written, and the Err is modeled.
```

***

### TxDenyList

```ts
type TxDenyList = 
  | "$connect"
  | "$disconnect"
  | "$on"
  | "$transaction"
  | "$use"
  | "$extends"
  | "$tryTransaction";
```

Defined in: [packages/prisma/src/index.ts:370](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L370)

What an interactive-transaction client cannot do: Prisma's own
`ITXClientDenyList`, plus `$tryTransaction` itself — nested transactions are
not a thing, and the itx client has no `$transaction` for the bridge to
delegate to. Name a `tx` with [TransactionClient](#transactionclient) rather than
`Omit`-ing this by hand.

***

### UnwrapPrismaTuple

```ts
type UnwrapPrismaTuple<P> = { -readonly [K in keyof P]: P[K] extends Prisma.PrismaPromise<infer X> ? X : never };
```

Defined in: [packages/prisma/src/index.ts:417](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L417)

The results of a batch `$tryTransaction([...])`: each `PrismaPromise<T>`
unwrapped to its `T`. A fixed tuple keeps positional types; a dynamic
`PrismaPromise<T>[]` collapses to `T[]` — the same duality as core's `all`.

#### Type Parameters

| Type Parameter |
| ------ |
| `P` *extends* readonly `unknown`\[] |

#### Remarks

Prisma's own `UnwrapTuple` lives at `runtime.Types.Utils.UnwrapTuple`, behind
a runtime entry path this package deliberately never imports (it moved
between Prisma 6 and 7), so the mapping is written here.

***

### UpdateError

```ts
type UpdateError = 
  | RecordNotFound
  | UniqueConstraintViolation
  | ForeignKeyViolation;
```

Defined in: [packages/prisma/src/index.ts:254](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L254)

What `tryUpdate` can fail with.

***

### UpdateManyError

```ts
type UpdateManyError = 
  | UniqueConstraintViolation
  | ForeignKeyViolation;
```

Defined in: [packages/prisma/src/index.ts:264](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L264)

What `tryUpdateMany` / `tryUpdateManyAndReturn` can fail with.

***

### UpsertError

```ts
type UpsertError = 
  | UniqueConstraintViolation
  | ForeignKeyViolation
  | RecordNotFound;
```

Defined in: [packages/prisma/src/index.ts:262](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L262)

What `tryUpsert` can fail with.

## Variables

### unthrownPrisma

```ts
const unthrownPrisma: (client) => PrismaClientExtends<InternalArgs<{
}, {
  $allModels: {
     tryAggregate: AsyncResult<Result<T, A, "aggregate">, never>;
     tryCount: AsyncResult<Result<T, A, "count">, never>;
     tryCreate: AsyncResult<Result<T, A, "create">, CreateError>;
     tryCreateMany: AsyncResult<Result<T, A, "createMany">, CreateManyError>;
     tryCreateManyAndReturn: AsyncResult<Result<T, A, "createManyAndReturn">, CreateManyError>;
     tryDelete: AsyncResult<Result<T, A, "delete">, DeleteError>;
     tryDeleteMany: AsyncResult<Result<T, A, "deleteMany">, DeleteManyError>;
     tryFindFirst: AsyncResult<Result<T, A, "findFirst">, never>;
     tryFindFirstOrThrow: AsyncResult<Result<T, A, "findFirstOrThrow">, RecordNotFound>;
     tryFindMany: AsyncResult<Result<T, A, "findMany">, never>;
     tryFindUnique: AsyncResult<Result<T, A, "findUnique">, never>;
     tryFindUniqueOrThrow: AsyncResult<Result<T, A, "findUniqueOrThrow">, RecordNotFound>;
     tryGroupBy: AsyncResult<Result<T, A, "groupBy">, never>;
     tryPaginate: CursorPaginator<Result<T, A, "findMany">, NonNullable<Args<T, "findMany">["cursor"]>>;
     tryUpdate: AsyncResult<Result<T, A, "update">, UpdateError>;
     tryUpdateMany: AsyncResult<Result<T, A, "updateMany">, UpdateManyError>;
     tryUpdateManyAndReturn: AsyncResult<Result<T, A, "updateManyAndReturn">, UpdateManyError>;
     tryUpsert: AsyncResult<Result<T, A, "upsert">, UpsertError>;
  };
}, {
}, {
  $tryTransaction: TryTransaction;
}>>;
```

Defined in: [packages/prisma/src/index.ts:589](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L589)

The Prisma Client extension. Apply it with `$extends` to add the `try*`
methods to every model delegate, and `$tryTransaction` to the client.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `client` | `any` |

#### Returns

`PrismaClientExtends`<`InternalArgs`<{
}, {
`$allModels`: {
`tryAggregate`: `AsyncResult`<`Result`<`T`, `A`, `"aggregate"`>, `never`>;
`tryCount`: `AsyncResult`<`Result`<`T`, `A`, `"count"`>, `never`>;
`tryCreate`: `AsyncResult`<`Result`<`T`, `A`, `"create"`>, [`CreateError`](#createerror)>;
`tryCreateMany`: `AsyncResult`<`Result`<`T`, `A`, `"createMany"`>, [`CreateManyError`](#createmanyerror)>;
`tryCreateManyAndReturn`: `AsyncResult`<`Result`<`T`, `A`, `"createManyAndReturn"`>, [`CreateManyError`](#createmanyerror)>;
`tryDelete`: `AsyncResult`<`Result`<`T`, `A`, `"delete"`>, [`DeleteError`](#deleteerror)>;
`tryDeleteMany`: `AsyncResult`<`Result`<`T`, `A`, `"deleteMany"`>, [`DeleteManyError`](#deletemanyerror)>;
`tryFindFirst`: `AsyncResult`<`Result`<`T`, `A`, `"findFirst"`>, `never`>;
`tryFindFirstOrThrow`: `AsyncResult`<`Result`<`T`, `A`, `"findFirstOrThrow"`>, [`RecordNotFound`](#recordnotfound)>;
`tryFindMany`: `AsyncResult`<`Result`<`T`, `A`, `"findMany"`>, `never`>;
`tryFindUnique`: `AsyncResult`<`Result`<`T`, `A`, `"findUnique"`>, `never`>;
`tryFindUniqueOrThrow`: `AsyncResult`<`Result`<`T`, `A`, `"findUniqueOrThrow"`>, [`RecordNotFound`](#recordnotfound)>;
`tryGroupBy`: `AsyncResult`<`Result`<`T`, `A`, `"groupBy"`>, `never`>;
`tryPaginate`: [`CursorPaginator`](#cursorpaginator)<`Result`<`T`, `A`, `"findMany"`>, `NonNullable`<`Args`<`T`, `"findMany"`>\[`"cursor"`]>>;
`tryUpdate`: `AsyncResult`<`Result`<`T`, `A`, `"update"`>, [`UpdateError`](#updateerror)>;
`tryUpdateMany`: `AsyncResult`<`Result`<`T`, `A`, `"updateMany"`>, [`UpdateManyError`](#updatemanyerror)>;
`tryUpdateManyAndReturn`: `AsyncResult`<`Result`<`T`, `A`, `"updateManyAndReturn"`>, [`UpdateManyError`](#updatemanyerror)>;
`tryUpsert`: `AsyncResult`<`Result`<`T`, `A`, `"upsert"`>, [`UpsertError`](#upserterror)>;
};
}, {
}, {
`$tryTransaction`: [`TryTransaction`](#trytransaction);
}>>

#### Remarks

Typing follows Prisma's documented `$allModels` pattern: `this: T` binds the
concrete delegate, `Prisma.Exact` checks args, and `Prisma.Result` computes
the payload — so `select` / `include` inference survives the wrap.

#### Example

```ts
import { PrismaClient } from "./generated/prisma/client.ts";
import { unthrownPrisma } from "@unthrown/prisma";

const db = new PrismaClient({ adapter }).$extends(unthrownPrisma);

const users = db.user.tryFindMany({ select: { id: true } });
//    ^? AsyncResult<{ id: number }[], never>  — a read has no modeled failure
```

## Functions

### qualifyPrismaError()

```ts
function qualifyPrismaError<D>(cause, defect): D | PrismaQueryError;
```

Defined in: [packages/prisma/src/index.ts:206](https://github.com/btravstack/unthrown/blob/f4578e4b398ad7f3913ba2dec0343621762bbb27/packages/prisma/src/index.ts#L206)

Qualify a Prisma rejection — the runtime half of the bridge, and a ready-made
`qualify` for any boundary you build yourself (raw SQL).

#### Type Parameters

| Type Parameter |
| ------ |
| `D` |

#### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `cause` | `unknown` | the rejected value from a Prisma query. |
| `defect` | (`cause`) => `D` | the defect helper the boundary injects (never import it). |

#### Returns

`D` | [`PrismaQueryError`](#prismaqueryerror)

#### Remarks

The three P-codes that describe a **domain** outcome map to their tagged
errors — `P2002` → [UniqueConstraintViolation](#uniqueconstraintviolation), `P2003` →
[ForeignKeyViolation](#foreignkeyviolation), `P2025` / `P2018` → [RecordNotFound](#recordnotfound).

**Everything else is a defect**, with the original cause preserved: a dropped
connection, a pool timeout, a deadlock, an unmapped P-code, a malformed query,
a client that could not start, an engine panic. None of those is something
domain code branches on — they are logged and turned into a 500 at the edge,
which is precisely what the defect channel is for. Modelling them would force
every call site to carry an arm that duplicates its own `defect` arm.

A defect is not a crash: it flows through the pipeline untouched and is folded
by `match`'s `defect` handler like any other unmodeled failure.

#### Example

```ts
// Pass it straight to a boundary — `defect` is injected for you.
const rows = fromPromise(db.$queryRaw`SELECT 1`, qualifyPrismaError);
```
