--- url: /unthrown/tutorial/getting-started.md --- # Getting started > **Tutorial.** A hands-on first lesson. Follow it top to bottom and you'll have > written, chained, and folded your first `Result`s. We keep explanation to a > minimum here and link out to it — the goal is to *do*, not to study. By the end you will have a small program that parses a value and handles every outcome as a value — with no `try`/`catch` to write. It takes about ten minutes. ## Step 1 — Install ::: code-group ```sh [pnpm] pnpm add unthrown ``` ```sh [npm] npm install unthrown ``` ```sh [yarn] yarn add unthrown ``` ::: `unthrown` is ESM-first, ships dual CJS/ESM builds with full types, and has **zero runtime dependencies** — the exhaustive error matcher is built-in (exported as `match` / `P`). Use it with TypeScript in `strict` mode. ## Step 2 — Return a failure instead of throwing A `Result` is either an **`Ok`** carrying a value `T`, or an **`Err`** carrying a *modeled* error `E`. `E` lists only the failures you *anticipate*. Say you're parsing a user-supplied age. Two things can go wrong. Model both instead of throwing: ```ts import { Ok, Err, type Result } from "unthrown"; type AgeError = "not_a_number" | "negative"; function parseAge(input: string): Result { const n = Number(input); if (Number.isNaN(n)) return Err("not_a_number"); if (n < 0) return Err("negative"); return Ok(n); } parseAge("42"); // => Ok(42) parseAge("-3"); // => Err("negative") parseAge("x"); // => Err("not_a_number") ``` Nothing is thrown — both outcomes come back as values. Notice the signature now tells the whole truth: a caller can *see* that `parseAge` may fail, and how. ## Step 3 — Transform and chain Success combinators run only on `Ok`; an `Err` passes straight through, so you can chain without checking at every step: ```ts const adult = parseAge("42") .map((n) => n + 1) // => Ok(43) — map: callback returns a plain value .flatMap((n) => (n >= 18 ? Ok(n) : Err("underage"))); // => Ok(43) — flatMap: callback returns a Result // adult: Result — flatMap unioned the error channels ``` The value stays wrapped in a `Result` the whole way — you extract it once, at the edge, in Step 4. Nothing is thrown along the way. And when a step fails, the rest of the chain is skipped: ```ts const parsed = parseAge("x") // => Err("not_a_number") .map((n) => n + 1); // callback never runs — still Err("not_a_number") if (parsed.isErr()) parsed.error; // => "not_a_number" ``` Rule of thumb: reach for `map` when your callback returns a plain value, `flatMap` when it returns another `Result`. (The full picture is in the [combinator reference](../reference/combinators) — you don't need it yet.) ## Step 4 — Handle every outcome with `match` At the edge of your program, fold a `Result` into a single value with `match`. You handle three runtime channels — `ok`, `errCases`, and a `defect` channel for the *unexpected* (you'll meet it in the next step): ```ts const message = parseAge("-3").match({ ok: (age) => `age is ${age}`, // `errCases` receives an exhaustive matcher — one branch per error. It // matches plain strings too (no tag required), and a missing case won't compile. errCases: (matcher) => matcher .with("negative", () => "must be positive") .with("not_a_number", () => "not a number"), defect: (cause) => { console.error(cause); // a bug slipped through — log it, don't leak it return "something went wrong"; }, }); // => "must be positive" ``` Try deleting the `.with("not_a_number", …)` branch — your editor will flag it as a compile error. That's the point: the error channel is matched **exhaustively**, so a new failure can never be silently ignored. ## Step 5 — Meet a defect What happens if a callback throws by accident — a typo, a `JSON.parse` on bad input? `unthrown` **catches it and turns it into a `Defect`**, a third state that is *not* part of your error type: ```ts const result = parseAge("42").map((age) => { throw new Error("boom"); // an unexpected bug }); result.isDefect(); // => true — not an Err, and not in AgeError ``` Because a thrown bug becomes a defect (never an `Err`), the single `match` from Step 4 needs **no surrounding `try`/`catch`** — the `defect` arm catches everything unexpected. That is the whole promise of the library: modeled failures travel as values, and bugs are quarantined in their own channel. ## What you built You now have a function that: * returns its failures as typed values instead of throwing; * chains transformations that skip automatically on failure; * folds every outcome — success, modeled error, and unexpected bug — in one exhaustive `match`. ## Where to go next * **Continue the tutorial:** [Crossing an async boundary](./crossing-an-async-boundary) — the same ideas, applied to promises. * **Understand the defect channel:** [The Defect Channel](../explanation/the-defect-channel). * **Look up a combinator:** [Combinator reference](../reference/combinators). --- --- url: /unthrown/tutorial/crossing-an-async-boundary.md --- # Crossing an async boundary > **Tutorial.** The second lesson. You've written and folded sync `Result`s in > [Getting started](./getting-started); now you'll bring a promise into the same > world — safely — and handle it with one `match` at the edge. Real programs cross async boundaries: they fetch, they query a database, they read a file. This lesson turns a rejecting promise into a `Result` and shows why the extra step it asks of you is worth it. ## Step 1 — Wrap a promise with `fromPromise` Say you have a function that fetches a user and **rejects** on a 404: ```ts declare function fetchUser(id: string): Promise; // rejects with NotFoundError on a 404 ``` Bring it into `unthrown` with `fromPromise`. It asks for a second argument, `qualify`, and this is the heart of the lesson: **you must decide what each rejection means.** Is it a modeled error, or an unexpected bug? ```ts import { fromPromise, TaggedError } from "unthrown"; class NotFound extends TaggedError("NotFound") {} // our modeled domain failure const user = fromPromise(fetchUser(id), (cause, defect) => cause instanceof NotFoundError ? new NotFound() : defect(cause), ); // user: AsyncResult ``` Read the `qualify` line out loud: "if the rejection was a `NotFoundError`, model it as `NotFound`; otherwise it's a bug — `defect(cause)`." The `defect` helper is handed to you by the boundary; you never import it. Notice the resulting type: `AsyncResult`. The bug branch (`defect(cause)`) is **not** in the error type — defects are invisible to `E`. There is no path here that leaves you with `unknown` to deal with. (The reasoning is in [Qualification](../explanation/qualification) — but you don't need it to proceed.) ## Step 2 — Chain, just like a sync Result An `AsyncResult` has the **same methods** as a `Result`. Chain it exactly as you did in lesson 1 — the callbacks stay synchronous: ```ts const name = fromPromise(fetchUser(id), (cause, defect) => cause instanceof NotFoundError ? new NotFound() : defect(cause), ) .map((u) => u.name) // runs on success .map((n) => n.trim()); // still AsyncResult ``` ## Step 3 — `await` collapses it to a `Result` An `AsyncResult` is awaitable. `await` it, and you get back an ordinary `Result` you can `match` — and it **never throws**, because every rejection was already captured as an `Err` or a `Defect`: ```ts const settled = await user; // Result ``` ## Step 4 — One `match` at the edge Put it together into a request handler. There is **no `try`/`catch`** anywhere: a modeled `NotFound` lands in `err`, and anything unexpected — a network failure, a bug in a `.map` — lands in `defect`: ```ts const status = await user.match({ ok: () => 200, errCases: (matcher) => matcher.with({ _tag: "NotFound" }, () => 404), defect: (cause) => { logger.error(cause); return 500; // everything unexpected }, }); ``` `match` accepts the `AsyncResult` directly and resolves to a `Promise`, so you can `await` the whole expression. (You could also `await user` first, then `match` the plain `Result` — same result.) ## Step 5 — Add a second async step To do more async work, you don't reach for an `async` callback — those are deliberately not allowed, because a rejection inside one would skip the triage you just did. Instead you re-enter through another boundary and compose with `flatMap`: ```ts const order = await fromPromise(loadCart(id), qualify).flatMap((cart) => fromPromise(checkout(cart), qualify), ); ``` The extra `fromPromise` isn't ceremony — it's the same forced decision as Step 1, guaranteeing the second call's failures are triaged too. (Why callbacks stay sync: [The async model](../explanation/async-model).) ## What you built You now know how to: * bring a rejecting promise into `unthrown` with `fromPromise`, deciding per cause whether it's a modeled error or a defect; * chain an `AsyncResult` with the same combinators as a sync `Result`; * `await` it into a `Result` that never throws, and fold it with one `match`. ## Where to go next * **Solve specific tasks:** the [How-to guides](../how-to/qualify-a-boundary) cover boundaries, tagged errors, do-notation, and framework integrations. * **Understand the design:** [Qualification](../explanation/qualification) and [The async model](../explanation/async-model). * **Look things up:** [Combinator reference](../reference/combinators). --- --- url: /unthrown/how-to/upgrade-to-v5.md --- # Upgrade from 4.x to 5.0 > **How-to.** A checklist for moving an existing codebase from `unthrown@4.x` to > `5.0`. Most of it is mechanical renames the compiler will point at; two changes > are worth doing deliberately. Work top to bottom. ## At a glance | Kind | 4.x | 5.0 | | ---------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | **Renamed** (loud) | `mapErr` / `flatMapErr` / `recoverErr` / `tapErr` / `flatTapErr` | `mapErrCases` / `flatMapErrCases` / `recoverErrCases` / `tapErrCases` / `flatTapErrCases` | | **Renamed** (loud) | `match({ ok, err, defect })` | `match({ ok, errCases, defect })` | | **Renamed export** | `UnwrapError` | `GetError` | | **Removed** (aliases) | `unwrap` / `unwrapErr` / `unwrapOr` / `unwrapOrElse` | `get` / `getErr` / `getOr` / `getOrElse` | | **Removed** (aliases) | `orElse` / `recover` | `flatMapErrCases` / `recoverErrCases` | | **Removed** | `matchTags` / the `TagHandlers` type | `match({ …, errCases: (m) => m.with(P.tag("…"), …) })` | | **Renamed** (loud) | the standalone `tag("…")` export | `P.tag("…")` — it lives in the pattern namespace with every other constructor | | **Changed, same name** | `getOrThrow()` on any `Result` | gated to a **non-empty** error channel (use `get()` otherwise) | | **Packaging** | `ts-pattern` bundled as a dependency | the matcher is **built-in** — no dependency at all | | **Packaging** | `@unthrown/pattern` (`match` / `P` / `tag`) | absorbed into core — import them from `unthrown` | | **New** | — | `ensure`, `DoAsync`, and the built-in `match` / `P` / `NonExhaustiveError` | Everything except the two rows below is a compile error at the old call site, so `pnpm typecheck` is your migration to-do list. ## 1. Nothing to install — the matcher is built-in unthrown's exhaustive matcher is its own module (same `.with(…)` / `P` call-site shape ts-pattern users know), exported as `match` / `P` / `NonExhaustiveError`. There is **no dependency to install** alongside `unthrown` — and no version of any third-party library can change what "exhaustive" means. (History, if you followed the betas: early v5 bundled `ts-pattern`, then briefly declared it a peer; the built-in matcher replaced it. If you added `ts-pattern` for unthrown's sake, you can remove it — unless your own code imports it directly for other matching.) One boundary to know: patterns built by the real `ts-pattern` library are **not** accepted by unthrown's matchers (and vice versa). Import `P` / `match` from `"unthrown"` at unthrown call sites; keep `ts-pattern` for your own unrelated matching if you use it. ## 2. Rename the error-channel combinators Every Err-channel combinator gained a `…Cases` suffix, because each takes a matcher over the error's *cases*, not a plain `(error) => …` callback. The old names no longer exist, so the compiler flags each site: ```diff - result.mapErr((m) => m.with(tag("NotFound"), wrap)) + result.mapErrCases((m) => m.with(P.tag("NotFound"), wrap)) ``` The arm moved too — `tag(…)` is now `P.tag(…)`, a separate change covered in [§7](#_7-tag-moved-onto-p). Same for `flatMapErr` → `flatMapErrCases`, `recoverErr` → `recoverErrCases`, `tapErr` → `tapErrCases`, `flatTapErr` → `flatTapErrCases`. See [Exhaustive error matching](../explanation/exhaustive-error-matching) for why. ## 3. Rename `match`'s error handler — `err` → `errCases` ::: warning The one break the compiler almost missed In 5.0 the `match` error handler receives the **matcher**, not the error value, and its key is renamed `err` → `errCases` to match the combinators. That rename is what makes the change **loud**: a leftover 4.x `err: (error) => …` handler still satisfied the new matcher constraint whenever it threw (a throwing handler returns `never`, which vacuously satisfies it), so it compiled and then threw the *matcher object* at runtime. The renamed key turns that into an excess-property compile error instead. ::: ```diff result.match({ ok: (value) => value, - err: (error) => handleError(error), + errCases: (matcher) => matcher.with(P._, (error) => handleError(error)), defect: (cause) => report(cause), }) ``` The `P._` arm above is the **mechanical** port — a 4.x `err` callback was a blanket handler, and one wildcard reproduces it exactly. Treat it as a way station, not a destination: replace it with one arm per case in `E` (grouping those that share a handler) so the site starts failing the build when the union grows. That is the whole reason the handler changed shape. `@unthrown/oxlint`'s [`no-catch-all-pattern`](./lint-your-codebase#no-catch-all-pattern), now in the recommended preset, will point at every arm still waiting to be converted. If your old `err` handler was `(error) => { throw error }`, prefer [`getOrThrow()`](../reference/combinators) over re-throwing inside a match arm as a mechanical stopgap during the port — it throws the modeled error as-is, matching the old behavior with one call. Treat it the same way as the `P._` arm above: a way station, not the destination. Once the site is converted for real, fold the channel instead (`match` / `recoverErrCases` + `get`) — the opt-in [`no-get-or-throw`](./lint-your-codebase#no-get-or-throw) rule flags any `getOrThrow()` left outside a test file. ## 4. Replace the removed aliases The `@deprecated` aliases from the 4.x line are gone (one concept, one name): | Removed | Use | | -------------- | ------------------------------------------------------ | | `unwrap` | `get` | | `unwrapErr` | `getErr` | | `unwrapOr` | `getOr` | | `unwrapOrElse` | `getOrElse` | | `orElse` | `flatMapErrCases` | | `recover` | `recoverErrCases` | | `matchTags` | `match({ …, errCases: (m) => m.with(P.tag("…"), …) })` | `UnwrapError` (the throw type of `get`/`getErr`) is renamed **`GetError`**. ## 5. Check the two behavioural gates * **`getOrThrow()`** now compiles only when the error channel is **non-empty**. On a `Result` there is nothing to throw, so the compiler steers you to `get()`. The diagnostic names the reason. * **`get()` / `getErr()`** are unchanged, but if you were relying on `getOrThrow` as a universal extractor, split by channel state: `get()` when `E = never`, `getOrThrow()` when it isn't. ## 6. `@unthrown/pattern` is gone `match` and `P` are now exported by `unthrown` itself, and the package's `tag` helper is now `P.tag` (see the next section). Drop the `@unthrown/pattern` dependency and re-point the imports: ```diff - import { match, P, tag } from "@unthrown/pattern"; + import { match, P } from "unthrown"; ``` ## 7. `tag` moved onto `P` `tag(t)` builds the `{ _tag: t }` pattern — it is a pattern constructor, so it now lives in the pattern namespace beside `P._`, `P.instanceOf`, `P.when` and the rest. The standalone export is **removed**, not deprecated: one concept, one spelling. ```diff - import { tag } from "unthrown"; + import { P } from "unthrown"; result.mapErrCases((matcher) => matcher - .with(tag("NotFound"), () => 404) - .with(tag("Conflict"), () => 409), + .with(P.tag("NotFound"), () => 404) + .with(P.tag("Conflict"), () => 409), ); ``` The missing `tag` export is a compile error at every import site, and each call site follows from it. Nothing about the pattern's behaviour changed. ## What you gained * **`ensure`** — validate or refine a success in place (`Result`, or a type-guard narrowing `T`). * **`DoAsync()`** — the pre-lifted async twin of `Do()`. * **`match` / `P`** as first-class re-exports, so the error matcher is one import. --- --- url: /unthrown/how-to/migrate-from-try-catch.md --- # Migrate from try/catch > **How-to.** Convert throwing code to `Result` incrementally — one function at a > time, no big-bang rewrite. You don't need a design review to start. Wrap one function, see the shape at one call site, and stop there until it's obviously worth doing again. ## Wrap a throwing function Say you have a function that throws, called from a `try`/`catch`: ```ts function loadConfig(text: string): Config { try { return JSON.parse(text) as Config; // throws SyntaxError on bad input } catch (cause) { console.error("invalid config", cause); return DEFAULT_CONFIG; } } ``` Wrap the throwing function with `fromThrowable`. `qualify` decides which causes are modeled and which are bugs — here a `SyntaxError` is expected, anything else is a defect: ```ts import { fromThrowable } from "unthrown"; const parseConfig = fromThrowable( (text: string) => JSON.parse(text) as Config, (cause, defect) => cause instanceof SyntaxError ? ("invalid_json" as const) : defect(cause), ); // (text: string) => Result ``` The call site drops its `try`/`catch` for a combinator: ```ts function loadConfig(text: string): Config { return parseConfig(text).getOr(DEFAULT_CONFIG); } ``` ## Wrap a rejecting promise Same move for a rejecting promise — wrap it with `fromPromise`: ```ts import { fromPromise } from "unthrown"; function getUser(id: string) { return fromPromise( fetch(`/api/users/${id}`).then((res) => { if (!res.ok) throw new NotFoundError(id); return res.json() as Promise; }), (cause, defect) => cause instanceof NotFoundError ? ("not_found" as const) : defect(cause), ); // AsyncResult } ``` The call site becomes an ordinary `Result`, `await`ed once: ```ts const user = await getUser(id); // Result user.match({ ok: (u) => render(u), errCases: (matcher) => matcher.with("not_found", () => render404()), // the one modeled error defect: (cause) => render500(cause), }); ``` (New to boundaries? [Qualify a boundary](./qualify-a-boundary) covers the `from*` family in full.) ## You don't have to convert the whole codebase `Result` composes at whatever boundary you choose to draw it — no requirement that every function up and down the stack returns one. `getOrThrow()` lets you re-enter throw-land at the edges you haven't converted yet, on purpose — it throws the modeled error **as-is** (unlike `get()`, which only compiles once the error channel is `never`): ```ts // Only the read is converted. Everything downstream still expects a plain // Config, or a thrown error — getOrThrow() is the deliberate seam. function loadConfig(text: string): Config { return parseConfig(text).getOrThrow(); // throws "invalid_json" on bad input } ``` This is a mid-migration seam, not the final shape: `getOrThrow()`'s lasting home is **tests and scripts**, and a call like the one above is exactly what the opt-in [`no-get-or-throw`](./lint-your-codebase#no-get-or-throw) rule flags once you turn it on — so revisit `loadConfig` once its callers are ready to hold a `Result` instead. Convert the parts where an untyped failure actually costs you something — a boundary you keep getting wrong, a `catch` block that silently swallows a bug. Leave the rest throwing until it earns the conversion. ## `try`/`catch` idioms → combinators A `catch` block sees one opaque value; a matcher sees the **cases**. Each row below names them — `parseConfig`'s channel is the single `"invalid_json"` case, so that is what the arms spell out: | `try`/`catch` idiom | unthrown combinator | Example | | ------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------- | | catch-and-default | `getOr(fallback)` | `parseConfig(text).getOr(DEFAULT_CONFIG)` | | catch-and-rethrow-wrapped | `mapErrCases((matcher) => …)` | `parseConfig(text).mapErrCases((m) => m.with("invalid_json", (e) => new ConfigError(e)))` | | catch-log-rethrow | `tapErrCases((matcher) => …)` | `parseConfig(text).tapErrCases((m) => m.with("invalid_json", (e) => logger.warn(e)))` | | `finally` cleanup | run before eliminating, or in every `match` arm | see below | `catch-and-rethrow-wrapped` — turn a caught error into a modeled `Err`: ```ts // before: throw new ConfigError(cause) // after: ConfigError becomes a modeled Err, not a throw parseConfig(text).mapErrCases((matcher) => matcher.with("invalid_json", (e) => new ConfigError(e)), ); ``` `catch-log-rethrow` — log, keep the original error, still propagate as an `Err`: ```ts parseConfig(text).tapErrCases((matcher) => matcher.with("invalid_json", (e) => logger.warn("bad config", e)), ); ``` Add a second case to `qualify` later — say a `"missing_field"` — and every one of these arms stops compiling until you say what it does. That is the trade a `catch (cause)` block can never make. `finally` has no combinator counterpart — a `Result` pipeline has no single point that always runs on the way out, since `Ok`, `Err`, and `Defect` can each take a different path. Do the cleanup either **unconditionally before** a combinator that could short-circuit, or **inside every arm** of the terminal `match`: ```ts const result = parseConfig(text).map((c) => apply(connection, c)); result.match({ ok: (v) => { connection.close(); return v; }, errCases: (matcher) => matcher.with("invalid_json", (e) => { connection.close(); return handleErr(e); }), defect: (cause) => { connection.close(); throw cause; // still a bug — let it bubble after cleanup }, }); ``` ## Where to go next * The boundary constructors in full: [Qualify a boundary](./qualify-a-boundary). * Fold the converted result: [Handle results at the edge](./handle-results-at-the-edge). * Coming from neverthrow instead: [Migrate from neverthrow](./migrate-from-neverthrow). --- --- url: /unthrown/how-to/migrate-from-neverthrow.md --- # Migrate from neverthrow > **How-to.** Both libraries return failures as values. Most of the API maps > one-to-one; the migration is mechanical for ~90% of your code. The other 10% is > where the two genuinely disagree — do that part on purpose, not by > search-and-replace. ## API mapping | neverthrow | unthrown | Notes | | ------------------------------------ | ------------------------------------------------- | -------------------------------------------------------------------------------------- | | `ok(v)` / `err(e)` | `Ok(v)` / `Err(e)` | constructors are capitalized | | `result.andThen(f)` | `result.flatMap(f)` | one name per concept | | `result.map(f)` | same | callbacks must be synchronous | | `result.mapErr(f)` | `result.mapErrCases((matcher) => …)` | an exhaustive match — one `.with(…)` arm per case in `E`, not a single callback | | `result.orElse(f)` | `result.flatMapErrCases((matcher) => …)` | `flatMap` on the error channel; same exhaustive matcher | | `result.match(okFn, errFn)` | `match({ ok, errCases: (matcher) => …, defect })` | the third channel is new, and `errCases` takes the same exhaustive matcher — see below | | `result.unwrapOr(v)` | `result.getOr(v)` | still throws on a Defect (a bug is not an absent value) | | `ResultAsync` | `AsyncResult` | `await` collapses it to a `Result`; it never rejects | | `ResultAsync.fromPromise(p, mapErr)` | `fromPromise(p, qualify)` | `qualify` must return `E` **or** `defect(cause)` — triage is forced | | `ResultAsync.fromSafePromise(p)` | `fromSafePromise(p)` | a rejection becomes a `Defect`, not an `Err` | | `Result.combine([...])` | `all([...])` | any `Defect` dominates | | `Result.combineWithAllErrors` | — | error accumulation is deliberately excluded | | `safeTry(function* …)` | `Do().bind(…).let(…)` | see [do-notation](./sequence-dependent-steps) | | `fromThrowable(fn, mapErr)` | `fromThrowable(fn, qualify)` | same idea, plus the defect arm | Most rows are a rename. `andThen` → `flatMap` is unthrown's [one-name-per-concept](../explanation/design-decisions#one-name-per-concept-no-aliases) rule. The one behavioral change to know up front: `mapErrCases` (and the other error combinators) take an **exhaustive matcher** rather than a plain callback. Port a `mapErr(f)` by **naming each case** the old callback silently absorbed — `.mapErrCases((matcher) => matcher.with(P.tag("NotFound"), f).with(P.tag("Conflict"), f))` — and let the compiler tell you when you have missed one. That enumeration is the migration's actual payoff; the reasoning is in [Exhaustive error matching](../explanation/exhaustive-error-matching). The rest of the table is where the libraries genuinely differ. ## Delta 1 — the defect channel In neverthrow, a throw inside `.map` (or a bug that slips past `mapErr`) escapes as a real exception — and an async one rejects the underlying `ResultAsync`. In practice every handler still needs a `try`/`catch` as a backstop. In unthrown, a throw inside any **combinator** becomes a `Defect` — a third state, not part of `E`, that flows down the pipeline to `match`'s mandatory `defect` arm. So the `try`/`catch` around the pipeline goes away: ```ts // neverthrow — a try/catch backstop is load-bearing, not defensive fluff app.get("/users/:id", async (req, res) => { try { const result = await getUser(req.params.id).map((user) => formatUser(user)); // a bug in formatUser rejects the ResultAsync result.match( (view) => res.status(200).json(view), (error) => res.status(404).json({ error: error.message }), ); } catch (cause) { console.error(cause); // one bucket for "everything else that went wrong" res.status(500).json({ error: "internal error" }); } }); ``` ```ts // unthrown — the same bug becomes a Defect inside the pipeline; no try/catch import { P } from "unthrown"; // getUser: (id: string) => AsyncResult app.get("/users/:id", async (req, res) => { const result = await getUser(req.params.id).map((user) => formatUser(user)); // a bug in formatUser → Defect result.match({ ok: (view) => res.status(200).json(view), errCases: (matcher) => matcher .with(P.tag("NotFound"), () => res.status(404).json({ error: "not found" }), ) .with(P.tag("Forbidden"), () => res.status(403).json({ error: "forbidden" }), ), defect: (cause) => { console.error(cause); // everything the pipeline caught lands here res.status(500).json({ error: "internal error" }); }, }); }); ``` One precise caveat: the containment covers the **combinators**, not `match`'s own callbacks — keep those trivial (send the response, log) and put anything failable in a pipeline step above. ## Delta 2 — `qualify` replaces the error mapper neverthrow's `fromPromise` maps *every* rejection into `E` — the mapper is total, with no way to say "this one is a bug." unthrown's `qualify` makes you decide, per cause, which bucket it goes in. The mechanical rewrite is: ```ts (e) => toE(e) // becomes (cause, defect) => (isExpected(cause) ? toE(cause) : defect(cause)) ``` If every cause your old mapper handled really was expected, this is a one-line change. If some were "whatever, stick it in `E` and move on," that's exactly the smell the defect channel exists to surface — route those through `defect(cause)`. ## What you can delete after migrating * the eslint `must-use-result` setup — `@unthrown/oxlint` ships a syntactic [`no-unhandled-result`](./lint-your-codebase#no-unhandled-result) rule; * defensive `try`/`catch` around combinator chains — the defect channel is the backstop now; * any `E = unknown` / `E = Error` unions that existed to absorb "everything else" — that is the defect channel's job now. ## Where to go next * Why the error matcher: [Exhaustive error matching](../explanation/exhaustive-error-matching). * The channel that replaces your backstop: [The Defect Channel](../explanation/the-defect-channel). * A side-by-side of both libraries: [Comparison](../explanation/comparison). --- --- url: /unthrown/how-to/migrate-from-boxed.md --- # Migrate from Boxed > **How-to.** Boxed (`@bloodyowl/boxed`) and unthrown agree on the core — > failures as values, a `Result` you match on — so most of the `Result` surface > maps row for row. The real work sits in the types Boxed has and unthrown > deliberately does not: `Option`, `AsyncData`, and `Future`'s untriaged error > channel. Do those on purpose, not by search-and-replace. ## API mapping | Boxed | unthrown | Notes | | -------------------------------------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------- | | `Result.Ok(v)` / `Result.Error(e)` | `Ok(v)` / `Err(e)` | free functions, not statics | | `result.map(f)` / `result.flatMap(f)` | same | callbacks must be synchronous | | `result.mapError(f)` | `result.mapErrCases((matcher) => …)` | an exhaustive match — one `.with(…)` arm per case in `E`, not a single callback | | `result.match({ Ok, Error })` | `match({ ok, errCases: (matcher) => …, defect })` | the third channel is new — see below | | `result.getWithDefault(v)` / `getOr(v)` | `result.getOr(v)` | still throws on a Defect (a bug is not an absent value) | | `result.toUndefined()` / `toNull()` | `getOrUndefined()` / `getOrNull()` | same recovery, `get…` spelling | | `result.tapOk(f)` / `tapError(f)` | `tap(f)` / `tapErrCases((matcher) => …)` | the error observer takes the same exhaustive matcher | | `Result.fromExecution(fn)` | `fromThrowable(fn, qualify)` | wraps the **function**; `qualify` triages each throw into `E` or `defect(cause)` | | `Result.fromNullable(v)` (+ `fromNull`, `fromUndefined`) | `fromNullable(v, onAbsent)` | absence gets a **named** error, not `undefined` in `E` | | `Result.all([...])` / `allFromDict({...})` | `all([...])` / `allFromDict({...})` | same shapes; any `Defect` dominates | | `Future>` | `AsyncResult` | both never reject — the kinship that makes this migration natural | | `Future.fromPromise(p)` | `fromPromise(p, qualify)` | Boxed hands you `Result`; `qualify` forces the triage instead | | `future.mapOk(f)` / `future.mapError(f)` | `asyncResult.map(f)` / `mapErrCases(…)` | the `Ok`-suffix disappears — the combinators are channel-named already | | `future.flatMapOk(f)` | `asyncResult.flatMap(f)` | `f` may return a `Result` or an `AsyncResult` | | `future.mapOkToResult(f)` | `flatMap(f)` — or `ensure(pred, onFail)` | when `f` only gates its own argument, `ensure` is the named form | | `future.mapErrorToResult(f)` | `flatMapErrCases((matcher) => …)` | fallback on the error channel, exhaustively | | `Future.all([...])` | `allAsync([...])` | `Future.allFromDict` → `allFromDictAsync` | | `Option` | — | deliberately no `Option` — see below | | `AsyncData` / `Deferred` | — | request-lifecycle state, not error handling — see below | | `Future.retry` / `Future.concurrent` | — | orchestrate with your async tooling **before** the `fromPromise` boundary | ## Delta 1 — `Option` disappears unthrown has no `Option` type, on purpose: absence is expressed with the type system we already trust. Each `Option` in your code is one of three things — decide which, per site: ```ts // 1. Absence is a normal, expected shape → T | undefined function findCached(sku: string): Item | undefined { return cache.get(sku) ?? undefined; } // 2. Absence is a failure the caller must handle → Result function requireItem(sku: string): Result { return fromNullable(cache.get(sku), () => new ItemNotFound({ sku })); } // 3. A nullable third-party API crossing into a pipeline → fromNullable at the boundary const port = fromNullable(process.env["PORT"], () => "port_unset" as const); ``` An `Option`-returning helper whose callers all fold with a default (`getWithDefault`) is case 1 — the migration usually *deletes* the combinator chain, because with `T | undefined` a plain conditional does the folding. `option.toResult(error)` sites are case 2 by definition. Resist inventing a local `Option` to keep the shapes — the [design decision](../explanation/design-decisions) is that two ways to spell absence is one too many. ## Delta 2 — the error channel is triaged, and defects get their own lane Boxed's `Future.fromPromise` gives you `Result` — every rejection, expected or not, lands in the error channel as `Error` (usually behind an `as Error` cast). unthrown's boundary makes you decide, per cause: ```ts // Boxed — everything is Error, the cast is load-bearing Future.fromPromise(api.get(`/items/${sku}`)).mapError((e) => e as Error); // unthrown — each rejection is triaged into a named case or the defect channel fromPromise(api.get(`/items/${sku}`), (cause, defect) => isHttpNotFound(cause) ? new ItemNotFound({ sku }) : defect(cause), ); ``` If a boundary's rejections really are all one anticipated failure, qualify them all into one named case (`(cause) => new FetchFailed({ sku, cause })`) — ignoring the injected `defect` helper is a legitimate "fully modeled" decision. What you may not do is keep `E = Error`: the [`no-ambiguous-error-type`](./lint-your-codebase#no-ambiguous-error-type) rule holds the line, and everything that was "whatever, stick it in `Error`" now belongs to [the defect channel](../explanation/the-defect-channel). The payoff mirrors the [neverthrow migration](./migrate-from-neverthrow#delta-1--the-defect-channel): a throw inside any combinator becomes a `Defect` and flows to `match`'s mandatory `defect` arm, so the defensive `try`/`catch` around pipelines goes away. ## Delta 3 — `AsyncData` has no target, and that's fine `AsyncData` models a request's *lifecycle* (`NotAsked` / `Loading` / `Done`), which is UI state, not error handling — unthrown deliberately stays out of it. Two honest options: ```ts // Model it yourself — a small discriminated union, matchable natively type ItemState = | { tag: "NotAsked" } | { tag: "Loading" } | { tag: "Done"; result: Result }; ``` or keep using Boxed's `AsyncData` for view state while the data layer speaks unthrown — the two compose fine, since the `Done` payload can hold an unthrown `Result`. What should **not** survive is `AsyncData` used as an error-handling device deep in the data layer. One caveat either way: a `Result` does not survive `structuredClone`/JSON — fold it with `match` before persisting or sending state over a wire. ## Migrate gradually with the bridge `@unthrown/boxed` keeps a mixed codebase compiling while you migrate module by module: `fromBoxed` / `fromBoxedFuture` lift a still-Boxed dependency into a pipeline (never a `Defect` — Boxed has only two channels), and `toBoxed` / `toBoxedFuture` serve a not-yet-migrated caller, with a **mandatory `onDefect`** so a defect is never silently folded into the caller's `E`. See [Interoperate with other libraries](./interoperate-with-libraries) for the rules of that seam. ## What you can delete after migrating * the `as Error` casts on `mapError` — `qualify` replaced them with a decision; * `Option` wrapper helpers whose callers all folded with a default — `T | undefined` plus a conditional does it without a wrapper; * defensive `try`/`catch` around combinator chains — the defect channel is the backstop now. ## Where to go next * Why there is no `Option`: [Design decisions](../explanation/design-decisions). * The channel Boxed doesn't have: [The Defect Channel](../explanation/the-defect-channel). * The same migration from neverthrow: [Migrate from neverthrow](./migrate-from-neverthrow). --- --- url: /unthrown/how-to/qualify-a-boundary.md --- # Qualify a boundary > **How-to.** Bring untyped failures — a nullable value, a throwing function, a > rejecting promise — into a `Result`. For *why* every boundary forces a triage > decision, see [Qualification](../explanation/qualification). The edges of your program are where untyped failure enters. Pick the constructor that matches the shape of the edge. | The edge is… | use | error channel | | -------------------------------------------- | ------------------- | -------------------------- | | a nullable value (`T \| null`) | `fromNullable` | your modeled `Err` | | a throwing function, some throws modeled | `fromThrowable` | `Exclude` | | a throwing function, every throw a bug | `fromSafeThrowable` | `never` | | a rejecting promise, some rejections modeled | `fromPromise` | `Exclude` | | a rejecting promise, every rejection a bug | `fromSafePromise` | `never` | | a callback-style API (events, listeners) | `fromExecutor` | your modeled `E` | ## `fromNullable` — absence as a modeled error `null` / `undefined` become a modeled `Err`; anything else (including falsy `0`, `""`, `false`) becomes `Ok`: ```ts import { fromNullable } from "unthrown"; const cache = new Map([["a", 1]]); fromNullable(cache.get("a"), () => "missing"); // Ok(1) fromNullable(cache.get("z"), () => "missing"); // Err("missing") ``` This is the sanctioned bridge for nullable third-party APIs — and the reason `unthrown` ships no `Option` type (see [Design decisions](../explanation/design-decisions#no-option-type)). ## `fromThrowable` — wrap a throwing function Pass a `qualify` function that triages the thrown cause into a modeled error `E` or a defect. Its **second argument is a `defect` helper** the boundary injects — call it to mark a cause as unmodeled (you never import it): ```ts import { fromThrowable } from "unthrown"; const parse = fromThrowable(JSON.parse, (cause, defect) => cause instanceof SyntaxError ? ("invalid_json" as const) : defect(cause), ); parse("{ not json"); // Err("invalid_json") parse("{}"); // Ok({}) ``` A throw *inside* `qualify` is itself treated as a defect. ## `fromPromise` — qualify every rejection `fromPromise` wraps a promise (or a thunk returning one) as an `AsyncResult`. Every rejection **must** be triaged: ```ts import { fromPromise, TaggedError } from "unthrown"; class NotFound extends TaggedError("NotFound") {} // our modeled domain failure class NotFoundError extends Error {} // what `fetchUser` rejects with on a 404 const user = fromPromise(fetchUser(id), (cause, defect) => cause instanceof NotFoundError ? new NotFound() : defect(cause), ); // AsyncResult ``` The error channel is inferred as `Exclude` — the `Defect` arm of `qualify`'s return is **subtracted**, never inferred into `E`. A `qualify` that returns *only* `defect(cause)` gives `AsyncResult`. `qualify` must be synchronous (an `async` one won't compile). ## `fromSafePromise` / `fromSafeThrowable` — when any failure is a bug When a failure would be a bug, not an anticipated outcome, skip `qualify`. The error channel is `never`; any failure becomes a defect: ```ts import { fromSafePromise, fromSafeThrowable } from "unthrown"; const config = fromSafePromise(loadTrustedConfig()); // AsyncResult // The row came from our own schema; a decode throw is a bug, not an outcome. const decode = fromSafeThrowable((row: Row) => userSchema.parse(row)); decode(row); // Result ``` These are the explicit, named form of the `(cause, defect) => defect(cause)` you would otherwise spell out — reach for them only when "everything here is a defect" is a **decision**, and keep `fromThrowable` / `fromPromise` wherever some failures are anticipated. ## Recipe: bridge a nullable lookup A cache or `Map` that returns `T | undefined` becomes a `Result` with a modeled `NotFound`: ```ts import { fromNullable, TaggedError } from "unthrown"; class NotFound extends TaggedError("NotFound")<{ id: string }> {} const fromCache = (id: string) => fromNullable(cache.get(id), () => new NotFound({ id })); fromCache("u_1").map((p) => p.name); // Result ``` ## Recipe: wrap a throwing parser Third-party code that throws is bridged once, at the boundary. The `qualify` function triages each throw into a modeled error or a defect: ```ts import { fromThrowable, TaggedError } from "unthrown"; class InvalidProfile extends TaggedError("InvalidProfile")<{ field: string }> {} const parseProfile = fromThrowable( (raw: string) => JSON.parse(raw) as Profile, (cause, defect) => cause instanceof SyntaxError ? new InvalidProfile({ field: "json" }) : defect(cause), ); parseProfile('{"name":"Ada"}'); // Result ``` ## The payoff: one handler at the edge Because every boundary is qualified and every in-pipeline throw becomes a defect, the edge of your program needs no `try`/`catch` — just one exhaustive `match`: ```ts const status = await user.match({ ok: () => 200, errCases: (matcher) => matcher.with({ _tag: "NotFound" }, () => 404), // your modeled NotFound defect: (cause) => { logger.error(cause); return 500; // everything unexpected }, }); ``` ## Bridging a callback API `fromPromise` needs a promise. When the API you are bridging is callback- or event-based, `fromExecutor` is the boundary — the `new Promise` of this library, except that the settler takes a `Result`: ```ts import { fromExecutor, Err, Ok } from "unthrown"; const startServer = (port: number) => fromExecutor((settle, defect) => { server.once("error", (cause) => isAddrInUse(cause) ? settle(Err(new PortInUse(port))) : settle(defect(cause)), ); server.listen(port, () => settle(Ok(server))); }); ``` Because the settler names the variant, there is no `qualify` to write and no `unknown` can reach `E`. The injected `defect` helper is how an unmodeled failure reaches the defect channel — and it is the *only* way from inside an asynchronous callback, since a `throw` there runs in its own turn, long after the executor body returned. Two things to know. `T` and `E` cannot be inferred from the body, so supply them explicitly or let them flow from an annotated target. And an executor that never settles yields an `AsyncResult` that never resolves — the one hazard `fromPromise` does not have, and exactly `new Promise`'s. ## Where to go next * Fold that handler cleanly: [Handle results at the edge](./handle-results-at-the-edge). * Give your errors a matchable shape: [Model errors](./model-errors). * The design rationale: [Qualification](../explanation/qualification). --- --- url: /unthrown/how-to/model-errors.md --- # Model errors > **How-to.** Define matchable domain errors and fold a `Result` on them. Core > `Result` is generic in `E` and **unconstrained** — the only thing the > matcher needs is an `E` TypeScript can discriminate. `TaggedError` is > unthrown's convenience for getting one, **not** a requirement: if you already > have an error convention, [keep it](#use-the-errors-you-already-have). ## Define a tagged error `TaggedError` is the shape unthrown proposes when you have no convention yet: a discriminant, a typed payload, and `Error` semantics, without writing the class boilerplate three times. `TaggedError(tag)` builds a base class you extend. Supply a payload with an instantiation expression; omit it for a payload-less error: ```ts import { TaggedError } from "unthrown"; class NotFound extends TaggedError("NotFound") {} class Forbidden extends TaggedError("Forbidden")<{ user: string }> {} new NotFound()._tag; // "NotFound" new Forbidden({ user: "bob" }).user; // "bob" ``` The class extends `Error` (so `instanceof Error` holds and stacks work) and the `_tag` is authoritative (a payload can't overwrite it). Compose a union for a precise error type: ```ts type ApiError = NotFound | Forbidden; function authorize(id: string): Result { // ... } ``` ## Set the message `message` is **not** a payload field — it's the human string owned by `Error`, so it's reserved (a payload `message` is a compile error, like `name` and `stack`). Set it the standard way, **once per subclass**, with `override message`: ```ts class TicketNotFound extends TaggedError("TicketNotFound")<{ ticketId: string; }> { override message = "ticket not found"; } new TicketNotFound({ ticketId: "t1" }).message; // "ticket not found" ``` The field may interpolate the payload via `this` — the base populates the payload fields before the subclass field initialiser runs: ```ts class InvalidState extends TaggedError("InvalidState")<{ got: string; want: string; }> { override message = `expected ${this.want}, got ${this.got}`; } ``` Keeping the message off the payload is deliberate: contextual detail lives in **typed fields** — greppable, matchable, defined once per error type — rather than baked into a per-call string. For a message that needs real branching, set `this.message` in a constructor override. ## Namespace a tag without renaming the error `_tag` is the discriminant the matcher dispatches on; `Error.name` is the label in stack traces and logs. By default they're the same, but a second `options.name` argument decouples them — so you can namespace a tag for collision-safety without that prefix leaking into the display name: ```ts class RetryableError extends TaggedError("@my-lib/RetryableError", { name: "RetryableError", }) { override message = "boom"; } const e = new RetryableError(); e._tag; // "@my-lib/RetryableError" — namespaced discriminant e.name; // "RetryableError" — clean stack-trace label ``` ## Fold a tagged union with `match` To fold a `Result` whose error is a tagged union straight to a value, use `match`. Its `ok` and `defect` handlers are plain callbacks; its **`errCases` handler receives the matcher** — add one branch per tag with `P.tag(t)` and **return the un-terminated builder** (`match` calls `.exhaustive()` for you): ```ts import { P } from "unthrown"; const status = authorize(id).match({ ok: () => 200, defect: (cause) => { logger.error(cause); return 500; }, errCases: (matcher) => matcher .with(P.tag("NotFound"), () => 404) .with(P.tag("Forbidden"), (e) => { audit(e.user); // narrowed to Forbidden — `user` is available return 403; }), }); ``` Miss a tag and it **won't compile** — exhaustiveness is enforced by the type, with no `.exhaustive()` to forget. For an `AsyncResult`, `match` resolves to a `Promise`. Unlike the error *combinators* (`mapErrCases`, `flatMapErrCases`, …), `match`'s `errCases` handler receives **no `defect` helper** — `match` is total elimination to a value, and a `Result` that already carries a defect is handled by the `defect:` case. To keep matching *inside* the pipeline (transforming or recovering the error rather than eliminating it), reach for those combinators — see the [combinator reference](../reference/combinators#the-error-channel). ## Use the errors you already have `TaggedError` is a **convention, not a requirement**. Nothing in core constrains `E` — there is no `E extends { _tag: string }` anywhere — and `P.tag("X")` is just sugar for the object pattern `{ _tag: "X" }`, one pattern among several. The matcher matches by **structure**, so an error convention you already have works unchanged. Every shape below is a module of the runnable [existing error types example](../examples/existing-errors) — it typechecks and its specs run in CI, so these are not snippets that can quietly rot. ### Your own error classes Any discriminant field does the job — here a `kind` on a shared base class: ```ts abstract class DomainError extends Error { abstract readonly kind: string; } class TicketNotFound extends DomainError { readonly kind = "TicketNotFound" as const; constructor(readonly ticketId: string) { super(`ticket ${ticketId} not found`); } } class TicketLocked extends DomainError { readonly kind = "TicketLocked" as const; constructor(readonly lockedBy: string) { super("ticket locked"); } } type TicketError = TicketNotFound | TicketLocked; ``` `mapErrCases` takes the same matcher the `match` handler does — one branch per case, each narrowed to its own variant, and the un-terminated builder returned: ```ts const withStatus = loadTicket(id).mapErrCases((matcher) => matcher .with({ kind: "TicketNotFound" }, (e) => ({ status: 404, id: e.ticketId })) .with({ kind: "TicketLocked" }, (e) => ({ status: 423, by: e.lockedBy })), ); // ^? AsyncResult ``` Drop the `TicketLocked` branch and it stops compiling — exhaustiveness comes from the union's shape, not from `TaggedError`. ### A plain union type, no classes at all `E` doesn't have to be an `Error` subclass either. A union of plain objects discriminated by a `code` behaves identically, and **grouped patterns** let several cases share one handler without a wildcard: ```ts type PaymentError = | { code: "CARD_DECLINED"; declineCode: string } | { code: "INSUFFICIENT_FUNDS" } | { code: "RATE_LIMITED"; retryAfter: number }; const status = charge(order).match({ ok: () => 200, defect: () => 500, errCases: (matcher) => matcher // grouped: one handler, two named cases — not a wildcard .with( { code: "CARD_DECLINED" }, { code: "INSUFFICIENT_FUNDS" }, () => 402, ) .with({ code: "RATE_LIMITED" }, () => 429), }); ``` Grouping is the answer when several errors deserve the same response: the union stays written out, so adding a fourth code still stops the build here. ### Classes with no discriminant field For third-party or legacy classes carrying no tag at all, `P.instanceOf` is the pattern — the branch is narrowed to the class instance: ```ts declare const parsed: Result; const described = parsed.mapErrCases((matcher) => matcher .with(P.instanceOf(ParseError), (e) => `bad syntax at ${e.at}`) .with(P.instanceOf(TimeoutError), (e) => `gave up after ${e.afterMs}ms`), ); ``` `P.when(guard)` covers whatever the other two can't express — an arbitrary type guard, including one over a primitive. ### What `E` *does* have to be Exhaustiveness is `Exclude` over the union, so the one real requirement is that `E` is a union TypeScript can **discriminate**: a `_tag` / `kind` / `code` field, structurally distinct class shapes, or a guard. What does not work is a set of structurally identical classes (they collapse into one union member) or a widened `E` like `Error`, `string` or `unknown` — with nothing to enumerate, the only arm that terminates the match is the `P._` escape hatch, which gives back the blanket `catch` the matcher exists to remove. [`no-ambiguous-error-type`](./lint-your-codebase#no-ambiguous-error-type) flags those `E`s for exactly that reason; a named union of your own types passes. `P._` remains for what enumeration genuinely cannot express — a helper generic in `E`, or an `E` that is a single type rather than a union — and is covered in [Exhaustive error matching](../explanation/exhaustive-error-matching#generic-boundary-helpers-the-catch-all-is-the-only-form-that-compiles). ## Where to go next * Match inside a pipeline: [Combinator reference](../reference/combinators#the-error-channel). * Why the matcher, not a callback: [Exhaustive error matching](../explanation/exhaustive-error-matching). * Test the errors you defined: [Test with Vitest](./test-with-vitest). --- --- url: /unthrown/how-to/sequence-dependent-steps.md --- # Sequence dependent steps with do-notation > **How-to.** When several steps each depend on the values of the ones before, > `Do` / `bind` / `let` flatten nested `flatMap` callbacks into a linear chain > that accumulates a named scope — with the same defect guarantees as every other > combinator. ## Build a scope with `Do` · `bind` · `let` Start a chain with `Do()` (an empty object scope), then grow it: * **`bind(name, f)`** — `f` receives the scope so far and returns a `Result`. On `Ok`, its value is added to the scope under `name`; on `Err`/`Defect` the chain short-circuits. Error types **union** across binds. * **`let(name, f)`** — the pure-value counterpart: `f` returns a plain value (not a `Result`), added under `name`. ```ts import { Do } from "unthrown"; const view = Do() .bind("user", () => findUser(id)) // Result .bind("org", ({ user }) => findOrg(user.orgId)) // Result .let("label", ({ user, org }) => `${user.name} @ ${org.name}`) .map(({ user, org, label }) => render(user, org, label)); // Result ``` Each step's callback is typed with everything bound so far, and the final value is the accumulated object. The scope is **readonly** — you don't mutate it mid-chain. `Do` is capitalised because `do` is a reserved word. ## It's just a `Result` A do-chain is an ordinary `Result` at every step — `bind`/`let` are methods on the normal surface, so you can mix in `map`, `flatMap`, `match`, and the rest freely, and a thrown callback still becomes a `Defect`: ```ts import { Do, Ok, Err, P, TaggedError } from "unthrown"; class TooSmall extends TaggedError("TooSmall") {} declare const input: number; Do() .bind("n", () => (input >= 2 ? Ok(input) : Err(new TooSmall()))) .let("doubled", ({ n }) => n * 2) .match({ ok: ({ n, doubled }) => `${n} → ${doubled}`, errCases: (matcher) => matcher.with(P.tag("TooSmall"), () => "too small"), defect: (cause) => `bug: ${String(cause)}`, }); ``` ## Go async To sequence asynchronous steps, lift the chain with `toAsync()` (or start from `DoAsync()`). From there a `bind` may return a `Result` **or** an `AsyncResult` (never a raw `Promise` — see [Qualify a boundary](./qualify-a-boundary)): ```ts import { Do, fromPromise, P, TaggedError } from "unthrown"; class UserNotFound extends TaggedError("UserNotFound") {} declare class MissingRowError extends Error {} const profile = await Do() .toAsync() .bind("user", () => fromPromise(fetchUser(id), (c, defect) => c instanceof MissingRowError ? new UserNotFound() : defect(c), ), ) .bind("posts", ({ user }) => fromPromise(fetchPosts(user.id), (c, defect) => defect(c)), ) .let("count", ({ posts }) => posts.length) .match({ ok: (s) => s, errCases: (matcher) => matcher.with(P.tag("UserNotFound"), () => null), defect: () => null, }); ``` Because binds **union** their error types, adding a failable step also adds a case to `E` — and the `errCases` matcher at the end stops compiling until that new case is named. Enumerating the arms is what makes the chain self-auditing. ## When to reach for named functions instead If a chain grows long enough that `Do` feels heavy, that is usually a sign the steps deserve named functions composed with `flatMap`. `unthrown` deliberately ships no generator (`gen` / `safeTry`) do-notation — the reasoning is in [Design decisions](../explanation/design-decisions#no-generator-do-notation-gen-safetry). ## Where to go next * Combine *independent* (not dependent) results: [Combine parallel results](./combine-parallel-results). * The combinators you can mix in: [Combinator reference](../reference/combinators). --- --- url: /unthrown/how-to/combine-parallel-results.md --- # Combine parallel results > **How-to.** Collect several *independent* `Result`s into one. For *dependent* > steps (each needs the previous value), use > [do-notation](./sequence-dependent-steps) instead. ## Combine an array with `all` `all` collects a tuple/array of `Result`s into a `Result` of all their values. The first `Err` short-circuits; any `Defect` dominates (even over an earlier `Err`). A fixed tuple keeps its positional types; a dynamic `Result[]` collapses to `Result`: ```ts import { all, Ok, type Result } from "unthrown"; all([Ok(1), Ok("two"), Ok(true)]).get(); // => [1, "two", true] (typed [number, string, boolean]) all([Ok(1), Ok(2)] as Result[]).get(); // => number[] ``` ## Combine a record with `allFromDict` For **named** parallel work, `allFromDict` takes a record instead — same rules, no tupling: ```ts import { allFromDict, Ok } from "unthrown"; allFromDict({ id: Ok(1), name: Ok("ada") }).get(); // => { id: 1, name: "ada" } ``` Both short-circuit on the first `Err` — this is **not** error accumulation (see [Design decisions](../explanation/design-decisions#no-error-accumulation-validation)). ## Combine async results concurrently `allAsync` and `allFromDictAsync` are the asynchronous counterparts — same folding rules, inputs resolved **concurrently** (order preserved), and (like every `AsyncResult`) they never reject: ```ts import { allAsync } from "unthrown"; // loadProfile / loadPosts / loadFollowers each return an AsyncResult const page = allAsync([loadProfile(id), loadPosts(id), loadFollowers(id)]); // AsyncResult<[Profile, Post[], User[]], ProfileError> page.map(([profile, posts, followers]) => renderPage(profile, posts, followers), ); ``` Use `allFromDictAsync` to key the concurrent results by name instead of position. ## Where to go next * Sequence *dependent* steps: [Sequence dependent steps](./sequence-dependent-steps). * The full aggregate surface: [Result & AsyncResult surface](../reference/result-surface#aggregating-all-allfromdict). --- --- url: /unthrown/how-to/handle-results-at-the-edge.md --- # Handle results at the edge > **How-to.** Fold a `Result` into a response at the boundary of your program — > one `match`, no `try`/`catch`. These recipes share a small **user profile > service** whose errors are [tagged](./model-errors). ```ts import { TaggedError } from "unthrown"; class NotFound extends TaggedError("NotFound")<{ id: string }> {} class Forbidden extends TaggedError("Forbidden") {} type ProfileError = NotFound | Forbidden; ``` ## An HTTP handler — one `match` Because every boundary is qualified and every in-pipeline throw becomes a defect, a request handler needs **no `try`/`catch`** — just one `match` mapping each channel to a status code. `fetch` only *rejects* on a network error — a 404/403 resolves normally — so the modeled statuses are mapped in a `flatMap` (a `throw` there, like an unexpected status or malformed JSON, becomes a `Defect`): ```ts import { fromPromise, Err, P } from "unthrown"; const loadProfile = (id: string) => // A network error (a rejected fetch) is unexpected → defect. fromPromise(fetch(`/api/users/${id}`), (c, defect) => defect(c)).flatMap( (res) => { if (res.status === 404) return Err(new NotFound({ id })); if (res.status === 403) return Err(new Forbidden()); if (!res.ok) throw new Error(`unexpected status ${res.status}`); // → Defect return fromPromise(res.json() as Promise, (c, defect) => defect(c), ); // malformed JSON → Defect }, ); // AsyncResult async function handler(id: string): Promise { return (await loadProfile(id)).match({ ok: (profile) => ({ status: 200, body: profile }), errCases: (matcher) => matcher .with(P.tag("NotFound"), (e) => ({ status: 404, body: e })) .with(P.tag("Forbidden"), (e) => ({ status: 403, body: e })), defect: (cause) => { logger.error(cause); // a real bug — log it, don't leak it return { status: 500, body: "Internal Error" }; }, }); } ``` A network failure or malformed response lands in `defect` → 500. The modeled `NotFound` / `Forbidden` land in `err` → 404 / 403. The type told you which is which. ::: warning Keep `match` handlers trivial The throw → defect containment covers the **combinators**, not `match`'s own callbacks — `match` invokes your handlers directly. Keep them trivial edge code (send the response, log) and put anything failable in a pipeline step above. ::: ## A complete route (Hono) A full route, no `try`/`catch` anywhere: a Standard Schema validator parses the path param, `flatMap` feeds the parsed id into a repository call that returns its own `AsyncResult`, and `match`'s matcher folds every tag to a status code: ```ts import { Hono } from "hono"; import { z } from "zod"; import { fromSchema } from "@unthrown/standard-schema"; import { P, TaggedError, type AsyncResult } from "unthrown"; class InvalidId extends TaggedError("InvalidId") {} type User = { id: string; name: string }; // The repository is its own boundary — it already hands back a qualified // AsyncResult, so there's nothing left to triage at the call site. declare const userRepo: { findById(id: string): AsyncResult }; const parseId = fromSchema(z.uuid()); const app = new Hono(); app.get("/users/:id", (c) => { const user = parseId(c.req.param("id")) // oxlint-disable-next-line unthrown/no-catch-all-pattern -- E is a single issues array, not a union .mapErrCases((matcher) => matcher.with(P._, () => new InvalidId())) .toAsync() .flatMap((id) => userRepo.findById(id)); // AsyncResult return user.match({ ok: (u) => c.json(u, 200), errCases: (matcher) => matcher .with(P.tag("InvalidId"), () => c.json({ error: "invalid id" }, 400)) .with(P.tag("NotFound"), (e) => c.json({ error: `no user ${e.id}` }, 404), ), defect: (cause) => { logger.error(cause); return c.json({ error: "Internal Error" }, 500); }, }); }); ``` `match` accepts an `AsyncResult` directly and resolves to a `Promise` — Hono awaits whatever the handler returns, so there's no manual `await` to remember. ## Extract instead of matching When you don't need per-channel branching, an extractor leaves the `Result` world with a fallback. All of them **recover an `Err` but rethrow a `Defect`** (a bug is not an absent value): ```ts loadConfig(text).getOr(DEFAULT_CONFIG); // Err → fallback; Defect → throws result.getOrNull(); // Err → null; Defect → throws result.getOrThrow(); // Err → throws the modeled error as-is; Defect → throws ``` `getOrThrow` is a **test-and-script** tool — "this `Result` had better be `Ok`" *is* the assertion there, and a throw is the right failure mode. At a production edge, fold the channel instead: `match` for per-channel branching, or `recoverErrCases` (empties `E`, so `get()` compiles) when there's no branching to do. The opt-in [`no-get-or-throw`](./lint-your-codebase#no-get-or-throw) rule enforces that boundary, exempting test files through an oxlint `overrides` entry. Full family in the [combinator reference](../reference/combinators#eliminating-a-result). ## Where to go next * Bring the boundary in first: [Qualify a boundary](./qualify-a-boundary). * Validate input at the edge: [Validate with Standard Schema](./validate-with-standard-schema). * Keep `match` handlers honest: [Comparison](../explanation/comparison#2-what-happens-when-a-map-callback-throws). --- --- url: /unthrown/how-to/validate-with-standard-schema.md --- # Validate with Standard Schema > **How-to.** Turn any [Standard Schema](https://standardschema.dev) validator > (Zod, Valibot, ArkType, …) into a function that returns a `Result` whose error > is the validator's own **issues array** — a failed validation is an anticipated > outcome, not a defect. ```sh pnpm add @unthrown/standard-schema ``` The only dependency is the tiny, types-only `@standard-schema/spec` — your validator library provides the runtime. ## Turn a schema into a `Result`-returning validator ```ts import { fromSchema } from "@unthrown/standard-schema"; import { z } from "zod"; const parseUser = fromSchema(z.object({ id: z.string() })); const ok = parseUser({ id: "u_1" }); if (ok.isOk()) ok.value; // { id: "u_1" } const bad = parseUser({ id: 1 }); if (bad.isErr()) bad.error; // readonly StandardSchemaV1.Issue[] ``` * `fromSchema(schema)` → `(input) => Result` for a **synchronous** schema (it throws a `TypeError` if the schema is async — use the next one). * `fromSchemaAsync(schema)` → `(input) => AsyncResult`, accepting sync **or** async schemas. A validator that *throws* (rather than returning issues) becomes a `Defect`; the `AsyncResult` never rejects. ## Reduce issues to per-field messages The error channel is the issues array — map it in the `errCases` arm. `E` here is a **single** type (`SchemaIssues`), not a union of tags, so there are no cases to enumerate: `P._` *is* the enumeration, and one branch takes the whole array and reduces it to per-field messages. (Everywhere `E` is a real union, name the cases instead — see [Exhaustive error matching](../explanation/exhaustive-error-matching).) ```ts import { P } from "unthrown"; import { z } from "zod"; import { fromSchema, type SchemaIssues } from "@unthrown/standard-schema"; const signupSchema = z.object({ email: z.email(), password: z.string().min(8), }); const parseSignup = fromSchema(signupSchema); const fieldOf = (issue: SchemaIssues[number]) => { const segment = issue.path?.[0]; const key = typeof segment === "object" ? segment.key : segment; return key === undefined ? "_form" : String(key); }; type ValidationResult = | { ok: true; data: { email: string; password: string } } | { ok: false; fieldErrors: Record }; function validateSignup(input: unknown): ValidationResult { return parseSignup(input).match({ ok: (data) => ({ ok: true, data }), errCases: (matcher) => // oxlint-disable-next-line unthrown/no-catch-all-pattern -- E is a single issues array, not a union matcher.with(P._, (issues) => ({ ok: false as const, fieldErrors: issues.reduce>( (byField, issue) => { const field = fieldOf(issue); (byField[field] ??= []).push(issue.message); return byField; }, {}, ), })), defect: (cause) => { logger.error(cause); // the validator itself threw — a real bug, not a bad form return { ok: false, fieldErrors: { _form: ["Something went wrong."] } }; }, }); } validateSignup({ email: "not-an-email", password: "short" }); // { ok: false, fieldErrors: { email: [...], password: [...] } } ``` The `defect` arm only fires if the schema itself throws instead of returning issues — a bug in the validator, not a bad submission. ## Where to go next * Feed the parsed value into a pipeline: [Handle results at the edge](./handle-results-at-the-edge). * Other library bridges: [Interoperate with other libraries](./interoperate-with-libraries). --- --- url: /unthrown/how-to/use-with-prisma.md --- # Use with Prisma > **How-to.** [`@unthrown/prisma`](/api/prisma/) is a > [Prisma](https://www.prisma.io) Client extension that bridges queries into an > [`AsyncResult`](../explanation/async-model) whose error channel is exactly the > failures *that operation* can raise. ```sh pnpm add @unthrown/prisma unthrown ``` ## Apply the extension `$extends(unthrownPrisma)` adds `try`-prefixed variants of the model delegate operations **alongside** the raw promise ones: ```ts import { unthrownPrisma } from "@unthrown/prisma"; import { PrismaClient } from "./generated/prisma/client.ts"; const db = new PrismaClient({ adapter }).$extends(unthrownPrisma); const users = db.user.tryFindMany({ select: { id: true } }); // ^? AsyncResult<{ id: number }[], never> ``` Qualification happens **once, inside the extension** — no raw `Promise`, and so no un-triaged rejection, ever reaches your code. `select` / `include` payload inference survives the wrap, so the success type is still narrowed by your query. ## Per-operation error unions `E` carries **only domain outcomes** — things a caller did, or a legitimate state conflict, that your code actually branches on. Each operation's channel is exactly what that operation can raise, so you never write a handler for a case that can't happen: | Method | Error channel | | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | `tryFindMany` / `tryFindUnique` / `tryFindFirst` / `tryCount` / `tryAggregate` / `tryGroupBy` | `never` | | `tryFindUniqueOrThrow` / `tryFindFirstOrThrow` | `RecordNotFound` | | `tryCreate` / `tryUpsert` / `tryUpdate` | `UniqueConstraintViolation \| ForeignKeyViolation \| RecordNotFound` | | `tryDelete` | `ForeignKeyViolation \| RecordNotFound` | | `tryCreateMany` / `tryCreateManyAndReturn` | `UniqueConstraintViolation \| ForeignKeyViolation` | | `tryUpdateMany` / `tryUpdateManyAndReturn` | `UniqueConstraintViolation \| ForeignKeyViolation` | | `tryDeleteMany` | `ForeignKeyViolation` | | `tryPaginate(...).withCursor(...)` | `InvalidCursor` | `UniqueConstraintViolation` is `P2002` (a 409, and it carries the offending `fields`), `ForeignKeyViolation` is `P2003` (a 400), and `RecordNotFound` is `P2025` — plus `P2018`, which says the same thing from the to-many side of a nested write (a 404). ::: danger Those four codes are the whole modeled set `P2002`, `P2003`, `P2018`, `P2025` — and nothing else. **Every other P-code becomes a [`Defect`](../explanation/the-defect-channel)**, including ones that read like domain outcomes: `P2007` (malformed value / inconsistent column data), `P2023` (inconsistent column data), `P2000` (value too long), `P2011` (null constraint), `P2015` (related record not found). The table above is a **boundary**, not a menu. That matters wherever a defect is retried rather than surfaced. Folded at an HTTP edge, a defect is a 500 and the request is over. Inside a **Temporal activity** — or any supervisor that retries on a thrown error — an `Err` you convert to a non-retryable failure fails fast, while a defect is rethrown and **retried**. A `P2007` from a malformed id can never succeed on a retry, so a path that carries that id (an `onError` handler, a dead-letter reprocessor) retries forever. Re-qualify such a code explicitly — see [below](#migrating-a-hand-rolled-qualifier). ::: A **read has no modeled failure at all**. Absence is `null`, and a database that will not answer is a defect — so `tryFindMany` is `AsyncResult`. Note where `RecordNotFound` does **not** appear: the **batch** mutations (`*Many` and their `*AndReturn` twins). Those are the only operations genuinely free of it — they accept no nested writes, and zero matches is `Ok({ count: 0 })`, not an error. `tryCreate` and `tryUpsert` *do* carry it, which is worth a second look: neither has a row of its own to miss, but a **nested `connect`** does. ```ts db.post.tryCreate({ data: { title, author: { connect: { id: authorId } } } }); // Err(RecordNotFound) when that author does not exist — P2025. ``` ::: tip Absence is not an error `tryFindUnique` returns `Ok(null)` for a miss — a missing row is an anticipated value, not a failure. Reach for `tryFindUniqueOrThrow` when the absence *is* the error you want to model (`RecordNotFound`). ::: ## Everything infrastructural is a defect 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 reaches your error channel. They go to the [defect channel](../explanation/the-defect-channel), with the original cause preserved. That is not a demotion. **A defect is not a crash**: it flows through the pipeline untouched and is folded at the edge by `match`'s `defect` handler, exactly where you already turn unexpected failures into a 500. The channel means "not worth threading through domain code", not "fatal". The test is simple — *would you branch on it?* You genuinely handle a duplicate email (409) or a missing parent row (404). You do not write domain logic for a severed TCP connection; you log it and return a 500. Modelling it would only force every call site to carry an arm that does the same thing as the `defect` arm sitting right beside it: ```ts // What modelling infrastructure failures would cost you, at EVERY call site: errCases: (matcher) => matcher .with(P.tag("UniqueConstraintViolation"), (e) => resp.conflict(e.fields)) .with(P.tag("DriverError"), (e) => resp.serverError(e)), // ← this defect: (cause) => resp.serverError(cause), // ← and this ``` ::: tip The one carve-out: pagination cursors A cursor is an **opaque string from the outside world**, turned into a query by your `parseCursor`. A client sending garbage is anticipated input you answer with a 400 — so it is modeled, as `InvalidCursor`. A throw out of `getCursor` (which reads rows *you* fetched) is a bug, and stays a defect. See [Cursor pagination](#cursor-pagination) below. ::: ::: warning Retries Deadlocks (`P2034`) and pool timeouts (`P2024`) are defects too, so a retry wrapper reaches for `recoverDefect` and inspects the cause, rather than matching a tag. That is one place in a codebase — versus an arm at every call site. ::: ### Migrating a hand-rolled qualifier {#migrating-a-hand-rolled-qualifier} Replacing your own `try`/`catch` qualifier with `try*` is not a like-for-like swap: **diff your old qualifier against the four modeled codes**, because anything else it used to turn into an `Err` now lands on the defect channel. The migration is silent by every signal you would normally trust — the type check passes (the `Err` channel legitimately shrank), and a repository unit test asserting the `Ok` path passes too. What changes is the behaviour of the *failure* path, one layer up. Re-qualify the codes you were modelling with `recoverDefect`, right where the query is issued: ```ts import { RecordNotFound } from "@unthrown/prisma"; import { Err, type AsyncResult } from "unthrown"; // Recognized by `name` + a string `code`, not `instanceof`: Prisma's runtime // module path moves between majors, and an `instanceof` against the wrong copy // silently fails. This is the same check the extension itself uses. const hasCode = (cause: unknown, code: string): boolean => cause instanceof Error && cause.name === "PrismaClientKnownRequestError" && (cause as { code?: unknown }).code === code; const findUser = (id: string): AsyncResult => db.user.tryFindUniqueOrThrow({ where: { id } }).recoverDefect((cause) => { // A malformed id is the same domain outcome as a missing row — and it can // never succeed on a retry, so it must not stay a defect. if (hasCode(cause, "P2007")) return Err(new RecordNotFound({ cause })); // oxlint-disable-next-line unthrown/no-throw -- rethrow keeps the defect intact throw cause; }); ``` The `throw cause` is caught by the pipeline's own throw-to-defect net, so everything you did not name stays a defect with its original cause — no `try`/`catch`, and nothing untriaged leaks into `E`. Keep the comment: without it, the next reader "simplifies" the branch away. Re-qualifying into the error the operation *already* models — `RecordNotFound` here — keeps `E` unchanged, so no call site has to grow an arm. A code that is genuinely a different outcome gets your own tagged error, and every exhaustive match on that channel stops compiling until it is handled, which is the point. ## Handle the errors Because the errors are [tagged](./model-errors), driving `match`'s `errCases` handler with the matcher gives you an exhaustive fold — the compiler lists exactly the cases the operation can hit: ```ts import { P } from "unthrown"; const created = await db.user.tryCreate({ data: { email, name } }); return created.match({ ok: (user) => resp.created(user), errCases: (matcher) => matcher .with(P.tag("UniqueConstraintViolation"), (e) => resp.conflict(`taken: ${e.fields.join(", ")}`), ) .with(P.tag("ForeignKeyViolation"), P.tag("RecordNotFound"), () => resp.badRequest("unknown reference"), ), defect: (cause) => resp.serverError(cause), }); // Exactly the three cases a create can raise — no more, no fewer. Add a case to // the union and every call site like this one stops compiling until it is // handled. Everything else (a dropped connection, a deadlock, a bug) lands in // the one `defect` arm. ``` When several tags deserve the same response, **group** them in one arm rather than reaching for a wildcard — the list stays explicit, so a new P-code still lights the call site up: ```ts matcher.with( P.tag("UniqueConstraintViolation"), P.tag("ForeignKeyViolation"), P.tag("RecordNotFound"), () => resp.badRequest("bad write"), ); ``` ## Transactions `$tryTransaction` runs an interactive transaction whose callback speaks `AsyncResult`. An `Err` anywhere in the chain triggers a **ROLLBACK** and comes back out as the same typed error; the `try*` methods are available on the transaction client `tx`: ```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 } }, }), ), ); // ^? AsyncResult // Any Err → both updates rolled back, and the Err is in `moved`. ``` * An `Err` from the callback rolls back and re-surfaces as that same modeled error. * A [`Defect`](../explanation/the-defect-channel) also rolls back and **stays a defect** — including a callback that *throws* instead of returning an `AsyncResult`. A bug is never quietly downgraded into your error channel. * Nesting is a compile error: `tx` has no `$tryTransaction`. * Naming the `tx` parameter of a helper factored out of the callback is `TransactionClient` — use it rather than restating the deny list by hand, which drifts silently (`Omit` of a key that does not exist is not an error): ```ts import type { TransactionClient } from "@unthrown/prisma"; type Tx = TransactionClient; const chargeFees = (tx: Tx, id: number, fee: number) => tx.account.tryUpdate({ where: { id }, data: { balance: { decrement: fee } }, }); ``` ### Batch transactions For independent writes with no application logic between them, `$tryTransaction` also takes an **array** — Prisma's batch form, one round trip, all or nothing: ```ts const rows = db.$tryTransaction(inputs.map((data) => db.user.create({ data }))); // ^? AsyncResult ``` A fixed tuple keeps positional types (`[db.user.create(…), db.user.count()]` → `AsyncResult<[User, number], …>`); a dynamic array collapses to a list, the same duality as core's `all`. Two consequences of Prisma's batch form needing **unexecuted** `PrismaPromise`s, both deliberate: * The array holds the **raw** delegate methods — `db.user.create(...)`, not `tryCreate`. A `try*` method has already run and returns an `AsyncResult`, so passing one is a compile error. * `E` is the whole `PrismaQueryError` union rather than the per-operation narrowing you get from `try*`: a raw `PrismaPromise` carries no error-type information. Infrastructure failures are still defects, exactly as everywhere else. `maxWait` and `timeout` are not accepted — they govern an interactive transaction's open window, which a batch does not have. `isolationLevel` is. ## Cursor pagination `tryPaginate(query).withCursor(...)` follows the [`prisma-extension-pagination`](https://github.com/deptyped/prisma-extension-pagination) cursor API — same option names, same `[results, meta]` shape: ```ts import { P } from "unthrown"; const page = await db.user .tryPaginate({ where: { active: true }, orderBy: { id: "asc" } }) .withCursor({ limit: 20, after: req.query.cursor }); // ^? Result<[User[], CursorPaginationMeta], InvalidCursor> page.match({ ok: ([users, meta]) => json({ users, nextCursor: meta.endCursor, hasMore: meta.hasNextPage }), errCases: (matcher) => matcher.with(P.tag("InvalidCursor"), () => badRequest("bad cursor")), defect: serverError, }); ``` Four deliberate differences from upstream: a cursor pointing at a now-filtered-out row doesn't skip the first element (folds in the fix for [deptyped/prisma-extension-pagination#35](https://github.com/deptyped/prisma-extension-pagination/issues/35)); `after` and `before` are mutually exclusive (a page runs in one direction, and passing both used to silently drop `after`); `before` + `limit: null` is a compile error; and the default cursor preserves the id's type (all-digit → number/`bigint`, otherwise string). Provide `getCursor` / `parseCursor` for composite keys. A malformed cursor is a modeled `InvalidCursor` rather than a defect — the one place a Prisma validation error is treated as anticipated input, because the cursor comes from the client rather than from your code. A throw out of `getCursor`, which reads rows the query just returned, is a bug and stays a defect. ## Raw methods and raw SQL The bridge is additive: `db.user.findMany(...)` (the raw promise) is still there, for exactly two things — composing the array a batch `$tryTransaction([...])` runs, and raw SQL. Qualify raw SQL yourself at the boundary, reusing the exported `qualifyPrismaError`: ```ts import { fromPromise } from "unthrown"; import { qualifyPrismaError } from "@unthrown/prisma"; const rows = fromPromise(db.$queryRaw`SELECT 1`, qualifyPrismaError); // ^? AsyncResult ``` `qualifyPrismaError` **is** a `qualify` — the boundary injects the `defect` helper as its second argument, so the same triage you get inside the extension (including routing the three bug-shaped Prisma errors to the defect channel) applies to your own boundaries for free. See the [API reference](/api/prisma/) for every method's exact signature. ## Where to go next * Serve these results over RPC: [Use with oRPC](./use-with-orpc). * Fold them at the edge: [Handle results at the edge](./handle-results-at-the-edge). --- --- url: /unthrown/how-to/use-with-drizzle.md --- # Use with Drizzle > **How-to.** [`@unthrown/drizzle`](/api/drizzle/) **replaces** the > [Drizzle ORM](https://orm.drizzle.team) Postgres database rather than wrapping > one: every query resolves to an > [`AsyncResult`](../explanation/async-model) whose error channel is exactly the > failures *that operation* can raise. ```sh pnpm add @unthrown/drizzle drizzle-orm pg unthrown ``` `drizzle-orm` (`^1.0.0-rc`) and `pg` (`^8.16.0`) are peer dependencies — this package sits on drizzle's own Postgres builder tree, so you bring your own copy of it. ::: tip Contributing to this package Its test suite runs against a **real PostgreSQL**, started for the run by [testcontainers](https://testcontainers.com), so **a running Docker daemon is required** to run it locally. That is a deliberate departure from the rest of this monorepo, whose suites are self-contained: the behaviour under test *is* PostgreSQL's SQLSTATE reporting, constraint naming and transaction semantics, and a fake would only pin our own assumptions about them. ::: ## Construct the database The call forms are **exactly** drizzle's own, so migrating a call site is an import change: ```ts import { drizzle } from "@unthrown/drizzle/node-postgres"; // A connection string — the factory builds the pool. const db = drizzle("postgres://localhost/app"); // …with configuration. const db = drizzle("postgres://localhost/app", { relations }); // A client you own. const db = drizzle({ client: pool, relations }); // Connection details, as a string or a `pg.PoolConfig`. const db = drizzle({ connection: { host, database, user }, relations }); ``` There is deliberately **no positional-client form**: `drizzle(pool)` does not compile, because drizzle has none either and a second spelling of `{ client: pool }` would mean a call site no longer ports back by changing the import. The config carries `relations` (drizzle's `defineRelations` schema, backing `db.query`), `logger` and `codecs`. There is no `try*` prefix to learn — every method on the database *already* speaks `AsyncResult`. ## Reads have no modeled failure A read's error channel is `never`, so `get()` compiles: ```ts import { eq } from "drizzle-orm"; const found = await db.select().from(users).where(eq(users.id, id)); // ^? Result<{ id: number; email: string }[], never> const rows = found.get(); ``` `never` here is **not** a promise of infallibility — it is the statement that nothing a read can hit is worth branching on. A dropped connection, a pool timeout, a statement that will not compile: all of those are [defects](../explanation/the-defect-channel), and `get()` panics on one, exactly as it does anywhere else. That is enforced at **runtime**, not merely declared: the read builders route through `fromSafePromise`, so even a `23xxx` reaching a read path — narrowly reachable, via a `SELECT` calling a volatile function that writes — becomes a `Defect` rather than an `Err` the type says cannot exist. The declaration cannot drift from the runtime, which is the trap `@unthrown/prisma` once shipped by omitting an error from `E` that the runtime still produced. Four builders are reads, and all three routes into them agree — `await`, `.execute()`, and `prepare(name).execute()`: | Operation | Error channel | | --------------------------------- | ------------------------------------------- | | `db.select()` / `selectDistinct…` | `never` | | `db.$count(…)` | `never` | | `db.query..findMany/First` | `never` | | `db.refreshMaterializedView(…)` | `never` | | `db.insert(…)` | `PgQueryError` | | `db.update(…)` | `PgQueryError` | | `db.delete(…)` | `PgQueryError` | | ``db.execute(sql`…`)`` | `PgQueryError` | | `db.transaction(fn)` | the callback's own `E`, plus `PgQueryError` | ::: warning `refreshMaterializedView` is a read by decision `REFRESH MATERIALIZED VIEW … CONCURRENTLY` genuinely *can* raise a `23505` against the view's unique index. It is classified as a read anyway: a matview whose own definition produces duplicates is a bug in that definition, not a domain outcome a request handler branches on. ::: ## Writes carry the full constraint union Nothing is narrowed per-operation. A `delete` can still raise `23505` through an `ON DELETE SET DEFAULT`, and an `insert` can still raise `23503` through a foreign key — so every write carries the same five: | Tag | SQLSTATE | Payload | | --------------------------- | -------- | ---------------------------------------- | | `UniqueConstraintViolation` | `23505` | `constraint`, `table`, `detail`, `cause` | | `ForeignKeyViolation` | `23503` | `constraint`, `table`, `detail`, `cause` | | `NotNullViolation` | `23502` | **`column`**, `table`, `detail`, `cause` | | `CheckViolation` | `23514` | `constraint`, `table`, `detail`, `cause` | | `ExclusionViolation` | `23P01` | `constraint`, `table`, `detail`, `cause` | `NotNullViolation` carries `column` rather than `constraint` because `23502` names the offending column and has no constraint name of its own. Nothing parses `detail` for a column list — PostgreSQL localizes message text, so only `constraint` / `table` / `column` are read. A query builder is a **thenable**, not an `AsyncResult`. To reach the combinators, either `await` it into a `Result` first, or end the chain in `.execute()`: ```ts import { P } from "unthrown"; const created = await db .insert(users) .values({ id, email }) .returning() .execute() .mapErrCases((matcher, defect) => matcher .with( P.tag("UniqueConstraintViolation"), (e) => `taken: ${e.constraint}` as const, ) .with( P.tag("ForeignKeyViolation"), P.tag("NotNullViolation"), P.tag("CheckViolation"), P.tag("ExclusionViolation"), (e) => defect(e), ), ); ``` Every case is named. Grouping several tags in one arm keeps the list explicit, so a sixth SQLSTATE added later lights up every call site — which is the point. Handling all five empties the channel, and `get()` starts compiling on a write: ```ts const inserted = ( await db .insert(users) .values({ id, email }) .execute() .recoverErrCases((matcher) => matcher.with( P.tag("UniqueConstraintViolation"), P.tag("ForeignKeyViolation"), P.tag("NotNullViolation"), P.tag("CheckViolation"), P.tag("ExclusionViolation"), () => "rejected" as const, ), ) ).get(); ``` Folding at the edge is the same matcher, through `match`: ```ts const r = await db.insert(users).values({ id, email }); return r.match({ ok: (res) => resp.created(res), errCases: (matcher) => matcher .with(P.tag("UniqueConstraintViolation"), (e) => resp.conflict(e.constraint), ) .with(P.tag("NotNullViolation"), (e) => resp.badRequest(e.column)) .with( P.tag("ForeignKeyViolation"), P.tag("CheckViolation"), P.tag("ExclusionViolation"), () => resp.badRequest("bad write"), ), defect: (cause) => resp.serverError(cause), }); ``` ## Everything infrastructural is a defect A deadlock (`40P01`), a serialization failure (`40001`), a statement timeout (`57014`), too many connections (`53300`), a syntax error, a dropped connection, a non-Postgres cause: none of those reaches your error channel. They go to the [defect channel](../explanation/the-defect-channel), with the original cause preserved. The cause you receive is drizzle's own `DrizzleQueryError`, exactly as stock drizzle raises it: it names the failing statement (`query`) and its bound `params`, with the driver's error one level down under `.cause`. node-postgres' `DatabaseError` carries `code`, `constraint`, `table`, `column` and `detail` but *not* the SQL, so the wrapper is what makes a logged defect say **which** query blew up. Anything reading the SQLSTATE should follow one `cause` level — the `sqlState` helper below does. That is not a demotion. **A defect is not a crash**: it flows through the pipeline untouched and is folded at the edge by `match`'s `defect` handler, exactly where you already turn unexpected failures into a 500. The test is *would you branch on it?* You genuinely handle a duplicate email (409) or a violated check (400). You do not write domain logic for a severed TCP connection. Modelling those would force **every write call site** to carry an arm doing precisely what the `defect` arm beside it already does. ### Retries live in one wrapper Because `40001` and `40P01` are defects, a retry wrapper reaches for `recoverDefect` and inspects the cause — one place in a codebase, rather than an arm at every call site: ```ts import type { AsyncResult } from "unthrown"; const RETRYABLE = new Set(["40001", "40P01"]); /** The driver's SQLSTATE, through drizzle's `DrizzleQueryError` wrapper if present. */ const sqlState = (cause: unknown): string | undefined => { if (typeof cause !== "object" || cause === null) return undefined; const code: unknown = (cause as { code?: unknown }).code; if (typeof code === "string") return code; return sqlState((cause as { cause?: unknown }).cause); }; const withRetry = ( run: () => AsyncResult, attempts = 3, ): AsyncResult => run().recoverDefect((cause) => { if (attempts <= 1 || !RETRYABLE.has(sqlState(cause) ?? "")) throw cause; return withRetry(run, attempts - 1); }); const moved = await withRetry(() => db.transaction((tx) => tx.update(accounts).set({ balance }).execute(), { isolationLevel: "serializable", }), ); ``` The `throw cause` is caught by the pipeline's own throw-to-defect net, so a cause that is not retryable stays a defect with its original value — no `try`/`catch` at the call site, and nothing leaks into `E`. ## Transactions `Ok` commits. `Err` **and** `Defect` both roll back, and an `Err` re-surfaces typed, so rolling back costs no information: ```ts const moved = await db.transaction((tx) => tx .update(accounts) .set({ balance: sql`${accounts.balance} - ${amount}` }) .where(eq(accounts.id, from)) .execute() .flatMap(() => tx .update(accounts) .set({ balance: sql`${accounts.balance} + ${amount}` }) .where(eq(accounts.id, to)) .execute(), ), ); // ^? Result<…, PgQueryError> ``` * There is deliberately **no `tx.rollback()`**. Drizzle needs one because its rollback signal is a throw; here the signal is an `Err`, and a second spelling of one concept is exactly what this library does not do. * The callback owes an `AsyncResult`, so each step ends in `.execute()` and the steps compose with `flatMap` (or `DoAsync().bind(…)`). * A read inside the transaction still has `E = never` **at the callback**, so it composes without an arm for an error it cannot raise. * `PgQueryError` joins the result's channel **whatever the callback's own `E`**, because the control statements fail on their own account: a `DEFERRABLE` constraint is checked at `COMMIT`, so a unique violation can be raised by the commit rather than by any statement the callback ran. That is why `get()` never compiles on a transaction's result, however clean the callback was. * Nesting is a **savepoint**. `Ok` releases it; `Err` and `Defect` roll back to it, leaving the enclosing transaction open to decide for itself: ```ts const r = await db.transaction((tx) => tx .transaction((nested) => nested.insert(logs).values({ message }).execute()) .recoverErrCases((matcher) => matcher.with( P.tag("UniqueConstraintViolation"), P.tag("ForeignKeyViolation"), P.tag("NotNullViolation"), P.tag("CheckViolation"), P.tag("ExclusionViolation"), () => undefined, ), ), ); // The savepoint rolled back; the outer transaction still commits. ``` `tx.setTransaction({ isolationLevel: "serializable" })` sets the characteristics of a transaction already in progress; the `db.transaction(fn, config)` second argument renders them into the `BEGIN`. ## The escape hatch `db.$client` is the very client you passed (or the pool the factory built), so a stock drizzle database over the same pool — for a migration runner, or an API this package does not model — is one line away: ```ts import { drizzle as drizzleStock } from "drizzle-orm/node-postgres"; const raw = drizzleStock({ client: db.$client, relations }); ``` For a boundary of your own, `qualifyPgError` **is** a `qualify` in the [qualification](../explanation/qualification) sense — the boundary injects the `defect` helper as its second argument — so it drops straight into a `fromPromise`: ```ts import { fromPromise } from "unthrown"; import { qualifyPgError } from "@unthrown/drizzle"; const rows = fromPromise( () => pool.query("insert into users values ($1)", [id]), qualifyPgError, ); // ^? AsyncResult ``` See the [API reference](/api/drizzle/) for every builder's exact signature. ## Where to go next * Serve these results over RPC: [Use with oRPC](./use-with-orpc). * Fold them at the edge: [Handle results at the edge](./handle-results-at-the-edge). --- --- url: /unthrown/how-to/use-with-orpc.md --- # Use with oRPC > **How-to.** [`@unthrown/orpc`](/api/orpc/) bridges [oRPC](https://orpc.dev) > (v2) and unthrown in both directions: server handlers that *return* a `Result`, > and a client whose every call yields an > [`AsyncResult`](../explanation/async-model) — with oRPC's end-to-end typed > errors as the modeled error channel. ```sh pnpm add @unthrown/orpc unthrown ``` oRPC's error model already agrees with the [thesis](../explanation/why-unthrown): an error a procedure **declares** (`.errors({...})`) or **returns as a value** is *inferable* — typed end-to-end — while everything else collapses to `INTERNAL_SERVER_ERROR`. That is exactly the `Err` / [`Defect`](../explanation/the-defect-channel) split: | unthrown | oRPC v2 | | ------------ | --------------------------------------------- | | `Ok(value)` | the procedure's output | | `Err(error)` | a returned `ORPCError` — inferable, typed E2E | | `Defect` | everything else (`INTERNAL_SERVER_ERROR`) | Qualification happens **once, inside the bridge**: the triage decision was already made when the procedure declared (or returned) its errors, so no per-call `qualify` is asked of you. ::: info oRPC v2 The package targets oRPC **v2** (peer range `^2.0.0-beta`), whose returned-`ORPCError` inference is what the server half builds on. Its majors track oRPC's cadence, not the unthrown family's. ::: ## Server: handlers that return a `Result` `handlerResult` adapts a `Result`-returning handler into a plain oRPC handler — your service layer keeps speaking `Result`, and the endpoint stops needing to unwrap it into throws: ```ts import { P } from "unthrown"; import { handlerResult } from "@unthrown/orpc/server"; import { os } from "@orpc/server"; import * as z from "zod"; // repo.findPlanet: (id: string) => AsyncResult const find = os .input(z.object({ id: z.string() })) .errors({ NOT_FOUND: {}, CONFLICT: {} }) .handler( handlerResult(({ input, errors }) => repo.findPlanet(input.id).mapErrCases( (matcher, defect) => matcher .with(P.tag("NotFound"), () => errors.NOT_FOUND()) // modeled → typed for the client .with(P.tag("Conflict"), () => errors.CONFLICT()) .with(P.tag("Unavailable"), (e) => defect(e.cause)), // infrastructure → defect ), ), ); ``` Naming every case is the point: the matcher makes the transport boundary state, per case, which failures the client is invited to handle and which are bugs. Add a case to the repository and this endpoint stops compiling until it decides. * `Ok` becomes the procedure's output. * `Err` is **returned as a value**; oRPC marks it inferable, so the client sees it fully typed. The error channel is constrained to `ORPCError` — the `mapErrCases` that turns a domain error into one (here `errors.NOT_FOUND()`) is the explicit triage point at the transport boundary. * A `Defect` rethrows its original cause, which oRPC collapses to `INTERNAL_SERVER_ERROR`. A bug stays a defect — it never becomes a typed error your client is invited to handle. A returned `ORPCError` needs no `.errors({...})` declaration — v2 infers it from the handler's type: ```ts const limited = os.handler( handlerResult(({ input }) => tooMany(input) ? Err(new ORPCError("RATE_LIMITED", { data: { retryAfter: 60 } })) : Ok("welcome"), ), ); // the client's error channel: ORPCError<"RATE_LIMITED", { retryAfter: number }> ``` The handler may be synchronous, `async`, or return an `AsyncResult` directly — an elimination edge is exempt from the no-thenable rule (same as `match` handlers). ### The `.result()` builder extension If you prefer a builder method over wrapping, opt into the extension — one side-effectful import: ```ts import { P } from "unthrown"; import "@unthrown/orpc/extensions/result"; const find = os .input(z.object({ id: z.string() })) .errors({ NOT_FOUND: {}, CONFLICT: {} }) .result(({ input, errors }) => repo.findPlanet(input.id).mapErrCases((matcher, defect) => matcher .with(P.tag("NotFound"), () => errors.NOT_FOUND()) .with(P.tag("Conflict"), () => errors.CONFLICT()) .with(P.tag("Unavailable"), (e) => defect(e.cause)), ), ); ``` It is available on every builder state and on contract-first `implement(...)` implementers, and is runtime-identical to `.handler(handlerResult(...))`. Everything else in the package is side-effect-free; reach for `handlerResult` when patching a third-party prototype is unwelcome. ## Client: calls that return an `AsyncResult` `createResultClient` wraps an oRPC client so every procedure returns an `AsyncResult` — the mirror of oRPC's own `createSafeClient`: ```ts import { createResultClient } from "@unthrown/orpc/client"; const rc = createResultClient(client); const greeting = await rc.planet .find({ id }) .map((planet) => `Hello, ${planet.name}!`) .match({ ok: (msg) => msg, // the matcher branches on the ORPCError `code`, not a `_tag` errCases: (matcher) => matcher .with({ code: "NOT_FOUND" }, () => "Hello, void!") .with({ code: "CONFLICT" }, () => "Hello, again!"), defect: () => "Hello, bug tracker!", }); ``` `E` is exactly the set of codes the procedure declares or returns — so listing them is finite and mechanical, and adding a code server-side lights up every client call site. The error channel is the raw inferable `ORPCError` union, discriminated by `code` — deliberately **not** re-wrapped into [tagged errors](./model-errors): oRPC already ships a discriminated error type, and one concept should have one name. Branch on `code` — in `match`'s `errCases` matcher (as above), a `switch`, or a standalone `match`. Because these are plain `ORPCError`s rather than `TaggedError`s, `P.tag(...)` doesn't apply — match on the `code` field instead. Anything non-inferable — a network failure, an undeclared throw collapsed to `INTERNAL_SERVER_ERROR`, a malformed response — is a `Defect`: it flows past your error combinators and [panics at `get`](../explanation/the-defect-channel), because it is a bug (or an outage), not an outcome your domain models. `fromCall` is the one-shot form, and also lifts oRPC's server-side `call(procedure, input)`: ```ts import { fromCall } from "@unthrown/orpc/client"; import { call } from "@orpc/server"; const planet = await fromCall(client.planet.find({ id })); // a client call const seeded = await fromCall(call(find, { id: "1" })); // a server-side call ``` Call options (`signal`, `context`, `lastEventId`) pass through untouched. ::: warning Streaming is out of scope Event-iterator procedures don't collapse to one `Result` — modelling a stream's per-event and terminal failures is its own design. Call those on the raw client. ::: ## End to end Both halves compose into one error vocabulary across layers — a [Prisma](./use-with-prisma)-backed service chains into an oRPC handler, and the browser consumes it, all in `Result`: ```ts import { P } from "unthrown"; // server — the one mapErrCases is the whole edge, and it is exhaustive: a new P-code // in the union becomes a compile error here, never a silent 500. const createUser = os .input(z.object({ email: z.string() })) .errors({ EMAIL_TAKEN: {} }) .handler( handlerResult(({ input, errors }) => db.user .tryCreate({ data: input }) .mapErrCases((matcher) => matcher .with(P.tag("UniqueConstraintViolation"), () => errors.EMAIL_TAKEN(), ) .with( P.tag("ForeignKeyViolation"), P.tag("Unavailable"), (e) => new ORPCError("INTERNAL_SERVER_ERROR", { cause: e }), ), ), ), ); // client const outcome = await rc.createUser({ email }); if (outcome.isErr() && outcome.error.code === "EMAIL_TAKEN") { form.setError("email", "already registered"); } ``` ## Where to go next * The service layer behind it: [Use with Prisma](./use-with-prisma). * The `Err`/`Defect` split it maps onto: [The Defect Channel](../explanation/the-defect-channel). --- --- url: /unthrown/how-to/test-with-vitest.md --- # Test with Vitest > **How-to.** [`@unthrown/vitest`](/api/vitest/) adds custom > [Vitest](https://vitest.dev) matchers for asserting on `Result` and > `AsyncResult` values. ```sh pnpm add -D @unthrown/vitest ``` `vitest` is a peer dependency. ## Register the matchers Import the package once — in a test or, better, a Vitest [setup file](https://vitest.dev/config/#setupfiles) — to register the matchers and pull in their type augmentation: ```ts // vitest.setup.ts import "@unthrown/vitest"; ``` ## Assert on a Result ```ts import { Ok, Err } from "unthrown"; import { expect, test } from "vitest"; test("matchers", () => { expect(Ok(1)).toBeOk(); expect(Ok(1)).toBeOkWith(1); // deep equality on the value expect(Err("e")).toBeErr(); expect(Err(new NotFound())).toBeErrTagged("NotFound"); expect(aDefect).toBeDefect(); expect(aDefect).toBeDefectWith(expect.any(TypeError)); // assert the cause expect(Ok(1)).not.toBeErr(); // negations work too }); ``` | Matcher | Passes when | | ------------------------------ | ------------------------------------------------------------------------------------------------- | | `toBeOk()` | the result is `Ok` | | `toBeOkWith(value)` | the result is `Ok` and the value deep-equals `value` | | `toBeErr()` | the result is `Err` | | `toBeErrWith(value)` | the result is `Err` and the error deep-equals `value` | | `toBeErrTagged(tag)` | the result is `Err` whose error has `_tag === tag` | | `toBeErrTagged(tag, expected)` | …and its payload matches `expected` (exact for a plain object, partial for an asymmetric matcher) | | `toBeDefect()` | the result is a `Defect` | | `toBeDefectWith(cause)` | the result is a `Defect` whose `cause` deep-equals `cause` | ## Assert on a tagged error's payload `toBeErrTagged` takes an optional second argument to also assert the tagged error's payload — its own fields, minus the keys `TaggedError` reserves (`_tag`, `name`, `message`, `stack`). A plain object matches it **exactly**; an asymmetric matcher matches it **partially**: ```ts import { Err, TaggedError } from "unthrown"; import { expect } from "vitest"; class NotFound extends TaggedError("NotFound")<{ id: number; msg: string }> {} // exact — every payload field must match expect(Err(new NotFound({ id: 1, msg: "nope" }))).toBeErrTagged("NotFound", { id: 1, msg: "nope", }); // partial — only the listed fields are checked expect(Err(new NotFound({ id: 1, msg: "nope" }))).toBeErrTagged( "NotFound", expect.objectContaining({ id: 1 }), ); ``` The reserved keys are skipped so the exact form keeps working with the standard way of setting a message — `override message = "…"` lands as an own property on the instance, but it is `Error`'s human string, not payload: ```ts class HttpError extends TaggedError("HttpError")<{ status: number }> { override message = `http ${this.status}`; } // the payload is `{ status }` — the message is not part of it expect(Err(new HttpError({ status: 500 }))).toBeErrTagged("HttpError", { status: 500, }); ``` ## Async results — `await` is required Each matcher detects a thenable `AsyncResult` and awaits it internally. That means for an `AsyncResult` you **must `await` the assertion**: ```ts await expect(fromPromise(load(), qualify)).toBeOk(); await expect(fromSafePromise(Promise.reject(boom))).toBeDefect(); ``` ::: danger Don't forget the await Always `await expect(asyncResult)…`. As a safety net, importing the package also registers an `afterEach` hook: a test that ends with async assertions still pending **fails** with an explicit message naming the un-awaited matchers **and the line that created them**, instead of passing silently. ``` @unthrown/vitest: 1 async assertion(s) (toBeOk) were still pending when the test ended — a forgotten `await`. … Created at: loadUser (src/user.spec.ts:42:18). ``` The full stack is on the error's `cause`, for reporters that render it. ::: ## Where to go next * Define the errors you're asserting on: [Model errors](./model-errors). * Keep dropped results out of your code: [Lint your codebase](./lint-your-codebase). --- --- url: /unthrown/how-to/lint-your-codebase.md --- # Lint your codebase > **How-to.** [`@unthrown/oxlint`](https://github.com/btravstack/unthrown/tree/main/packages/oxlint) > is an [oxlint](https://oxc.rs/docs/guide/usage/linter) plugin that turns > unthrown's theses into automated checks the type system can't enforce on its > own — a lazy `E`, a dropped `Result`, a blanket `P._`, an ignored matcher, a > raw `throw`, a thrown-away error channel. ```sh pnpm add -D @unthrown/oxlint oxlint ``` ## Set up Register the plugin and turn its rules on in your `.oxlintrc.json`: ```json { "jsPlugins": [{ "name": "unthrown", "specifier": "@unthrown/oxlint" }], "rules": { "unthrown/no-ambiguous-error-type": "error", "unthrown/no-unhandled-result": "error", "unthrown/no-unused-matcher": "error", "unthrown/prefer-async-result": "error", "unthrown/no-throw": "error", "unthrown/no-get-or-throw": "error", "unthrown/no-catch-all-pattern": "error" }, "overrides": [ { "files": ["**/*.test.ts", "**/*.spec.ts"], "rules": { "unthrown/no-get-or-throw": "off" } } ] } ``` The default export also exposes a `recommended` preset — an oxlint config that registers the plugin and enables `no-ambiguous-error-type`, `no-unhandled-result`, `no-unused-matcher`, `prefer-async-result`, and `no-catch-all-pattern` (`no-throw` and `no-get-or-throw` are the two explicit opt-ins) — for setups that build their config programmatically (`import unthrown from "@unthrown/oxlint"` → `unthrown.recommended`). `oxlint` is a peer dependency; JS plugins require oxlint ≥ 1.69. ## The rules ### `unthrown/no-ambiguous-error-type` {#no-ambiguous-error-type} The `E` in `Result` / `AsyncResult` should name the **anticipated** domain failures — not "anything went wrong". This flags the catch-all error types: ```ts import type { Result } from "unthrown"; type A = Result; // ✗ flagged type B = Result; // ✗ flagged type C = Result; // ✗ flagged type D = Result; // ✗ flagged type E = Result; // ✓ type F = Result; // ✓ type G = Result; // ✓ — an intentionally error-free result ``` The whole point of the [defect channel](../explanation/the-defect-channel) is that bugs **don't** belong in `E`; this rule keeps them out. It is purely syntactic — it sees the type argument as written and does not chase aliases (an alias resolving to `unknown` is not followed). Name your error types honestly and this limit never bites. The same table applies to the matcher's [`returnType()`](../explanation/exhaustive-error-matching#declaring-the-output-returntype-r) pin — but **only where the pin declares the error channel**, which is inside a `mapErrCases` callback: there the builder's output *becomes* the new `E`. ```ts // result: Result result.mapErrCases((m) => m.returnType().with(P.tag("NotFound"), (e) => e), ); // ✗ flagged — this is E result.mapErrCases((m) => m.returnType().with(P.tag("NotFound"), () => new ApiError()), ); // ✓ result.recoverErrCases((m) => m.returnType().with(P.tag("NotFound"), (e) => e), ); // ✓ — the SUCCESS type result.tapErrCases((m) => m.returnType().with(P.tag("NotFound"), log)); // ✓ — discarded result.match({ ok, defect, errCases: (m) => m.returnType().with(P.tag("NotFound"), id), }); // ✓ — a folded value ``` `flatMapErrCases` / `flatTapErrCases` need no separate check: their builder output must be a `Result`, so a *bare* ambiguous pin does not type-check at all, and an ambiguous `E2` **nested** in a `Result` pin is caught by the same rule (it reads type arguments wherever they occur, annotation or not). Two syntactic limits, deliberate — the pin is recognised on the callback's own matcher parameter, so a matcher first copied into another variable (`const b = m; b.returnType()`), or a callback declared elsewhere and passed by reference (`result.mapErrCases(handler)`), is not seen. Writing the pin where the matcher is handed to you keeps the check honest. This is also the one check anchored on shape rather than on an import: a `returnType()` call on the matcher parameter of a `mapErrCases` callback is unthrown's own vocabulary, so no `Result` binding needs resolving. ### `unthrown/prefer-async-result` {#prefer-async-result} Prefer `AsyncResult` over `Promise>`. A raw `Promise` can still **reject**, reintroducing the throw channel that `AsyncResult` is designed to eliminate. ```ts type Slow = Promise>; // ✗ → AsyncResult ``` Autofixable. When `AsyncResult` is not already in scope, the fix **adds the specifier** to your existing `unthrown` import rather than leaving you to do it by hand: ```ts // before ─ `--fix` ─▶ after import type { Result } from "unthrown"; import type { Result, AsyncResult } from "unthrown"; ``` That covers the common case: a file imports `Result`, which is what trips the rule, and has never needed `AsyncResult`. The added specifier is `type`-qualified unless the declaration is already `import type { … }`, so a types-only import stays types-only — under [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax) a bare specifier would make the declaration value-bearing and emit a runtime import the file never had: ```ts // before ─ `--fix` ─▶ after import { type Result } from "unthrown"; import { type Result, type AsyncResult } from "unthrown"; ``` The fix is withheld where applying it would not compile or would not mean what it says — the rule still reports: | Situation | Why no fix | | ---------------------------------------------------- | ---------------------------------------------------------------- | | An `async` function's own return-type annotation | An `async` function must return a native `Promise` | | The return position of a function **type** | The implementer may be an `async` function | | `AsyncResult` already names something else in scope | Adding the specifier would collide, not resolve | | A namespace import (`import * as U from "unthrown"`) | No specifier list to extend; `U.AsyncResult` is a different edit | ### `unthrown/no-unhandled-result` {#no-unhandled-result} An errors-as-values `Result` only works if the value is actually **held**. This rule flags a `Result` / `AsyncResult` dropped on the floor — a bare expression-statement call to something known to produce one: ```ts import { Err, fromPromise, Result } from "unthrown"; Err("denied"); // ✗ dropped — the error channel is silently discarded await fromPromise(p, qualify); // ✗ still dropped — awaiting yields a Result, then discards it Result.Ok(1); // ✗ facade companion calls count too saveUser(u); // ✗ if saveUser is locally declared as `(): AsyncResult<…>` const r = Err("denied"); // ✓ bound return fromPromise(p, qualify); // ✓ returned ``` It recognises, purely syntactically: the unthrown-imported producers (`Ok`, `Err`, `OkAsync`, `ErrAsync`, `Do`, the `from*` boundaries, the `all*` aggregates, renamed imports included); the facade companions (`Result.Ok(...)`); and a **locally-declared** function whose return annotation is unthrown's `Result` / `AsyncResult`. A dropped method *chain* (`r.map(f);`) or a function whose `Result`-ness lives behind an imported declaration needs the type checker and is out of scope — no false positives is the design priority. ### `unthrown/no-throw` {#no-throw} **An opt-in rule** — not part of the `recommended` preset, because it bans a core language statement. For codebases committed to errors-as-values end-to-end, it closes the loop: ordinary errors are *returned*, so a raw `throw` is either a modeled failure in disguise or an unmodeled one that belongs to the defect channel's machinery. ```ts function parse(input: string) { if (!input) throw new Error("empty"); // ✗ — return Err(new EmptyInput()) instead } ``` Every sanctioned form is a call, not a statement, so the rule stays clean on them: a modeled failure → `return Err(...)`; a failure that is genuinely unmodeled here → fold it into the defect channel with [`recoverErrCases`](../reference/combinators#the-error-channel) + [`get`](../reference/combinators#eliminating-a-result); a known-technical precondition throw → keep it in a plain helper wrapped **once** with [`fromSafeThrowable`](./qualify-a-boundary); a genuinely deliberate remaining `throw` — a framework that reads the thrown value, say — → a targeted `// oxlint-disable-next-line unthrown/no-throw -- ` comment. The rule has no options and no autofix — the disable comment is the escape hatch. ::: warning Removed in 5.4.0, restored in 5.5.0 This rule was deleted in `@unthrown/oxlint` 5.4.0 on the reasoning that a bare `ThrowStatement` report belongs in a `no-restricted-syntax` entry. oxlint does not implement `no-restricted-syntax`, so that left a codebase banning `throw` with nothing — and because oxlint refuses to parse a config naming an unknown rule, the upgrade failed the *whole* lint run rather than just the rule ([#227](https://github.com/btravstack/unthrown/issues/227)). 5.5.0 restores it, unchanged and still opt-in. ::: ### `unthrown/no-get-or-throw` {#no-get-or-throw} **An opt-in rule** — the other half of `no-throw`. `getOrThrow()` extracts `T` but **throws the modeled error as-is** on `Err`, which abandons errors-as-values at the very last step: a caller of the enclosing function sees a throw, not a channel, and every guarantee the exhaustive matcher bought upstream is gone. ```ts const user = findUser(id).getOrThrow(); // ✗ flagged ``` Fold the error channel instead. `recoverErrCases` empties `E`, so `get()` compiles, and a case routed to the injected `defect(...)` panics with its original cause — with every case still named: ```ts const user = findUser(id) .recoverErrCases( (matcher, defect) => matcher .with(P.tag("NotFound"), () => anonymousUser) // ✓ recovered to a value .with(P.tag("Denied"), (e) => defect(e)), // ✓ genuinely unmodeled here ) .get(); ``` The rule matches a **zero-argument** `.getOrThrow()` member call, so Effect's one-argument `Option.getOrThrow(o)` / `Either.getOrThrow(e)` are left alone. A computed access (`r["getOrThrow"]()`) and a detached reference (`const f = r.getOrThrow`) are documented misses — both are deliberate evasions, and the `oxlint-disable` comment is the sanctioned escape. #### Keeping it in tests `getOrThrow()` is the right tool in a test, where "this `Result` had better be `Ok`" *is* the assertion and a throw is the correct failure mode — though [`@unthrown/vitest`](./test-with-vitest)'s matchers (`toBeOk`, `toBeOkWith`, `toBeErrTagged`, `toBeDefect`, …) are usually the better tool for the assertion itself; reach for `getOrThrow()` when you just need the value. The rule has no `allow` option on purpose — oxlint's own `overrides` already does this, and works with whatever glob your tests use: ```json { "rules": { "unthrown/no-get-or-throw": "error" }, "overrides": [ { "files": ["**/*.test.ts", "**/*.spec.ts"], "rules": { "unthrown/no-get-or-throw": "off" } } ] } ``` #### Stacking with `no-throw` The two rules close different doors, and enabling both closes the room: | | `no-throw` off | `no-throw` on | | ------------------------- | --------------- | ------------------------------------------------------------ | | **`no-get-or-throw` off** | escapes: both | escape: `getOrThrow()` | | **`no-get-or-throw` on** | escape: `throw` | **no lint-clean escape — fold with `recoverErrCases`+`get`** | ### `unthrown/no-catch-all-pattern` {#no-catch-all-pattern} Enumerating every error case is the library's [default position](../explanation/exhaustive-error-matching#enumerate-the-cases-the-wildcard-is-the-exception), so this rule is part of the `recommended` preset. It bans the universal catch-all `P._` — and ts-pattern's `P.any` alias — wherever `P` is imported from `unthrown` or `ts-pattern` — a wildcard makes *any* match exhaustive, which means it keeps compiling as `E` grows and silently absorbs each new case. ```ts result.mapErrCases((m) => m.with(P._, (e) => e)); // ✗ — the catch-all // ✓ — enumerate every case; group cases that share a handler result.mapErrCases((m) => m.with(P.tag("NotFound"), P.tag("Forbidden"), (e) => e), ); ``` Because a matched builder must still be exhaustive, removing `P._` makes the compiler point at each unhandled case until every one is named — the rule and the type checker push the same way. `P._` remains a legitimate **escape hatch** in exactly two cases, and the rule **exempts them itself when the file proves them**: a helper still **generic in `E`**, where no list of tag arms can prove coverage and the catch-all is the only form that compiles; and an **`E` that is a single non-union type**, where one arm *is* the enumeration. The proof is syntactic — the matcher is traced to its receiver, and the receiver to an in-file `Result` / `AsyncResult` annotation (a variable or parameter annotation, or the return annotation of a function declared in the same file). When the annotated `E` is not a union (in-file aliases are seen through; an *imported* named type counts as the single abstraction it names), nothing is reported: ```ts function toPromise(result: Result): T { return result.match({ ok: (value) => value, errCases: (matcher) => matcher.with(P._, (error) => { // exempt: `result` is annotated `Result` and `E` is a type parameter throw error; }), defect: (cause) => { throw cause; }, }); } ``` Where no annotation is in reach — most commonly a receiver returned by a function **imported from another module**, which per-file analysis cannot see — the rule still reports, and the targeted disable comment remains the honest escape hatch: ```ts // oxlint-disable-next-line unthrown/no-catch-all-pattern -- E is SchemaIssues: one type, nothing to enumerate errCases: (matcher) => matcher.with(P._, (issues) => abort(describe(issues))), ``` (Annotating the receiver in-file — `const parsed: Result = readEnv()` — also lifts the proof into view and drops the comment.) The rule has no options and no autofix. Where the helper needs no matcher at all, the `isOk` / `isErr` / `isDefect` guards carry no exhaustiveness obligation and need no disable comment. ### `unthrown/no-unused-matcher` {#no-unused-matcher} `no-catch-all-pattern` guards the exhaustiveness contract against the wildcard; this rule — also in the `recommended` preset — guards it from the other side. A `…Cases` callback (the five error combinators, and `match`'s `errCases` handler) that never uses the matcher it was handed sources its exhaustiveness from a builder bound to some **other** value, and neither the type checker nor the runtime can tell: the constraint on the callback's return is structural (`ExhaustiveMatch`), so any exhaustive builder satisfies it, and `noUnusedParameters` never fires because the parameter is not unused — it is simply never declared. ```ts // ✗ flagged — compiles clean, but the branch is chosen by `decoy`, not the error const recovered = await source.recoverErrCases(() => match(decoy) .with(P.tag("A"), () => "recovered as A") .with(P.tag("B"), () => "recovered as B"), ); // ✓ the injected matcher is the only builder bound to the actual error const recovered = await source.recoverErrCases((matcher) => matcher.with(P.tag("A"), P.tag("B"), () => "recovered"), ); ``` The borrowed builder fails in one of two ways, neither diagnosable at the call site: a branch matches the foreign value and a **plausible wrong value** comes back (with the Err channel typing as fully handled), or nothing matches, `.run()` throws `NonExhaustiveError`, and the modeled error becomes a **Defect** — a deliberately non-retryable failure turned retryable. The rule reports a callback whose matcher parameter is absent or never read, and — separately, to catch a trivial reference like `void matcher` fronting for a foreign builder — any second `match(...)` (unthrown's or ts-pattern's) built in the callback's **own** body. Branch handlers are nested functions and stay free to match their payload (`.with(P.tag("A"), (e) => match(e.code)…)` is that inner value's ordinary match). There is no escape hatch and no autofix: a `…Cases` callback that does not use its matcher is never what you meant. ## Import resolution All the `Result`-aware rules resolve import bindings via scope analysis, through the **imported** name — so a renamed import (`import type { Result as R } from "unthrown"`) is still recognised, a decoy (`import { Ok as Result } from "somewhere"`) is not, and a namespace import's qualified `U.Result` resolves too. A `Result` from another library is left alone. ## Where to go next * Why bugs must stay out of `E`: [The Defect Channel](../explanation/the-defect-channel). * Why `AsyncResult` over `Promise`: [The async model](../explanation/async-model). --- --- url: /unthrown/how-to/interoperate-with-libraries.md --- # Interoperate with other libraries > **How-to.** Thin `to*` / `from*` bridges between `Result` / `AsyncResult` and > the neighbours in the errors-as-values space. Nothing to learn beyond "which > direction am I going." | Package | Peer dependency | Bridges | | ------------------------------------------ | ------------------ | -------------------------- | | [`@unthrown/effect`](/api/effect/) | `effect` | `Exit`, `Either`, `Effect` | | [`@unthrown/neverthrow`](/api/neverthrow/) | `neverthrow` | `Result`, `ResultAsync` | | [`@unthrown/boxed`](/api/boxed/) | `@bloodyowl/boxed` | `Result`, `Future` | For [Standard Schema](https://standardschema.dev) validators (Zod, Valibot, ArkType), see the dedicated [Validate with Standard Schema](./validate-with-standard-schema) guide. ## The one rule: does the neighbour have a defect channel? unthrown has **three** channels — `Ok`, `Err`, and the out-of-band `Defect`. Most libraries have only two. That single difference decides every signature. * **Coming *in*** (`from*`), a two-channel result is only ever an `Ok` or an `Err` — the bridge **never** produces a `Defect`. * **Going *out*** (`to*`) to a two-channel type, a `Defect` has nowhere to live. Rather than silently fold it into your domain error, the bridge **forces** you to triage it with a mandatory `onDefect: (cause) => E`. There is no one-arg form. ```ts import { Ok } from "unthrown"; import { toNeverthrow } from "@unthrown/neverthrow"; // onDefect is required — the compiler will not let you drop a defect. toNeverthrow(Ok(1), (cause) => ({ _tag: "Bug", cause })); ``` ## Effect — a genuine bijection Effect is the exception: it *does* have a defect channel (`Cause.die`), so `Result ↔ Exit` round-trips losslessly. ```ts import { Ok, Err, P, TaggedError } from "unthrown"; import { toExit, fromEffect } from "@unthrown/effect"; import { Effect } from "effect"; class NotFound extends TaggedError("NotFound") {} class Timeout extends TaggedError("Timeout") {} type User = { name: string }; toExit(Ok(1)); // Exit.succeed(1) toExit(Err("e")); // Exit.fail("e") — a modeled Cause.fail // a Defect would become Exit.die(cause) // Run an Effect and collect its outcome; a die/interrupt becomes a Defect. // Effect's error channel arrives as E, so name each of its cases: declare const loadUser: Effect.Effect; await fromEffect(loadUser).match({ ok: (user) => user.name, errCases: (matcher) => matcher .with(P.tag("NotFound"), () => "missing") .with(P.tag("Timeout"), () => "timed out"), defect: String, }); ``` `toEffect` also accepts an `AsyncResult`, and `toEither` — since `Either` has no defect channel — takes the same mandatory `onDefect`. ## Async pairs Every package mirrors its sync pair for the asynchronous types: * `@unthrown/effect` — `fromEffect` returns an `AsyncResult`; `toEffect` accepts one. * `@unthrown/neverthrow` — `toNeverthrowAsync` / `fromNeverthrowAsync` bridge `AsyncResult ↔ ResultAsync`. * `@unthrown/boxed` — `toBoxedFuture` / `fromBoxedFuture` bridge `AsyncResult ↔ Future`. On the way in, an *unexpected* rejection inside the neighbour's async type becomes a `Defect` — never a silently-swallowed error. (Boxed's `Future` has no failure channel and never rejects, so for `fromBoxedFuture` this is a defensive guarantee rather than a path you can actually hit.) ## Where to go next * Why the `to*` triage is mandatory: [Qualification](../explanation/qualification). * Validators as results: [Validate with Standard Schema](./validate-with-standard-schema). --- --- url: /unthrown/reference/combinators.md --- # Combinator reference > **Reference.** A complete, structured description of the method surface: what > each combinator does, which channel it touches, and how it moves the type. For > the reasoning behind the error-channel matcher, see > [Exhaustive error matching](../explanation/exhaustive-error-matching). For each > method's full signature and prose, see > [`ResultMethods`](/api/core/#resultmethods) and > [`AsyncResultMethods`](/api/core/#asyncresultmethods) in the API reference. Every combinator runs its callback **only on its own channel** and turns a thrown callback into a `Defect`. `Result` and `AsyncResult` expose the **same set** of combinators with the same per-channel behavior; only their signatures differ (an `AsyncResult` combinator returns an `AsyncResult`, its eliminators a `Promise`, and its binds also accept an `AsyncResult`). The [Result and AsyncResult](#result-and-asyncresult) section covers the deltas. ## By intent The `→ Result<…>` half of each signature is the tell — it shows how the combinator moves the channels: `flatMap` widens `E` to `E | E2`, `recoverErrCases` empties it to `never`, `flatMapErrCases` widens the value to `T | U`. The error combinators take an [exhaustive matcher](#the-error-channel) rather than a single callback; the signatures below abbreviate its callback as `(matcher) => …`. | I want to… | use | signature | channel | | ---------------------------------------------- | ----------------- | ------------------------------------------------------------ | ------------ | | transform the success value | `map` | `(v: T) => U` → `Result` | Ok | | chain a `Result`-returning step | `flatMap` | `(v: T) => Result` → `Result` | Ok | | run a side effect, keep the value | `tap` | `(v: T) => void` → `Result` | Ok | | run a **failable** side effect, keep the value | `flatTap` | `(v: T) => Result` → `Result` | Ok | | validate a success / refine its type | `ensure` | `((v: T) => boolean, (v: T) => E2)` → `Result` | Ok | | sequence steps into a named scope | `Do`/`bind`/`let` | `bind(k, (scope) => Result)` → `Result<{…}, E \| E2>` | Ok | | replace the value with a constant | `as` | `(value: U)` → `Result` | Ok | | drop the value (success type becomes `void`) | `discard` | `()` → `Result` | Ok | | transform the error (matched) | `mapErrCases` | `(matcher) => …` → `Result` | Err | | try a fallback that returns a `Result` | `flatMapErrCases` | `(matcher) => …` → `Result` | Err | | turn an error into a success value | `recoverErrCases` | `(matcher) => …` → `Result` | Err | | run a side effect on the error | `tapErrCases` | `(matcher) => …` → `Result` | Err | | run a **failable** side effect on the error | `flatTapErrCases` | `(matcher) => …` → `Result` | Err | | recover from a defect (rare) | `recoverDefect` | `(cause) => Result` → `Result` | Defect | | observe a defect, e.g. log it | `tapDefect` | `(cause) => void` → `Result` | Defect | | observe **any** failure (error *or* defect) | `tapFailure` | `(f: FailureView) => void` → `Result` | Err + Defect | | handle all three channels at the edge | `match` | `{ ok, errCases, defect }` → `R` | all | | combine an array of `Result`s | `all` | `Result[]` → `Result` | — | | combine a record of `Result`s | `allFromDict` | `{ [k]: Result }` → `Result<{ [k]: T }, E>` | — | ## Behavior at a glance A combinator touches **only its own channel**; the other two flow through untouched (`tapFailure` is the one combinator whose "own channel" spans both failures). The `Defect` column is "passes ▸" everywhere except `recoverDefect`, the observers (`tapDefect` / `tapFailure`), and `match`: | method | on `Ok` | on `Err` | on `Defect` | resulting `E` | | --------------------------------- | -------- | ------------- | ----------- | --------------- | | `map` | runs `f` | passes ▸ | passes ▸ | `E` | | `flatMap` | runs `f` | passes ▸ | passes ▸ | `E \| E2` | | `tap` / `flatTap` | runs `f` | passes ▸ | passes ▸ | `E` / `E \| E2` | | `ensure` | runs `f` | passes ▸ | passes ▸ | `E \| E2` | | `mapErrCases` | passes ▸ | runs a branch | passes ▸ | `E2` | | `flatMapErrCases` | passes ▸ | runs a branch | passes ▸ | `E2` | | `recoverErrCases` | passes ▸ | branch → `Ok` | passes ▸ | `never` | | `tapErrCases` / `flatTapErrCases` | passes ▸ | runs a branch | passes ▸ | `E` / `E \| E2` | | `recoverDefect` | passes ▸ | passes ▸ | runs `f` | `E \| E2` | | `tapDefect` | passes ▸ | passes ▸ | runs `f` | `E` | | `tapFailure` | passes ▸ | runs `f` | runs `f` | `E` | | `match` | `ok()` | `errCases()` | `defect()` | — | ::: tip `recoverErrCases`'s `never` under-describes the runtime `recoverErrCases` empties only the **error** channel to `never` — a `Defect` can still be present at runtime and flows past it untouched. See [The Defect Channel](../explanation/the-defect-channel#recovererrcases-clears-the-error-channel-not-the-runtime). ::: ## The error channel The error combinators — `mapErrCases`, `flatMapErrCases`, `recoverErrCases`, `tapErrCases`, `flatTapErrCases` — do not take a single callback. Their callback receives a built-in match builder over the error (`match(error)`; the patterns are re-exported from `unthrown` as `P`), and you **return the un-terminated builder** — the combinator calls `.exhaustive()` for you: ```ts import { P } from "unthrown"; db.reading.tryFindUniqueOrThrow({ where: { id } }).mapErrCases( (matcher, defect) => matcher .with(P.tag("RecordNotFound"), () => new ReadingNotFoundException(id)) .with(P.tag("Unavailable"), (e) => defect(e.cause)), // deliberate defect — the tag leaves E ); ``` A match that misses a case **does not compile** — there is no `.exhaustive()` to forget, and no `.otherwise()` to slip in a fallback. The rationale is in [Exhaustive error matching](../explanation/exhaustive-error-matching). The rules: * **Match on anything, not just `_tag`.** The matcher matches by structure, so a `code`-discriminated union (the oRPC shape), a plain string, a guard (`.with({ code: "NOT_FOUND", id: "special" }, …)`), or grouped patterns (`.with(a, b, handler)` — one strategy for several cases) all work. `P.tag("X")` is sugar for the `{ _tag: "X" }` pattern, narrowing to the variant and its payload. * **The outgoing `E` is the union of the branch returns.** A branch receives the narrowed variant **and the injected `defect` helper** (the same second argument `qualify` gets at a boundary): `defect(cause)` converts a case to a defect, and its `Defect` arm is subtracted from the outgoing `E` (`Exclude`) — so defecting a case removes it from the modeled channel. A branch that `throw`s also becomes a defect, but `defect(...)` is the lint-clean, expression-position form. * **…unless you declare it.** `matcher.returnType()`, called directly after the matcher is handed to you, pins the output to `R`: every branch is checked against it (a mismatch is reported on that branch) and the outgoing channel is `R` rather than the union of the branch returns. Reach for it when a signature decides the type — most sharply in code generic in `E`. A `defect(…)` branch stays legal under a pin. See [Exhaustive error matching](../explanation/exhaustive-error-matching#declaring-the-output-returntype-r). * **Cases that share a strategy are *grouped*, not wildcarded.** `.with(a, b, handler)` runs one handler for several patterns while keeping both named, so the union stays written out and a new case still breaks the build. This is the answer whenever you'd reach for "and everything else the same way". * **`P._` is the catch-all of last resort.** One wildcard branch — `matcher.with(P._, (e) => wrap(e))` — makes any match exhaustive, which is exactly why it is not the default shape: it keeps compiling when `E` grows, and that is the guarantee the matcher exists to provide. Reserve it for the one place enumeration *cannot* work — a helper still generic in `E` (see [Generic boundary helpers](../explanation/exhaustive-error-matching#generic-boundary-helpers-the-catch-all-is-the-only-form-that-compiles)) — or for an `E` that is a single type with no cases to list. `@unthrown/oxlint`'s [`no-catch-all-pattern`](../how-to/lint-your-codebase#no-catch-all-pattern), in its recommended preset, enforces that. * **There is no error-channel identity.** `mapErrCases((m) => m)` is not a no-op — it only type-checks when `E` is `never` and otherwise fails to compile (see [The Defect Channel](../explanation/the-defect-channel#no-identity-on-the-error-channel)). To pass the error through, observe it with `tapErrCases`, or re-emit each case by name (`.with(P.tag("NotFound"), (e) => e)…`). * **Observers match exhaustively too.** `tapErrCases` and `flatTapErrCases` take the same builder; the error is observed and then flows through unchanged. Their branch returns are ignored (`tapErrCases`) or thread only a *new* effect failure (`flatTapErrCases`) — the one exception being a branch that returns the injected `defect(cause)`, which in either observer behaves like the `throw` it stands for. `tapDefect` / `tapFailure` keep single callbacks — their payloads carry no discriminant to match. * **A non-exhaustive match is a `Defect` if it ever slips past the types.** Only reachable outside the typed contract (a widened cast, a JS caller): the matcher throws `NonExhaustiveError`, which the combinator's throw-to-defect net turns into a `Defect`. ### Doing one thing for several errors When several cases deserve the same handling — logging is the classic case — **group** them in one arm. The handler is written once; the cases stay named, so the day `E` grows the call site still lights up: ```ts import { P } from "unthrown"; // loadUser: (id: string) => Result // log whatever the error is, then let it flow through unchanged loadUser(id).tapErrCases((matcher) => matcher.with( P.tag("NotFound"), P.tag("Forbidden"), P.tag("Unavailable"), (e) => logger.error(e), ), ); ``` The same shape works for every error combinator — transform, recover, or fold at the edge — and mixes freely with per-case arms: ```ts // result: Result // one case handled specially, the rest sharing a strategy result.tapErrCases((matcher) => matcher .with(P.tag("RateLimited"), (e) => metrics.rateLimit(e.retryAfter)) .with(P.tag("NotFound"), P.tag("Forbidden"), (e) => logger.error(e)), ); result.recoverErrCases((matcher) => matcher .with(P.tag("RateLimited"), (e) => e.retryAfter) .with(P.tag("NotFound"), P.tag("Forbidden"), () => fallback), ); result.match({ ok: (v) => v, errCases: (matcher) => matcher .with(P.tag("RateLimited"), (e) => `retry in ${e.retryAfter}`) .with(P.tag("NotFound"), P.tag("Forbidden"), (e) => `failed: ${e}`), defect: (c) => `bug: ${c}`, }); ``` A `P._` branch would be shorter, and that is the trade it makes: it **keeps compiling when you enrich `E`**, silently absorbing the new case. Grouping costs one identifier per case and keeps the compiler on your side. Reach for `P._` only where enumeration is impossible — see [Generic boundary helpers](../explanation/exhaustive-error-matching#generic-boundary-helpers-the-catch-all-is-the-only-form-that-compiles). ## Result and AsyncResult Every combinator above exists on **both** `Result` and `AsyncResult` — same names, same channel behavior. `AsyncResult` (what you get from `fromPromise` / `fromSafePromise` / `fromExecutor`, or by lifting a sync `Result` with `.toAsync()`) differs in exactly three ways: * **Callbacks stay synchronous.** A raw `Promise` may never enter a combinator — that would skip qualification and silently become a defect. Do async work by re-entering a boundary and composing it with `flatMap`. (See [The async model](../explanation/async-model).) * **The `Result`-returning combinators accept `Result` *or* `AsyncResult`.** `flatMap`, `flatTap`, `flatMapErrCases`, `flatTapErrCases`, `bind`, and `recoverDefect` take a callback returning either, so you can mix sync and async steps in one chain. * **Eliminators return a `Promise`.** `await result.match({ … })` / `await result.get()` — or `await` the `AsyncResult` first to collapse it to a `Result`, then match synchronously. Use this table to move between the two: | I have… and want to… | use | | ----------------------------------------- | ----------------------------------------------------- | | build an `AsyncResult` from a value/error | `OkAsync(v)` / `ErrAsync(e)` (no `Ok(v).toAsync()`) | | lift a sync `Result` into async | `result.toAsync()` → `AsyncResult` | | collapse an `AsyncResult` to a `Result` | `await asyncResult` | | add an **async** step mid-chain | `.flatMap((v) => fromPromise(work(v), qualify))` | | add a **sync** step to an async chain | `.flatMap((v) => Ok(v + 1))` — a `Result` is accepted | | combine async results | `allAsync` / `allFromDictAsync` | ```ts // A chain that crosses an async boundary stays an AsyncResult to the end. const status = await findUser(id) // Result (sync) .toAsync() // AsyncResult // the boundary's qualify decides what it adds to E — here, LoadFailed .flatMap((user) => fromPromise(loadOrders(user.id), () => ({ _tag: "LoadFailed" as const })), ) .map((orders) => orders.length) // sync callback, still AsyncResult .match({ ok: (n) => n, // the boundary widened E, so both cases are named here errCases: (matcher) => matcher .with(P.tag("NotFound"), () => 0) .with(P.tag("LoadFailed"), () => -2), defect: () => -1, }); // await collapses it ``` ## The pairs that are easy to confuse **`map` vs `flatMap`** — does your callback return a plain value or a `Result`? A `(value) => U` is `map`; a `(value) => Result` is `flatMap` (otherwise you nest a `Result>`). **`flatMap` vs `flatTap`** — both take a `Result`-returning callback. `flatMap` **replaces** the value with the callback's; `flatTap` **discards** it and keeps the original (a validation or write whose *outcome* matters but whose *value* you don't need). `tapErrCases`/`flatTapErrCases` are the same pair on the error channel. **`tap` vs `flatTap`** — decided by what the *effect* returns, not by what you do with its value (both keep the original). An effect that cannot fail — logging, a metric — is `tap`; an effect that returns a `Result`/`AsyncResult` **must** be sequenced with `flatTap` on the matching surface, because a `tap` callback cannot thread it. ::: warning A failable effect inside `tap` is silently dropped `tap` ignores its callback's return value, so the effect's outcome is lost — in one of two shapes: * a **sync `Result`** returned from the callback compiles (a `Result` is not a thenable), but its `Err` is silently discarded; * an **`AsyncResult`** is rejected at compile time (it is awaitable, so `NotThenable` catches it) — and the tempting "fix" of wrapping the call in braces compiles, but leaves the effect **floating**: never awaited, its `Err`/`Defect` unobserved. ```ts .tap((user) => { auditLog.record(user); // AsyncResult — floats, never awaited }) ``` Sequence the effect instead. A `Result`-returning effect goes in `flatTap` on either surface; an `AsyncResult`-returning one only in the **async** `flatTap`: ```ts .flatTap((user) => auditLog.record(user)) ``` ::: **`flatMapErrCases` vs `recoverErrCases`** — both run on `Err`. `recoverErrCases` produces a plain success value (emptying the error channel to `never`); `flatMapErrCases` produces another `Result` (which may still be an `Err`). **`recoverErrCases` vs `recoverDefect`** — `recoverErrCases` handles a modeled `Err`; `recoverDefect` is the only combinator that can **consume** a `Defect`. Neither is the other's fallback — a defect flows past `recoverErrCases` untouched. **`tapErrCases` + `tapDefect` vs `tapFailure`** — when the *same* effect applies to both failures (a shared logger, a metric, a rollback trigger), `tapFailure` runs it once for either. Its callback receives the discriminated **failure variant** (`FailureView`, i.e. `ErrView | DefectView`) rather than a payload — so branch on `failure.tag` when you need the typed `error`, or treat it opaquely. It only *observes*: there is deliberately no `recoverFailure`. ## Eliminating a Result Reach for an eliminator once you're done chaining: * `match` — the default at the edge; fold all three channels into one value. * `get` / `getErr` — extract; type-gated to compile only when the opposite channel is `never` (`get` needs `Result`, `getErr` needs `Result`), and *panicking* (rethrowing the cause) on a defect. * `getOr` / `getOrElse` / `getOrNull` / `getOrUndefined` — recover an `Err` to a fallback, but **re-throw a defect** (it's a bug, not an absent value). * `getOrThrow` — extract `T`, but **throw the modeled error as-is** on `Err` (panicking on a defect). A deliberate escape hatch off errors-as-values, at home in **tests and scripts** where "this `Result` had better be `Ok`" is the assertion. In production, fold the channel instead — `recoverErrCases` empties `E`, so `get()` compiles — or use `match` / `flatMapErrCases`. The opt-in [`no-get-or-throw`](../how-to/lint-your-codebase#no-get-or-throw) rule enforces that, exempting tests through an oxlint `overrides` entry. In a test, [`@unthrown/vitest`](../how-to/test-with-vitest)'s matchers (`toBeOk`, `toBeOkWith`, `toBeErrTagged`, `toBeDefect`, …) are usually the better tool — reach for `getOrThrow()` when you just need the value. On an `AsyncResult` every eliminator returns a `Promise` — `await` it (an `Err` or `Defect` still throws/rejects, exactly as above). ## Where to go next * The type surface these methods live on: [Result and AsyncResult](./result-surface). * Why the error channel is a matcher: [Exhaustive error matching](../explanation/exhaustive-error-matching). * Full signatures and prose: [`ResultMethods`](/api/core/#resultmethods) in the API reference. --- --- url: /unthrown/reference/result-surface.md --- # Result & AsyncResult surface > **Reference.** The shape of the two core types, the constructors and guards > that produce and narrow them, and the aggregate helpers. For per-method > signatures see the [combinator reference](./combinators) and the generated > [API reference](/api/core/); for terminology, the [glossary](./glossary). ## Three runtime states, two type parameters A `Result` has **three** runtime states but only **two** type parameters: | State | Meaning | Visible in the type? | | ---------- | --------------------------------------- | -------------------- | | **Ok** | success carrying a `T` | yes (`T`) | | **Err** | an *anticipated* domain failure (`E`) | yes (`E`) | | **Defect** | an *unmodeled* failure (a bug, a panic) | **no** — invisible | The defect channel is explained on [its own page](../explanation/the-defect-channel). A `Result` is a real **discriminated union** — each variant carries a `tag` of `"Ok"` / `"Err"` / `"Defect"` plus its payload (`value` / `error` / `cause`) — intersected with the shared method surface. So it matches **natively** (a `switch` on `tag`, or `match(r).with({ tag: "Ok" }, …).exhaustive()`) **and** chains fluently. The payload is reachable only after narrowing. `AsyncResult` shares that method surface as an awaitable wrapper typed `Awaitable>` — a success-only thenable whose internal promise never rejects. `await` collapses it to a `Result`. Its combinator callbacks are synchronous; see [The async model](../explanation/async-model). ## The method surface Every `Result` shares one method surface, grouped by the channel it touches: * **success** (runs on `Ok`): `map`, `flatMap`, `ensure`, `tap`, `flatTap`, `as`, `discard` * **do-notation** (runs on `Ok`): `bind`, `let` — accumulate a named scope; see [Sequence dependent steps](../how-to/sequence-dependent-steps) * **error** (runs on `Err`): `mapErrCases`, `flatMapErrCases`, `recoverErrCases`, `tapErrCases`, `flatTapErrCases` — all take an **exhaustive matcher** over the error * **defect** (the only door to a `Defect`): `recoverDefect`, `tapDefect` * **failure** (runs on `Err` **or** `Defect`): `tapFailure` — observe either failing channel without consuming it * **eliminate**: `match`, `get`, `getErr`, `getOr`, `getOrElse`, `getOrNull`, `getOrUndefined`, `getOrThrow` A combinator only runs its callback on its own channel — the other states flow through untouched: ```ts import { Ok, Err, type Result } from "unthrown"; const two: Result = Ok(2); two.map((n) => n + 1); // => Ok(3) Err("boom").map((n) => n + 1); // => Err("boom") — the success callback is skipped two.mapErrCases((m) => m.with("boom", (e) => `wrapped: ${e}`)); // => Ok(2) — the error branch is skipped ``` The `mapErrCases` above carries a real, exhaustive matcher; on an `Ok` it simply never runs. (There is no error-channel identity — `mapErrCases((m) => m)` is not a no-op; see [Exhaustive error matching](../explanation/exhaustive-error-matching#no-identity-on-the-error-channel).) The full behavior grid and per-method signatures are in the [combinator reference](./combinators). The fluent surface is also documented, method by method, on the [`ResultMethods`](/api/core/#resultmethods) and [`AsyncResultMethods`](/api/core/#asyncresultmethods) types. ## Constructors The constructors are tree-shakeable free functions: | Constructor | Produces | Notes | | ----------------- | ------------------------ | ------------------------------------------------------------ | | `Ok(value)` | `Result` | `Ok()` (no arg) constructs a `void` success | | `Err(error)` | `Result` | | | `OkAsync(value)` | `AsyncResult` | pre-lifted `Ok(value).toAsync()`; `OkAsync()` mirrors `Ok()` | | `ErrAsync(error)` | `AsyncResult` | pre-lifted `Err(error).toAsync()` | | `Do()` | `Result<{}, never>` | do-notation entry — an empty object scope | | `DoAsync()` | `AsyncResult<{}, never>` | pre-lifted `Do().toAsync()`; alias `AsyncResult.Do` | There is **no** `Defect` constructor — a defect-state `Result` arises only at boundaries, and the qualify-time `defect` helper is injected, not exported. See [Design decisions](../explanation/design-decisions#no-defect-constructor). ## Guards `isOk` / `isErr` / `isDefect` narrow to `OkView` / `ErrView` / `DefectView`, in two call styles that narrow identically — standalone functions and methods (the methods are `this is …` predicates): ```ts import { isOk } from "unthrown"; const r: Result = Ok(7); if (isOk(r)) r.value; // number (standalone function) if (r.isErr()) r.error; // string (method — narrows too) ``` To narrow an **`unknown`** value at an untyped boundary, use the standalone `isResult(x)`. It checks the value carries the `Result` prototype (an `instanceof` check with a `Symbol.for("unthrown.Result")` brand fallback, so a `Result` from another copy of the library still passes), so a plain look-alike like `{ tag: "Ok" }` is **not** matched. ## The `Result` / `AsyncResult` facades If you prefer a namespace over free functions, two companion objects alias the same entry points — **grouped by what they return**, so each static lives in exactly one place: ```ts import { Result, AsyncResult } from "unthrown"; // Result.* — everything that yields a Result (sync) Result.Ok(1); Result.fromNullable(map.get(key), () => "absent"); Result.all([Result.Ok(1), Result.Ok(2)]); // AsyncResult.* — everything that yields an AsyncResult await AsyncResult.fromPromise(fetchUser(id), (c, defect) => defect(c)); await AsyncResult.all([ AsyncResult.fromSafePromise(loadA()), AsyncResult.fromSafePromise(loadB()), ]); ``` The free functions remain the primary, tree-shakeable API; the companions are an opt-in alias (a separate export — `import { Ok }` never pulls one in). Importing a companion *value* trades that tree-shaking for the namespace. Inside `AsyncResult` the aggregates and pre-lifted entry points drop the `Async` suffix the free functions carry (`AsyncResult.all` **is** `allAsync`; `AsyncResult.Ok` **is** `OkAsync`) — the namespace already says async. ## Aggregating: `all` / `allFromDict` `all` collects a **tuple/array** of `Result`s into a `Result` of all their values; `allFromDict` takes a **record** for named results. Both short-circuit on the first `Err`, and any `Defect` dominates (even over an earlier `Err`). Neither is error accumulation. ```ts import { all, allFromDict, Ok, type Result } from "unthrown"; all([Ok(1), Ok("two"), Ok(true)]).get(); // => [1, "two", true] (typed [number, string, boolean]) all([Ok(1), Ok(2)] as Result[]).get(); // => number[] (dynamic array collapses) allFromDict({ id: Ok(1), name: Ok("ada") }).get(); // => { id: 1, name: "ada" } ``` `allAsync` and `allFromDictAsync` are the asynchronous counterparts — same folding rules, inputs resolved concurrently (order preserved), and (like every `AsyncResult`) they never reject: ```ts import { allAsync, fromSafePromise } from "unthrown"; const [a, b] = ( await allAsync([fromSafePromise(loadA()), fromSafePromise(loadB())]) ).get(); ``` ## Interop constructors | Function | Produces | Purpose | | ------------------- | ------------------------- | ---------------------------------------------- | | `fromNullable` | `Result` | `null`/`undefined` → modeled `Err` | | `fromThrowable` | `(…) => Result` | wrap a throwing fn; mandatory `qualify` | | `fromSafeThrowable` | `(…) => Result` | wrap a throwing fn; every throw a `Defect` | | `fromPromise` | `AsyncResult` | wrap a promise; mandatory `qualify` | | `fromSafePromise` | `AsyncResult` | wrap a promise; every rejection a `Defect` | | `fromExecutor` | `AsyncResult` | wrap a callback API; settler names the variant | Their tasks and signatures are covered in [Qualify a boundary](../how-to/qualify-a-boundary). ## Where to go next * Choose the right method: [Combinator reference](./combinators). * The terms used above: [Glossary](./glossary). * Every symbol, generated from source: [API reference](/api/core/). --- --- url: /unthrown/reference/glossary.md --- # Glossary > **Reference.** Short definitions of the terms used throughout the > documentation. Each links to the page that explains it in depth. **`Result`** : A discriminated union of three runtime states — `Ok`, `Err`, `Defect` — intersected with the fluent method surface. `E` names only the *anticipated* domain failures. See [Result & AsyncResult surface](./result-surface). **`AsyncResult`** : The asynchronous counterpart of `Result`, typed as `Awaitable>`. Its internal promise never rejects; `await` collapses it to a `Result`. See [The async model](../explanation/async-model). **`Ok`** : The success variant of a `Result`, carrying a value of type `T`. **`Err`** : The *modeled* failure variant, carrying an error of type `E`. An `Err` is an anticipated outcome your callers are expected to handle. **`Defect`** : The *unmodeled* failure variant — a bug, a panic, an un-triaged rejection. It is invisible to the type (never appears in `E`) and can only be observed by `match`, `recoverDefect`, or the `tapDefect` / `tapFailure` observers. See [The Defect Channel](../explanation/the-defect-channel). **qualify** : The mandatory function passed to `fromPromise` / `fromThrowable` that triages each raw failure into a modeled error (which enters `E`) or `defect(cause)` (which does not). It is synchronous, and its `Defect` arm is subtracted from `E`. See [Qualification](../explanation/qualification). **`defect` (the helper)** : A helper *injected* at every triage site — inside `qualify` and in each error-match branch — that marks a cause as unmodeled. It is never imported; there is no public `Defect` constructor. **panic** : What `get` / `getErr` / the `getOr*` family do on a `Defect`: they rethrow the original cause with its original stack, rather than recovering it. `never` on the error channel means the *modeled* channel is empty, not that `get()` cannot throw. See [The Defect Channel](../explanation/the-defect-channel#get-is-asymmetric). **tagged error** : The recommended error convention — a class extending `Error` with a `_tag` discriminant, built with `TaggedError(tag)`. Core `Result` stays generic in `E`; only the tag-aware utilities require `E extends { _tag: string }`. See [Model errors](../how-to/model-errors). **matcher** : The built-in `match(error)` builder handed to every error combinator's callback. You return it un-terminated; the combinator runs `.exhaustive()`, so a missing case does not compile. See [Exhaustive error matching](../explanation/exhaustive-error-matching). **`P` / `P.tag(t)`** : `P` is unthrown's pattern namespace (`P._`, `P.tag`, `P.instanceOf`, `P.when`). `P.tag(t)` is sugar for the `{ _tag: t }` pattern, narrowing to a tagged variant and its payload — the everyday way to write an arm. `P._` is the universal catch-all; it makes any match exhaustive, so it is reserved for the two cases enumeration cannot express — a helper generic in `E`, or an `E` that is a single type rather than a union of cases — rather than used as a default. See [Exhaustive error matching](../explanation/exhaustive-error-matching#generic-boundary-helpers-the-catch-all-is-the-only-form-that-compiles). **`Awaitable`** : A success-only thenable type — resolves to `R`, models no rejection channel. `AsyncResult` is `Awaitable>`. **boundary** : An edge of your program where untyped failure enters — a throwing function, a rejecting promise, a nullable API. Each is crossed with a `from*` constructor that forces qualification. See [Qualify a boundary](../how-to/qualify-a-boundary). **combinator** : Any method on the fluent surface (`map`, `flatMap`, `mapErrCases`, `tap`, …) that transforms or observes a channel and returns another `Result` / `AsyncResult`. A throw inside a combinator becomes a `Defect`. **eliminator** : A method that leaves the `Result` world — `match`, `get` / `getErr`, and the `getOr*` family — folding or extracting a plain value. --- --- url: /unthrown/api.md --- # API Reference This reference is generated from the source with [TypeDoc](https://typedoc.org/) at build time. ## Packages * [**unthrown**](./core/) — the core `Result` / `AsyncResult` types, constructors (`Ok`, `Err` — a `Defect` has no constructor; it arises only at boundaries), guards, boundary interop (`fromNullable`, `fromThrowable`, `fromSafeThrowable`, `fromPromise`, `fromSafePromise`), aggregation (`all` / `allFromDict`), the tagged-error factory (`TaggedError`), and the built-in `match` / `P` (`P.tag` included) that drive the exhaustive error matcher. * [**@unthrown/vitest**](./vitest/) — custom Vitest matchers (`toBeOk`, `toBeOkWith`, `toBeErr`, `toBeErrWith`, `toBeErrTagged`, `toBeDefect`). * [**@unthrown/effect**](./effect/) — bijective `Result ↔ Exit` bridges (Effect has a genuine defect channel, `Cause.die`), plus `toEither` with a mandatory `onDefect`. * [**@unthrown/neverthrow**](./neverthrow/) — `to*`/`from*` bridges to neverthrow's `Result`/`ResultAsync`; every `to*` takes a mandatory `onDefect` (neverthrow has no defect channel). * [**@unthrown/boxed**](./boxed/) — `to*`/`from*` bridges to Boxed's `Result`/`Future`; every `to*` takes a mandatory `onDefect`. * [**@unthrown/standard-schema**](./standard-schema/) — `fromSchema` / `fromSchemaAsync`: run any Standard Schema validator (Zod, Valibot, ArkType) into a `Result` with the validation issues as the modeled error. * [**@unthrown/orpc**](./orpc/) — the oRPC (v2) bridge: `handlerResult` / `.result()` for `Result`-returning procedure handlers, `createResultClient` / `fromCall` for an `AsyncResult` client, with the inferable `ORPCError` union as the modeled error. * [**@unthrown/prisma**](./prisma/) — a Prisma Client extension (`$extends(unthrownPrisma)`) adding `try*` variants of every model operation (each an `AsyncResult` whose error channel is exactly the P-codes it can raise), plus `$tryTransaction` and `tryPaginate(...).withCursor(...)`. * [**@unthrown/drizzle**](./drizzle/) — a Drizzle ORM Postgres database that *replaces* the stock one: every query resolves to an `AsyncResult`, with the five integrity-constraint SQLSTATEs as tagged errors, reads declaring `E = never`, and `Result`-driven transactions. `@unthrown/oxlint` (the recommended rules `no-ambiguous-error-type`, `no-catch-all-pattern`, `no-unhandled-result`, `no-unused-matcher`, `prefer-async-result`, and the opt-in `no-get-or-throw`) has no generated API page — it is documented in the [Linting guide](../how-to/lint-your-codebase). --- --- url: /unthrown/explanation/why-unthrown.md --- # Why unthrown? > **Explanation.** This page is about *understanding* — why the library exists > and what problem it solves. If you'd rather get your hands on the code first, > start with the [Getting Started tutorial](../tutorial/getting-started). `unthrown` is a small, focused TypeScript library for **explicit errors as values**, with a separate **defect channel** for the unexpected. The name states the concern: ordinary errors are *unthrown* — returned as values, not flung up the stack. Only a true defect ever throws, and only at `get`. ## The problem with throwing A thrown exception is invisible to the type system. A function typed `(id: string) => User` might throw `NotFoundError`, `TimeoutError`, or a `TypeError` from a typo — the signature promises none of it, and the compiler won't make you handle any of it. Errors-as-values libraries fix this by returning a `Result` so failures are part of the type. But most of them stop there, and that leaves a gap. ```ts // Before: the signature hides every failure — and a bug in a callback // escapes as a runtime exception three layers up. function getUser(id: string): User; // throws NotFoundError? TimeoutError? TypeError? // After: anticipated failures are in the type; a thrown bug becomes a // Defect that can't masquerade as either. function getUser(id: string): Result; getUser(id) .map((u) => new URL(u.website).host) // malformed URL — TypeError → Defect, NOT an Err .match({ ok: render, // every case in E is named — add a third and this stops compiling errCases: (matcher) => matcher .with(P.tag("NotFound"), () => showMessage("not found")) .with(P.tag("Timeout"), () => showMessage("timed out")), defect: report500, }); ``` ## The gap: unexpected failures There are really **two** kinds of failure: * **Anticipated** domain errors — "user not found", "payment declined". You model these, and callers handle them. * **Unexpected** failures — a thrown `TypeError`, an un-triaged promise rejection, a bug in a callback. These are not part of your domain; they are defects. If a library folds both into the same `E`, a bug starts to look like a domain error. You write a `match` that "handles" `E`, and a `TypeError` quietly flows down the success-recovery path. The type said you were safe; the runtime disagreed. ## How unthrown is different `unthrown` keeps a **third runtime state** — a `Defect` — that is **invisible to the type**. `Result` exposes only your anticipated errors in `E`. Anything unexpected becomes a defect that short-circuits to the edge, where you log it and return a 500. A defect can only be observed by `match`, `recoverDefect`, or the `tapDefect` / `tapFailure` observers; it is never silently recovered by `getOr`, `getOrNull`, or `recoverErrCases`. This is the idea the rest of the library follows from. It has [its own page](./the-defect-channel). Two more deliberate choices follow from it: * **Qualification is enforced at every boundary.** `fromPromise` / `fromThrowable` take a mandatory `qualify` function that triages each failure into a modeled error or a defect. There is no code path that yields `unknown` in `E`. See [Qualification](./qualification). * **Throws are caught and become defects.** A `throw` inside any combinator (`.map`, `.flatMap`, …) is captured as a defect rather than escaping — which is what lets an HTTP handler do a single `match({ ok, errCases, defect })` with no surrounding `try`/`catch`. ## Why this matters more with AI in the loop Most code today is written with an assistant in the loop, and the economics of that loop reward exactly what errors-as-values provides. A model converges on correct code fastest when a mistake is caught **at author time by the type checker** rather than **at run time by a crash**: a compile error is local, specific, and available before anything executes, whereas a thrown exception costs a full generate → run → observe → retry cycle just to *discover* that something can fail. Thrown exceptions give a model nothing to work with. A signature `(id: string) => User` hides every way it can fail, so neither the model nor the compiler can tell that a caller forgot to handle a timeout — the failure surfaces later, as a stack trace, in a separate iteration. `Result` puts every anticipated failure *in the type*, which turns the type checker into a specification the model must satisfy: a non-exhaustive `match`, an unhandled `PaymentDeclined`, a forgotten `Err` arm each become a compile error the moment they're written. That is the tightest correction signal there is — immediate, mechanical, and free of a run. The defect channel is what keeps that signal sharp. If unexpected failures were folded into `E` as `unknown` or `Error`, exhaustiveness would degrade into "handle the catch-all" and stop meaning anything. By holding `E` to exactly the modeled errors and routing the unexpected to a separate, type-invisible defect, `unthrown` keeps `E` a precise contract — so the type stays worth checking and the compiler keeps telling the model something *true*. The enforced `qualify` at every boundary reinforces this: it forces an explicit triage decision at each `fromPromise` / `fromThrowable` instead of letting `unknown` be swallowed and carried forward. The [`@unthrown/oxlint`](../how-to/lint-your-codebase) rule `no-ambiguous-error-type` guards the same line from the other side, failing the build when `unknown` / `any` / `Error` leak back into `E`. ## Compared to the alternatives * **neverthrow / boxed / byethrow** — model errors as values, but have no proper channel for *unexpected* errors, and a throw inside a `.map` callback either escapes as a real exception or gets folded into `E`. `boxed` also ships an `Option` type — a second way to express absence that `unthrown` deliberately omits (see [Design decisions](./design-decisions)). * **effect** — extremely powerful, and it *does* have a defect channel, but it is heavy: it conflates error handling with context, runtime, dependency injection, and more. `unthrown` does one thing. `unthrown` borrows Effect's best idea — a defect (`die`) channel distinct from modeled errors — and ships just that, in a library small enough to be *done*. For a feature-by-feature table across all of these, see [Comparison](./comparison). ## Where to go next * Build something: [Getting Started](../tutorial/getting-started). * Understand the core idea: [The Defect Channel](./the-defect-channel). * See how it stacks up: [Comparison](./comparison). --- --- url: /unthrown/explanation/the-defect-channel.md --- # The Defect Channel > **Explanation.** This page explains the idea that sets `unthrown` apart and > the reasoning behind how a defect behaves. For the tasks it touches — producing > a defect, recovering one — see [Qualify a boundary](../how-to/qualify-a-boundary) > and the [combinator reference](../reference/combinators). A **defect** is a failure you did not model — a thrown `TypeError`, an un-triaged promise rejection, a bug in a callback. It is the third runtime state of a `Result`, and it is **invisible to the type**: it never appears in `E`. This is the idea that sets `unthrown` apart. A defect is a value (not a thrown exception), so errors-as-values stays uniform — but it behaves very differently from a modeled `Err`. ## Throw → defect Any value thrown by a callback inside a combinator is **caught and converted to a defect**, never allowed to escape: ```ts const r = Ok(1).map(() => { throw new Error("boom"); }); r.isDefect(); // => true ``` This is what makes "no `try`/`catch` at the edge" real: a bug in a `.map` becomes a defect, short-circuits the pipeline, and is handled once at `match`. ## A defect flows through almost everything A defect passes through **every** method untouched — *except* `match`, `recoverDefect`, and the observers `tapDefect` / `tapFailure` (which observe it without consuming it). The success **and** error combinators never see it — even when the error channel is fully typed: ```ts import { Ok, type Result } from "unthrown"; // A pipeline whose error channel is modeled as "boom", but whose success // callback throws — so at runtime `d` is a Defect. (`never` widens to "boom", // so the annotation is a legal widening of `Ok(1).map(…)`.) const d: Result = Ok(1).map((): number => { throw new Error("bug"); }); d.map((n) => n + 1); // still a Defect — the success callback is skipped d.mapErrCases((m) => m.with("boom", () => "handled")); // still a Defect — the branch never runs d.recoverErrCases((m) => m.with("boom", () => 0)); // still a Defect — see below ``` The matchers above are the real, exhaustive form — one branch per modeled error. They simply never run here, because a defect is not an `Err`: the error combinators only touch the `Err` channel, and a defect flows straight past them. ### No identity on the error channel ::: warning `mapErrCases((m) => m)` is not an identity It can be tempting to write `mapErrCases((matcher) => matcher)` — returning the matcher untouched — as a "do nothing" on the error channel. It is **not**. The combinator terminates the builder with `.exhaustive()` for you, and a builder with no `.with(…)` branch is only exhaustive when `E` is `never`. On any real error channel it fails to compile; if it slips past the types (a cast), it throws `NonExhaustiveError` at runtime, which becomes a `Defect`. There is no "no-op" on the error channel — every branch of the union must be handled, which is the whole point (see [Exhaustive error matching](./exhaustive-error-matching)). To genuinely pass the error through unchanged, use an observer (`tapErrCases`) — or re-emit each case by name (`.with(P.tag("NotFound"), (e) => e)…`). ::: ## `recoverErrCases` clears the error channel, not the runtime `recoverErrCases` turns an `Err` into an `Ok`, so its type is `Result`. But `never` describes only the **error** channel — a defect can still be present at runtime: ```ts // the "boom" branch is what supplies the `U` in `Result` const recovered = d.recoverErrCases((matcher) => matcher.with("boom", () => 99), ); // type: Result recovered.isDefect(); // => true — `never` does NOT mean "total" ``` A defect is a bug; you should not be able to accidentally "recover" it into a success. So the recovering eliminators **rethrow** on a defect: ```ts d.getOr(0); // throws the original cause d.getOrNull(); // throws the original cause d.getOrElse(() => 0); // throws the original cause ``` They recover a modeled `Err`, never an unmodeled defect. ::: warning `getOr` / `getOrNull` still throw on a defect It's tempting to read `getOr(0)` as "always give me a value." It doesn't — it supplies the fallback for a modeled `Err` but **rethrows a defect** (a bug is not an absent value). If you must not throw, handle the defect explicitly first with `match` or `recoverDefect`. ::: ## `get` is asymmetric `get()` / `getErr()` are **type-gated**: `get()` only compiles when the error channel is `never` (`Result`), `getErr()` only when the success channel is `never` (`Result`). Calling `.get()` on a still-fallible `Result` is a compile error, not a runtime throw — so the `Err` case can't reach either eliminator in well-typed code. The remaining wrong-variant throw (`GetError`) is a defensive runtime guard for unsound edges (e.g. a cast), not something you should hit normally. A `Defect`, though, is invisible to the type system — `never` on the error channel says nothing about it (see above). So on a `Defect`, `get()` / `getErr()` **rethrow the original cause** with its original stack — so an unhandled defect reaches the global handler looking like the real failure, not wrapped in library noise. ```ts try { d.get(); } catch (e) { e === boom; // true — same instance, original stack } ``` ## The only door: `recoverDefect` When you genuinely need to handle a defect — say, to convert a third-party library's thrown error back into a modeled one — use `recoverDefect`. It is the only combinator that can observe a defect, and it re-enters the modeled world by returning a `Result`: ```ts d.recoverDefect((cause) => cause instanceof RangeError ? Err("out_of_range") : Err("unknown"), ); ``` Use `tapDefect` to observe a defect's cause (e.g. logging) without changing it. When the same observation applies to a modeled `Err` too — one logger, one rollback trigger for "it went KO" — `tapFailure` runs it on either failure, passing the discriminated variant (`ErrView | DefectView`) so you can still branch on `tag`. It observes without consuming; there is deliberately no `recoverFailure` — recovering a defect stays a separate, loud `recoverDefect`. Recovering a defect should feel awkward — usually you don't. You let it bubble to the edge, log it, and return a 500. ## Producing a defect on purpose Sometimes a condition is *anticipated* but still not a domain outcome — a required config value is missing, a "can't happen" branch is reached. You want the defect channel (the edge's 500), not an `Err` that every caller must thread through `E`. There is deliberately **no** `Defect(...)` constructor for this. The primitive already exists — it is `throw`. The throw → defect rule at the top of this page is not merely a safety net for accidental bugs; it is the *sanctioned syntax* for declaring one: ```ts // Inside a pipeline: just throw. The combinator converts it. pipeline.tap(() => { if (!config.apiKey) throw new MissingConfigError(); }); ``` And if you find yourself wanting to *mint* a defect mid-chain, the failure usually happened somewhere earlier — put the boundary at its origin instead: ```ts // An ordinary function that throws on a bug — perfectly idiomatic JS. function requireConfig(key: string): string { const value = process.env[key]; if (value === undefined) throw new MissingConfigError(key); return value; } // Wrapped ONCE at its boundary: every throw is a defect, by decision. const readConfig = fromSafeThrowable(requireConfig); readConfig("API_KEY").toAsync().flatMap(callTheApi); ``` For the residual case — you hold a cause in hand and need to *start* a chain in defect state — the documented idiom is `fromSafeThrowable(() => { throw cause })()` (add `.toAsync()` for an `AsyncResult`). ::: info Why no constructor? Once minting a defect is one frictionless call, "I don't feel like modeling this error" starts flowing into the defect channel — and the discipline that makes `E` trustworthy erodes. The friction is a forcing function: either model the failure as an `Err`, or throw at its true origin. This was weighed and decided in [#77](https://github.com/btravstack/unthrown/issues/77), and is recorded among the [design decisions](./design-decisions). ::: ## Where to go next * The rule that keeps defects *out* of `E`: [Qualification](./qualification). * Why the error channel is matched exhaustively: [Exhaustive error matching](./exhaustive-error-matching). * The per-combinator behavior grid: [Combinator reference](../reference/combinators). --- --- url: /unthrown/explanation/qualification.md --- # Qualification at the boundary > **Explanation.** This page is about *why* every boundary forces a triage > decision. For the concrete API — `fromThrowable`, `fromPromise`, > `fromNullable`, and the `fromSafe*` pair — see > [Qualify a boundary](../how-to/qualify-a-boundary). The edges of your program — a throwing function, a rejecting promise, a nullable third-party API — are where **untyped failure** enters. Everything inside a `Result` pipeline is already triaged into `Ok` / `Err` / `Defect`; the boundary is the one place a raw `unknown` shows up. `unthrown`'s position is that this is exactly where the decision must be forced: is this failure a **modeled error** or a **defect**? ## The original sin: `unknown` in `E` Most errors-as-values libraries spell their promise boundary like this: ```ts fromPromise(p): AsyncResult; ``` That single `unknown` is the leak. It flows into your error type, and from there into every consumer. You reach for a `match` or a `mapErrCases`, discover the error is `unknown`, and now you either cast it (a lie the compiler can't check) or widen `E` to `unknown` all the way up. The type that was supposed to be a precise contract quietly became "something went wrong." `unthrown` closes this by making `qualify` **mandatory**: ```ts fromPromise(p, (cause, defect) => cause instanceof NotFoundError ? new NotFound() : defect(cause), ); ``` `qualify` receives the raw `cause` and a `defect` helper the boundary injects. Every branch must end in one of two places: a **modeled error** (which enters `E`) or `defect(cause)` (which does not). There is no third option, and there is no code path that yields `unknown` in `E`. ## `Exclude` — the defect arm is subtracted The error channel is inferred as `Exclude`, where `R` is `qualify`'s return type. The `Defect` arm is **subtracted**, never inferred into `E`: * a `qualify` returning `NotFound | Defect` yields `AsyncResult`; * a `qualify` returning *only* `defect(cause)` yields `AsyncResult` — not `AsyncResult`. This is what keeps the defect channel out-of-band. Modeled failures are in the type; the unmodeled ones are routed to the invisible third state. The subtraction is sound because `Defect` is `unique symbol`-branded — no domain error is ever assignable to it, so there is no way to accidentally smuggle a real error into the defect arm or vice versa. ## `qualify` is synchronous — on purpose `qualify` must be synchronous. Its return type intersects `NotThenable`, so an `async qualify` does not compile. This is not an arbitrary restriction: if `qualify` could be async, its returned `Promise` would land in `E` **un-triaged** — the exact leak the boundary exists to prevent. A thenable that slips past the types at runtime is turned into a `Defect` (never `Err(Promise)`), and the orphaned thenable is adopted-and-silenced so a later rejection can't float unhandled. The same rule is why an `AsyncResult`'s combinator callbacks are synchronous — a raw `Promise` may never enter a combinator, because its rejection would silently become a defect and skip the triage. Async work re-enters only through `fromPromise` / `fromSafePromise` and composes via `flatMap`. That story has its own page: [The async model](./async-model). ## When *every* failure is a bug: `fromSafe*` Sometimes "everything here is a defect" is the correct, deliberate decision — a promise that should never fail in a *modeled* way, a function whose every throw is a bug. For those, `fromSafePromise` / `fromSafeThrowable` skip `qualify` entirely and give `E = never`; any failure becomes a defect. These are escape hatches from qualification, not shortcuts. They are the *named*, explicit form of the `(cause, defect) => defect(cause)` you would otherwise write out — an on-the-record "I decided this is all defects", not a convenience that quietly drops the triage. Keep `fromThrowable` / `fromPromise` wherever some failures are genuinely anticipated. ## Sync boundaries are sync on both sides `fromThrowable` / `fromSafeThrowable` wrap a **synchronous** function, and that applies to `fn` as much as to `qualify`. A synchronous boundary only ever sees a synchronous `throw`, so an `async` `fn` rejects long after the boundary has returned — its rejection could never reach `qualify`. Rather than hand back an `Ok` wrapping a live promise whose rejection escapes triage (and then floats as an unhandled rejection), the boundary produces a **defect**: ```ts const bad = fromSafeThrowable(async () => fetchUser(id)); bad(); // => Defect(TypeError: … `fn` returned a thenable …) const good = fromSafePromise(() => fetchUser(id)); // AsyncResult ``` Reach for `fromPromise` / `fromSafePromise` for async work. (This one is caught at runtime rather than by the type system: banning a thenable return at compile time would also reject generic functions, so `fromSafeThrowable(structuredClone)` would stop compiling.) ## The payoff Because every boundary is qualified and every in-pipeline throw becomes a defect, the interior of your program never handles a raw `unknown`, and its edge needs no `try`/`catch` — just one exhaustive `match` that folds `Ok` / `Err` / `Defect` into a response. The forced triage at the boundary is what makes that single handler trustworthy: every failure has already been sorted into "modeled" or "bug" before it arrives. ## Where to go next * Do it: [Qualify a boundary](../how-to/qualify-a-boundary). * The state the defect arm routes to: [The Defect Channel](./the-defect-channel). * Why async callbacks stay synchronous: [The async model](./async-model). --- --- url: /unthrown/explanation/async-model.md --- # The async model > **Explanation.** This page explains the design of `AsyncResult` — why it never > rejects and why its callbacks are synchronous. For the tasks (lifting, > composing, awaiting) see [Crossing an async > boundary](../tutorial/crossing-an-async-boundary) and the > [combinator reference](../reference/combinators#result-and-asyncresult). An `AsyncResult` is the asynchronous counterpart of `Result`. It has the **same method surface**, and `await`-ing it collapses it to a `Result`. Two design choices make it behave the way it does, and both fall out of the same principle: **failure must stay triaged**. ## It is `Awaitable`, not `PromiseLike` An `AsyncResult`'s internal promise **never rejects**. Every rejection or thrown value is captured as an `Err` (via `qualify`) or a `Defect`, so `await`-ing one always yields a `Result` and never throws. Because of that, it is typed as a success-only `Awaitable>` rather than a full `PromiseLike` — there is no rejection channel to model, so the type advertises none. It is still a thenable at runtime (that is how `await` collapses it, and its `then` forwards `onrejected` defensively), but it is deliberately **not** interchangeable with a raw promise. A raw `Promise` *can* reject; an `AsyncResult` cannot. That distinction is why the [`prefer-async-result`](../how-to/lint-your-codebase#prefer-async-result) lint rule steers you away from `Promise>`. One consequence: an `AsyncResult` has no `isOk` / `isErr` / `isDefect`. The state isn't known until it settles, so there is nothing to guard on yet. `await` it first — the guards live on the `Result` you get back. ::: info Eliminators still reject on a Defect The async eliminators reject when they hit a `Defect`: `await result.get()` rethrows the defect's cause, just like the synchronous `get()`. (Like its sync form, `get()` is type-gated — it compiles only when the error channel is `never` — so in well-typed code an `Err` can't reach it; a `Defect` is the only rejection you'll see.) It is the *internal* promise — the one `await result` resolves — that never rejects. Panicking on a defect is by design; see [The Defect Channel](./the-defect-channel#get-is-asymmetric). ::: ## Combinator callbacks are synchronous This is the rule that keeps qualification honest: > A raw `Promise` may **never** enter an `AsyncResult` combinator. If `.map(async …)` were allowed, a rejection inside that callback would silently become a defect — an un-qualified async boundary, exactly what [qualification](./qualification) exists to prevent. So combinator callbacks are synchronous. The `Result`-returning binds (`flatMap`, `flatMapErrCases`, `recoverDefect`, `bind`, …) accept a `Result` **or** an `AsyncResult`, but never a raw promise — a `Promise` has no `flatMap`, so the types keep it out. To do more async work, you re-enter through a qualified boundary and compose it with `flatMap`: ```ts const order = await fromPromise(loadCart(id), qualify).flatMap((cart) => fromPromise(checkout(cart), qualify), ); ``` The extra `fromPromise` is not ceremony — it is the forced triage decision that guarantees the failure becomes a modeled error or a defect, never an untyped `unknown`. The alternative — allowing `async` callbacks — would reintroduce the one leak the library is built to close, at the most convenient-looking spot. ## Why this is worth the constraint A single-axis `Result` can only stay sound if every combinator callback is total, and an `async` callback that can reject breaks that. By forbidding raw promises in the pipeline and forcing async re-entry through a boundary, `unthrown` guarantees that **every** way a failure can arise — a rejection, a throw, a returned `Err` — has passed through triage. That is what lets the whole program share one exhaustive `match` at its edge, with no `try`/`catch` and no rejection to forget to handle. ## Where to go next * The forced-triage rule this depends on: [Qualification](./qualification). * The type it routes bugs to: [The Defect Channel](./the-defect-channel). * Moving between `Result` and `AsyncResult`: [Combinator reference](../reference/combinators#result-and-asyncresult). --- --- url: /unthrown/explanation/exhaustive-error-matching.md --- # Exhaustive error matching > **Explanation.** This page explains *why* the error combinators take a > matcher instead of a plain callback, and why they carry a `*Cases` > suffix (`mapErrCases`, `tapErrCases`, …) rather than a bare `map`/`tap`-style > name. For the mechanics — the rules, grouped patterns, the per-method > signatures — see the [combinator reference](../reference/combinators#the-error-channel). Errors-as-values only pays off if the values **can't be silently dropped**. On the success channel that is easy — `T` is one type, so a `(value: T) => …` callback is exactly right. On the error channel it is not, and closing that gap is what shapes the entire error surface. ## The problem with a blanket error handler `E` is a **union of possibilities**: `NotFound | Forbidden | RateLimited`. A combinator that handed your callback the error *value* directly — ```ts (e) => wrap(e); // e: NotFound | Forbidden | RateLimited ``` — would keep compiling no matter how the union grows. Add a `PaymentDeclined` tag a year later and this call site does not change, does not warn, does not fail. It silently absorbs the new case. That is precisely the blanket handler errors-as-values is supposed to eliminate: the whole reason to make failures values is so the compiler forces you to *account for each one*. ## The solution: an exhaustive matcher, terminated for you So the error combinators — `mapErrCases`, `flatMapErrCases`, `recoverErrCases`, `tapErrCases`, `flatTapErrCases` — do not take a single callback. Their callback receives a built-in **match builder** over the error, and you **return the un-terminated builder**. The combinator calls `.exhaustive()` itself: ```ts db.reading.tryFindUniqueOrThrow({ where: { id } }).mapErrCases( (matcher, defect) => matcher .with(P.tag("RecordNotFound"), () => new ReadingNotFoundException(id)) .with(P.tag("Unavailable"), (e) => defect(e.cause)), // deliberate defect — the tag leaves E ); ``` Because the combinator runs `.exhaustive()`, a match that misses a case **does not compile** — there is no `.exhaustive()` to forget, and no `.otherwise()` to smuggle in a fallback. The day you enrich the error channel — a new Prisma P-code, a new oRPC code — **every site that consumes that channel lights up red**, and you are forced to decide how the new case is handled exactly where the decision belongs. Each branch receives the narrowed variant *and* an injected `defect` helper — the same helper [`qualify`](./qualification) gets — so converting a case into a defect (`defect(e.cause)`) is a sanctioned, in-line move, and its `Defect` arm is subtracted from the outgoing `E` just like at a boundary. ## No identity on the error channel A natural first instinct is that returning the matcher untouched must be a no-op: ```ts result.mapErrCases((matcher) => matcher); // ⚠️ not an identity ``` It isn't. The combinator terminates the builder with `.exhaustive()`, and a builder with **no `.with(…)` branch** is only exhaustive when the input has been narrowed to `never` — i.e. when `E` is already `never`. That is the one case where it type-checks, which is exactly what makes it a trap: it appears to work on an error-free `Result`, then fails to compile the moment the channel carries a real error. If it ever reaches runtime past a cast, `.exhaustive()` throws `NonExhaustiveError`, which the [throw → defect](./the-defect-channel#throw-defect) net turns into a `Defect`. There is deliberately **no** identity on the error channel. Passing the error through unchanged is a real decision with a real spelling: * to *observe* and pass through, use `tapErrCases` (an observer); * to *re-emit* cases unchanged, name them — grouped in one arm if they share the treatment: `.with(P.tag("NotFound"), P.tag("Forbidden"), (e) => e)`. Grouped patterns are the honest form of "several cases, one strategy": the handler is written once, but every case is still spelled out, so enriching `E` still breaks the build. That is the property the whole design is buying. ## Enumerate the cases; the wildcard is the exception `P._` matches anything, so a single `.with(P._, …)` arm makes *any* match exhaustive — including matches over unions it has never seen. That is precisely what makes it the wrong default. A wildcard turns the compile error you wanted into silence: the day a `PaymentDeclined` joins `E`, every wildcard-terminated site keeps building and quietly routes the new case down whatever path was already there. So the library's position is: **name the cases**. Group them when several share a handler. Reach for `P._` in exactly two situations, and say why in a comment when you do: 1. **A helper generic in `E`** — enumeration is impossible in principle, not just inconvenient (the next section). 2. **An `E` that is a single type**, not a union of cases — a validator's issues array, say. There is nothing to enumerate; one arm *is* the enumeration. `@unthrown/oxlint`'s [`no-catch-all-pattern`](../how-to/lint-your-codebase#no-catch-all-pattern) — part of its recommended preset — encodes this: `P._` is reported, and the two sanctioned uses are exempted automatically when an in-file `Result` annotation proves them; where the proof is out of reach (a receiver imported from another module), the site carries a targeted `oxlint-disable` comment saying which case it is. ## Why the `*Cases` suffix? A bare `mapErr` / `tapErr` would promise the functional-programming functor contract — that the callback receives the error *value*. It doesn't: it receives a **matcher over the error's cases**. The `*Cases` suffix names that difference honestly, so the signature tells you what the callback gets before you write it: * **The success surface keeps `map` / `tap`.** Those callbacks really do hand you the value, so the functor name is true there. * **The error surface says `*ErrCases`** — `mapErrCases`, `flatMapErrCases`, `recoverErrCases`, `tapErrCases`, `flatTapErrCases` — because the callback builds a match over the union's cases. Each matcher *branch* still hands you the error, narrowed to its exact case, so the functor intuition holds *inside* a branch, where there is a single concrete value. Naming both surfaces the same (`map` / `mapErr`) was considered and **reversed** (2026-07): the symmetry read nicely but lied about the protocol, and a reader reaching for `mapErr((e) => …)` — the shape that name implies — hit a type error with no hint why. The suffix trades a little visual symmetry for a name that matches the behavior. Other options — plural `mapErrs`, `catchErrs` + observers — were rejected for saying even less about what the callback receives. There is deliberately **no** bare `mapErr((e) => …)` variant alongside `mapErrCases` — a plain callback over the union is exactly the blanket handler the matcher exists to eliminate. ## The one eliminator that still folds the error: `match` `match` applies the same exhaustive matcher to its `errCases` handler: ```ts result.match({ ok: (v) => v, errCases: (matcher) => matcher .with(P.tag("NotFound"), () => 404) .with(P.tag("Forbidden"), () => 403), defect: (cause) => 500, }); ``` so folding at the edge is exhaustive too — there is no blanket error callback left to silently drop a case. Its `errCases` handler receives the matcher but **no `defect` helper**: `match` folds to a plain value, with no `Defect` output channel, and a `Result` that already carries a defect is handled by the separate `defect:` case. ## Generic boundary helpers: the catch-all is the only form that compiles This is `P._`'s remaining purpose — not a convenience, a necessity. Exhaustiveness is proven *at the call site*, from the concrete error union. Inside a **generic** helper — one whose error type is still a type parameter `E` — no list of tag arms can prove coverage, because the compiler cannot know what `E` will contain. Enumeration is not merely tedious here; it is impossible. The **catch-all can** prove it: `.with(P._, …)` is a state transition to "nothing remains" that does not depend on `E` at all, so a catch-all-terminated builder compiles even in fully generic code: ```ts // ✅ Compiles for any E: the catch-all is provably exhaustive by construction. function toPromise(result: Result): T { return result.match({ ok: (value) => value, errCases: (matcher) => // The lint rule exempts this arm itself: `result` is annotated // `Result` in this file, and `E` is an unresolved type parameter. matcher.with(P._, (error) => { throw error; }), defect: (cause) => { throw cause; }, }); } ``` The exemption is narrow by construction: the `UniversalPattern` type that unlocks the catch-all overload is carried by `P._` alone. Even a `P.when` guard that happens to accept everything is *not* assignable to it — the overload fires only for a pattern the type system **knows** covers the whole input. There is no way to widen this hole from user code. ```ts // ❌ Still won't compile — and shouldn't: tag arms can never be shown to cover // an unresolved E. Only the catch-all (or a concrete union) can. function partial(result: Result) { return result.mapErrCases((matcher) => matcher.with(P.tag("NotFound"), () => 404), ); } ``` (Earlier v5 betas, which delegated matching to ts-pattern, rejected even the catch-all form here — the original issue #145. The built-in matcher fixed it.) Often the better answer at a boundary is not to match at all. The narrowing guards split by *channel* with no per-case branching and carry no exhaustiveness obligation — which is what unthrown's own interop bridges use, simply because nothing there needs a matcher: ```ts // ✅ Also fine — and usually preferable: guards make no exhaustiveness claim, // so there is no wildcard to justify. function toPromise(result: Result): T { if (result.isErr()) throw result.error; if (result.isDefect()) throw result.cause; return result.value; } ``` Reach for the generic catch-all only when the helper genuinely needs the matcher's shape — a `.returnType()` pin, say (next section). Otherwise the guards say the same thing with less machinery. ## Declaring the output: `returnType()` By default a match's output type is **inferred** — the union of whatever the branches return. That is the right default when the branches are the source of truth. It is the wrong one when a **signature** is: a boundary helper, a bridge, an adapter whose return type is already decided. There, inference works backwards, and a branch that drifts off-spec silently widens the result instead of failing. `.returnType()`, called directly after `match(…)`, declares the output once: ```ts // Generic in E again — so the catch-all is the only arm that can compile here. const toApiError = (result: Result): Result => result.mapErrCases((matcher) => // No disable needed: the rule sees `result: Result` and exempts // the catch-all over an unresolved `E` itself. matcher .returnType() .with(P._, (error) => new ApiError({ status: 500, error })), ); ``` Three things change: * **The match evaluates to `R`**, not to the union of the branch returns — so the helper's declared return type is what actually flows out. * **Every branch is checked against `R`**, and a mismatch is reported **on the offending branch** rather than downstream at the call site. Assignability is checked in full; one honest caveat — excess-property checking does *not* fire through the pin, so a branch returning an object literal with an **extra** property still compiles where an explicit `(): R =>` annotation would reject it. A misspelled optional property can therefore slip through; a wrong or missing one cannot. * **Branch returns get a contextual type**, so object literals infer against `R` with no per-branch annotation. The injected `defect` helper stays legal under a pin — the defect channel is not part of the declared output: ```ts result.mapErrCases( (matcher, defect) => matcher .returnType() .with(P.tag("RecordNotFound"), () => new ApiError({ status: 404 })) .with(P.tag("Unavailable"), (e) => defect(e.cause)), // still fine ); ``` Exhaustiveness is unaffected: a missing case is still a compile error. Pinning declares *what comes out*, not *what is covered* — so a pinned match over a concrete union still names every case. One thing a pin must not do is *widen* the error channel. In `mapErrCases` the declared output **is** the new `E`, so `returnType()` there re-opens [Thesis #1](./why-unthrown) — through a type argument, where a `Result` annotation would have been rejected. `@unthrown/oxlint`'s [`no-ambiguous-error-type`](../how-to/lint-your-codebase#no-ambiguous-error-type) (in its recommended preset) flags exactly that pin, and deliberately leaves the others alone: `recoverErrCases` pins the *success* type, `tapErrCases`'s branch results are discarded, and `match` folds to a plain value — an ambiguous pin is legitimate in all three. `.returnType()` is allowed **before any arm has produced an output**, and only once — once there is an inferred output for the pin to contradict, pinning (or re-pinning) does not compile. In practice that means calling it directly after `match(…)`. The gate is about output, not position: an earlier arm whose handler returns `never` — one that always throws — contributes nothing, so it does not close the gate. That is sound; a `never` branch can contradict no declared type. ## Where to go next * The mechanics and every rule: [Combinator reference](../reference/combinators#the-error-channel). * Define matchable error types: [Model errors](../how-to/model-errors). * Why this discipline matters most with AI in the loop: [Why unthrown](./why-unthrown#why-this-matters-more-with-ai-in-the-loop). --- --- url: /unthrown/explanation/comparison.md --- # Comparison > **Explanation.** How `unthrown` relates to the other errors-as-values > libraries, and when one of them is the better fit. If you're migrating, the > how-to guides for [try/catch](../how-to/migrate-from-try-catch) and > [neverthrow](../how-to/migrate-from-neverthrow) are more practical. The short version: they all return failures as values; they differ on **whether *unexpected* failures get their own channel**, and on **what happens when a callback throws**. ## At a glance | | **unthrown** | **neverthrow** | **boxed** | **effect** | **byethrow** | | ---------------------------------- | --------------------------------- | ---------------------- | ---------- | --------------------- | ----------------------------------- | | Result representation | discriminated union **+ methods** | class | class | lazy effect | discriminated union (plain objects) | | API style | fluent **and** matchable | fluent | fluent | pipe / generators | pipe (free functions) | | Defect channel (separate from `E`) | ✅ `Defect` | ❌ | ❌ | ✅ `Cause.die` | ❌ | | Throw in `map`/`flatMap` callback | **caught → `Defect`** | propagates | propagates | caught | propagates¹ | | Async model | `AsyncResult` (never rejects) | `ResultAsync` | `Future` | `Effect` | `Promise` (**can reject**) | | Boundary forces error typing | ✅ mandatory `qualify` | partial² | partial² | ✅ | ✅ `catch` (or `safe`) | | `Option` type | ❌ (deliberate) | ❌ | ✅ | ✅ | ❌ | | Tagged errors | ✅ `TaggedError` | ❌ | ❌ | ✅ `Data.TaggedError` | ❌ | | Error accumulation | ❌ (deliberate) | `combineWithAllErrors` | ❌ | ✅ | ✅ `collect` | | Runtime dependencies (core) | **0** (matcher built-in) | 0 | 0 | a runtime | 0 | ¹ byethrow's combinators don't `try/catch`; it relies on an oxlint rule (`no-throw-in-callback`) to keep throws out of callbacks. ² They force typing at explicit `fromPromise`/`fromThrowable`-style boundaries, but a throw inside a later `map` is not re-qualified. ## The two differences that actually matter ### 1. A separate channel for the unexpected Every library here models *anticipated* failures as values. The question is what happens to an **un**anticipated one — a `TypeError` from a typo, a thrown non-`Error`, a bug in a callback you typed as total. * **neverthrow, boxed, byethrow** have one failure axis. An unexpected throw either escapes as a real exception or, if you catch it, gets folded into `E` — at which point your domain error type is a lie (it now also means "some bug"). * **effect** has a real defect channel (`Cause.die`) distinct from the typed error — but brings a whole runtime, context, and dependency-injection system with it. * **unthrown** ships *just* that idea: a third `Defect` state that is **invisible to the type**. `E` stays exactly your modeled errors; a bug becomes a defect that short-circuits to the edge and can only be observed by `match`, `recoverDefect`, or the `tapDefect` / `tapFailure` observers. See [The Defect Channel](./the-defect-channel). This is the line unthrown borrows from Effect and almost nothing else has: *your `E` should never have to include "and also, maybe a bug."* ### 2. What happens when a `.map` callback throws You can type a callback `(value: T) => U`, but the type system can't promise it won't *also* throw — `JSON.parse`, a surprise `null`, a throwing getter. * In **neverthrow** and **byethrow**, a combinator callback is assumed total. A throw inside `.map`/`andThen` propagates as a real exception (byethrow leans on the `no-throw-in-callback` lint rule to discourage it; the runtime doesn't contain it). Its async result can therefore **reject**. * In **unthrown**, a throw inside any combinator is **caught and converted to a `Defect`** — nothing escapes a pipeline as a raw throw, and an `AsyncResult`'s internal promise **never rejects**. That is the runtime guarantee that lets an HTTP adapter do a single `match({ ok, errCases, defect })` with no surrounding `try/catch`. See [The async model](./async-model). A single-axis Result can only stay sound if every combinator callback is total — and you can't guarantee that. The defect channel is what removes the assumption. ## When another library is the better fit This isn't a clean sweep — pick the tool for the job: * **byethrow** — if you want a lightweight, pipe-idiomatic Result with **one** failure axis and don't need the defect distinction, it's an excellent, smaller, more mature choice. It also ships error-accumulating `collect`, which unthrown deliberately omits. * **neverthrow** — the established, widely-adopted class-based option; reach for it if ecosystem maturity outweighs the defect channel. * **boxed** — if you specifically want an `Option` type and a broader functional toolkit (`Future`, `AsyncData`, `Option`, `Result`) in one package. * **effect** — if you actually want the platform: dependency injection, structured concurrency, a scheduler. unthrown is what you reach for when you want effect's defect idea **without** adopting effect. unthrown's bet is narrow on purpose: the modeled-vs-defect split, qualification forced at boundaries, and a runtime that can't leak a raw throw — and nothing else. If those three are what you want, that's the whole library. ## Where to go next * Coming from neverthrow: [Migrate from neverthrow](../how-to/migrate-from-neverthrow). * Coming from raw `try`/`catch`: [Migrate from try/catch](../how-to/migrate-from-try-catch). * The deliberate omissions, in one place: [Design decisions](./design-decisions). --- --- url: /unthrown/explanation/design-decisions.md --- # Design decisions > **Explanation.** `unthrown` is defined as much by what it leaves out as by what > it ships. This page collects the deliberate exclusions and the reasoning > behind them, so a missing feature reads as a decision rather than an oversight. The guiding aim is that the library can be **"done"** — small enough to hold in your head, with one name per concept and no surface that has to keep growing. Each omission below was weighed against that aim. ## No `Option` type Absence is expressed with the type system you already trust — `T | undefined`, `T | null`, or `Result` — and nullable third-party APIs cross into `Result` through [`fromNullable`](../how-to/qualify-a-boundary#fromnullable-absence-as-a-modeled-error). A dedicated `Option` would be a second way to say "maybe absent", competing with the union types TypeScript already models well. `boxed` ships one; `unthrown` deliberately does not. One concept, one representation. ## No generator do-notation (`gen` / `safeTry`) If you come from neverthrow's `safeTry` or Effect's `gen`, you may miss `yield*`-style flattening. The [`Do`/`bind`/`let`](../how-to/sequence-dependent-steps) notation covers the same sequential code without the generator machinery: ```ts // Generator style (not in unthrown): safeTry(function* () { const user = yield* findUser(id); const plan = yield* findPlan(user); return Ok({ user, plan }); }); // unthrown's Do-notation — same flattening, no generator: Do() .bind("user", () => findUser(id)) .bind("plan", ({ user }) => findPlan(user)); ``` The two are semantically equivalent for sequential code. What the generator buys — early `return` mid-block, `try`/`finally` around yields — comes at the cost of a second composition style, generator-transpilation overhead, and a `yield*` operator whose error-channel typing surprises people. If a chain grows long enough that `Do` feels heavy, that is usually a sign the steps deserve named functions composed with `flatMap`. ## No error accumulation (`Validation`) `all` / `allFromDict` (and their async pair) **short-circuit on the first `Err`** — they are not error accumulation. There is no `combineWithAllErrors`, no `Validation` applicative. Accumulating every failure is a genuinely different operation with a different type (`Result`-shaped), most useful for form validation — and for that case the [Standard Schema bridge](../how-to/validate-with-standard-schema) already hands you the validator's full issues array as the modeled error. Building a second accumulation primitive into the core would widen the surface for a job a validator does better. ## No `Defect` constructor A defect-state `Result` has no public constructor. The primitive is already `throw` — the [throw → defect](./the-defect-channel#throw-defect) rule is the sanctioned syntax — and the qualify-time `defect` helper is *injected* wherever a triage decision is made (`qualify` at a boundary, the error-match branches), never exported. The reasoning is friction as a forcing function: once minting a defect is one frictionless call, "I don't feel like modeling this error" starts flowing into the defect channel, and the discipline that makes `E` trustworthy erodes. Scoping the injection to triage sites keeps that friction. Weighed and decided in [#77](https://github.com/btravstack/unthrown/issues/77). ## No serialization A `Result` does not survive `structuredClone` / JSON by design — the method surface and the frozen prototype don't round-trip. Fold it with `match` at the boundary and re-enter through a constructor or a boundary on the other side. A `Result` is an in-process control-flow value, not a wire format. ## No `recoverFailure`, no channel-moving operators `tapFailure` observes both KO channels, but there is deliberately no `recoverFailure`: frictionless defect recovery would erode the channel's meaning, so recovering stays the separate, loud `recoverDefect`, and handling both channels for good is `match`. There are likewise no operators that move a value between channels — `Err`→`Defect` would erase the modeled type, and `Defect`→`Err` would put `unknown` back into `E`, violating the first thesis. ## One name per concept — no aliases There is no `andThen` (it's `flatMap`), no `chain`, no `bind` outside do-notation, no `orElse`/`recover` aliases for the error combinators. The extractor family is spelled only `get…` (`get`/`getErr`/`getOr`/`getOrElse`/`getOrNull`/`getOrUndefined`/`getOrThrow`); the old `unwrap*` aliases were removed. Convenience aliases multiply the surface and force every reader to learn that two names mean one thing. Resisting them is part of staying "done". Naming follows behavior, even when that breaks symmetry with the success surface: the error-matcher combinators carry a `*Cases` suffix (`mapErrCases`, `flatMapErrCases`, `recoverErrCases`, `tapErrCases`, `flatTapErrCases`) rather than the bare `mapErr` / `tapErr`, because their callback receives a matcher over the error's *cases*, not the value. The suffix is the honest name — see [Exhaustive error matching](./exhaustive-error-matching#why-the-cases-suffix). ## Where to go next * The channel several of these decisions protect: [The Defect Channel](./the-defect-channel). * How `unthrown` compares to libraries that made other choices: [Comparison](./comparison). --- --- url: /unthrown/api/core.md --- **unthrown** *** # unthrown ## Facade ### AsyncResult ```ts type AsyncResult = AsyncResultType; ``` Defined in: [packages/core/src/facade.ts:116](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L116) `AsyncResult` — the async counterpart of [Result](#result-1). Shares its name with the [companion object](#asyncresult-1) above (value and type are one name); this is the type half. #### Type Parameters | Type Parameter | | ------ | | `T` | | `E` | #### Remarks `AsyncResult` carries the async fluent surface; its combinators (`map`, `flatMap`, `match`, `get`, …) are documented one per entry — with their async signatures — on [AsyncResultMethods](#asyncresultmethods). For "which one do I reach for?", see the [Choosing a combinator](/reference/combinators) guide. *** ### Result ```ts type Result = ResultType; ``` Defined in: [packages/core/src/facade.ts:50](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L50) `Result` — the core discriminated union. Shares its name with the [companion object](#result-1) above (the value and type are one name); this is the type half. #### Type Parameters | Type Parameter | | ------ | | `T` | | `E` | #### Remarks A `Result` is a discriminated union, so TypeDoc can't list its methods on this alias. Its fluent combinators (`map`, `flatMap`, `match`, `get`, …) are documented one per entry on [ResultMethods](#resultmethods) — the shared method surface every variant carries. For "which one do I reach for?", see the [Choosing a combinator](/reference/combinators) guide. *** ### AsyncResult ```ts const AsyncResult: object; ``` Defined in: [packages/core/src/facade.ts:116](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L116) Companion object grouping the **`AsyncResult`-producing** entry points under the matching namespace: [AsyncResult.Ok](#property-ok), [AsyncResult.Err](#property-err), [AsyncResult.Do](#property-do), [AsyncResult.fromExecutor](#property-fromexecutor), [AsyncResult.fromPromise](#property-frompromise), [AsyncResult.fromSafePromise](#property-fromsafepromise), [AsyncResult.all](#property-all), [AsyncResult.allFromDict](#property-allfromdict). #### Type Declaration #### Constructors | Name | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | | `Err()` | <`E`>(`error`) => `AsyncResult`<`never`, `E`> | `ErrAsync` | [packages/core/src/facade.ts:118](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L118) | | `Ok()` | { (): `AsyncResult`<`void`, `never`>; <`T`> (`value`): `AsyncResult`<`T`, `never`>; } | `OkAsync` | [packages/core/src/facade.ts:117](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L117) | #### Interop | Name | Type | Defined in | | ------ | ------ | ------ | | `fromExecutor()` | <`T`, `E`>(`executor`) => `AsyncResult`<`T`, `E`> | [packages/core/src/facade.ts:120](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L120) | | `fromPromise()` | <`T`, `R`>(`promise`, `qualify`, ...`_guard`) => `AsyncResult`<`T`, `Exclude`<`R`, `Defect`>> | [packages/core/src/facade.ts:121](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L121) | | `fromSafePromise()` | <`T`>(`promise`) => `AsyncResult`<`T`, `never`> | [packages/core/src/facade.ts:122](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L122) | #### Do-notation | Name | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | | `Do()` | () => `AsyncResult`<{ }, `never`> | `DoAsync` | [packages/core/src/facade.ts:119](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L119) | #### Aggregate | Name | Type | Default value | Defined in | | ------ | ------ | ------ | ------ | | `all()` | <`Rs`>(`results`) => `AsyncResult`<`AllOk`<`Rs`, { \[K in string | number | symbol]: AsyncOkOf\ }>, [`AsyncErrOf`](#asyncerrof)<`Rs`\[`number`]>> | `allAsync` | [packages/core/src/facade.ts:123](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L123) | | `allFromDict()` | <`R`>(`results`) => `AsyncResult`<{ \[K in string | number | symbol]: AsyncOkOf\ }, [`AsyncErrOf`](#asyncerrof)<`R`\[keyof `R`]>> | `allFromDictAsync` | [packages/core/src/facade.ts:124](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L124) | #### Remarks The async sibling of [Result](#result-1). Statics are grouped by what they **return**, so the pre-lifted constructors, `fromExecutor`, `fromPromise`/`fromSafePromise`, and the async aggregates sit here rather than on [Result](#result-1); the namespace already conveys "async", so the members drop the `Async` suffix their free functions carry (`AsyncResult.Ok` is `OkAsync`; `AsyncResult.Err` is `ErrAsync`; `AsyncResult.Do` is `DoAsync`; `AsyncResult.all` is `allAsync`; `AsyncResult.allFromDict` is `allFromDictAsync`). Like [Result](#result-1), the free functions remain the primary, tree-shakeable API; the value `AsyncResult` and the type [AsyncResult](#asyncresult-1) share one name. #### Example ```ts import { AsyncResult } from "unthrown"; const user = await AsyncResult.fromPromise( fetchUser(id), (c, defect) => defect(c), ); user.get(); // => the fetched user (on success) ``` *** ### Result ```ts const Result: object; ``` Defined in: [packages/core/src/facade.ts:50](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L50) Companion object grouping the **`Result`-producing** entry points under a single, discoverable namespace: [Result.Ok](#property-ok-1), [Result.Err](#property-err-1), [Result.Do](#property-do-1), [Result.fromNullable](#property-fromnullable), [Result.fromThrowable](#property-fromthrowable), [Result.fromSafeThrowable](#property-fromsafethrowable), [Result.all](#property-all-1), [Result.allFromDict](#property-allfromdict-1), [Result.isOk](#property-isok), [Result.isErr](#property-iserr), [Result.isDefect](#property-isdefect), [Result.isResult](#property-isresult). #### Type Declaration #### Constructors | Name | Type | Defined in | | ------ | ------ | ------ | | `Err()` | <`E`>(`error`) => `Result`<`never`, `E`> | [packages/core/src/facade.ts:52](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L52) | | `Ok()` | { (): `Result`<`void`, `never`>; <`T`> (`value`): `Result`<`T`, `never`>; } | [packages/core/src/facade.ts:51](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L51) | #### Interop | Name | Type | Defined in | | ------ | ------ | ------ | | `fromNullable()` | <`T`, `E`>(`value`, `onAbsent`) => `Result`<`NonNullable`<`T`>, `E`> | [packages/core/src/facade.ts:54](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L54) | | `fromSafeThrowable()` | <`A`, `T`>(`fn`) => (...`args`) => `Result`<`T`, `never`> | [packages/core/src/facade.ts:56](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L56) | | `fromThrowable()` | <`A`, `T`, `R`>(`fn`, `qualify`) => (...`args`) => `Result`<`T`, `Exclude`<`R`, `Defect`>> | [packages/core/src/facade.ts:55](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L55) | #### Do-notation | Name | Type | Defined in | | ------ | ------ | ------ | | `Do()` | () => `Result`<{ }, `never`> | [packages/core/src/facade.ts:53](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L53) | #### Guards | Name | Type | Defined in | | ------ | ------ | ------ | | `isDefect()` | <`T`, `E`>(`r`) => `r is DefectView` | [packages/core/src/facade.ts:61](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L61) | | `isErr()` | <`T`, `E`>(`r`) => `r is ErrView` | [packages/core/src/facade.ts:60](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L60) | | `isOk()` | <`T`, `E`>(`r`) => `r is OkView` | [packages/core/src/facade.ts:59](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L59) | | `isResult()` | (`x`) => `x is Result` | [packages/core/src/facade.ts:62](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L62) | #### Aggregate | Name | Type | Defined in | | ------ | ------ | ------ | | `all()` | <`Rs`>(`results`) => `Result`<`AllOk`<`Rs`, { \[K in string | number | symbol]: OkOf\ }>, [`ErrOf`](#errof)<`Rs`\[`number`]>> | [packages/core/src/facade.ts:57](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L57) | | `allFromDict()` | <`R`>(`results`) => `Result`<{ \[K in string | number | symbol]: OkOf\ }, [`ErrOf`](#errof)<`R`\[keyof `R`]>> | [packages/core/src/facade.ts:58](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/facade.ts#L58) | #### Remarks Purely additive sugar — each member **is** the corresponding free function. The free functions remain the primary, tree-shakeable API; importing only `{ Ok }` never pulls this object in. The value `Result` and the type [Result](#result-1) share one name (the companion-object pattern). The **async** entry points live on the sibling [AsyncResult](#asyncresult-1) companion (`AsyncResult.fromPromise`, `AsyncResult.all`, …), grouped by what they return — a static lives in exactly one namespace. #### Example ```ts import { Result } from "unthrown"; Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).get(); // => 2 ``` ## Types ### DefectView Defined in: [packages/core/src/types.ts:645](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L645) The `Defect` variant of a [Result](#result): an unmodeled failure carrying a `cause`. This is what a successful `isDefect` guard narrows to, exposing `.cause`. It also carries the shared fluent surface ([ResultMethods](#resultmethods)). #### Example ```ts if (r.isDefect()) r.cause; // r: DefectView here — .cause is `unknown` ``` #### Extends * [`ResultMethods`](#resultmethods)<`T`, `E`> #### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `T` | `never` | | `E` | `never` | #### Properties | Property | Modifier | Type | Defined in | | ------ | ------ | ------ | ------ | | `cause` | `readonly` | `unknown` | [packages/core/src/types.ts:647](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L647) | | `tag` | `readonly` | `"Defect"` | [packages/core/src/types.ts:646](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L646) | #### Methods ##### as() ```ts as(value): Result; ``` Defined in: [packages/core/src/types.ts:220](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L220) Replace the success value with a constant `value`. Runs only on `Ok`; `Err` and `Defect` pass through. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the replacement value type. | ###### Parameters | Parameter | Type | | ------ | ------ | | `value` | `U` | ###### Returns `Result`<`U`, `E`> ###### Inherited from ```ts ResultMethods.as ``` ##### bind() ```ts bind(name, f): Result<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E | E2>; ``` Defined in: [packages/core/src/types.ts:193](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L193) Do-notation: run `f` for a `Result` and **bind its value** under `name` in an accumulating object scope. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `K` *extends* `string` | the key the bound value is stored under. | | `U` | the bound value type. | | `E2` | the error type `f` may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `name` | `K` | the scope key. | | `f` | (`scope`) => `Result`<`U`, `E2`> | produces a `Result` from the accumulated scope. | ###### Returns `Result`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E` | `E2`> ###### Remarks Begin a chain with [Do](#do) (an empty object scope) and grow it step by step. `f` receives the scope accumulated so far and returns a `Result`; on `Ok` the value is added as `{ ...scope, [name]: value }`, on `Err`/`Defect` the chain short-circuits. Errors union (`E | E2`). A throw becomes a `Defect` — as does calling `bind` on a non-object scope (e.g. `Ok(5).bind`), which is misuse: the scope is always an object inside a real `Do()` chain. (`let` is the pure-value counterpart.) ###### Inherited from ```ts ResultMethods.bind ``` ##### discard() ```ts discard(): Result; ``` Defined in: [packages/core/src/types.ts:229](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L229) Drop the success value, collapsing the success type to `void`. The named form of `map(() => undefined)`. Runs only on `Ok` (the value is replaced with `undefined`); `Err` and `Defect` pass through. Unlike `as(undefined)` — which produces `Result` — the success type is `void`: the value's story ends here. ###### Returns `Result`<`void`, `E`> ###### Inherited from ```ts ResultMethods.discard ``` ##### ensure() ###### Call Signature ```ts ensure(predicate, onFail): Result; ``` Defined in: [packages/core/src/types.ts:264](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L264) Validate the success value — keep the `Ok` when `predicate` holds, otherwise fail into the **modeled** channel with `Err(onFail(value))`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the refined success type (type-guard form). | | `E2` | the error type `onFail` produces. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `predicate` | (`value`) => `value is U` | the check; a type guard refines `T` to `U`. | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | maps the failing value to the modeled error. | ###### Returns `Result`<`U`, `E` | `E2`> ###### Remarks The named form of `flatMap((v) => (p(v) ? Ok(v) : Err(e)))`. With a **type-guard** predicate (`(v): v is U`) the success type is **refined** to `U` on the way through (this overload). Runs only on `Ok` — a passing value flows through as the *same* `Ok`; `Err` and `Defect` pass through untouched. A throw in `predicate` or `onFail` becomes a `Defect`. Both callbacks are synchronous: an async `onFail` is rejected at compile time ([NotThenable](#notthenable)), and an async predicate does not type-check either — its `Promise` is not a `boolean` (and, being truthy, would have silently always passed). ###### Example ```ts // boolean form: gate a value Ok(-1).ensure((n) => n > 0, (n) => `negative: ${n}`); // Err("negative: -1") // type-guard form: refine the success type declare const r: Result; const s = r.ensure( (v): v is string => typeof v === "string", () => "not_a_string" as const, ); // Result ``` ###### Inherited from ```ts ResultMethods.ensure ``` ###### Call Signature ```ts ensure(predicate, onFail): Result; ``` Defined in: [packages/core/src/types.ts:272](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L272) Boolean form of [ensure](#ensure-4) — validates without refining, keeping the success type `T`. ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `predicate` | (`value`) => `boolean` | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | ###### Returns `Result`<`T`, `E` | `E2`> ###### Inherited from ```ts ResultMethods.ensure ``` ##### flatMap() ```ts flatMap(f): Result; ``` Defined in: [packages/core/src/types.ts:137](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L137) Sequence a dependent, `Result`-returning step (monadic bind). Runs `f` only on `Ok`; `Err` and `Defect` pass through. The error channels combine, widening to `E | E2`. If `f` throws, the throw becomes a `Defect`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the success type of the next step. | | `E2` | the error type the next step may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `Result`<`U`, `E2`> | produces the next `Result` from the current success value. | ###### Returns `Result`<`U`, `E` | `E2`> ###### Inherited from ```ts ResultMethods.flatMap ``` ##### flatMapErrCases() ```ts flatMapErrCases(f): Result>, ErrOf>>; ``` Defined in: [packages/core/src/types.ts:320](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L320) Sequence from an `Err` by producing another `Result` — the error-channel mirror of [flatMap](#flatmap-4), **matching the error exhaustively** ([ErrMatcher](#errmatcher); the combinator calls `.exhaustive()`). Each branch returns a `Result`; the outgoing channels are the unions of the branch-returned `Result`s' channels. A branch may return `defect(cause)`. Runs only on `Err`; `Ok` and `Defect` pass through. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`Result`<`unknown`, `unknown`> | `Defect`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match; each branch produces a fallback `Result`. | ###### Returns `Result`<`T` | [`OkOf`](#okof)<`MatchOut`<`M`>>, [`ErrOf`](#errof)<`MatchOut`<`M`>>> ###### Inherited from ```ts ResultMethods.flatMapErrCases ``` ##### flatTap() ```ts flatTap(f): Result; ``` Defined in: [packages/core/src/types.ts:173](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L173) Run a **failable** side effect on the success value, keeping the original value but threading the effect's error. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `E2` | the error type the effect may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `Result`<`unknown`, `E2`> | the failable side effect; its `Ok` value is ignored. | ###### Returns `Result`<`T`, `E` | `E2`> ###### Remarks This is to [tap](#tap-4) what [flatMap](#flatmap-4) is to [map](#map-4): `f` returns a `Result`, but its **success value is discarded** — on success the original value flows through (`Result`), while an `Err` (or `Defect`) from `f` short-circuits. Runs only on `Ok`; `Err` and `Defect` pass through. If `f` throws, the throw becomes a `Defect`. Use it for a validation or write whose *result* matters but whose *value* you don't need. ###### Inherited from ```ts ResultMethods.flatTap ``` ##### flatTapErrCases() ```ts flatTapErrCases(f): Result; ``` Defined in: [packages/core/src/types.ts:393](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L393) Run a **failable** side effect on the error, keeping the original error but threading the effect's own error — **matched exhaustively** ([ErrMatcher](#errmatcher)). ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`Result`<`unknown`, `E2`>> | builds the match; each branch is a failable effect (its `Ok` is ignored). | ###### Returns `Result`<`T`, `E` | `E2`> ###### Remarks The error-channel mirror of [flatTap](#flattap-4): each branch returns a `Result` whose **success value is discarded** — on the effect's `Ok` the original `Err` flows through, while an `Err`/`Defect` from a branch short-circuits and threads its error. Note the asymmetry with a *throw*: a branch that **returns** a Defect-state `Result` **replaces** the original `Err` (Defect-dominance, the short-circuit rule — it is not aggregated), whereas a branch that **throws** produces a `Defect` aggregating `[thrown, original failure]` (observing a failure by throwing never destroys it). A branch returning the injected `defect(cause)` marker — reachable under a `returnType` pin — follows the *throw* rule, since it is the lint-clean, expression-position form of one. ###### Inherited from ```ts ResultMethods.flatTapErrCases ``` ##### get() ```ts get(this): T; ``` Defined in: [packages/core/src/types.ts:498](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L498) Extract the success value. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `Result`<`T`, `never`> | ###### Returns `T` the `Ok` value. ###### Remarks Compiles only when the error channel is empty (`E = never`) — eliminate modeled errors first (`match` / `recoverErrCases` / `flatMapErrCases`), or reach for the `getOr` / `getOrElse` / `getOrNull` / `getOrUndefined` family (which recover an `Err`). If you get a `'this' context` type error here, that is the gate: the receiver still has a non-`never` error channel. `E = never` empties only the **modeled** error channel — a `Defect` can still be present, and `get()` **rethrows its original cause** (it *panics*); `Result` does not mean `get()` cannot throw. ###### Inherited from ```ts ResultMethods.get ``` ##### getErr() ```ts getErr(this): E; ``` Defined in: [packages/core/src/types.ts:512](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L512) Extract the modeled error. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `Result`<`never`, `E`> | ###### Returns `E` the `Err` value. ###### Remarks Compiles only when the success channel is empty (`T = never`) — eliminate the success case first. `T = never` is rarely the case in practice (a `Result` you hold usually still has a success type), so to inspect an error prefer an `isErr()` guard or, in tests, `@unthrown/vitest`'s `toBeErrWith`. A `Defect` still **rethrows its original cause** (a defect is a bug, not an absent value), so this does not mean `getErr()` can't throw. ###### Inherited from ```ts ResultMethods.getErr ``` ##### getOr() ```ts getOr(fallback): T | U; ``` Defined in: [packages/core/src/types.ts:521](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L521) The success value, or `fallback` on `Err`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the fallback type (may differ from `T`; the return widens to `T | U`). | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `fallback` | `U` | returned when the result is an `Err` (may be a different type; the return widens to `T | U`). | ###### Returns `T` | `U` ###### Throws Re-throws on a `Defect` — a Defect is a bug, not an absent value, so it is never silently replaced. ###### Inherited from ```ts ResultMethods.getOr ``` ##### getOrElse() ```ts getOrElse(f): T | U; ``` Defined in: [packages/core/src/types.ts:529](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L529) The success value, or `f(error)` on `Err`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the fallback type (may differ from `T`; the return widens to `T | U`). | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`error`) => `U` | lazily computes the fallback from the error (may return a different type; the return widens to `T | U`). | ###### Returns `T` | `U` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrElse ``` ##### getOrNull() ```ts getOrNull(): T | null; ``` Defined in: [packages/core/src/types.ts:535](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L535) The success value, or `null` on `Err`. ###### Returns `T` | `null` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrNull ``` ##### getOrThrow() ```ts getOrThrow(this): T; ``` Defined in: [packages/core/src/types.ts:573](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L573) The success value, or **throw** the modeled error on `Err`. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | \[`E`] *extends* \[`never`] ? `"unthrown: getOrThrow is unnecessary here — the Err channel is empty (E = never), so there is nothing to throw. Use get() instead."` : `Result`<`T`, `E`> | ###### Returns `T` the `Ok` value. ###### Remarks A deliberate escape hatch off the errors-as-values model — it **throws the `Err` value as-is** at the call site, so a caller of the enclosing function sees a throw rather than a channel. Its home is **tests and scripts**, where "this `Result` had better be `Ok`" is the assertion and a throw is the correct failure mode. In production code, fold the error channel instead: [recoverErrCases](#recovererrcases-4) empties `E`, so [get](#get-4) compiles and a case routed to the injected `defect(...)` panics with its original cause — with every case still named. [match](#match-4) and [flatMapErrCases](#flatmaperrcases-4) are the other two ways to keep the error a value. `@unthrown/oxlint`'s opt-in `no-get-or-throw` rule enforces this, exempting test files through an oxlint `overrides` entry. Type-gated as the **complement** of [get](#get-4): it compiles only when the error channel is **non-empty** (`E` is not `never`) — there must be a modeled error for it to throw. On a `Result` there is nothing to throw, so `getOrThrow` does not compile; use `get()` (which gates the other way). Together they partition extraction by the error channel's state, with no overlap. ###### Throws the modeled `error` on `Err`; re-throws the original `cause` on a `Defect` (a panic, like the rest of the `getOr…` family). ###### Inherited from ```ts ResultMethods.getOrThrow ``` ##### getOrUndefined() ```ts getOrUndefined(): T | undefined; ``` Defined in: [packages/core/src/types.ts:541](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L541) The success value, or `undefined` on `Err`. ###### Returns `T` | `undefined` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrUndefined ``` ##### isDefect() ```ts isDefect(): this is DefectView; ``` Defined in: [packages/core/src/types.ts:584](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L584) Whether this result is a `Defect` — narrows `this` to its [DefectView](#defectview) on `true`. ###### Returns `this is DefectView` ###### Inherited from ```ts ResultMethods.isDefect ``` ##### isErr() ```ts isErr(): this is ErrView; ``` Defined in: [packages/core/src/types.ts:582](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L582) Whether this result is `Err` — narrows `this` to its [ErrView](#errview) on `true`. ###### Returns `this is ErrView` ###### Inherited from ```ts ResultMethods.isErr ``` ##### isOk() ```ts isOk(): this is OkView; ``` Defined in: [packages/core/src/types.ts:580](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L580) Whether this result is `Ok` — narrows `this` to its [OkView](#okview) on `true`. ###### Returns `this is OkView` ###### Inherited from ```ts ResultMethods.isOk ``` ##### let() ```ts let(name, f): Result<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E>; ``` Defined in: [packages/core/src/types.ts:212](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L212) Do-notation: run `f` for a **plain value** and bind it under `name` in the accumulating object scope. The pure-value counterpart of [bind](#bind-4). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `K` *extends* `string` | the key the value is stored under. | | `U` | the value type. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `name` | `K` | the scope key. | | `f` | (`scope`) => `U` & [`NotThenable`](#notthenable)<`U`> | computes a value from the accumulated scope. | ###### Returns `Result`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E`> ###### Remarks `f` receives the scope and returns a value (not a `Result`); it is added as `{ ...scope, [name]: value }`. Runs only on `Ok`; `Err`/`Defect` pass through. A throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Inherited from ```ts ResultMethods.let ``` ##### map() ```ts map(f): Result; ``` Defined in: [packages/core/src/types.ts:126](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L126) Transform the success value with `f`. Runs `f` only on `Ok`; `Err` and `Defect` pass through untouched. If `f` throws, the thrown value is captured as a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the mapped success type. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `U` & [`NotThenable`](#notthenable)<`U`> | maps the current success value to a new one. | ###### Returns `Result`<`U`, `E`> ###### Inherited from ```ts ResultMethods.map ``` ##### mapErrCases() ```ts mapErrCases(f): Result, Defect>>; ``` Defined in: [packages/core/src/types.ts:304](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L304) Transform the modeled error by **matching it exhaustively**. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match over the error (returns the un-terminated builder). | ###### Returns `Result`<`T`, `Exclude`<`MatchOut`<`M`>, `Defect`>> ###### Remarks The callback receives `match(error)` (an [ErrMatcher](#errmatcher)) and the injected `defect` helper. Chain `.with(pattern, handler)` and **return the un-terminated builder** — `mapErrCases` calls `.exhaustive()` itself, so a missing case is a compile error at the call site (there is no `.exhaustive()` to forget, and no way to slip in `.otherwise()`). The outgoing error type is the union of the branch returns with the `Defect` arm subtracted (`Exclude`) — a branch returning `defect(cause)` converts that case to a `Defect` and drops it from `E`. Runs only on `Err`; `Ok` and `Defect` pass through. A branch that throws also becomes a `Defect`. **Name every case.** Match on anything the matcher supports — `_tag`, `code`, structural shape, guards — and group the cases that share a handler with `.with(a, b, handler)`. `.with(P._, …)` is the wildcard **escape hatch**, not the default: it makes any match exhaustive, so it also absorbs every case `E` grows later. Two uses are sanctioned — a helper generic in `E`, where no arm list can prove exhaustiveness against an unresolved type parameter, and an `E` that is a single type rather than a union of cases (see [P](#p) for both). `@unthrown/oxlint`'s `no-catch-all-pattern` (in its `recommended` preset) flags the rest. ###### Inherited from ```ts ResultMethods.mapErrCases ``` ##### match() ```ts match(cases): ROk | RDefect | MatchOut; ``` Defined in: [packages/core/src/types.ts:477](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L477) Exhaustively fold all three runtime states into a single value. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `ROk` | the `ok` handler return type. | | `RDefect` | the `defect` handler return type. | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the `errCases` handler returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `cases` | { `defect`: (`cause`) => `RDefect`; `errCases`: (`matcher`) => `M`; `ok`: (`value`) => `ROk`; } | the `ok`/`defect` handlers plus the `errCases` matcher builder. | | `cases.defect` | (`cause`) => `RDefect` | - | | `cases.errCases` | (`matcher`) => `M` | - | | `cases.ok` | (`value`) => `ROk` | - | ###### Returns `ROk` | `RDefect` | `MatchOut`<`M`> ###### Remarks Exactly one handler runs. Together with the throw-to-Defect guarantee, this is typically the single place a pipeline is handled at the edge — mapping `Ok`/`Err`/`Defect` to (for example) 2xx / 4xx / 5xx with no `try`/`catch`. The `errCases` handler does not take a single blanket callback: it receives `match(error)` (an [ErrMatcher](#errmatcher)) and **matches the error exhaustively**, exactly like the error combinators — which is why the key carries the same `…Cases` suffix. Chain `.with(pattern, handler)` and **return the un-terminated builder** — `match` calls `.exhaustive()` itself, so a missing case is a compile error at the call site (no `.exhaustive()` to forget). Folding at the edge names every case too — `.with(P._, …)` is the wildcard escape hatch, not the default. Unlike the combinators the branches receive **no `defect` helper** — `match` is total elimination to a value, with no `Defect` output channel; the `defect` case handles a `Result` that already carries one. (A `Result` is also a discriminated union — for richer whole-`Result` matching, `match(result).with(…)`.) ###### Inherited from ```ts ResultMethods.match ``` ##### recoverDefect() ```ts recoverDefect(f): Result; ``` Defined in: [packages/core/src/types.ts:413](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L413) Recover from a `Defect` — the **only** combinator that can touch one. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | a success type the recovery may produce. | | `E2` | an error type the recovery may produce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`cause`) => `Result`<`U`, `E2`> | maps the Defect's unknown cause to a recovering `Result`. | ###### Returns `Result`<`T` | `U`, `E` | `E2`> ###### Remarks Runs `f` only when a `Defect` is present, re-entering the modeled world by returning a `Result` (an `Ok` or a fresh `Err`). `Ok` and `Err` pass through. Recovering a Defect should be rare: usually you let it bubble to the edge. If `f` throws, the throw becomes a new `Defect`. ###### Inherited from ```ts ResultMethods.recoverDefect ``` ##### recoverErrCases() ```ts recoverErrCases(f): Result, Defect>, never>; ``` Defined in: [packages/core/src/types.ts:338](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L338) Recover from an `Err` by producing a success value, emptying the error channel — **matching the error exhaustively** ([ErrMatcher](#errmatcher)). Pairs with [recoverDefect](#recoverdefect-4). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match; each branch produces a success value. | ###### Returns `Result`<`T` | `Exclude`<`MatchOut`<`M`>, `Defect`>, `never`> ###### Remarks The result type is `Result`, but `never` describes only the **error** channel — a `Defect` can still be present at runtime. A branch may return `defect(cause)` (which stays a `Defect`, not a recovery). Runs only on `Err`; `Ok` and `Defect` pass through. ###### Inherited from ```ts ResultMethods.recoverErrCases ``` ##### tap() ```ts tap(f): Result; ``` Defined in: [packages/core/src/types.ts:156](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L156) Run a side effect on the success value and pass the `Result` through unchanged. Runs only on `Ok`. If `f` throws, the throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect (its return value is ignored). | ###### Returns `Result`<`T`, `E`> ###### Remarks `f`'s return value is **ignored** — a `Result` returned by the effect compiles but is discarded, `Err` and all. If the effect can fail, sequence it instead of tapping it: a `Result`-returning effect goes in [flatTap](#flattap-4); an `AsyncResult`-returning effect cannot be sequenced from the sync surface — lift the chain with [toAsync](#toasync-3) and use the async [flatTap](#flattap-3) (which accepts both). ###### Inherited from ```ts ResultMethods.tap ``` ##### tapDefect() ```ts tapDefect(f): Result; ``` Defined in: [packages/core/src/types.ts:423](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L423) Run a side effect on a present `Defect`'s cause (e.g. logging) and pass the `Defect` through unchanged. If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`cause`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect over the unknown cause. | ###### Returns `Result`<`T`, `E`> ###### Inherited from ```ts ResultMethods.tapDefect ``` ##### tapErrCases() ```ts tapErrCases(f): Result; ``` Defined in: [packages/core/src/types.ts:365](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L365) Run a side effect on the error — **matched exhaustively** ([ErrMatcher](#errmatcher)) — and pass the `Result` through unchanged. ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`R` & [`NotThenable`](#notthenable)<`R`>> | builds the match; branch returns are ignored, bar `defect(cause)`. | ###### Returns `Result`<`T`, `E`> ###### Remarks The callback builds a match whose branches run side effects; their return values are ignored and the original `Err` flows through. Exhaustive like the transformers, and like them it wants every case named — `.with(P._, …)` remains the wildcard escape hatch. If a branch throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An **async branch is rejected at compile time** ([NotThenable](#notthenable) on the builder output): because the branch results are discarded, a returned `Promise` would float unobserved and its rejection would vanish. The one branch return that is **not** discarded is the injected `defect(cause)` marker: it is the lint-clean, expression-position form of a `throw`, so it follows the throw rule above (an `AggregateError` of `[the branch's cause, original failure]`), never a silent no-op. A failable `Result`-returning effect belongs in [flatTapErrCases](#flattaperrcases-4). ###### Inherited from ```ts ResultMethods.tapErrCases ``` ##### tapFailure() ```ts tapFailure(f): Result; ``` Defined in: [packages/core/src/types.ts:449](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L449) Run a side effect on **any failure** — `Err` or `Defect` — and pass the `Result` through unchanged. The one cross-channel observer, for the shared "it went KO" concern (logging, metrics, rollback) that would otherwise be duplicated across [tapErrCases](#taperrcases-4) and [tapDefect](#tapdefect-4). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`failure`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect over the failure variant (its return value is ignored). | ###### Returns `Result`<`T`, `E`> ###### Remarks `f` receives the narrowed **failure variant** ([FailureView](#failureview)), not a payload — the payload union `E | unknown` would collapse to `unknown` and lose `E`'s typing. Branch on `failure.tag` to reach the typed payload (`"Err"` → `failure.error: E`, `"Defect"` → `failure.cause: unknown`), or treat it opaquely for a shared logger. Runs on `Err` and `Defect`; `Ok` passes through. It **observes without consuming**: the failure flows on unchanged — to also recover, use [recoverErrCases](#recovererrcases-4) / [recoverDefect](#recoverdefect-4) (deliberately separate acts) or [match](#match-4) at the edge. If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Inherited from ```ts ResultMethods.tapFailure ``` ##### toAsync() ```ts toAsync(): AsyncResult; ``` Defined in: [packages/core/src/types.ts:587](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L587) Lift this synchronous `Result` into an [AsyncResult](#asyncresult). ###### Returns `AsyncResult`<`T`, `E`> ###### Inherited from ```ts ResultMethods.toAsync ``` *** ### ErrView Defined in: [packages/core/src/types.ts:628](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L628) The `Err` variant of a [Result](#result): a modeled failure carrying an `error`. This is what a successful `isErr` guard narrows to, exposing `.error`. It also carries the shared fluent surface ([ResultMethods](#resultmethods)). #### Remarks **Note the parameter order: `ErrView` puts the error type *first*** — the reverse of the `` order used by [OkView](#okview), [DefectView](#defectview), and [Result](#result) — because `Result` narrows to `ErrView` (the error is the payload the guard makes reachable). You rarely write it by hand (a failed `isErr()` narrows to it for you); if you do, mind the flip — `ErrView`, not `ErrView`. #### Example ```ts if (r.isErr()) r.error; // r: ErrView here — .error is an E ``` #### Extends * [`ResultMethods`](#resultmethods)<`T`, `E`> #### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `E` | - | | `T` | `never` | #### Properties | Property | Modifier | Type | Defined in | | ------ | ------ | ------ | ------ | | `error` | `readonly` | `E` | [packages/core/src/types.ts:630](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L630) | | `tag` | `readonly` | `"Err"` | [packages/core/src/types.ts:629](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L629) | #### Methods ##### as() ```ts as(value): Result; ``` Defined in: [packages/core/src/types.ts:220](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L220) Replace the success value with a constant `value`. Runs only on `Ok`; `Err` and `Defect` pass through. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the replacement value type. | ###### Parameters | Parameter | Type | | ------ | ------ | | `value` | `U` | ###### Returns `Result`<`U`, `E`> ###### Inherited from ```ts ResultMethods.as ``` ##### bind() ```ts bind(name, f): Result<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E | E2>; ``` Defined in: [packages/core/src/types.ts:193](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L193) Do-notation: run `f` for a `Result` and **bind its value** under `name` in an accumulating object scope. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `K` *extends* `string` | the key the bound value is stored under. | | `U` | the bound value type. | | `E2` | the error type `f` may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `name` | `K` | the scope key. | | `f` | (`scope`) => `Result`<`U`, `E2`> | produces a `Result` from the accumulated scope. | ###### Returns `Result`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E` | `E2`> ###### Remarks Begin a chain with [Do](#do) (an empty object scope) and grow it step by step. `f` receives the scope accumulated so far and returns a `Result`; on `Ok` the value is added as `{ ...scope, [name]: value }`, on `Err`/`Defect` the chain short-circuits. Errors union (`E | E2`). A throw becomes a `Defect` — as does calling `bind` on a non-object scope (e.g. `Ok(5).bind`), which is misuse: the scope is always an object inside a real `Do()` chain. (`let` is the pure-value counterpart.) ###### Inherited from ```ts ResultMethods.bind ``` ##### discard() ```ts discard(): Result; ``` Defined in: [packages/core/src/types.ts:229](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L229) Drop the success value, collapsing the success type to `void`. The named form of `map(() => undefined)`. Runs only on `Ok` (the value is replaced with `undefined`); `Err` and `Defect` pass through. Unlike `as(undefined)` — which produces `Result` — the success type is `void`: the value's story ends here. ###### Returns `Result`<`void`, `E`> ###### Inherited from ```ts ResultMethods.discard ``` ##### ensure() ###### Call Signature ```ts ensure(predicate, onFail): Result; ``` Defined in: [packages/core/src/types.ts:264](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L264) Validate the success value — keep the `Ok` when `predicate` holds, otherwise fail into the **modeled** channel with `Err(onFail(value))`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the refined success type (type-guard form). | | `E2` | the error type `onFail` produces. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `predicate` | (`value`) => `value is U` | the check; a type guard refines `T` to `U`. | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | maps the failing value to the modeled error. | ###### Returns `Result`<`U`, `E` | `E2`> ###### Remarks The named form of `flatMap((v) => (p(v) ? Ok(v) : Err(e)))`. With a **type-guard** predicate (`(v): v is U`) the success type is **refined** to `U` on the way through (this overload). Runs only on `Ok` — a passing value flows through as the *same* `Ok`; `Err` and `Defect` pass through untouched. A throw in `predicate` or `onFail` becomes a `Defect`. Both callbacks are synchronous: an async `onFail` is rejected at compile time ([NotThenable](#notthenable)), and an async predicate does not type-check either — its `Promise` is not a `boolean` (and, being truthy, would have silently always passed). ###### Example ```ts // boolean form: gate a value Ok(-1).ensure((n) => n > 0, (n) => `negative: ${n}`); // Err("negative: -1") // type-guard form: refine the success type declare const r: Result; const s = r.ensure( (v): v is string => typeof v === "string", () => "not_a_string" as const, ); // Result ``` ###### Inherited from ```ts ResultMethods.ensure ``` ###### Call Signature ```ts ensure(predicate, onFail): Result; ``` Defined in: [packages/core/src/types.ts:272](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L272) Boolean form of [ensure](#ensure-4) — validates without refining, keeping the success type `T`. ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `predicate` | (`value`) => `boolean` | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | ###### Returns `Result`<`T`, `E` | `E2`> ###### Inherited from ```ts ResultMethods.ensure ``` ##### flatMap() ```ts flatMap(f): Result; ``` Defined in: [packages/core/src/types.ts:137](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L137) Sequence a dependent, `Result`-returning step (monadic bind). Runs `f` only on `Ok`; `Err` and `Defect` pass through. The error channels combine, widening to `E | E2`. If `f` throws, the throw becomes a `Defect`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the success type of the next step. | | `E2` | the error type the next step may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `Result`<`U`, `E2`> | produces the next `Result` from the current success value. | ###### Returns `Result`<`U`, `E` | `E2`> ###### Inherited from ```ts ResultMethods.flatMap ``` ##### flatMapErrCases() ```ts flatMapErrCases(f): Result>, ErrOf>>; ``` Defined in: [packages/core/src/types.ts:320](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L320) Sequence from an `Err` by producing another `Result` — the error-channel mirror of [flatMap](#flatmap-4), **matching the error exhaustively** ([ErrMatcher](#errmatcher); the combinator calls `.exhaustive()`). Each branch returns a `Result`; the outgoing channels are the unions of the branch-returned `Result`s' channels. A branch may return `defect(cause)`. Runs only on `Err`; `Ok` and `Defect` pass through. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`Result`<`unknown`, `unknown`> | `Defect`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match; each branch produces a fallback `Result`. | ###### Returns `Result`<`T` | [`OkOf`](#okof)<`MatchOut`<`M`>>, [`ErrOf`](#errof)<`MatchOut`<`M`>>> ###### Inherited from ```ts ResultMethods.flatMapErrCases ``` ##### flatTap() ```ts flatTap(f): Result; ``` Defined in: [packages/core/src/types.ts:173](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L173) Run a **failable** side effect on the success value, keeping the original value but threading the effect's error. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `E2` | the error type the effect may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `Result`<`unknown`, `E2`> | the failable side effect; its `Ok` value is ignored. | ###### Returns `Result`<`T`, `E` | `E2`> ###### Remarks This is to [tap](#tap-4) what [flatMap](#flatmap-4) is to [map](#map-4): `f` returns a `Result`, but its **success value is discarded** — on success the original value flows through (`Result`), while an `Err` (or `Defect`) from `f` short-circuits. Runs only on `Ok`; `Err` and `Defect` pass through. If `f` throws, the throw becomes a `Defect`. Use it for a validation or write whose *result* matters but whose *value* you don't need. ###### Inherited from ```ts ResultMethods.flatTap ``` ##### flatTapErrCases() ```ts flatTapErrCases(f): Result; ``` Defined in: [packages/core/src/types.ts:393](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L393) Run a **failable** side effect on the error, keeping the original error but threading the effect's own error — **matched exhaustively** ([ErrMatcher](#errmatcher)). ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`Result`<`unknown`, `E2`>> | builds the match; each branch is a failable effect (its `Ok` is ignored). | ###### Returns `Result`<`T`, `E` | `E2`> ###### Remarks The error-channel mirror of [flatTap](#flattap-4): each branch returns a `Result` whose **success value is discarded** — on the effect's `Ok` the original `Err` flows through, while an `Err`/`Defect` from a branch short-circuits and threads its error. Note the asymmetry with a *throw*: a branch that **returns** a Defect-state `Result` **replaces** the original `Err` (Defect-dominance, the short-circuit rule — it is not aggregated), whereas a branch that **throws** produces a `Defect` aggregating `[thrown, original failure]` (observing a failure by throwing never destroys it). A branch returning the injected `defect(cause)` marker — reachable under a `returnType` pin — follows the *throw* rule, since it is the lint-clean, expression-position form of one. ###### Inherited from ```ts ResultMethods.flatTapErrCases ``` ##### get() ```ts get(this): T; ``` Defined in: [packages/core/src/types.ts:498](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L498) Extract the success value. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `Result`<`T`, `never`> | ###### Returns `T` the `Ok` value. ###### Remarks Compiles only when the error channel is empty (`E = never`) — eliminate modeled errors first (`match` / `recoverErrCases` / `flatMapErrCases`), or reach for the `getOr` / `getOrElse` / `getOrNull` / `getOrUndefined` family (which recover an `Err`). If you get a `'this' context` type error here, that is the gate: the receiver still has a non-`never` error channel. `E = never` empties only the **modeled** error channel — a `Defect` can still be present, and `get()` **rethrows its original cause** (it *panics*); `Result` does not mean `get()` cannot throw. ###### Inherited from ```ts ResultMethods.get ``` ##### getErr() ```ts getErr(this): E; ``` Defined in: [packages/core/src/types.ts:512](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L512) Extract the modeled error. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `Result`<`never`, `E`> | ###### Returns `E` the `Err` value. ###### Remarks Compiles only when the success channel is empty (`T = never`) — eliminate the success case first. `T = never` is rarely the case in practice (a `Result` you hold usually still has a success type), so to inspect an error prefer an `isErr()` guard or, in tests, `@unthrown/vitest`'s `toBeErrWith`. A `Defect` still **rethrows its original cause** (a defect is a bug, not an absent value), so this does not mean `getErr()` can't throw. ###### Inherited from ```ts ResultMethods.getErr ``` ##### getOr() ```ts getOr(fallback): T | U; ``` Defined in: [packages/core/src/types.ts:521](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L521) The success value, or `fallback` on `Err`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the fallback type (may differ from `T`; the return widens to `T | U`). | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `fallback` | `U` | returned when the result is an `Err` (may be a different type; the return widens to `T | U`). | ###### Returns `T` | `U` ###### Throws Re-throws on a `Defect` — a Defect is a bug, not an absent value, so it is never silently replaced. ###### Inherited from ```ts ResultMethods.getOr ``` ##### getOrElse() ```ts getOrElse(f): T | U; ``` Defined in: [packages/core/src/types.ts:529](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L529) The success value, or `f(error)` on `Err`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the fallback type (may differ from `T`; the return widens to `T | U`). | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`error`) => `U` | lazily computes the fallback from the error (may return a different type; the return widens to `T | U`). | ###### Returns `T` | `U` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrElse ``` ##### getOrNull() ```ts getOrNull(): T | null; ``` Defined in: [packages/core/src/types.ts:535](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L535) The success value, or `null` on `Err`. ###### Returns `T` | `null` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrNull ``` ##### getOrThrow() ```ts getOrThrow(this): T; ``` Defined in: [packages/core/src/types.ts:573](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L573) The success value, or **throw** the modeled error on `Err`. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | \[`E`] *extends* \[`never`] ? `"unthrown: getOrThrow is unnecessary here — the Err channel is empty (E = never), so there is nothing to throw. Use get() instead."` : `Result`<`T`, `E`> | ###### Returns `T` the `Ok` value. ###### Remarks A deliberate escape hatch off the errors-as-values model — it **throws the `Err` value as-is** at the call site, so a caller of the enclosing function sees a throw rather than a channel. Its home is **tests and scripts**, where "this `Result` had better be `Ok`" is the assertion and a throw is the correct failure mode. In production code, fold the error channel instead: [recoverErrCases](#recovererrcases-4) empties `E`, so [get](#get-4) compiles and a case routed to the injected `defect(...)` panics with its original cause — with every case still named. [match](#match-4) and [flatMapErrCases](#flatmaperrcases-4) are the other two ways to keep the error a value. `@unthrown/oxlint`'s opt-in `no-get-or-throw` rule enforces this, exempting test files through an oxlint `overrides` entry. Type-gated as the **complement** of [get](#get-4): it compiles only when the error channel is **non-empty** (`E` is not `never`) — there must be a modeled error for it to throw. On a `Result` there is nothing to throw, so `getOrThrow` does not compile; use `get()` (which gates the other way). Together they partition extraction by the error channel's state, with no overlap. ###### Throws the modeled `error` on `Err`; re-throws the original `cause` on a `Defect` (a panic, like the rest of the `getOr…` family). ###### Inherited from ```ts ResultMethods.getOrThrow ``` ##### getOrUndefined() ```ts getOrUndefined(): T | undefined; ``` Defined in: [packages/core/src/types.ts:541](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L541) The success value, or `undefined` on `Err`. ###### Returns `T` | `undefined` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrUndefined ``` ##### isDefect() ```ts isDefect(): this is DefectView; ``` Defined in: [packages/core/src/types.ts:584](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L584) Whether this result is a `Defect` — narrows `this` to its [DefectView](#defectview) on `true`. ###### Returns `this is DefectView` ###### Inherited from ```ts ResultMethods.isDefect ``` ##### isErr() ```ts isErr(): this is ErrView; ``` Defined in: [packages/core/src/types.ts:582](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L582) Whether this result is `Err` — narrows `this` to its [ErrView](#errview) on `true`. ###### Returns `this is ErrView` ###### Inherited from ```ts ResultMethods.isErr ``` ##### isOk() ```ts isOk(): this is OkView; ``` Defined in: [packages/core/src/types.ts:580](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L580) Whether this result is `Ok` — narrows `this` to its [OkView](#okview) on `true`. ###### Returns `this is OkView` ###### Inherited from ```ts ResultMethods.isOk ``` ##### let() ```ts let(name, f): Result<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E>; ``` Defined in: [packages/core/src/types.ts:212](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L212) Do-notation: run `f` for a **plain value** and bind it under `name` in the accumulating object scope. The pure-value counterpart of [bind](#bind-4). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `K` *extends* `string` | the key the value is stored under. | | `U` | the value type. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `name` | `K` | the scope key. | | `f` | (`scope`) => `U` & [`NotThenable`](#notthenable)<`U`> | computes a value from the accumulated scope. | ###### Returns `Result`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E`> ###### Remarks `f` receives the scope and returns a value (not a `Result`); it is added as `{ ...scope, [name]: value }`. Runs only on `Ok`; `Err`/`Defect` pass through. A throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Inherited from ```ts ResultMethods.let ``` ##### map() ```ts map(f): Result; ``` Defined in: [packages/core/src/types.ts:126](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L126) Transform the success value with `f`. Runs `f` only on `Ok`; `Err` and `Defect` pass through untouched. If `f` throws, the thrown value is captured as a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the mapped success type. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `U` & [`NotThenable`](#notthenable)<`U`> | maps the current success value to a new one. | ###### Returns `Result`<`U`, `E`> ###### Inherited from ```ts ResultMethods.map ``` ##### mapErrCases() ```ts mapErrCases(f): Result, Defect>>; ``` Defined in: [packages/core/src/types.ts:304](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L304) Transform the modeled error by **matching it exhaustively**. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match over the error (returns the un-terminated builder). | ###### Returns `Result`<`T`, `Exclude`<`MatchOut`<`M`>, `Defect`>> ###### Remarks The callback receives `match(error)` (an [ErrMatcher](#errmatcher)) and the injected `defect` helper. Chain `.with(pattern, handler)` and **return the un-terminated builder** — `mapErrCases` calls `.exhaustive()` itself, so a missing case is a compile error at the call site (there is no `.exhaustive()` to forget, and no way to slip in `.otherwise()`). The outgoing error type is the union of the branch returns with the `Defect` arm subtracted (`Exclude`) — a branch returning `defect(cause)` converts that case to a `Defect` and drops it from `E`. Runs only on `Err`; `Ok` and `Defect` pass through. A branch that throws also becomes a `Defect`. **Name every case.** Match on anything the matcher supports — `_tag`, `code`, structural shape, guards — and group the cases that share a handler with `.with(a, b, handler)`. `.with(P._, …)` is the wildcard **escape hatch**, not the default: it makes any match exhaustive, so it also absorbs every case `E` grows later. Two uses are sanctioned — a helper generic in `E`, where no arm list can prove exhaustiveness against an unresolved type parameter, and an `E` that is a single type rather than a union of cases (see [P](#p) for both). `@unthrown/oxlint`'s `no-catch-all-pattern` (in its `recommended` preset) flags the rest. ###### Inherited from ```ts ResultMethods.mapErrCases ``` ##### match() ```ts match(cases): ROk | RDefect | MatchOut; ``` Defined in: [packages/core/src/types.ts:477](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L477) Exhaustively fold all three runtime states into a single value. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `ROk` | the `ok` handler return type. | | `RDefect` | the `defect` handler return type. | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the `errCases` handler returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `cases` | { `defect`: (`cause`) => `RDefect`; `errCases`: (`matcher`) => `M`; `ok`: (`value`) => `ROk`; } | the `ok`/`defect` handlers plus the `errCases` matcher builder. | | `cases.defect` | (`cause`) => `RDefect` | - | | `cases.errCases` | (`matcher`) => `M` | - | | `cases.ok` | (`value`) => `ROk` | - | ###### Returns `ROk` | `RDefect` | `MatchOut`<`M`> ###### Remarks Exactly one handler runs. Together with the throw-to-Defect guarantee, this is typically the single place a pipeline is handled at the edge — mapping `Ok`/`Err`/`Defect` to (for example) 2xx / 4xx / 5xx with no `try`/`catch`. The `errCases` handler does not take a single blanket callback: it receives `match(error)` (an [ErrMatcher](#errmatcher)) and **matches the error exhaustively**, exactly like the error combinators — which is why the key carries the same `…Cases` suffix. Chain `.with(pattern, handler)` and **return the un-terminated builder** — `match` calls `.exhaustive()` itself, so a missing case is a compile error at the call site (no `.exhaustive()` to forget). Folding at the edge names every case too — `.with(P._, …)` is the wildcard escape hatch, not the default. Unlike the combinators the branches receive **no `defect` helper** — `match` is total elimination to a value, with no `Defect` output channel; the `defect` case handles a `Result` that already carries one. (A `Result` is also a discriminated union — for richer whole-`Result` matching, `match(result).with(…)`.) ###### Inherited from ```ts ResultMethods.match ``` ##### recoverDefect() ```ts recoverDefect(f): Result; ``` Defined in: [packages/core/src/types.ts:413](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L413) Recover from a `Defect` — the **only** combinator that can touch one. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | a success type the recovery may produce. | | `E2` | an error type the recovery may produce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`cause`) => `Result`<`U`, `E2`> | maps the Defect's unknown cause to a recovering `Result`. | ###### Returns `Result`<`T` | `U`, `E` | `E2`> ###### Remarks Runs `f` only when a `Defect` is present, re-entering the modeled world by returning a `Result` (an `Ok` or a fresh `Err`). `Ok` and `Err` pass through. Recovering a Defect should be rare: usually you let it bubble to the edge. If `f` throws, the throw becomes a new `Defect`. ###### Inherited from ```ts ResultMethods.recoverDefect ``` ##### recoverErrCases() ```ts recoverErrCases(f): Result, Defect>, never>; ``` Defined in: [packages/core/src/types.ts:338](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L338) Recover from an `Err` by producing a success value, emptying the error channel — **matching the error exhaustively** ([ErrMatcher](#errmatcher)). Pairs with [recoverDefect](#recoverdefect-4). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match; each branch produces a success value. | ###### Returns `Result`<`T` | `Exclude`<`MatchOut`<`M`>, `Defect`>, `never`> ###### Remarks The result type is `Result`, but `never` describes only the **error** channel — a `Defect` can still be present at runtime. A branch may return `defect(cause)` (which stays a `Defect`, not a recovery). Runs only on `Err`; `Ok` and `Defect` pass through. ###### Inherited from ```ts ResultMethods.recoverErrCases ``` ##### tap() ```ts tap(f): Result; ``` Defined in: [packages/core/src/types.ts:156](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L156) Run a side effect on the success value and pass the `Result` through unchanged. Runs only on `Ok`. If `f` throws, the throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect (its return value is ignored). | ###### Returns `Result`<`T`, `E`> ###### Remarks `f`'s return value is **ignored** — a `Result` returned by the effect compiles but is discarded, `Err` and all. If the effect can fail, sequence it instead of tapping it: a `Result`-returning effect goes in [flatTap](#flattap-4); an `AsyncResult`-returning effect cannot be sequenced from the sync surface — lift the chain with [toAsync](#toasync-3) and use the async [flatTap](#flattap-3) (which accepts both). ###### Inherited from ```ts ResultMethods.tap ``` ##### tapDefect() ```ts tapDefect(f): Result; ``` Defined in: [packages/core/src/types.ts:423](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L423) Run a side effect on a present `Defect`'s cause (e.g. logging) and pass the `Defect` through unchanged. If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`cause`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect over the unknown cause. | ###### Returns `Result`<`T`, `E`> ###### Inherited from ```ts ResultMethods.tapDefect ``` ##### tapErrCases() ```ts tapErrCases(f): Result; ``` Defined in: [packages/core/src/types.ts:365](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L365) Run a side effect on the error — **matched exhaustively** ([ErrMatcher](#errmatcher)) — and pass the `Result` through unchanged. ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`R` & [`NotThenable`](#notthenable)<`R`>> | builds the match; branch returns are ignored, bar `defect(cause)`. | ###### Returns `Result`<`T`, `E`> ###### Remarks The callback builds a match whose branches run side effects; their return values are ignored and the original `Err` flows through. Exhaustive like the transformers, and like them it wants every case named — `.with(P._, …)` remains the wildcard escape hatch. If a branch throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An **async branch is rejected at compile time** ([NotThenable](#notthenable) on the builder output): because the branch results are discarded, a returned `Promise` would float unobserved and its rejection would vanish. The one branch return that is **not** discarded is the injected `defect(cause)` marker: it is the lint-clean, expression-position form of a `throw`, so it follows the throw rule above (an `AggregateError` of `[the branch's cause, original failure]`), never a silent no-op. A failable `Result`-returning effect belongs in [flatTapErrCases](#flattaperrcases-4). ###### Inherited from ```ts ResultMethods.tapErrCases ``` ##### tapFailure() ```ts tapFailure(f): Result; ``` Defined in: [packages/core/src/types.ts:449](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L449) Run a side effect on **any failure** — `Err` or `Defect` — and pass the `Result` through unchanged. The one cross-channel observer, for the shared "it went KO" concern (logging, metrics, rollback) that would otherwise be duplicated across [tapErrCases](#taperrcases-4) and [tapDefect](#tapdefect-4). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`failure`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect over the failure variant (its return value is ignored). | ###### Returns `Result`<`T`, `E`> ###### Remarks `f` receives the narrowed **failure variant** ([FailureView](#failureview)), not a payload — the payload union `E | unknown` would collapse to `unknown` and lose `E`'s typing. Branch on `failure.tag` to reach the typed payload (`"Err"` → `failure.error: E`, `"Defect"` → `failure.cause: unknown`), or treat it opaquely for a shared logger. Runs on `Err` and `Defect`; `Ok` passes through. It **observes without consuming**: the failure flows on unchanged — to also recover, use [recoverErrCases](#recovererrcases-4) / [recoverDefect](#recoverdefect-4) (deliberately separate acts) or [match](#match-4) at the edge. If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Inherited from ```ts ResultMethods.tapFailure ``` ##### toAsync() ```ts toAsync(): AsyncResult; ``` Defined in: [packages/core/src/types.ts:587](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L587) Lift this synchronous `Result` into an [AsyncResult](#asyncresult). ###### Returns `AsyncResult`<`T`, `E`> ###### Inherited from ```ts ResultMethods.toAsync ``` *** ### OkView Defined in: [packages/core/src/types.ts:603](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L603) The `Ok` variant of a [Result](#result): a success carrying a `value`. This is what a successful `isOk` guard narrows to, making `.value` reachable. It also carries the shared fluent surface ([ResultMethods](#resultmethods)). #### Example ```ts if (r.isOk()) r.value; // r: OkView here — .value is a T ``` #### Extends * [`ResultMethods`](#resultmethods)<`T`, `E`> #### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `T` | - | | `E` | `never` | #### Properties | Property | Modifier | Type | Defined in | | ------ | ------ | ------ | ------ | | `tag` | `readonly` | `"Ok"` | [packages/core/src/types.ts:604](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L604) | | `value` | `readonly` | `T` | [packages/core/src/types.ts:605](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L605) | #### Methods ##### as() ```ts as(value): Result; ``` Defined in: [packages/core/src/types.ts:220](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L220) Replace the success value with a constant `value`. Runs only on `Ok`; `Err` and `Defect` pass through. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the replacement value type. | ###### Parameters | Parameter | Type | | ------ | ------ | | `value` | `U` | ###### Returns `Result`<`U`, `E`> ###### Inherited from ```ts ResultMethods.as ``` ##### bind() ```ts bind(name, f): Result<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E | E2>; ``` Defined in: [packages/core/src/types.ts:193](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L193) Do-notation: run `f` for a `Result` and **bind its value** under `name` in an accumulating object scope. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `K` *extends* `string` | the key the bound value is stored under. | | `U` | the bound value type. | | `E2` | the error type `f` may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `name` | `K` | the scope key. | | `f` | (`scope`) => `Result`<`U`, `E2`> | produces a `Result` from the accumulated scope. | ###### Returns `Result`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E` | `E2`> ###### Remarks Begin a chain with [Do](#do) (an empty object scope) and grow it step by step. `f` receives the scope accumulated so far and returns a `Result`; on `Ok` the value is added as `{ ...scope, [name]: value }`, on `Err`/`Defect` the chain short-circuits. Errors union (`E | E2`). A throw becomes a `Defect` — as does calling `bind` on a non-object scope (e.g. `Ok(5).bind`), which is misuse: the scope is always an object inside a real `Do()` chain. (`let` is the pure-value counterpart.) ###### Inherited from ```ts ResultMethods.bind ``` ##### discard() ```ts discard(): Result; ``` Defined in: [packages/core/src/types.ts:229](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L229) Drop the success value, collapsing the success type to `void`. The named form of `map(() => undefined)`. Runs only on `Ok` (the value is replaced with `undefined`); `Err` and `Defect` pass through. Unlike `as(undefined)` — which produces `Result` — the success type is `void`: the value's story ends here. ###### Returns `Result`<`void`, `E`> ###### Inherited from ```ts ResultMethods.discard ``` ##### ensure() ###### Call Signature ```ts ensure(predicate, onFail): Result; ``` Defined in: [packages/core/src/types.ts:264](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L264) Validate the success value — keep the `Ok` when `predicate` holds, otherwise fail into the **modeled** channel with `Err(onFail(value))`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the refined success type (type-guard form). | | `E2` | the error type `onFail` produces. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `predicate` | (`value`) => `value is U` | the check; a type guard refines `T` to `U`. | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | maps the failing value to the modeled error. | ###### Returns `Result`<`U`, `E` | `E2`> ###### Remarks The named form of `flatMap((v) => (p(v) ? Ok(v) : Err(e)))`. With a **type-guard** predicate (`(v): v is U`) the success type is **refined** to `U` on the way through (this overload). Runs only on `Ok` — a passing value flows through as the *same* `Ok`; `Err` and `Defect` pass through untouched. A throw in `predicate` or `onFail` becomes a `Defect`. Both callbacks are synchronous: an async `onFail` is rejected at compile time ([NotThenable](#notthenable)), and an async predicate does not type-check either — its `Promise` is not a `boolean` (and, being truthy, would have silently always passed). ###### Example ```ts // boolean form: gate a value Ok(-1).ensure((n) => n > 0, (n) => `negative: ${n}`); // Err("negative: -1") // type-guard form: refine the success type declare const r: Result; const s = r.ensure( (v): v is string => typeof v === "string", () => "not_a_string" as const, ); // Result ``` ###### Inherited from ```ts ResultMethods.ensure ``` ###### Call Signature ```ts ensure(predicate, onFail): Result; ``` Defined in: [packages/core/src/types.ts:272](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L272) Boolean form of [ensure](#ensure-4) — validates without refining, keeping the success type `T`. ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `predicate` | (`value`) => `boolean` | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | ###### Returns `Result`<`T`, `E` | `E2`> ###### Inherited from ```ts ResultMethods.ensure ``` ##### flatMap() ```ts flatMap(f): Result; ``` Defined in: [packages/core/src/types.ts:137](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L137) Sequence a dependent, `Result`-returning step (monadic bind). Runs `f` only on `Ok`; `Err` and `Defect` pass through. The error channels combine, widening to `E | E2`. If `f` throws, the throw becomes a `Defect`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the success type of the next step. | | `E2` | the error type the next step may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `Result`<`U`, `E2`> | produces the next `Result` from the current success value. | ###### Returns `Result`<`U`, `E` | `E2`> ###### Inherited from ```ts ResultMethods.flatMap ``` ##### flatMapErrCases() ```ts flatMapErrCases(f): Result>, ErrOf>>; ``` Defined in: [packages/core/src/types.ts:320](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L320) Sequence from an `Err` by producing another `Result` — the error-channel mirror of [flatMap](#flatmap-4), **matching the error exhaustively** ([ErrMatcher](#errmatcher); the combinator calls `.exhaustive()`). Each branch returns a `Result`; the outgoing channels are the unions of the branch-returned `Result`s' channels. A branch may return `defect(cause)`. Runs only on `Err`; `Ok` and `Defect` pass through. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`Result`<`unknown`, `unknown`> | `Defect`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match; each branch produces a fallback `Result`. | ###### Returns `Result`<`T` | [`OkOf`](#okof)<`MatchOut`<`M`>>, [`ErrOf`](#errof)<`MatchOut`<`M`>>> ###### Inherited from ```ts ResultMethods.flatMapErrCases ``` ##### flatTap() ```ts flatTap(f): Result; ``` Defined in: [packages/core/src/types.ts:173](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L173) Run a **failable** side effect on the success value, keeping the original value but threading the effect's error. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `E2` | the error type the effect may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `Result`<`unknown`, `E2`> | the failable side effect; its `Ok` value is ignored. | ###### Returns `Result`<`T`, `E` | `E2`> ###### Remarks This is to [tap](#tap-4) what [flatMap](#flatmap-4) is to [map](#map-4): `f` returns a `Result`, but its **success value is discarded** — on success the original value flows through (`Result`), while an `Err` (or `Defect`) from `f` short-circuits. Runs only on `Ok`; `Err` and `Defect` pass through. If `f` throws, the throw becomes a `Defect`. Use it for a validation or write whose *result* matters but whose *value* you don't need. ###### Inherited from ```ts ResultMethods.flatTap ``` ##### flatTapErrCases() ```ts flatTapErrCases(f): Result; ``` Defined in: [packages/core/src/types.ts:393](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L393) Run a **failable** side effect on the error, keeping the original error but threading the effect's own error — **matched exhaustively** ([ErrMatcher](#errmatcher)). ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`Result`<`unknown`, `E2`>> | builds the match; each branch is a failable effect (its `Ok` is ignored). | ###### Returns `Result`<`T`, `E` | `E2`> ###### Remarks The error-channel mirror of [flatTap](#flattap-4): each branch returns a `Result` whose **success value is discarded** — on the effect's `Ok` the original `Err` flows through, while an `Err`/`Defect` from a branch short-circuits and threads its error. Note the asymmetry with a *throw*: a branch that **returns** a Defect-state `Result` **replaces** the original `Err` (Defect-dominance, the short-circuit rule — it is not aggregated), whereas a branch that **throws** produces a `Defect` aggregating `[thrown, original failure]` (observing a failure by throwing never destroys it). A branch returning the injected `defect(cause)` marker — reachable under a `returnType` pin — follows the *throw* rule, since it is the lint-clean, expression-position form of one. ###### Inherited from ```ts ResultMethods.flatTapErrCases ``` ##### get() ```ts get(this): T; ``` Defined in: [packages/core/src/types.ts:498](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L498) Extract the success value. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `Result`<`T`, `never`> | ###### Returns `T` the `Ok` value. ###### Remarks Compiles only when the error channel is empty (`E = never`) — eliminate modeled errors first (`match` / `recoverErrCases` / `flatMapErrCases`), or reach for the `getOr` / `getOrElse` / `getOrNull` / `getOrUndefined` family (which recover an `Err`). If you get a `'this' context` type error here, that is the gate: the receiver still has a non-`never` error channel. `E = never` empties only the **modeled** error channel — a `Defect` can still be present, and `get()` **rethrows its original cause** (it *panics*); `Result` does not mean `get()` cannot throw. ###### Inherited from ```ts ResultMethods.get ``` ##### getErr() ```ts getErr(this): E; ``` Defined in: [packages/core/src/types.ts:512](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L512) Extract the modeled error. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `Result`<`never`, `E`> | ###### Returns `E` the `Err` value. ###### Remarks Compiles only when the success channel is empty (`T = never`) — eliminate the success case first. `T = never` is rarely the case in practice (a `Result` you hold usually still has a success type), so to inspect an error prefer an `isErr()` guard or, in tests, `@unthrown/vitest`'s `toBeErrWith`. A `Defect` still **rethrows its original cause** (a defect is a bug, not an absent value), so this does not mean `getErr()` can't throw. ###### Inherited from ```ts ResultMethods.getErr ``` ##### getOr() ```ts getOr(fallback): T | U; ``` Defined in: [packages/core/src/types.ts:521](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L521) The success value, or `fallback` on `Err`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the fallback type (may differ from `T`; the return widens to `T | U`). | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `fallback` | `U` | returned when the result is an `Err` (may be a different type; the return widens to `T | U`). | ###### Returns `T` | `U` ###### Throws Re-throws on a `Defect` — a Defect is a bug, not an absent value, so it is never silently replaced. ###### Inherited from ```ts ResultMethods.getOr ``` ##### getOrElse() ```ts getOrElse(f): T | U; ``` Defined in: [packages/core/src/types.ts:529](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L529) The success value, or `f(error)` on `Err`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the fallback type (may differ from `T`; the return widens to `T | U`). | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`error`) => `U` | lazily computes the fallback from the error (may return a different type; the return widens to `T | U`). | ###### Returns `T` | `U` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrElse ``` ##### getOrNull() ```ts getOrNull(): T | null; ``` Defined in: [packages/core/src/types.ts:535](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L535) The success value, or `null` on `Err`. ###### Returns `T` | `null` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrNull ``` ##### getOrThrow() ```ts getOrThrow(this): T; ``` Defined in: [packages/core/src/types.ts:573](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L573) The success value, or **throw** the modeled error on `Err`. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | \[`E`] *extends* \[`never`] ? `"unthrown: getOrThrow is unnecessary here — the Err channel is empty (E = never), so there is nothing to throw. Use get() instead."` : `Result`<`T`, `E`> | ###### Returns `T` the `Ok` value. ###### Remarks A deliberate escape hatch off the errors-as-values model — it **throws the `Err` value as-is** at the call site, so a caller of the enclosing function sees a throw rather than a channel. Its home is **tests and scripts**, where "this `Result` had better be `Ok`" is the assertion and a throw is the correct failure mode. In production code, fold the error channel instead: [recoverErrCases](#recovererrcases-4) empties `E`, so [get](#get-4) compiles and a case routed to the injected `defect(...)` panics with its original cause — with every case still named. [match](#match-4) and [flatMapErrCases](#flatmaperrcases-4) are the other two ways to keep the error a value. `@unthrown/oxlint`'s opt-in `no-get-or-throw` rule enforces this, exempting test files through an oxlint `overrides` entry. Type-gated as the **complement** of [get](#get-4): it compiles only when the error channel is **non-empty** (`E` is not `never`) — there must be a modeled error for it to throw. On a `Result` there is nothing to throw, so `getOrThrow` does not compile; use `get()` (which gates the other way). Together they partition extraction by the error channel's state, with no overlap. ###### Throws the modeled `error` on `Err`; re-throws the original `cause` on a `Defect` (a panic, like the rest of the `getOr…` family). ###### Inherited from ```ts ResultMethods.getOrThrow ``` ##### getOrUndefined() ```ts getOrUndefined(): T | undefined; ``` Defined in: [packages/core/src/types.ts:541](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L541) The success value, or `undefined` on `Err`. ###### Returns `T` | `undefined` ###### Throws Re-throws on a `Defect`. ###### Inherited from ```ts ResultMethods.getOrUndefined ``` ##### isDefect() ```ts isDefect(): this is DefectView; ``` Defined in: [packages/core/src/types.ts:584](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L584) Whether this result is a `Defect` — narrows `this` to its [DefectView](#defectview) on `true`. ###### Returns `this is DefectView` ###### Inherited from ```ts ResultMethods.isDefect ``` ##### isErr() ```ts isErr(): this is ErrView; ``` Defined in: [packages/core/src/types.ts:582](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L582) Whether this result is `Err` — narrows `this` to its [ErrView](#errview) on `true`. ###### Returns `this is ErrView` ###### Inherited from ```ts ResultMethods.isErr ``` ##### isOk() ```ts isOk(): this is OkView; ``` Defined in: [packages/core/src/types.ts:580](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L580) Whether this result is `Ok` — narrows `this` to its [OkView](#okview) on `true`. ###### Returns `this is OkView` ###### Inherited from ```ts ResultMethods.isOk ``` ##### let() ```ts let(name, f): Result<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E>; ``` Defined in: [packages/core/src/types.ts:212](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L212) Do-notation: run `f` for a **plain value** and bind it under `name` in the accumulating object scope. The pure-value counterpart of [bind](#bind-4). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `K` *extends* `string` | the key the value is stored under. | | `U` | the value type. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `name` | `K` | the scope key. | | `f` | (`scope`) => `U` & [`NotThenable`](#notthenable)<`U`> | computes a value from the accumulated scope. | ###### Returns `Result`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E`> ###### Remarks `f` receives the scope and returns a value (not a `Result`); it is added as `{ ...scope, [name]: value }`. Runs only on `Ok`; `Err`/`Defect` pass through. A throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Inherited from ```ts ResultMethods.let ``` ##### map() ```ts map(f): Result; ``` Defined in: [packages/core/src/types.ts:126](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L126) Transform the success value with `f`. Runs `f` only on `Ok`; `Err` and `Defect` pass through untouched. If `f` throws, the thrown value is captured as a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the mapped success type. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `U` & [`NotThenable`](#notthenable)<`U`> | maps the current success value to a new one. | ###### Returns `Result`<`U`, `E`> ###### Inherited from ```ts ResultMethods.map ``` ##### mapErrCases() ```ts mapErrCases(f): Result, Defect>>; ``` Defined in: [packages/core/src/types.ts:304](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L304) Transform the modeled error by **matching it exhaustively**. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match over the error (returns the un-terminated builder). | ###### Returns `Result`<`T`, `Exclude`<`MatchOut`<`M`>, `Defect`>> ###### Remarks The callback receives `match(error)` (an [ErrMatcher](#errmatcher)) and the injected `defect` helper. Chain `.with(pattern, handler)` and **return the un-terminated builder** — `mapErrCases` calls `.exhaustive()` itself, so a missing case is a compile error at the call site (there is no `.exhaustive()` to forget, and no way to slip in `.otherwise()`). The outgoing error type is the union of the branch returns with the `Defect` arm subtracted (`Exclude`) — a branch returning `defect(cause)` converts that case to a `Defect` and drops it from `E`. Runs only on `Err`; `Ok` and `Defect` pass through. A branch that throws also becomes a `Defect`. **Name every case.** Match on anything the matcher supports — `_tag`, `code`, structural shape, guards — and group the cases that share a handler with `.with(a, b, handler)`. `.with(P._, …)` is the wildcard **escape hatch**, not the default: it makes any match exhaustive, so it also absorbs every case `E` grows later. Two uses are sanctioned — a helper generic in `E`, where no arm list can prove exhaustiveness against an unresolved type parameter, and an `E` that is a single type rather than a union of cases (see [P](#p) for both). `@unthrown/oxlint`'s `no-catch-all-pattern` (in its `recommended` preset) flags the rest. ###### Inherited from ```ts ResultMethods.mapErrCases ``` ##### match() ```ts match(cases): ROk | RDefect | MatchOut; ``` Defined in: [packages/core/src/types.ts:477](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L477) Exhaustively fold all three runtime states into a single value. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `ROk` | the `ok` handler return type. | | `RDefect` | the `defect` handler return type. | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the `errCases` handler returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `cases` | { `defect`: (`cause`) => `RDefect`; `errCases`: (`matcher`) => `M`; `ok`: (`value`) => `ROk`; } | the `ok`/`defect` handlers plus the `errCases` matcher builder. | | `cases.defect` | (`cause`) => `RDefect` | - | | `cases.errCases` | (`matcher`) => `M` | - | | `cases.ok` | (`value`) => `ROk` | - | ###### Returns `ROk` | `RDefect` | `MatchOut`<`M`> ###### Remarks Exactly one handler runs. Together with the throw-to-Defect guarantee, this is typically the single place a pipeline is handled at the edge — mapping `Ok`/`Err`/`Defect` to (for example) 2xx / 4xx / 5xx with no `try`/`catch`. The `errCases` handler does not take a single blanket callback: it receives `match(error)` (an [ErrMatcher](#errmatcher)) and **matches the error exhaustively**, exactly like the error combinators — which is why the key carries the same `…Cases` suffix. Chain `.with(pattern, handler)` and **return the un-terminated builder** — `match` calls `.exhaustive()` itself, so a missing case is a compile error at the call site (no `.exhaustive()` to forget). Folding at the edge names every case too — `.with(P._, …)` is the wildcard escape hatch, not the default. Unlike the combinators the branches receive **no `defect` helper** — `match` is total elimination to a value, with no `Defect` output channel; the `defect` case handles a `Result` that already carries one. (A `Result` is also a discriminated union — for richer whole-`Result` matching, `match(result).with(…)`.) ###### Inherited from ```ts ResultMethods.match ``` ##### recoverDefect() ```ts recoverDefect(f): Result; ``` Defined in: [packages/core/src/types.ts:413](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L413) Recover from a `Defect` — the **only** combinator that can touch one. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | a success type the recovery may produce. | | `E2` | an error type the recovery may produce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`cause`) => `Result`<`U`, `E2`> | maps the Defect's unknown cause to a recovering `Result`. | ###### Returns `Result`<`T` | `U`, `E` | `E2`> ###### Remarks Runs `f` only when a `Defect` is present, re-entering the modeled world by returning a `Result` (an `Ok` or a fresh `Err`). `Ok` and `Err` pass through. Recovering a Defect should be rare: usually you let it bubble to the edge. If `f` throws, the throw becomes a new `Defect`. ###### Inherited from ```ts ResultMethods.recoverDefect ``` ##### recoverErrCases() ```ts recoverErrCases(f): Result, Defect>, never>; ``` Defined in: [packages/core/src/types.ts:338](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L338) Recover from an `Err` by producing a success value, emptying the error channel — **matching the error exhaustively** ([ErrMatcher](#errmatcher)). Pairs with [recoverDefect](#recoverdefect-4). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match; each branch produces a success value. | ###### Returns `Result`<`T` | `Exclude`<`MatchOut`<`M`>, `Defect`>, `never`> ###### Remarks The result type is `Result`, but `never` describes only the **error** channel — a `Defect` can still be present at runtime. A branch may return `defect(cause)` (which stays a `Defect`, not a recovery). Runs only on `Err`; `Ok` and `Defect` pass through. ###### Inherited from ```ts ResultMethods.recoverErrCases ``` ##### tap() ```ts tap(f): Result; ``` Defined in: [packages/core/src/types.ts:156](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L156) Run a side effect on the success value and pass the `Result` through unchanged. Runs only on `Ok`. If `f` throws, the throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect (its return value is ignored). | ###### Returns `Result`<`T`, `E`> ###### Remarks `f`'s return value is **ignored** — a `Result` returned by the effect compiles but is discarded, `Err` and all. If the effect can fail, sequence it instead of tapping it: a `Result`-returning effect goes in [flatTap](#flattap-4); an `AsyncResult`-returning effect cannot be sequenced from the sync surface — lift the chain with [toAsync](#toasync-3) and use the async [flatTap](#flattap-3) (which accepts both). ###### Inherited from ```ts ResultMethods.tap ``` ##### tapDefect() ```ts tapDefect(f): Result; ``` Defined in: [packages/core/src/types.ts:423](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L423) Run a side effect on a present `Defect`'s cause (e.g. logging) and pass the `Defect` through unchanged. If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`cause`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect over the unknown cause. | ###### Returns `Result`<`T`, `E`> ###### Inherited from ```ts ResultMethods.tapDefect ``` ##### tapErrCases() ```ts tapErrCases(f): Result; ``` Defined in: [packages/core/src/types.ts:365](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L365) Run a side effect on the error — **matched exhaustively** ([ErrMatcher](#errmatcher)) — and pass the `Result` through unchanged. ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`R` & [`NotThenable`](#notthenable)<`R`>> | builds the match; branch returns are ignored, bar `defect(cause)`. | ###### Returns `Result`<`T`, `E`> ###### Remarks The callback builds a match whose branches run side effects; their return values are ignored and the original `Err` flows through. Exhaustive like the transformers, and like them it wants every case named — `.with(P._, …)` remains the wildcard escape hatch. If a branch throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An **async branch is rejected at compile time** ([NotThenable](#notthenable) on the builder output): because the branch results are discarded, a returned `Promise` would float unobserved and its rejection would vanish. The one branch return that is **not** discarded is the injected `defect(cause)` marker: it is the lint-clean, expression-position form of a `throw`, so it follows the throw rule above (an `AggregateError` of `[the branch's cause, original failure]`), never a silent no-op. A failable `Result`-returning effect belongs in [flatTapErrCases](#flattaperrcases-4). ###### Inherited from ```ts ResultMethods.tapErrCases ``` ##### tapFailure() ```ts tapFailure(f): Result; ``` Defined in: [packages/core/src/types.ts:449](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L449) Run a side effect on **any failure** — `Err` or `Defect` — and pass the `Result` through unchanged. The one cross-channel observer, for the shared "it went KO" concern (logging, metrics, rollback) that would otherwise be duplicated across [tapErrCases](#taperrcases-4) and [tapDefect](#tapdefect-4). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`failure`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect over the failure variant (its return value is ignored). | ###### Returns `Result`<`T`, `E`> ###### Remarks `f` receives the narrowed **failure variant** ([FailureView](#failureview)), not a payload — the payload union `E | unknown` would collapse to `unknown` and lose `E`'s typing. Branch on `failure.tag` to reach the typed payload (`"Err"` → `failure.error: E`, `"Defect"` → `failure.cause: unknown`), or treat it opaquely for a shared logger. Runs on `Err` and `Defect`; `Ok` passes through. It **observes without consuming**: the failure flows on unchanged — to also recover, use [recoverErrCases](#recovererrcases-4) / [recoverDefect](#recoverdefect-4) (deliberately separate acts) or [match](#match-4) at the edge. If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Inherited from ```ts ResultMethods.tapFailure ``` ##### toAsync() ```ts toAsync(): AsyncResult; ``` Defined in: [packages/core/src/types.ts:587](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L587) Lift this synchronous `Result` into an [AsyncResult](#asyncresult). ###### Returns `AsyncResult`<`T`, `E`> ###### Inherited from ```ts ResultMethods.toAsync ``` *** ### AsyncErrOf ```ts type AsyncErrOf = R extends Awaitable ? ErrOf : never; ``` Defined in: [packages/core/src/types.ts:1061](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L1061) Extract the error type `E` from an [AsyncResult](#asyncresult) type — the async counterpart of [ErrOf](#errof). #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `R` | the `AsyncResult` type to inspect. | #### Example ```ts type E = AsyncErrOf>; // NotFound ``` *** ### AsyncOkOf ```ts type AsyncOkOf = R extends Awaitable ? OkOf : never; ``` Defined in: [packages/core/src/types.ts:1047](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L1047) Extract the success type `T` from an [AsyncResult](#asyncresult) type — the async counterpart of [OkOf](#okof). #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `R` | the `AsyncResult` type to inspect. | #### Example ```ts type T = AsyncOkOf>; // User ``` *** ### Awaitable ```ts type Awaitable = object; ``` Defined in: [packages/core/src/types.ts:733](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L733) A success-only thenable: awaitable, but deliberately **not** a full `PromiseLike`. #### Remarks An [AsyncResult](#asyncresult)'s internal promise never rejects, so `await`-ing one always yields a [Result](#result) and never throws — there is no rejection channel to model, and none is advertised. At runtime it is still a thenable (the only way `await` can collapse it), and `Promise.all` / `Promise.resolve` will still adopt it — harmlessly, since it settles to a `Result` and never rejects. What the narrowing prevents is treating it as a full promise: `.catch()` / `.finally()` do not type-check, because there is no rejection to handle. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the value `await` resolves to. | #### Methods ##### then() ```ts then(onfulfilled?): PromiseLike; ``` Defined in: [packages/core/src/types.ts:734](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L734) ###### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `R` | `T` | ###### Parameters | Parameter | Type | | ------ | ------ | | `onfulfilled?` | ((`value`) => `R` | `PromiseLike`<`R`>) | `null` | ###### Returns `PromiseLike`<`R`> *** ### ErrMatcher ```ts type ErrMatcher = ReturnType; ``` Defined in: [packages/core/src/types.ts:64](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L64) The built-in match builder over an error union `E`, as produced by `match(error)`. This is what an error combinator's callback receives — chain `.with(pattern, handler)` on it; the combinator itself calls `.exhaustive()`, so the callback returns the **un-terminated** builder. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `E` | the error union being matched. | #### Remarks Named via `ReturnType>` (i.e. `Matcher`), keeping this alias stable however the builder evolves. *** ### ErrOf ```ts type ErrOf = R extends object ? E : never; ``` Defined in: [packages/core/src/types.ts:1033](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L1033) Extract the error type `E` from a `Result` type — the counterpart of [OkOf](#okof). #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `R` | the `Result` type to inspect. | #### Example ```ts type E = ErrOf>; // NotFound ``` *** ### FailureView ```ts type FailureView = | ErrView | DefectView; ``` Defined in: [packages/core/src/types.ts:673](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L673) A failure variant of a [Result](#result): an [ErrView](#errview) **or** a [DefectView](#defectview). This is what a `tapFailure` callback receives — the discriminated variant rather than a payload, because the payload union `E | unknown` would collapse to `unknown` and lose `E`'s typing. Branch on `tag` to narrow (`"Err"` → `.error: E`, `"Defect"` → `.cause: unknown`). #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `E` | - | the modeled error type. | | `T` | `never` | the success value type (phantom here; a failure carries none). | #### Remarks Like [ErrView](#errview), the error type comes **first** (`FailureView`) — the error is the payload you are usually here for, and a shared observer can spell just `FailureView`. #### Example ```ts const logKo = (f: FailureView) => f.tag === "Err" ? logger.warn(f.error) : logger.error(f.cause); result.tapFailure(logKo); ``` *** ### Matcher ```ts type Matcher = object; ``` Defined in: [packages/core/src/matcher.ts:150](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L150) The match builder over an input union `E`. `Remaining` tracks the cases not yet covered by a `.with(…)` arm; `O` accumulates the branch output union. `.exhaustive` is callable only once `Remaining` is `never` — which is what the `ExhaustiveMatch` constraint requires — and `.run()` executes it. #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `E` | - | the full input union being matched. | | `Remaining` | - | the cases not yet covered. | | `O` | - | the union of branch return types so far. | | `Declared` | `Unset` | - | #### Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `exhaustive` | \[`Remaining`] *extends* \[`never`] ? () => `PinnedOut`<`Declared`, `O`> : `NonExhaustive`<`Remaining`> | Terminate the match. Typed callable only when every case is covered (`Remaining` is `never`); otherwise it is a branded diagnostic object naming the remaining cases, and the builder fails the `ExhaustiveMatch` constraint at the combinator call site. | [packages/core/src/matcher.ts:222](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L222) | | `returnType` | \[`O`] *extends* \[`never`] ? \[`Declared`] *extends* \[`Unset`] ? <`R`>() => [`Matcher`](#matcher)<`E`, `Remaining`, `never`, `R`> : `PinTooLate` : `PinTooLate` | Declare the match's output type up front: every subsequent branch handler is checked against `R`, and the match evaluates to `R` instead of the union of whatever the branches happened to return. **Remarks** Reach for it when the output is **decided by a signature rather than by the branches** — most sharply in code generic in `E`, where the fold's type has to be declared. It also stops a drifting branch from silently widening the outgoing type, reports the mismatch **on the offending branch**, and gives branch returns a contextual type (so object literals need no annotation). A branch may still return the injected `defect` helper's marker; the defect channel is not part of the declared output. Callable **before any arm has produced an output**, and only once (mirroring ts-pattern's up-front pin): once there is an inferred output for the pin to contradict — or the builder is already pinned — this is typed as a non-callable diagnostic. In practice that means calling it directly after `match(…)`; the gate is about output rather than position, so an earlier arm whose handler returns `never` (it always throws) contributes nothing and does not close it — sound, since a `never` branch can contradict no declared type. A no-op at runtime. **Type Param** **R** the declared output type of every branch. | [packages/core/src/matcher.ts:210](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L210) | #### Methods ##### run() ```ts run(): PinnedOut; ``` Defined in: [packages/core/src/matcher.ts:229](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L229) Execute the match (the combinators call this; it runs `.exhaustive()`). A value with no matching arm throws [NonExhaustiveError](#nonexhaustiveerror) — unreachable for well-typed callers. ###### Returns `PinnedOut`<`Declared`, `O`> ##### with() ###### Call Signature ```ts with(pattern, handler): Matcher; ``` Defined in: [packages/core/src/matcher.ts:165](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L165) The catch-all arm: `.with(P._, handler)` — the wildcard **escape hatch**, not the way to handle a concrete error union (name those cases; `@unthrown/oxlint`'s `no-catch-all-pattern`, in its `recommended` preset, flags the wildcard). It is a **state transition**, not a computation — it returns `Matcher` with the remaining cases literally `never`, so the builder is provably exhaustive even when `E` is an unresolved type parameter (a lazily-deferred `Exclude` would not resolve there). That is what makes it irreplaceable for a helper generic in `E`: it can terminate a match no arm list could (issue #145) — one of the two sanctioned uses (see [P](#p)). ###### Type Parameters | Type Parameter | | ------ | | `O2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `pattern` | [`UniversalPattern`](#universalpattern) | | `handler` | (`value`) => `BranchReturn`<`Declared`, `O2`> | ###### Returns [`Matcher`](#matcher)<`E`, `never`, `O` | `O2`, `Declared`> ###### Call Signature ```ts with(...args): Matcher>, O | O2, Declared>; ``` Defined in: [packages/core/src/matcher.ts:176](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L176) Add an arm: one or more patterns sharing a single handler (grouped patterns — `matcher.with(P.tag("A"), P.tag("B"), handler)`). The handler receives the input narrowed to what the patterns match (computed against `Remaining`, so cases already handled by earlier arms are excluded); the matched cases are subtracted from `Remaining`. ###### Type Parameters | Type Parameter | | ------ | | `Pts` *extends* readonly \[`unknown`, `unknown`] | | `O2` | ###### Parameters | Parameter | Type | | ------ | ------ | | ...`args` | \[`...patterns: Pts[]`, (`value`) => `BranchReturn`<`Declared`, `O2`>] | ###### Returns [`Matcher`](#matcher)<`E`, `Exclude`<`Remaining`, `MatchedOf`<`Pts`\[`number`]>>, `O` | `O2`, `Declared`> *** ### NotThenable ```ts type NotThenable = [Extract>] extends [never] ? unknown : "unthrown: combinator callbacks are synchronous — lift async work with fromPromise and compose with flatMap"; ``` Defined in: [packages/core/src/types.ts:47](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L47) Compile-time rejection of a thenable callback result — the type-level enforcement of "combinator callbacks are synchronous" (see the [AsyncResult](#asyncresult) remarks). #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `R` | the callback's inferred return type. | #### Remarks Resolves to `unknown` (a no-op in an intersection) for any non-thenable `R`, and to an explanatory string-literal type when `R` is a `PromiseLike` — so an `async` callback fails to compile with the explanation in the error. Without this, `async () => …` would be assignable to `() => void`, and its rejection would escape the pipeline as an unhandled rejection instead of a `Defect`. Lift async work with [fromPromise](#frompromise) and compose it with `flatMap`. Spelled with `Extract`, not `[R] extends [PromiseLike<…>]`, so the ban also fires when only SOME arms of a union return are thenable — a *sometimes*-async callback (`flag ? 1 : work()`) is still an unawaited effect whose rejection the pipeline never sees. The tuple-wrapped form is false for a partial union and let exactly that through. This is the same reasoning `fromPromise`'s async-qualify guard already used. *** ### OkOf ```ts type OkOf = R extends object ? T : never; ``` Defined in: [packages/core/src/types.ts:1019](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L1019) Extract the success type `T` from a `Result` type — derive one type from another instead of restating it (e.g. the payload a function returns). #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `R` | the `Result` type to inspect. | #### Example ```ts type R = Result; type U = OkOf; // User type E = ErrOf; // NotFound ``` *** ### PatternMatcher ```ts type PatternMatcher = object; ``` Defined in: [packages/core/src/matcher.ts:50](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L50) A `P.*` pattern: a runtime predicate plus the phantom type `M` it matches. The phantom is declaration-only (never present at runtime); it drives the type-level narrowing (`Extract`) and exhaustiveness (`Exclude`). #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` | the type this pattern matches. | #### Properties | Property | Modifier | Type | Defined in | | ------ | ------ | ------ | ------ | | `[MATCHES]?` | `readonly` | `M` | [packages/core/src/matcher.ts:52](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L52) | | `[PATTERN_BRAND]` | `readonly` | (`value`) => `boolean` | [packages/core/src/matcher.ts:51](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L51) | *** ### Settle ```ts type Settle = (result) => void; ``` Defined in: [packages/core/src/interop.ts:296](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L296) The settler a [fromExecutor](#fromexecutor) executor receives. Settles the pending `AsyncResult` **once** — later calls are no-ops, exactly as `resolve` is on a `Promise`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | | ------ | ------ | | `result` | `Result`<`T`, `E`> | `Defect` | #### Returns `void` *** ### TaggedErrorConstructor ```ts type TaggedErrorConstructor = (args) => TaggedErrorInstance; ``` Defined in: [packages/core/src/tagged.ts:39](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/tagged.ts#L39) The class constructor returned by [TaggedError](#taggederror). Generic in its payload: apply it with an instantiation expression at the `extends` site. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `Tag` *extends* `string` | the string literal discriminant. | #### Parameters | Parameter | Type | | ------ | ------ | | `args` | keyof `A` *extends* `never` ? `void` : `A` & `object` | #### Returns [`TaggedErrorInstance`](#taggederrorinstance)<`Tag`, `A`> #### Remarks When the payload is empty, the constructor takes **no** arguments (the `keyof A extends never ? void : A` trick); otherwise it takes the payload. The `name`, `message`, and `stack` keys are all **rejected** (`?: never`) because all three are reserved: `name` is the display label, `message` is the human string owned by `Error`, and `stack` is `Error`'s trace. Set the message the standard way — `override message = "…"` (or a constructor override) on the subclass — never as a free-form per-call payload field. The reservations are enforced at the call site, mirroring how [TaggedErrorInstance](#taggederrorinstance) excludes all three. (`cause` is deliberately **not** reserved: `Error.cause` is `unknown`, so a typed payload `cause` is a legitimate structured field.) *** ### TaggedErrorInstance ```ts type TaggedErrorInstance = Error & Readonly> & object; ``` Defined in: [packages/core/src/tagged.ts:16](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/tagged.ts#L16) The instance shape produced by a [TaggedError](#taggederror) class: an `Error` plus a `_tag` discriminant and the (readonly) payload fields. #### Type Declaration | Name | Type | Defined in | | ------ | ------ | ------ | | `_tag` | `Tag` | [packages/core/src/tagged.ts:17](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/tagged.ts#L17) | #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `Tag` *extends* `string` | the string literal discriminant. | | `A` *extends* `Props` | the payload object type. | *** ### UniversalPattern ```ts type UniversalPattern = PatternMatcher & object; ``` Defined in: [packages/core/src/matcher.ts:64](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L64) The statically-known universal pattern — the type of `P._` only. The phantom `UNIVERSAL` marker is *required*, so no other `PatternMatcher` (e.g. a `P.when` guard that happens to be universal) is assignable: the catch-all `.with` overload must only fire for a pattern the type system KNOWS covers everything. #### Type Declaration | Name | Type | Defined in | | ------ | ------ | ------ | | `[UNIVERSAL]` | `true` | [packages/core/src/matcher.ts:65](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L65) | ## Methods ### AsyncResultMethods ```ts type AsyncResultMethods = object; ``` Defined in: [packages/core/src/types.ts:757](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L757) The async method surface every [AsyncResult](#asyncresult) carries — the combinators (`map`, `flatMap`, `mapErrCases`, `match`, `get`, …) with their asynchronous signatures, documented one per entry below. The async mirror of [ResultMethods](#resultmethods): each entry links its synchronous counterpart and states only the async delta. #### Remarks Like [ResultMethods](#resultmethods), this type exists to **document** the surface — not to be authored against; you obtain it by holding an `AsyncResult`. Its combinator callbacks are **synchronous** (a raw `Promise` may never enter — see the [AsyncResult](#asyncresult) remarks); async work re-enters via [fromPromise](#frompromise) and composes with `flatMap`. Systematic differences from the sync surface: the binds return an `AsyncResult` (and additionally accept one), and the eliminators return a `Promise`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Methods ##### as() ```ts as(value): AsyncResult; ``` Defined in: [packages/core/src/types.ts:824](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L824) Asynchronous [as](#as-4): replaces the value with `value`. ###### Type Parameters | Type Parameter | | ------ | | `U` | ###### Parameters | Parameter | Type | | ------ | ------ | | `value` | `U` | ###### Returns `AsyncResult`<`U`, `E`> ##### bind() ```ts bind(name, f): AsyncResult<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E | E2>; ``` Defined in: [packages/core/src/types.ts:808](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L808) Asynchronous [bind](#bind-4) (do-notation). `f` may return a `Result` **or** an `AsyncResult`; its value is bound under `name` in the accumulating scope. ###### Type Parameters | Type Parameter | | ------ | | `K` *extends* `string` | | `U` | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `name` | `K` | | `f` | (`scope`) => | `Result`<`U`, `E2`> | [`Awaitable`](#awaitable)<`Result`<`U`, `E2`>> & `object` | ###### Returns `AsyncResult`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E` | `E2`> ##### discard() ```ts discard(): AsyncResult; ``` Defined in: [packages/core/src/types.ts:826](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L826) Asynchronous [discard](#discard-4): drops the value, collapsing the success type to `void`. ###### Returns `AsyncResult`<`void`, `E`> ##### ensure() ###### Call Signature ```ts ensure(predicate, onFail): AsyncResult; ``` Defined in: [packages/core/src/types.ts:834](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L834) Asynchronous [ensure](#ensure-4): validate the success value — and, with a type-guard predicate (this overload), **refine** it — failing into the modeled channel with `Err(onFail(value))`. Both callbacks are synchronous (an async `onFail` is rejected at compile time, [NotThenable](#notthenable)); a throw in either becomes a `Defect`. ###### Type Parameters | Type Parameter | | ------ | | `U` | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `predicate` | (`value`) => `value is U` | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | ###### Returns `AsyncResult`<`U`, `E` | `E2`> ###### Call Signature ```ts ensure(predicate, onFail): AsyncResult; ``` Defined in: [packages/core/src/types.ts:839](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L839) Boolean form of the asynchronous [ensure](#ensure-4) — validates without refining, keeping `T`. ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `predicate` | (`value`) => `boolean` | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | ###### Returns `AsyncResult`<`T`, `E` | `E2`> ##### flatMap() ```ts flatMap(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:777](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L777) Asynchronous [flatMap](#flatmap-4). Unlike the sync form, `f` may return a `Result` **or** an `AsyncResult` (never a raw `Promise`); a throw becomes a `Defect`. ###### Type Parameters | Type Parameter | | ------ | | `U` | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`value`) => | `Result`<`U`, `E2`> | [`Awaitable`](#awaitable)<`Result`<`U`, `E2`>> & `object` | ###### Returns `AsyncResult`<`U`, `E` | `E2`> ###### Remarks The async branch of `f`'s return type is spelled `Awaitable> & { flatMap: unknown }` rather than `AsyncResult`: this is what you get by returning an `AsyncResult` (it satisfies both), but inference runs through the `Awaitable` then-channel so `U`/`E2` stay precise instead of collapsing to `unknown`, while the `{ flatMap: unknown }` marker still rejects a bare `Promise` (it has no `flatMap`). Just return a `Result` or an `AsyncResult`. ##### flatMapErrCases() ```ts flatMapErrCases(f): AsyncResult< | T | OkOf> | AsyncOkOf>, | ErrOf> | AsyncErrOf>>; ``` Defined in: [packages/core/src/types.ts:857](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L857) Asynchronous [flatMapErrCases](#flatmaperrcases-4) — the same exhaustive [ErrMatcher](#errmatcher) form. Unlike the sync form, a branch may return a `Result` **or** an `AsyncResult`. ###### Type Parameters | Type Parameter | | ------ | | `M` *extends* `ExhaustiveMatch`< | `Result`<`unknown`, `unknown`> | `AsyncResult`<`unknown`, `unknown`> | `Defect`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | ###### Returns `AsyncResult`< | `T` | [`OkOf`](#okof)<`MatchOut`<`M`>> | [`AsyncOkOf`](#asyncokof)<`MatchOut`<`M`>>, | [`ErrOf`](#errof)<`MatchOut`<`M`>> | [`AsyncErrOf`](#asyncerrof)<`MatchOut`<`M`>>> ##### flatTap() ```ts flatTap(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:798](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L798) Asynchronous [flatTap](#flattap-4) — a failable tap that keeps the original value. `f` may return a `Result` **or** an `AsyncResult`; its `Ok` value is discarded, an `Err`/`Defect` short-circuits, and a throw becomes a `Defect`. ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`value`) => | `Result`<`unknown`, `E2`> | [`Awaitable`](#awaitable)<`Result`<`unknown`, `E2`>> & `object` | ###### Returns `AsyncResult`<`T`, `E` | `E2`> ##### flatTapErrCases() ```ts flatTapErrCases(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:904](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L904) Asynchronous [flatTapErrCases](#flattaperrcases-4) — the error-channel mirror of `flatTap`. `f` may return a `Result` **or** an `AsyncResult`; its `Ok` value is discarded, an `Err`/`Defect` from `f` threads through, and if `f` throws — or a branch returns the injected `defect(cause)` marker, the expression-position form of a throw — the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`Result`<`unknown`, `E2`> | `AsyncResult`<`unknown`, `E2`>> | ###### Returns `AsyncResult`<`T`, `E` | `E2`> ##### get() ```ts get(this): Promise; ``` Defined in: [packages/core/src/types.ts:951](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L951) Asynchronous [get](#get-4). Compiles only when the error channel is empty (`this: AsyncResult`); the returned promise rejects on a `Defect` (rethrowing its cause). ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `AsyncResult`<`T`, `never`> | ###### Returns `Promise`<`T`> ##### getErr() ```ts getErr(this): Promise; ``` Defined in: [packages/core/src/types.ts:957](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L957) Asynchronous [getErr](#geterr-4). Compiles only when the success channel is empty (`this: AsyncResult`); the returned promise rejects on a `Defect` (rethrowing its cause). ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `AsyncResult`<`never`, `E`> | ###### Returns `Promise`<`E`> ##### getOr() ```ts getOr(fallback): Promise; ``` Defined in: [packages/core/src/types.ts:959](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L959) Asynchronous [getOr](#getor-4). ###### Type Parameters | Type Parameter | | ------ | | `U` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fallback` | `U` | ###### Returns `Promise`<`T` | `U`> ##### getOrElse() ```ts getOrElse(f): Promise; ``` Defined in: [packages/core/src/types.ts:961](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L961) Asynchronous [getOrElse](#getorelse-4). ###### Type Parameters | Type Parameter | | ------ | | `U` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`error`) => `U` | ###### Returns `Promise`<`T` | `U`> ##### getOrNull() ```ts getOrNull(): Promise; ``` Defined in: [packages/core/src/types.ts:963](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L963) Asynchronous [getOrNull](#getornull-4). ###### Returns `Promise`<`T` | `null`> ##### getOrThrow() ```ts getOrThrow(this): Promise; ``` Defined in: [packages/core/src/types.ts:972](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L972) Asynchronous [getOrThrow](#getorthrow-4) — the returned promise **rejects** with the modeled error on `Err` (or the original cause on a `Defect`), rather than throwing synchronously. Gated the same way: it compiles only when the error channel is non-empty (`E` is not `never`). ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | \[`E`] *extends* \[`never`] ? `"unthrown: getOrThrow is unnecessary here — the Err channel is empty (E = never), so there is nothing to throw. Use get() instead."` : `AsyncResult`<`T`, `E`> | ###### Returns `Promise`<`T`> ##### getOrUndefined() ```ts getOrUndefined(): Promise; ``` Defined in: [packages/core/src/types.ts:965](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L965) Asynchronous [getOrUndefined](#getorundefined-4). ###### Returns `Promise`<`T` | `undefined`> ##### let() ```ts let(name, f): AsyncResult<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E>; ``` Defined in: [packages/core/src/types.ts:819](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L819) Asynchronous [let](#let-4) (do-notation). `f` returns a plain value, bound under `name`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `K` *extends* `string` | | `U` | ###### Parameters | Parameter | Type | | ------ | ------ | | `name` | `K` | | `f` | (`scope`) => `U` & [`NotThenable`](#notthenable)<`U`> | ###### Returns `AsyncResult`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E`> ##### map() ```ts map(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:763](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L763) Asynchronous [map](#map-4): transforms the success value with `f`. `f` is synchronous; a throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `U` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`value`) => `U` & [`NotThenable`](#notthenable)<`U`> | ###### Returns `AsyncResult`<`U`, `E`> ##### mapErrCases() ```ts mapErrCases(f): AsyncResult, Defect>>; ``` Defined in: [packages/core/src/types.ts:848](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L848) Asynchronous [mapErrCases](#maperrcases-4) — the same exhaustive [ErrMatcher](#errmatcher) form; the combinator calls `.exhaustive()`. ###### Type Parameters | Type Parameter | | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | ###### Returns `AsyncResult`<`T`, `Exclude`<`MatchOut`<`M`>, `Defect`>> ##### match() ```ts match(cases): Promise>; ``` Defined in: [packages/core/src/types.ts:941](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L941) Asynchronous [match](#match-4). Handlers are synchronous (the `errCases` handler returns an exhaustive [ErrMatcher](#errmatcher) builder, no `defect` helper); resolves to a `Promise` of the folded value. ###### Type Parameters | Type Parameter | | ------ | | `ROk` | | `RDefect` | | `M` *extends* `ExhaustiveMatch`<`unknown`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `cases` | { `defect`: (`cause`) => `RDefect`; `errCases`: (`matcher`) => `M`; `ok`: (`value`) => `ROk`; } | | `cases.defect` | (`cause`) => `RDefect` | | `cases.errCases` | (`matcher`) => `M` | | `cases.ok` | (`value`) => `ROk` | ###### Returns `Promise`<`ROk` | `RDefect` | `MatchOut`<`M`>> ##### recoverDefect() ```ts recoverDefect(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:915](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L915) Asynchronous [recoverDefect](#recoverdefect-4). `f` may return a `Result` or an `AsyncResult`. ###### Type Parameters | Type Parameter | | ------ | | `U` | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`cause`) => `Result`<`U`, `E2`> | `AsyncResult`<`U`, `E2`> | ###### Returns `AsyncResult`<`T` | `U`, `E` | `E2`> ##### recoverErrCases() ```ts recoverErrCases(f): AsyncResult, Defect>, never>; ``` Defined in: [packages/core/src/types.ts:871](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L871) Asynchronous [recoverErrCases](#recovererrcases-4) — the same exhaustive [ErrMatcher](#errmatcher) form. Branches are synchronous; a throw becomes a `Defect`. ###### Type Parameters | Type Parameter | | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | ###### Returns `AsyncResult`<`T` | `Exclude`<`MatchOut`<`M`>, `Defect`>, `never`> ##### tap() ```ts tap(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:791](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L791) Asynchronous [tap](#tap-4). `f` is synchronous; a throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)) — and so is a returned `AsyncResult` (it is awaitable). Beware the near-miss: *calling* an `AsyncResult`-returning effect inside the callback without returning it compiles and leaves the effect floating — fire-and-forget, never awaited, its `Err`/`Defect` unobserved. If the effect returns a `Result`/`AsyncResult`, use [flatTap](#flattap-3). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`value`) => `R` & [`NotThenable`](#notthenable)<`R`> | ###### Returns `AsyncResult`<`T`, `E`> ##### tapDefect() ```ts tapDefect(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:924](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L924) Asynchronous [tapDefect](#tapdefect-4). If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`cause`) => `R` & [`NotThenable`](#notthenable)<`R`> | ###### Returns `AsyncResult`<`T`, `E`> ##### tapErrCases() ```ts tapErrCases(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:888](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L888) Asynchronous [tapErrCases](#taperrcases-4). `f` is synchronous; if it throws — or a branch returns the injected `defect(cause)` marker, the expression-position form of a throw — the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async branch is rejected at compile time ([NotThenable](#notthenable) on the builder output) — other branch results are discarded, so a rejected `Promise` would float unobserved. The [tap](#tap-3) fire-and-forget caveat applies here too — a failable effect belongs in [flatTapErrCases](#flattaperrcases-3). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`R` & [`NotThenable`](#notthenable)<`R`>> | ###### Returns `AsyncResult`<`T`, `E`> ##### tapFailure() ```ts tapFailure(f): AsyncResult; ``` Defined in: [packages/core/src/types.ts:934](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L934) Asynchronous [tapFailure](#tapfailure-4) — the cross-channel observer. `f` receives the narrowed failure variant ([FailureView](#failureview)); if it throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | | ------ | ------ | | `f` | (`failure`) => `R` & [`NotThenable`](#notthenable)<`R`> | ###### Returns `AsyncResult`<`T`, `E`> *** ### ResultMethods ```ts type ResultMethods = object; ``` Defined in: [packages/core/src/types.ts:114](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L114) The fluent method surface every [Result](#result) variant carries — the combinators (`map`, `flatMap`, `mapErrCases`, `match`, `get`, …), documented one per entry below. Factored out so the three variants ([OkView](#okview), [ErrView](#errview), [DefectView](#defectview)) can each intersect it; [AsyncResult](#asyncresult) mirrors this surface with async signatures. #### Remarks This type exists to **document** the surface and to power narrowing — not to be authored against. You obtain it by holding a `Result` (or `AsyncResult`), never by implementing your own `Result`-like; treat it as read-only reference. #### Extended by * [`DefectView`](#defectview) * [`ErrView`](#errview) * [`OkView`](#okview) #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Methods ##### as() ```ts as(value): Result; ``` Defined in: [packages/core/src/types.ts:220](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L220) Replace the success value with a constant `value`. Runs only on `Ok`; `Err` and `Defect` pass through. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the replacement value type. | ###### Parameters | Parameter | Type | | ------ | ------ | | `value` | `U` | ###### Returns `Result`<`U`, `E`> ##### bind() ```ts bind(name, f): Result<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E | E2>; ``` Defined in: [packages/core/src/types.ts:193](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L193) Do-notation: run `f` for a `Result` and **bind its value** under `name` in an accumulating object scope. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `K` *extends* `string` | the key the bound value is stored under. | | `U` | the bound value type. | | `E2` | the error type `f` may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `name` | `K` | the scope key. | | `f` | (`scope`) => `Result`<`U`, `E2`> | produces a `Result` from the accumulated scope. | ###### Returns `Result`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E` | `E2`> ###### Remarks Begin a chain with [Do](#do) (an empty object scope) and grow it step by step. `f` receives the scope accumulated so far and returns a `Result`; on `Ok` the value is added as `{ ...scope, [name]: value }`, on `Err`/`Defect` the chain short-circuits. Errors union (`E | E2`). A throw becomes a `Defect` — as does calling `bind` on a non-object scope (e.g. `Ok(5).bind`), which is misuse: the scope is always an object inside a real `Do()` chain. (`let` is the pure-value counterpart.) ##### discard() ```ts discard(): Result; ``` Defined in: [packages/core/src/types.ts:229](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L229) Drop the success value, collapsing the success type to `void`. The named form of `map(() => undefined)`. Runs only on `Ok` (the value is replaced with `undefined`); `Err` and `Defect` pass through. Unlike `as(undefined)` — which produces `Result` — the success type is `void`: the value's story ends here. ###### Returns `Result`<`void`, `E`> ##### ensure() ###### Call Signature ```ts ensure(predicate, onFail): Result; ``` Defined in: [packages/core/src/types.ts:264](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L264) Validate the success value — keep the `Ok` when `predicate` holds, otherwise fail into the **modeled** channel with `Err(onFail(value))`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the refined success type (type-guard form). | | `E2` | the error type `onFail` produces. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `predicate` | (`value`) => `value is U` | the check; a type guard refines `T` to `U`. | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | maps the failing value to the modeled error. | ###### Returns `Result`<`U`, `E` | `E2`> ###### Remarks The named form of `flatMap((v) => (p(v) ? Ok(v) : Err(e)))`. With a **type-guard** predicate (`(v): v is U`) the success type is **refined** to `U` on the way through (this overload). Runs only on `Ok` — a passing value flows through as the *same* `Ok`; `Err` and `Defect` pass through untouched. A throw in `predicate` or `onFail` becomes a `Defect`. Both callbacks are synchronous: an async `onFail` is rejected at compile time ([NotThenable](#notthenable)), and an async predicate does not type-check either — its `Promise` is not a `boolean` (and, being truthy, would have silently always passed). ###### Example ```ts // boolean form: gate a value Ok(-1).ensure((n) => n > 0, (n) => `negative: ${n}`); // Err("negative: -1") // type-guard form: refine the success type declare const r: Result; const s = r.ensure( (v): v is string => typeof v === "string", () => "not_a_string" as const, ); // Result ``` ###### Call Signature ```ts ensure(predicate, onFail): Result; ``` Defined in: [packages/core/src/types.ts:272](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L272) Boolean form of [ensure](#ensure-4) — validates without refining, keeping the success type `T`. ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | | ------ | ------ | | `predicate` | (`value`) => `boolean` | | `onFail` | (`value`) => `E2` & [`NotThenable`](#notthenable)<`E2`> | ###### Returns `Result`<`T`, `E` | `E2`> ##### flatMap() ```ts flatMap(f): Result; ``` Defined in: [packages/core/src/types.ts:137](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L137) Sequence a dependent, `Result`-returning step (monadic bind). Runs `f` only on `Ok`; `Err` and `Defect` pass through. The error channels combine, widening to `E | E2`. If `f` throws, the throw becomes a `Defect`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the success type of the next step. | | `E2` | the error type the next step may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `Result`<`U`, `E2`> | produces the next `Result` from the current success value. | ###### Returns `Result`<`U`, `E` | `E2`> ##### flatMapErrCases() ```ts flatMapErrCases(f): Result>, ErrOf>>; ``` Defined in: [packages/core/src/types.ts:320](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L320) Sequence from an `Err` by producing another `Result` — the error-channel mirror of [flatMap](#flatmap-4), **matching the error exhaustively** ([ErrMatcher](#errmatcher); the combinator calls `.exhaustive()`). Each branch returns a `Result`; the outgoing channels are the unions of the branch-returned `Result`s' channels. A branch may return `defect(cause)`. Runs only on `Err`; `Ok` and `Defect` pass through. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`Result`<`unknown`, `unknown`> | `Defect`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match; each branch produces a fallback `Result`. | ###### Returns `Result`<`T` | [`OkOf`](#okof)<`MatchOut`<`M`>>, [`ErrOf`](#errof)<`MatchOut`<`M`>>> ##### flatTap() ```ts flatTap(f): Result; ``` Defined in: [packages/core/src/types.ts:173](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L173) Run a **failable** side effect on the success value, keeping the original value but threading the effect's error. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `E2` | the error type the effect may introduce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `Result`<`unknown`, `E2`> | the failable side effect; its `Ok` value is ignored. | ###### Returns `Result`<`T`, `E` | `E2`> ###### Remarks This is to [tap](#tap-4) what [flatMap](#flatmap-4) is to [map](#map-4): `f` returns a `Result`, but its **success value is discarded** — on success the original value flows through (`Result`), while an `Err` (or `Defect`) from `f` short-circuits. Runs only on `Ok`; `Err` and `Defect` pass through. If `f` throws, the throw becomes a `Defect`. Use it for a validation or write whose *result* matters but whose *value* you don't need. ##### flatTapErrCases() ```ts flatTapErrCases(f): Result; ``` Defined in: [packages/core/src/types.ts:393](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L393) Run a **failable** side effect on the error, keeping the original error but threading the effect's own error — **matched exhaustively** ([ErrMatcher](#errmatcher)). ###### Type Parameters | Type Parameter | | ------ | | `E2` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`Result`<`unknown`, `E2`>> | builds the match; each branch is a failable effect (its `Ok` is ignored). | ###### Returns `Result`<`T`, `E` | `E2`> ###### Remarks The error-channel mirror of [flatTap](#flattap-4): each branch returns a `Result` whose **success value is discarded** — on the effect's `Ok` the original `Err` flows through, while an `Err`/`Defect` from a branch short-circuits and threads its error. Note the asymmetry with a *throw*: a branch that **returns** a Defect-state `Result` **replaces** the original `Err` (Defect-dominance, the short-circuit rule — it is not aggregated), whereas a branch that **throws** produces a `Defect` aggregating `[thrown, original failure]` (observing a failure by throwing never destroys it). A branch returning the injected `defect(cause)` marker — reachable under a `returnType` pin — follows the *throw* rule, since it is the lint-clean, expression-position form of one. ##### get() ```ts get(this): T; ``` Defined in: [packages/core/src/types.ts:498](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L498) Extract the success value. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `Result`<`T`, `never`> | ###### Returns `T` the `Ok` value. ###### Remarks Compiles only when the error channel is empty (`E = never`) — eliminate modeled errors first (`match` / `recoverErrCases` / `flatMapErrCases`), or reach for the `getOr` / `getOrElse` / `getOrNull` / `getOrUndefined` family (which recover an `Err`). If you get a `'this' context` type error here, that is the gate: the receiver still has a non-`never` error channel. `E = never` empties only the **modeled** error channel — a `Defect` can still be present, and `get()` **rethrows its original cause** (it *panics*); `Result` does not mean `get()` cannot throw. ##### getErr() ```ts getErr(this): E; ``` Defined in: [packages/core/src/types.ts:512](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L512) Extract the modeled error. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | `Result`<`never`, `E`> | ###### Returns `E` the `Err` value. ###### Remarks Compiles only when the success channel is empty (`T = never`) — eliminate the success case first. `T = never` is rarely the case in practice (a `Result` you hold usually still has a success type), so to inspect an error prefer an `isErr()` guard or, in tests, `@unthrown/vitest`'s `toBeErrWith`. A `Defect` still **rethrows its original cause** (a defect is a bug, not an absent value), so this does not mean `getErr()` can't throw. ##### getOr() ```ts getOr(fallback): T | U; ``` Defined in: [packages/core/src/types.ts:521](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L521) The success value, or `fallback` on `Err`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the fallback type (may differ from `T`; the return widens to `T | U`). | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `fallback` | `U` | returned when the result is an `Err` (may be a different type; the return widens to `T | U`). | ###### Returns `T` | `U` ###### Throws Re-throws on a `Defect` — a Defect is a bug, not an absent value, so it is never silently replaced. ##### getOrElse() ```ts getOrElse(f): T | U; ``` Defined in: [packages/core/src/types.ts:529](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L529) The success value, or `f(error)` on `Err`. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the fallback type (may differ from `T`; the return widens to `T | U`). | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`error`) => `U` | lazily computes the fallback from the error (may return a different type; the return widens to `T | U`). | ###### Returns `T` | `U` ###### Throws Re-throws on a `Defect`. ##### getOrNull() ```ts getOrNull(): T | null; ``` Defined in: [packages/core/src/types.ts:535](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L535) The success value, or `null` on `Err`. ###### Returns `T` | `null` ###### Throws Re-throws on a `Defect`. ##### getOrThrow() ```ts getOrThrow(this): T; ``` Defined in: [packages/core/src/types.ts:573](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L573) The success value, or **throw** the modeled error on `Err`. ###### Parameters | Parameter | Type | | ------ | ------ | | `this` | \[`E`] *extends* \[`never`] ? `"unthrown: getOrThrow is unnecessary here — the Err channel is empty (E = never), so there is nothing to throw. Use get() instead."` : `Result`<`T`, `E`> | ###### Returns `T` the `Ok` value. ###### Remarks A deliberate escape hatch off the errors-as-values model — it **throws the `Err` value as-is** at the call site, so a caller of the enclosing function sees a throw rather than a channel. Its home is **tests and scripts**, where "this `Result` had better be `Ok`" is the assertion and a throw is the correct failure mode. In production code, fold the error channel instead: [recoverErrCases](#recovererrcases-4) empties `E`, so [get](#get-4) compiles and a case routed to the injected `defect(...)` panics with its original cause — with every case still named. [match](#match-4) and [flatMapErrCases](#flatmaperrcases-4) are the other two ways to keep the error a value. `@unthrown/oxlint`'s opt-in `no-get-or-throw` rule enforces this, exempting test files through an oxlint `overrides` entry. Type-gated as the **complement** of [get](#get-4): it compiles only when the error channel is **non-empty** (`E` is not `never`) — there must be a modeled error for it to throw. On a `Result` there is nothing to throw, so `getOrThrow` does not compile; use `get()` (which gates the other way). Together they partition extraction by the error channel's state, with no overlap. ###### Throws the modeled `error` on `Err`; re-throws the original `cause` on a `Defect` (a panic, like the rest of the `getOr…` family). ##### getOrUndefined() ```ts getOrUndefined(): T | undefined; ``` Defined in: [packages/core/src/types.ts:541](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L541) The success value, or `undefined` on `Err`. ###### Returns `T` | `undefined` ###### Throws Re-throws on a `Defect`. ##### isDefect() ```ts isDefect(): this is DefectView; ``` Defined in: [packages/core/src/types.ts:584](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L584) Whether this result is a `Defect` — narrows `this` to its [DefectView](#defectview) on `true`. ###### Returns `this is DefectView` ##### isErr() ```ts isErr(): this is ErrView; ``` Defined in: [packages/core/src/types.ts:582](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L582) Whether this result is `Err` — narrows `this` to its [ErrView](#errview) on `true`. ###### Returns `this is ErrView` ##### isOk() ```ts isOk(): this is OkView; ``` Defined in: [packages/core/src/types.ts:580](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L580) Whether this result is `Ok` — narrows `this` to its [OkView](#okview) on `true`. ###### Returns `this is OkView` ##### let() ```ts let(name, f): Result<{ [K in string | number | symbol]: (Omit & { readonly [P in string]: U })[K] }, E>; ``` Defined in: [packages/core/src/types.ts:212](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L212) Do-notation: run `f` for a **plain value** and bind it under `name` in the accumulating object scope. The pure-value counterpart of [bind](#bind-4). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `K` *extends* `string` | the key the value is stored under. | | `U` | the value type. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `name` | `K` | the scope key. | | `f` | (`scope`) => `U` & [`NotThenable`](#notthenable)<`U`> | computes a value from the accumulated scope. | ###### Returns `Result`<{ \[K in string | number | symbol]: (Omit\ & { readonly \[P in string]: U })\[K] }, `E`> ###### Remarks `f` receives the scope and returns a value (not a `Result`); it is added as `{ ...scope, [name]: value }`. Runs only on `Ok`; `Err`/`Defect` pass through. A throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ##### map() ```ts map(f): Result; ``` Defined in: [packages/core/src/types.ts:126](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L126) Transform the success value with `f`. Runs `f` only on `Ok`; `Err` and `Defect` pass through untouched. If `f` throws, the thrown value is captured as a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | the mapped success type. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `U` & [`NotThenable`](#notthenable)<`U`> | maps the current success value to a new one. | ###### Returns `Result`<`U`, `E`> ##### mapErrCases() ```ts mapErrCases(f): Result, Defect>>; ``` Defined in: [packages/core/src/types.ts:304](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L304) Transform the modeled error by **matching it exhaustively**. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match over the error (returns the un-terminated builder). | ###### Returns `Result`<`T`, `Exclude`<`MatchOut`<`M`>, `Defect`>> ###### Remarks The callback receives `match(error)` (an [ErrMatcher](#errmatcher)) and the injected `defect` helper. Chain `.with(pattern, handler)` and **return the un-terminated builder** — `mapErrCases` calls `.exhaustive()` itself, so a missing case is a compile error at the call site (there is no `.exhaustive()` to forget, and no way to slip in `.otherwise()`). The outgoing error type is the union of the branch returns with the `Defect` arm subtracted (`Exclude`) — a branch returning `defect(cause)` converts that case to a `Defect` and drops it from `E`. Runs only on `Err`; `Ok` and `Defect` pass through. A branch that throws also becomes a `Defect`. **Name every case.** Match on anything the matcher supports — `_tag`, `code`, structural shape, guards — and group the cases that share a handler with `.with(a, b, handler)`. `.with(P._, …)` is the wildcard **escape hatch**, not the default: it makes any match exhaustive, so it also absorbs every case `E` grows later. Two uses are sanctioned — a helper generic in `E`, where no arm list can prove exhaustiveness against an unresolved type parameter, and an `E` that is a single type rather than a union of cases (see [P](#p) for both). `@unthrown/oxlint`'s `no-catch-all-pattern` (in its `recommended` preset) flags the rest. ##### match() ```ts match(cases): ROk | RDefect | MatchOut; ``` Defined in: [packages/core/src/types.ts:477](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L477) Exhaustively fold all three runtime states into a single value. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `ROk` | the `ok` handler return type. | | `RDefect` | the `defect` handler return type. | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the `errCases` handler returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `cases` | { `defect`: (`cause`) => `RDefect`; `errCases`: (`matcher`) => `M`; `ok`: (`value`) => `ROk`; } | the `ok`/`defect` handlers plus the `errCases` matcher builder. | | `cases.defect` | (`cause`) => `RDefect` | - | | `cases.errCases` | (`matcher`) => `M` | - | | `cases.ok` | (`value`) => `ROk` | - | ###### Returns `ROk` | `RDefect` | `MatchOut`<`M`> ###### Remarks Exactly one handler runs. Together with the throw-to-Defect guarantee, this is typically the single place a pipeline is handled at the edge — mapping `Ok`/`Err`/`Defect` to (for example) 2xx / 4xx / 5xx with no `try`/`catch`. The `errCases` handler does not take a single blanket callback: it receives `match(error)` (an [ErrMatcher](#errmatcher)) and **matches the error exhaustively**, exactly like the error combinators — which is why the key carries the same `…Cases` suffix. Chain `.with(pattern, handler)` and **return the un-terminated builder** — `match` calls `.exhaustive()` itself, so a missing case is a compile error at the call site (no `.exhaustive()` to forget). Folding at the edge names every case too — `.with(P._, …)` is the wildcard escape hatch, not the default. Unlike the combinators the branches receive **no `defect` helper** — `match` is total elimination to a value, with no `Defect` output channel; the `defect` case handles a `Result` that already carries one. (A `Result` is also a discriminated union — for richer whole-`Result` matching, `match(result).with(…)`.) ##### recoverDefect() ```ts recoverDefect(f): Result; ``` Defined in: [packages/core/src/types.ts:413](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L413) Recover from a `Defect` — the **only** combinator that can touch one. ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `U` | a success type the recovery may produce. | | `E2` | an error type the recovery may produce. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`cause`) => `Result`<`U`, `E2`> | maps the Defect's unknown cause to a recovering `Result`. | ###### Returns `Result`<`T` | `U`, `E` | `E2`> ###### Remarks Runs `f` only when a `Defect` is present, re-entering the modeled world by returning a `Result` (an `Ok` or a fresh `Err`). `Ok` and `Err` pass through. Recovering a Defect should be rare: usually you let it bubble to the edge. If `f` throws, the throw becomes a new `Defect`. ##### recoverErrCases() ```ts recoverErrCases(f): Result, Defect>, never>; ``` Defined in: [packages/core/src/types.ts:338](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L338) Recover from an `Err` by producing a success value, emptying the error channel — **matching the error exhaustively** ([ErrMatcher](#errmatcher)). Pairs with [recoverDefect](#recoverdefect-4). ###### Type Parameters | Type Parameter | Description | | ------ | ------ | | `M` *extends* `ExhaustiveMatch`<`unknown`> | the exhaustive builder the callback returns. | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `M` | builds the match; each branch produces a success value. | ###### Returns `Result`<`T` | `Exclude`<`MatchOut`<`M`>, `Defect`>, `never`> ###### Remarks The result type is `Result`, but `never` describes only the **error** channel — a `Defect` can still be present at runtime. A branch may return `defect(cause)` (which stays a `Defect`, not a recovery). Runs only on `Err`; `Ok` and `Defect` pass through. ##### tap() ```ts tap(f): Result; ``` Defined in: [packages/core/src/types.ts:156](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L156) Run a side effect on the success value and pass the `Result` through unchanged. Runs only on `Ok`. If `f` throws, the throw becomes a `Defect`. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`value`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect (its return value is ignored). | ###### Returns `Result`<`T`, `E`> ###### Remarks `f`'s return value is **ignored** — a `Result` returned by the effect compiles but is discarded, `Err` and all. If the effect can fail, sequence it instead of tapping it: a `Result`-returning effect goes in [flatTap](#flattap-4); an `AsyncResult`-returning effect cannot be sequenced from the sync surface — lift the chain with [toAsync](#toasync-3) and use the async [flatTap](#flattap-3) (which accepts both). ##### tapDefect() ```ts tapDefect(f): Result; ``` Defined in: [packages/core/src/types.ts:423](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L423) Run a side effect on a present `Defect`'s cause (e.g. logging) and pass the `Defect` through unchanged. If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`cause`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect over the unknown cause. | ###### Returns `Result`<`T`, `E`> ##### tapErrCases() ```ts tapErrCases(f): Result; ``` Defined in: [packages/core/src/types.ts:365](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L365) Run a side effect on the error — **matched exhaustively** ([ErrMatcher](#errmatcher)) — and pass the `Result` through unchanged. ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`matcher`, `defect`) => `ExhaustiveMatch`<`R` & [`NotThenable`](#notthenable)<`R`>> | builds the match; branch returns are ignored, bar `defect(cause)`. | ###### Returns `Result`<`T`, `E`> ###### Remarks The callback builds a match whose branches run side effects; their return values are ignored and the original `Err` flows through. Exhaustive like the transformers, and like them it wants every case named — `.with(P._, …)` remains the wildcard escape hatch. If a branch throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An **async branch is rejected at compile time** ([NotThenable](#notthenable) on the builder output): because the branch results are discarded, a returned `Promise` would float unobserved and its rejection would vanish. The one branch return that is **not** discarded is the injected `defect(cause)` marker: it is the lint-clean, expression-position form of a `throw`, so it follows the throw rule above (an `AggregateError` of `[the branch's cause, original failure]`), never a silent no-op. A failable `Result`-returning effect belongs in [flatTapErrCases](#flattaperrcases-4). ##### tapFailure() ```ts tapFailure(f): Result; ``` Defined in: [packages/core/src/types.ts:449](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L449) Run a side effect on **any failure** — `Err` or `Defect` — and pass the `Result` through unchanged. The one cross-channel observer, for the shared "it went KO" concern (logging, metrics, rollback) that would otherwise be duplicated across [tapErrCases](#taperrcases-4) and [tapDefect](#tapdefect-4). ###### Type Parameters | Type Parameter | | ------ | | `R` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `f` | (`failure`) => `R` & [`NotThenable`](#notthenable)<`R`> | the side effect over the failure variant (its return value is ignored). | ###### Returns `Result`<`T`, `E`> ###### Remarks `f` receives the narrowed **failure variant** ([FailureView](#failureview)), not a payload — the payload union `E | unknown` would collapse to `unknown` and lose `E`'s typing. Branch on `failure.tag` to reach the typed payload (`"Err"` → `failure.error: E`, `"Defect"` → `failure.cause: unknown`), or treat it opaquely for a shared logger. Runs on `Err` and `Defect`; `Ok` passes through. It **observes without consuming**: the failure flows on unchanged — to also recover, use [recoverErrCases](#recovererrcases-4) / [recoverDefect](#recoverdefect-4) (deliberately separate acts) or [match](#match-4) at the edge. If `f` throws, the result is a `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` — observing a failure never destroys it. An async callback is rejected at compile time ([NotThenable](#notthenable)). ##### toAsync() ```ts toAsync(): AsyncResult; ``` Defined in: [packages/core/src/types.ts:587](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/types.ts#L587) Lift this synchronous `Result` into an [AsyncResult](#asyncresult). ###### Returns `AsyncResult`<`T`, `E`> ## Constructors ### P ```ts const P: Readonly<{ _: UniversalPattern; instanceOf: (cls) => PatternMatcher>; tag: (value) => object; when: (guard) => PatternMatcher; }>; ``` Defined in: [packages/core/src/matcher.ts:416](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L416) The pattern namespace (unthrown's own; the former ts-pattern `P`): * `P._` — the universal catch-all, and an **escape hatch** rather than the default: matching the error channel means naming its cases, so reach for this only where they cannot be named. Matches anything, and (because its phantom type is `unknown`) makes the builder provably exhaustive even when the matched input is an unresolved type parameter. Two situations are legitimate: a **helper generic in `E`**, where no arm list can prove exhaustiveness against an unresolved type parameter; and an **`E` that is a single type**, not a union of cases (a validator's issues array, say), where one arm *is* the enumeration. `@unthrown/oxlint`'s `no-catch-all-pattern` (in its `recommended` preset) flags every other use; keep the deliberate ones behind a targeted `oxlint-disable` saying which of the two it is. * `P.tag(value: Tag): { _tag: Tag }` — the `{ _tag: t }` object pattern, matching any value whose `_tag` equals `t` (a `TaggedError`, or any `_tag`-discriminated member) and narrowing the branch's parameter to that variant, payload included. The workhorse of the error channel: `matcher.with(P.tag("NotFound"), (e) => …)`. It composes like any other pattern — in a grouped arm (`.with(P.tag("A"), P.tag("B"), handler)`). * `P.instanceOf(Cls)` — an `instanceof` check, narrowing to the class instance type (for union members that are not tagged, e.g. a third-party error class). * `P.when(guard)` — an arbitrary type-guard predicate. Also the way to match a primitive shape (`P.when((v): v is string => typeof v === "string")`), and grouping patterns under one handler is what a `.with(a, b, handler)` arm already does. *** ### Err() ```ts function Err(error): Result; ``` Defined in: [packages/core/src/constructors.ts:61](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L61) Construct a failed [Result](#result) carrying a **modeled** error. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `error` | `E` | the domain error to wrap. | #### Returns `Result`<`never`, `E`> #### Example ```ts import { Err } from "unthrown"; Err("not_found").map((n) => n + 1); // => Err("not_found") (map skipped) Err("not_found").getErr(); // => "not_found" ``` *** ### ErrAsync() ```ts function ErrAsync(error): AsyncResult; ``` Defined in: [packages/core/src/constructors.ts:133](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L133) Construct a failed [AsyncResult](#asyncresult) carrying a **modeled** error — the pre-lifted form of [Err](#err), sparing you `Err(error).toAsync()`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `error` | `E` | the domain error to wrap. | #### Returns `AsyncResult`<`never`, `E`> #### Remarks The error-channel mirror of [OkAsync](#okasync); see it for the naming and the `AsyncResult.Err` companion alias. #### Example ```ts import { ErrAsync } from "unthrown"; ErrAsync("not_found"); // AsyncResult ``` *** ### match() ```ts function match(value): Matcher; ``` Defined in: [packages/core/src/matcher.ts:370](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L370) Begin a match over `value`. Chain `.with(pattern, …patterns, handler)` arms; terminate with `.exhaustive()` — or return the un-terminated builder to an unthrown error combinator / `match({ errCases })`, which runs it for you. #### Type Parameters | Type Parameter | | ------ | | `E` | #### Parameters | Parameter | Type | | ------ | ------ | | `value` | `E` | #### Returns [`Matcher`](#matcher)<`E`, `E`, `never`> #### Remarks This is unthrown's own matcher (the former ts-pattern re-export): the same call-site shape, with exhaustiveness computed by plain `Exclude` over the builder's `Remaining` parameter. Name every case of the input union; the `P._` catch-all is the escape hatch, and is provably exhaustive even over an unresolved generic input — one of the two cases it is irreplaceable for (see [P](#p)). *** ### Ok() #### Call Signature ```ts function Ok(): Result; ``` Defined in: [packages/core/src/constructors.ts:20](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L20) Construct a successful `void` [Result](#result) — `Result` — sparing you `Ok(undefined)` and typing the success channel `void`, not `undefined`. ##### Returns `Result`<`void`, `never`> ##### Example ```ts import { Ok } from "unthrown"; Ok(); // => a void success: Result ``` #### Call Signature ```ts function Ok(value): Result; ``` Defined in: [packages/core/src/constructors.ts:37](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L37) Construct a successful [Result](#result). ##### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | ##### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `value` | `T` | the success value to wrap. | ##### Returns `Result`<`T`, `never`> ##### Example ```ts import { Ok } from "unthrown"; Ok(2).map((n) => n + 1); // => Ok(3) Ok(42).get(); // => 42 ``` *** ### OkAsync() #### Call Signature ```ts function OkAsync(): AsyncResult; ``` Defined in: [packages/core/src/constructors.ts:79](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L79) Construct a successful `void` [AsyncResult](#asyncresult) — `AsyncResult` — the pre-lifted form of the no-arg [Ok](#ok), sparing you `Ok(undefined).toAsync()`. ##### Returns `AsyncResult`<`void`, `never`> ##### Example ```ts import { OkAsync } from "unthrown"; OkAsync(); // => a void success: AsyncResult ``` #### Call Signature ```ts function OkAsync(value): AsyncResult; ``` Defined in: [packages/core/src/constructors.ts:106](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L106) Construct a successful [AsyncResult](#asyncresult) from a pure value — the pre-lifted form of [Ok](#ok), sparing you `Ok(value).toAsync()`. ##### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | ##### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `value` | `T` | the success value to wrap. | ##### Returns `AsyncResult`<`T`, `never`> ##### Remarks Reach for this on the synchronous/early branch of an `AsyncResult`-returning function, so both branches share one return type without a trailing `.toAsync()`. Named with the `Async` suffix the async free functions carry (`allAsync`, `allFromDictAsync`); the [AsyncResult](#asyncresult) companion aliases it as `AsyncResult.Ok` (the namespace already says "async", so the suffix drops). ##### Example ```ts import { OkAsync, type AsyncResult } from "unthrown"; function loadItems(ids: string[]): AsyncResult { if (ids.length === 0) return OkAsync([]); // no more Ok([]).toAsync() return itemRepository.load(ids); } ``` ## Interop ### fromExecutor() ```ts function fromExecutor(executor): AsyncResult; ``` Defined in: [packages/core/src/interop.ts:339](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L339) Build an [AsyncResult](#asyncresult) from a callback-style API — this library's answer to `new Promise((resolve, reject) => …)`. #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `T` | `never` | the success type. | | `E` | `never` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `executor` | (`settle`, `defect`) => `void` | runs immediately; receives the settler and the `defect` helper. | #### Returns `AsyncResult`<`T`, `E`> #### Remarks The settler takes a **`Result`**, not a value-or-reason pair: the caller names the variant, so no `unknown` can enter `E` and there is no `qualify` to pass. For a failure that is *not* modeled, settle the injected `defect` helper's marker — the same injection `qualify` receives, and the only way to reach the defect channel from inside an asynchronous callback (a `throw` there runs in its own turn, long after the executor body returned). `T` and `E` cannot be inferred from the body, since `settle` is a parameter. Supply them explicitly, or let them flow from an annotated target. Absent either, both default to `never` (Thesis #3: no path may produce `unknown` in `E`) — so an unannotated call is a compile error at the `settle(...)` call site, not a silently-`unknown` channel. An executor that never settles yields an `AsyncResult` that never resolves — the one hazard [fromPromise](#frompromise) does not have, and identical to `new Promise`. #### Example ```ts import { fromExecutor, Err, Ok } from "unthrown"; const listen = (port: number) => fromExecutor((settle, defect) => { server.once("error", (cause) => isAddrInUse(cause) ? settle(Err(new PortInUse(port))) : settle(defect(cause)), ); server.listen(port, () => settle(Ok(server))); }); ``` *** ### fromNullable() ```ts function fromNullable(value, onAbsent): Result, E>; ``` Defined in: [packages/core/src/interop.ts:51](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L51) Bridge a nullable value into a [Result](#result): absence becomes a **modeled** `Err`. The sanctioned alternative to an `Option` type. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the (nullable) value type. | | `E` | the error produced when the value is absent. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `value` | `T` | `null` | `undefined` | the possibly-absent value. | | `onAbsent` | () => `E` | lazily produces the error for the absent case. | #### Returns `Result`<`NonNullable`<`T`>, `E`> #### Remarks `null` and `undefined` map to `Err(onAbsent())`; any other value (including falsy ones like `0`, `""`, `false`) maps to `Ok`. #### Example ```ts import { fromNullable } from "unthrown"; const map = new Map([["a", 1]]); fromNullable(map.get("a"), () => "absent").getOr(0); // => 1 fromNullable(map.get("z"), () => "absent"); // => Err("absent") fromNullable(0, () => "absent").getOr(-1); // => 0 (falsy but present) ``` *** ### fromPromise() ```ts function fromPromise( promise, qualify, ... _guard): AsyncResult>; ``` Defined in: [packages/core/src/interop.ts:215](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L215) Wrap a `Promise` (or a thunk producing one) as an [AsyncResult](#asyncresult), forcing every rejection to be triaged. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the resolved value type. | | `R` | `qualify`'s return type; the modeled error `E` is `Exclude` (its `Defect` arm, if any, is subtracted). | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `promise` | `Promise`<`T`> | (() => `Promise`<`T`>) | the promise, or a thunk returning one. | | `qualify` | (`cause`, `defect`) => `R` | triages a rejection `cause` into a modeled `E`, or marks it unmodeled by returning `defect(cause)` (the helper passed as its second arg). | | ...`_guard` | \[`Extract`<`R`, `PromiseLike`<`unknown`>>] *extends* \[`never`] ? \[] : \[`"unthrown: qualify must be synchronous — its Promise would land in E un-triaged"`] | compile-time only; never pass it. The phantom rest-tuple that enforces "qualify is synchronous": an `async` qualify makes this demand an impossible extra argument (whose type spells out the error), while a synchronous one leaves it empty. Encoded here — not on `qualify`'s return type — so `T`'s inference from `promise` is undisturbed. | #### Returns `AsyncResult`<`T`, `Exclude`<`R`, `Defect`>> #### Remarks `qualify` **must** map each rejection cause into a modeled error `E` or a `Defect` (via the injected `defect` helper, its second argument). The returned `AsyncResult`'s internal promise never rejects; `await`-ing it always yields a `Result`. A throw inside `qualify` is itself a `Defect`. `qualify` is **synchronous**: an `async` qualify is rejected at compile time ([NotThenable](#notthenable)), and a thenable slipped past the types at runtime becomes a `Defect` (never an `Err(Promise)`), its orphaned rejection silenced. The modeled error type is `Exclude` — the `Defect` arm of `qualify`'s return is **subtracted** from `E`, never inferred into it. So a `qualify` that returns *only* `defect(cause)` yields `E = never`; when every rejection is a Defect, prefer [fromSafePromise](#fromsafepromise). #### Example ```ts import { fromPromise } from "unthrown"; // A rejection with a NotFoundError becomes a modeled `Err`; anything else a Defect. const user = await fromPromise(fetchUser(id), (cause, defect) => cause instanceof NotFoundError ? ("not_found" as const) : defect(cause), ); if (user.isOk()) user.value; // => the fetched user // when fetchUser rejects with NotFoundError: user is Err("not_found") ``` *** ### fromSafePromise() ```ts function fromSafePromise(promise): AsyncResult; ``` Defined in: [packages/core/src/interop.ts:272](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L272) Wrap a `Promise` asserted **not** to fail in any modeled way: any rejection becomes a `Defect`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the resolved value type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `promise` | `Promise`<`T`> | (() => `Promise`<`T`>) | the promise, or a thunk returning one. | #### Returns `AsyncResult`<`T`, `never`> #### Remarks Use this only when a rejection genuinely indicates a bug rather than an anticipated outcome — the error channel is `never`, so there is nothing to triage. (`await`-ing still yields a `Result`; it never throws.) The synchronous counterpart is [fromSafeThrowable](#fromsafethrowable). #### Example ```ts import { fromSafePromise } from "unthrown"; (await fromSafePromise(Promise.resolve(3))).get(); // => 3 // a rejection becomes a Defect (never a modeled Err): await fromSafePromise(Promise.reject(new Error("boom"))); // => Defect(Error("boom")) ``` *** ### fromSafeThrowable() ```ts function fromSafeThrowable(fn): (...args) => Result; ``` Defined in: [packages/core/src/interop.ts:157](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L157) Wrap a throwing synchronous function asserted **not** to fail in any modeled way: any throw becomes a `Defect`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `A` *extends* `unknown`\[] | the wrapped function's argument tuple. | | `T` | the wrapped function's return type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `fn` | (...`args`) => `T` | the throwing function to wrap. | #### Returns a function with the same arguments returning `Result`. (...`args`) => `Result`<`T`, `never`> #### Remarks The synchronous counterpart of [fromSafePromise](#fromsafepromise). Use it only when a throw genuinely indicates a bug rather than an anticipated outcome — the error channel is `never`, so there is nothing to triage; there is no `qualify`. When some throws *are* anticipated, reach for [fromThrowable](#fromthrowable) and triage them. `fn` is **synchronous**: an `async` `fn` becomes a `Defect` (never `Ok()`), with its orphaned rejection silenced rather than left to float. Reach for [fromSafePromise](#fromsafepromise) to wrap async work. #### Example ```ts import { fromSafeThrowable } from "unthrown"; // A decode failure here is a bug (the row came from our own schema), so // every throw is a defect — no throwaway `(cause, defect) => defect(cause)`. const decode = fromSafeThrowable((row: Row) => userSchema.parse(row)); decode(row); // => Result — a throw becomes a Defect ``` *** ### fromThrowable() ```ts function fromThrowable(fn, qualify): (...args) => Result>; ``` Defined in: [packages/core/src/interop.ts:108](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L108) Wrap a throwing synchronous function so it returns a [Result](#result) instead of throwing. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `A` *extends* `unknown`\[] | the wrapped function's argument tuple. | | `T` | the wrapped function's return type. | | `R` | `qualify`'s return type; the modeled error `E` is `Exclude` (its `Defect` arm, if any, is subtracted). | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `fn` | (...`args`) => `T` | the throwing function to wrap. | | `qualify` | (`cause`, `defect`) => `R` & [`NotThenable`](#notthenable)<`R`> | triages a thrown `cause` into a modeled `E`, or marks it unmodeled by returning `defect(cause)` (the helper passed as its second arg). | #### Returns a function with the same arguments returning `Result`. (...`args`) => `Result`<`T`, `Exclude`<`R`, `Defect`>> #### Remarks `qualify` **must** triage every thrown cause into a modeled error `E` or a `Defect` (via the injected `defect` helper, its second argument) — there is no path that leaves `unknown` in `E`. A throw inside `qualify` itself is treated as a `Defect`. `qualify` is **synchronous**: an `async` qualify is rejected at compile time ([NotThenable](#notthenable)) — its `Promise` would land in `E` un-triaged — and a thenable slipped past the types at runtime becomes a `Defect` (never an `Err(Promise)`), its orphaned rejection silenced. `fn` is **synchronous** too. An `async` `fn` rejects *after* this boundary has already returned, so its rejection could never reach `qualify`: it becomes a `Defect` (never `Ok()`) and the orphaned rejection is silenced rather than left to float. Reach for [fromPromise](#frompromise) to wrap async work. The modeled error type is `Exclude` — the `Defect` arm of `qualify`'s return is **subtracted** from `E`, never inferred into it. So a `qualify` that returns *only* `defect(cause)` yields `E = never` (a Defect is out-of-band and must not pollute the error channel); reach for [fromSafeThrowable](#fromsafethrowable) when every throw is a Defect. #### Example ```ts import { fromThrowable } from "unthrown"; // Model the parse failure as an `Err`, everything unexpected as a `Defect`. const parse = fromThrowable( (text: string) => JSON.parse(text) as unknown, (cause, defect) => cause instanceof SyntaxError ? ("invalid_json" as const) : defect(cause), ); parse('{"ok":true}').getOr(null); // => { ok: true } parse("nope"); // => Err("invalid_json") ``` ## Do-notation ### Do() ```ts function Do(): Result<{ }, never>; ``` Defined in: [packages/core/src/do.ts:48](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/do.ts#L48) Start a do-notation chain with an empty object scope, grown step by step with `bind` (for `Result`-returning steps) and `let` (for pure values). #### Returns `Result`<{ }, `never`> #### Remarks Capitalised because `do` is a reserved word. Each step receives the scope accumulated so far; the error types union across `bind`s, and a throw in any step becomes a `Defect`. To go asynchronous, lift the chain with `toAsync()` (then a `bind` may return an `AsyncResult`). #### Examples ```ts import { Do, Ok } from "unthrown"; const result = Do() .bind("user", () => findUser(id)) // Result .bind("org", ({ user }) => findOrg(user.orgId)) // Result .let("label", ({ user, org }) => `${user.name} @ ${org.name}`) .map(({ user, org, label }) => render(user, org, label)); // Result ``` ```ts import { Do, Ok, Err } from "unthrown"; // Ok path — the scope accumulates: Do() .bind("a", () => Ok(2)) .let("b", ({ a }) => a * 10) .map(({ a, b }) => a + b); // => Ok(22) // Err path — the first Err short-circuits the rest: Do() .bind("a", () => Err("boom")) .let("b", ({ a }) => a); // => Err("boom") ``` *** ### DoAsync() ```ts function DoAsync(): AsyncResult<{ }, never>; ``` Defined in: [packages/core/src/do.ts:76](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/do.ts#L76) Start an **asynchronous** do-notation chain with an empty object scope — the pre-lifted form of [Do](#do), sparing you `Do().toAsync()`. #### Returns `AsyncResult`<{ }, `never`> #### Remarks From here a `bind` may return a `Result` **or** an `AsyncResult`; the scope accumulates exactly as in a sync [Do](#do) chain, and a throw in any step becomes a `Defect`. Named with the `Async` suffix the async free functions carry (`OkAsync`, `allAsync`); the [AsyncResult](#asyncresult) companion aliases it as `AsyncResult.Do` (the namespace already says "async", so the suffix drops). #### Example ```ts import { DoAsync, Ok } from "unthrown"; const result = await DoAsync() .bind("user", () => findUser(id)) // AsyncResult .bind("plan", ({ user }) => Ok(user.plan)) // a sync Result is accepted too .let("label", ({ user, plan }) => `${user.name} on ${plan}`); // Result<{ user: User; plan: Plan; label: string }, NotFound> ``` ## Guards ### isDefect() ```ts function isDefect(r): r is DefectView; ``` Defined in: [packages/core/src/constructors.ts:204](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L204) Type guard: narrow a [Result](#result) to its `Defect` variant, exposing `.cause`. #### Type Parameters | Type Parameter | | ------ | | `T` | | `E` | #### Parameters | Parameter | Type | | ------ | ------ | | `r` | `Result`<`T`, `E`> | #### Returns `r is DefectView` `true` when `r` is a `Defect`. #### Remarks A `Defect` has no public constructor — it only arises at a boundary (e.g. a callback throwing inside a combinator). This guard is how you detect one. #### Example ```ts import { isDefect, Ok } from "unthrown"; // A throw inside a combinator is captured as a Defect: const r = Ok(1).map(() => { throw new Error("boom"); }); isDefect(r); // => true isDefect(Ok(1)); // => false if (isDefect(r)) r.cause; // unknown, narrowed ``` *** ### isErr() ```ts function isErr(r): r is ErrView; ``` Defined in: [packages/core/src/constructors.ts:176](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L176) Type guard: narrow a [Result](#result) to its `Err` variant, exposing `.error`. #### Type Parameters | Type Parameter | | ------ | | `T` | | `E` | #### Parameters | Parameter | Type | | ------ | ------ | | `r` | `Result`<`T`, `E`> | #### Returns `r is ErrView` `true` when `r` is `Err`. #### Example ```ts import { isErr, Ok, Err, type Result } from "unthrown"; isErr(Err("boom")); // => true isErr(Ok(1)); // => false declare const r: Result; if (isErr(r)) r.error; // string, narrowed ``` *** ### isOk() ```ts function isOk(r): r is OkView; ``` Defined in: [packages/core/src/constructors.ts:155](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/constructors.ts#L155) Type guard: narrow a [Result](#result) to its `Ok` variant, exposing `.value`. #### Type Parameters | Type Parameter | | ------ | | `T` | | `E` | #### Parameters | Parameter | Type | | ------ | ------ | | `r` | `Result`<`T`, `E`> | #### Returns `r is OkView` `true` when `r` is `Ok`. #### Example ```ts import { isOk, Ok, Err, type Result } from "unthrown"; isOk(Ok(1)); // => true isOk(Err("boom")); // => false declare const r: Result; if (isOk(r)) r.value; // number, narrowed ``` *** ### isResult() ```ts function isResult(x): x is Result; ``` Defined in: [packages/core/src/core.ts:496](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/core.ts#L496) Type guard: is `x` a [Result](#result) (any of `Ok` / `Err` / `Defect`)? #### Parameters | Parameter | Type | | ------ | ------ | | `x` | `unknown` | #### Returns `x is Result` `true` when `x` is a `Result` produced by this library. #### Remarks Unlike [isOk](#isok-4) / [isErr](#iserr-4) / [isDefect](#isdefect-4), which narrow a value already known to be a `Result`, this narrows from `unknown` — useful at an untyped boundary. It checks the value carries the `Result` prototype (`instanceof` first, falling back to the `Symbol.for("unthrown.Result")` brand the prototype carries — so a `Result` built by **another copy** of unthrown, e.g. the CJS and ESM builds loaded side by side, is still recognised). A look-alike plain object (`{ tag: "Ok" }`) carries neither and is **not** matched. An `AsyncResult` is not a `Result` and returns `false`. #### Example ```ts import { isResult, Ok, P } from "unthrown"; isResult(Ok(1)); // => true isResult({ tag: "Ok" }); // => false (look-alike, wrong prototype) isResult(Ok(1).toAsync()); // => false (an AsyncResult is not a Result) const x: unknown = Ok(1); if (isResult(x)) // `E` is `unknown` here — an untyped boundary has no cases to enumerate, // so the `P._` escape hatch is the only arm that can terminate the match: // oxlint-disable-next-line unthrown/no-catch-all-pattern -- untyped boundary: `E` is `unknown` x.match({ ok: () => 1, errCases: (m) => m.with(P._, () => 0), defect: () => -1, }); ``` ## Tagged errors ### TaggedError() ```ts function TaggedError(tag, options?): TaggedErrorConstructor; ``` Defined in: [packages/core/src/tagged.ts:110](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/tagged.ts#L110) Build a base class for a tagged error — a class extending `Error` with a `_tag` string discriminant, in the style of Effect's `Data.TaggedError`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `Tag` *extends* `string` | the string literal discriminant. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `tag` | `Tag` | the discriminant value; also the default error `name`. | | `options?` | { `name?`: `string`; } | optional overrides. `options.name` sets `Error.name` independently of `tag` (defaults to `tag`). | | `options.name?` | `string` | - | #### Returns [`TaggedErrorConstructor`](#taggederrorconstructor)<`Tag`> #### Remarks Extend the returned class to declare a concrete error. Supply the payload with an instantiation expression; omit it for a payload-less error. The `message` is **not** a payload field — it is the human string owned by `Error`, not structured data, so it is reserved. Define it once per subclass the standard way, `override message = "…"` (it may interpolate the payload via `this`, which the base populates before the subclass field initialiser runs); a payload `message` is rejected at compile time, so contextual detail lives in typed fields, never baked into per-call prose. The `_tag` always reflects `tag` and cannot be overridden by the payload. `name` is likewise reserved — it is the display label (set it with `options.name`); a payload `name` is rejected at compile time (and excluded from the instance type), so it can't shadow `Error.name`. `stack` is reserved the same way — it is `Error`'s trace, and even an untyped payload `stack` cannot clobber the real one. `cause` is deliberately **not** reserved: `Error.cause` is typed `unknown`, so a payload `cause` (e.g. a wrapped driver error) is a legitimate, *narrowing* structured field. The matching half of the convention is `P.tag(t)` — the pattern constructor on the `P` namespace, which builds the `{ _tag: t }` pattern this factory's `_tag` is selected by (there is no standalone `tag` export). `_tag` is the discriminant matched by `P.tag` in the error combinators (`result.mapErrCases((matcher) => matcher.with(P.tag("NotFound"), …))`) and in `match`'s `errCases` handler; `Error.name` is the human-facing label in stack traces and logs. By default they coincide, but they can be **decoupled** with `options.name` — so a tag can be namespaced for collision-safety (`"@my-lib/RetryableError"`) without that slash-prefixed string leaking into `Error.name`: ```ts class RetryableError extends TaggedError("@my-lib/RetryableError", { name: "RetryableError", }) { override message = "operation failed; safe to retry"; } const e = new RetryableError(); e._tag; // "@my-lib/RetryableError" — namespaced discriminant e.name; // "RetryableError" — clean display name e.message; // "operation failed; safe to retry" — the standard Error.message ``` #### Example ```ts class NotFound extends TaggedError("NotFound") {} class HttpError extends TaggedError("HttpError")<{ status: number }> {} new NotFound()._tag; // => "NotFound" new HttpError({ status: 500 }).status; // => 500 ``` ## Aggregate ### all() ```ts function all(results): Result }>, ErrOf>; ``` Defined in: [packages/core/src/interop.ts:550](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L550) Collect a tuple/array of [Result](#result)s into a single `Result` of all their success values. #### Type Parameters | Type Parameter | | ------ | | `Rs` *extends* readonly `Result`<`unknown`, `unknown`>\[] | #### Parameters | Parameter | Type | | ------ | ------ | | `results` | readonly \[`Rs`] | #### Returns `Result`<`AllOk`<`Rs`, { \[K in string | number | symbol]: OkOf\ }>, [`ErrOf`](#errof)<`Rs`\[`number`]>> #### Remarks Short-circuits on the **first** `Err` (later entries are not inspected for their error); any `Defect` present **dominates**, winning even over an earlier `Err`. A **fixed tuple** keeps its positional types — `all([Ok(1), Ok("a")])` is `Result<[number, string], …>` — while a **dynamic array** `Result[]` collapses to `Result` with no cast. For a **record** keyed by name, use [allFromDict](#allfromdict). #### Example ```ts import { all, Ok, Err } from "unthrown"; all([Ok(1), Ok("a"), Ok(true)]).get(); // => [1, "a", true] (typed [number, string, boolean]) all([Ok(1), Err("e"), Ok(3)]); // => Err("e") (short-circuits on the first Err) ``` *** ### allAsync() ```ts function allAsync(results): AsyncResult }>, AsyncErrOf>; ``` Defined in: [packages/core/src/interop.ts:611](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L611) The asynchronous counterpart of [all](#all): combine a tuple/array of [AsyncResult](#asyncresult)s into one `AsyncResult` of all their success values. #### Type Parameters | Type Parameter | | ------ | | `Rs` *extends* readonly `AsyncResult`<`unknown`, `unknown`>\[] | #### Parameters | Parameter | Type | | ------ | ------ | | `results` | readonly \[`Rs`] | #### Returns `AsyncResult`<`AllOk`<`Rs`, { \[K in string | number | symbol]: AsyncOkOf\ }>, [`AsyncErrOf`](#asyncerrof)<`Rs`\[`number`]>> #### Remarks The inputs are resolved **concurrently** (order preserved); the resolved `Result`s are then folded with the same rules as [all](#all) — first `Err` short-circuits, any `Defect` dominates. As ever, the returned `AsyncResult`'s internal promise never rejects. For a **record**, use [allFromDictAsync](#allfromdictasync). #### Example ```ts import { allAsync, fromSafePromise } from "unthrown"; const both = allAsync([ fromSafePromise(Promise.resolve(1)), fromSafePromise(Promise.resolve(2)), ]); (await both).get(); // => [1, 2] ``` *** ### allFromDict() ```ts function allFromDict(results): Result<{ [K in string | number | symbol]: OkOf }, ErrOf>; ``` Defined in: [packages/core/src/interop.ts:579](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L579) Collect a **record** of [Result](#result)s into a single `Result` of a record of their success values — `allFromDict({ a: Result, b: Result })` is `Result<{ a: A; b: B }, E>`. The named counterpart of [all](#all), for parallel work you'd rather not tuple. #### Type Parameters | Type Parameter | | ------ | | `R` *extends* `ResultRecord` | #### Parameters | Parameter | Type | | ------ | ------ | | `results` | `R` | #### Returns `Result`<{ \[K in string | number | symbol]: OkOf\ }, [`ErrOf`](#errof)<`R`\[keyof `R`]>> #### Remarks Same folding rules as [all](#all): first `Err` short-circuits, any `Defect` dominates. This is **not** error accumulation. #### Example ```ts import { allFromDict, Ok, Err } from "unthrown"; allFromDict({ id: Ok(1), name: Ok("ada") }).get(); // => { id: 1, name: "ada" } allFromDict({ id: Ok(1), name: Err("missing") }); // => Err("missing") ``` *** ### allFromDictAsync() ```ts function allFromDictAsync(results): AsyncResult<{ [K in string | number | symbol]: AsyncOkOf }, AsyncErrOf>; ``` Defined in: [packages/core/src/interop.ts:654](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/interop.ts#L654) The asynchronous counterpart of [allFromDict](#allfromdict): combine a record of [AsyncResult](#asyncresult)s into one `AsyncResult` of a record of their values. #### Type Parameters | Type Parameter | | ------ | | `R` *extends* `AsyncResultRecord` | #### Parameters | Parameter | Type | | ------ | ------ | | `results` | `R` | #### Returns `AsyncResult`<{ \[K in string | number | symbol]: AsyncOkOf\ }, [`AsyncErrOf`](#asyncerrof)<`R`\[keyof `R`]>> #### Remarks Resolved concurrently (order preserved), folded with the [all](#all) rules, and the internal promise never rejects. #### Example ```ts import { allFromDictAsync, fromSafePromise } from "unthrown"; const both = allFromDictAsync({ a: fromSafePromise(Promise.resolve(1)), b: fromSafePromise(Promise.resolve("x")), }); (await both).get(); // => { a: 1, b: "x" } ``` ## Errors ### GetError Defined in: [packages/core/src/core.ts:59](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/core.ts#L59) Thrown by a [Result](#result)'s `get` / `getErr` when the assertion is wrong on a *modeled* result — `get()` on an `Err`, or `getErr()` on an `Ok`. #### Remarks The offending value is exposed two ways: the typed [GetError.error](#error) property for programmatic access, and the standard `Error.cause` for the runtime and devtools to chain — when `E` is an `Error` (e.g. a `TaggedError`) its original stack is printed under "caused by". A `Defect` is never wrapped in a `GetError`: its original cause is re-thrown (with its original stack) instead. `get()` and `getErr()` are type-gated (`this: Result` / `Result`), so the wrong-variant branch that throws this is unreachable through well-typed code — it remains only as a defensive guard against unsound runtime misuse (e.g. an `as` cast past the gate). #### Extends * `Error` #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `E` | `unknown` | the type of the [GetError.error](#error) it carries. | #### Constructors ##### Constructor ```ts new GetError(error): GetError; ``` Defined in: [packages/core/src/core.ts:65](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/core.ts#L65) ###### Parameters | Parameter | Type | | ------ | ------ | | `error` | `E` | ###### Returns [`GetError`](#geterror)<`E`> ###### Overrides ```ts Error.constructor ``` #### Properties | Property | Modifier | Type | Description | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | | `cause?` | `public` | `unknown` | - | `Error.cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 | | `error` | `readonly` | `E` | The offending value: the `Err` error for `get()`, or the `Ok` value for `getErr()`. | - | [packages/core/src/core.ts:64](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/core.ts#L64) | | `message` | `public` | `string` | - | `Error.message` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1075 | | `name` | `public` | `string` | - | `Error.name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 | | `stack?` | `public` | `string` | - | `Error.stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 | | `stackTraceLimit` | `static` | `number` | The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured *after* the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | `Error.stackTraceLimit` | node\_modules/.pnpm/@types+node@26.1.2/node\_modules/@types/node/globals.d.ts:67 | #### Methods ##### captureStackTrace() ```ts static captureStackTrace(targetObject, constructorOpt?): void; ``` Defined in: node\_modules/.pnpm/@types+node@26.1.2/node\_modules/@types/node/globals.d.ts:51 Creates a `.stack` property on `targetObject`, which when accessed returns a string representing the location in the code at which `Error.captureStackTrace()` was called. ```js const myObject = {}; Error.captureStackTrace(myObject); myObject.stack; // Similar to `new Error().stack` ``` The first line of the trace will be prefixed with `${myObject.name}: ${myObject.message}`. The optional `constructorOpt` argument accepts a function. If given, all frames above `constructorOpt`, including `constructorOpt`, will be omitted from the generated stack trace. The `constructorOpt` argument is useful for hiding implementation details of error generation from the user. For instance: ```js function a() { b(); } function b() { c(); } function c() { // Create an error without stack trace to avoid calculating the stack trace twice. const { stackTraceLimit } = Error; Error.stackTraceLimit = 0; const error = new Error(); Error.stackTraceLimit = stackTraceLimit; // Capture the stack trace above function b Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace throw error; } a(); ``` ###### Parameters | Parameter | Type | | ------ | ------ | | `targetObject` | `object` | | `constructorOpt?` | `Function` | ###### Returns `void` ###### Inherited from ```ts Error.captureStackTrace ``` ##### prepareStackTrace() ```ts static prepareStackTrace(err, stackTraces): any; ``` Defined in: node\_modules/.pnpm/@types+node@26.1.2/node\_modules/@types/node/globals.d.ts:55 ###### Parameters | Parameter | Type | | ------ | ------ | | `err` | `Error` | | `stackTraces` | `CallSite`\[] | ###### Returns `any` ###### See https://v8.dev/docs/stack-trace-api#customizing-stack-traces ###### Inherited from ```ts Error.prepareStackTrace ``` *** ### NonExhaustiveError Defined in: [packages/core/src/matcher.ts:242](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L242) Thrown by `.run()` / `.exhaustive()` when no arm matched the value. For well-typed callers the match is exhaustive by construction, so this is only reachable by a value that slipped past the types (a widened cast, a raw-JS caller); inside the error combinators the throw-to-defect net converts it to a `Defect`, and at the `match` edge it surfaces (a genuinely unmodeled value is a bug). #### Extends * `Error` #### Constructors ##### Constructor ```ts new NonExhaustiveError(input): NonExhaustiveError; ``` Defined in: [packages/core/src/matcher.ts:245](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L245) ###### Parameters | Parameter | Type | | ------ | ------ | | `input` | `unknown` | ###### Returns [`NonExhaustiveError`](#nonexhaustiveerror) ###### Overrides ```ts Error.constructor ``` #### Properties | Property | Modifier | Type | Description | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | | `cause?` | `public` | `unknown` | - | `Error.cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 | | `input` | `readonly` | `unknown` | The value no arm matched. | - | [packages/core/src/matcher.ts:244](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/core/src/matcher.ts#L244) | | `message` | `public` | `string` | - | `Error.message` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1075 | | `name` | `public` | `string` | - | `Error.name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 | | `stack?` | `public` | `string` | - | `Error.stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 | | `stackTraceLimit` | `static` | `number` | The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured *after* the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | `Error.stackTraceLimit` | node\_modules/.pnpm/@types+node@26.1.2/node\_modules/@types/node/globals.d.ts:67 | #### Methods ##### captureStackTrace() ```ts static captureStackTrace(targetObject, constructorOpt?): void; ``` Defined in: node\_modules/.pnpm/@types+node@26.1.2/node\_modules/@types/node/globals.d.ts:51 Creates a `.stack` property on `targetObject`, which when accessed returns a string representing the location in the code at which `Error.captureStackTrace()` was called. ```js const myObject = {}; Error.captureStackTrace(myObject); myObject.stack; // Similar to `new Error().stack` ``` The first line of the trace will be prefixed with `${myObject.name}: ${myObject.message}`. The optional `constructorOpt` argument accepts a function. If given, all frames above `constructorOpt`, including `constructorOpt`, will be omitted from the generated stack trace. The `constructorOpt` argument is useful for hiding implementation details of error generation from the user. For instance: ```js function a() { b(); } function b() { c(); } function c() { // Create an error without stack trace to avoid calculating the stack trace twice. const { stackTraceLimit } = Error; Error.stackTraceLimit = 0; const error = new Error(); Error.stackTraceLimit = stackTraceLimit; // Capture the stack trace above function b Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace throw error; } a(); ``` ###### Parameters | Parameter | Type | | ------ | ------ | | `targetObject` | `object` | | `constructorOpt?` | `Function` | ###### Returns `void` ###### Inherited from ```ts Error.captureStackTrace ``` ##### prepareStackTrace() ```ts static prepareStackTrace(err, stackTraces): any; ``` Defined in: node\_modules/.pnpm/@types+node@26.1.2/node\_modules/@types/node/globals.d.ts:55 ###### Parameters | Parameter | Type | | ------ | ------ | | `err` | `Error` | | `stackTraces` | `CallSite`\[] | ###### Returns `any` ###### See https://v8.dev/docs/stack-trace-api#customizing-stack-traces ###### Inherited from ```ts Error.prepareStackTrace ``` --- --- url: /unthrown/api/vitest.md --- **@unthrown/vitest** *** # @unthrown/vitest ## Type Aliases ### UnthrownMatchers ```ts type UnthrownMatchers = object; ``` Defined in: [index.ts:460](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L460) The matchers `@unthrown/vitest` contributes to Vitest's `expect`. For an `AsyncResult`, `await` the assertion; `toBeOkWith` compares deeply. #### Remarks Import the package once (e.g. in a test setup file) to register the matchers and pull in this type augmentation. For an `AsyncResult` the assertion is asynchronous and must be `await`ed. A forgotten `await` does not pass silently: an `afterEach` hook (registered on import, see [failOnForgottenAwait](#failonforgottenawait)) fails the test with an explicit message naming the matchers still pending when the test ended. #### Example ```ts import "@unthrown/vitest"; import { Ok, fromSafePromise } from "unthrown"; import { expect, test } from "vitest"; test("sync", () => { expect(Ok(1)).toBeOkWith(1); }); test("async", async () => { await expect(fromSafePromise(Promise.resolve(1))).toBeOk(); }); ``` #### See [The Testing guide](https://btravstack.github.io/unthrown/how-to/test-with-vitest) #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `R` | `unknown` | the assertion's chaining return type. | #### Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `toBeDefect` | () => `R` | `expect(result).toBeDefect()` asserts the result is a `Defect`. | [index.ts:482](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L482) | | `toBeDefectWith` | (`expected`) => `R` | Assert a `Defect` whose `cause` is deeply equal to `expected`. `expected` is typed `unknown` because **a defect's cause is `unknown` by design**: nothing reaches that channel through a typed error, so there is no tighter type to give it and no tag-aware variant to add. An asymmetric matcher works as elsewhere: `expect(result).toBeDefectWith(expect.any(TypeError))`. | [index.ts:492](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L492) | | `toBeErr` | () => `R` | `expect(Err("nope")).toBeErr()` asserts the result is `Err`, regardless of the error. | [index.ts:466](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L466) | | `toBeErrTagged` | (`tag`, `expected?`) => `R` | Assert an `Err` whose error has `_tag === tag`. Optionally pass `expected` to also match the error's payload — its own props minus the keys `TaggedError` reserves (`_tag`, `name`, `message`, `stack`), so a subclass's `override message = "…"` does not leak into an exact assertion. A plain object matches exactly, an asymmetric matcher (e.g. `expect.objectContaining(...)`) matches partially. An explicitly-passed `undefined` asserts the payload equals `undefined` (it does not degrade to tag-only). `expect(result).toBeErrTagged("NotFound", { id })` asserts the tag and payload. | [index.ts:479](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L479) | | `toBeErrWith` | (`expected`) => `R` | - | [index.ts:480](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L480) | | `toBeOk` | () => `R` | `expect(Ok(1)).toBeOk()` asserts the result is `Ok`, regardless of value. | [index.ts:462](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L462) | | `toBeOkWith` | (`value`) => `R` | `expect(Ok(1)).toBeOkWith(1)` asserts the result is `Ok` with a deeply-equal value. | [index.ts:464](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L464) | ## Variables ### toBeDefect ```ts const toBeDefect: (this, received, expected?) => ExpectationResult; ``` Defined in: [index.ts:402](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L402) #### Parameters | Parameter | Type | | ------ | ------ | | `this` | `MatcherState` | | `received` | `unknown` | | `expected?` | `unknown` | #### Returns `ExpectationResult` *** ### toBeDefectWith ```ts const toBeDefectWith: (this, received, expected?) => ExpectationResult; ``` Defined in: [index.ts:409](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L409) #### Parameters | Parameter | Type | | ------ | ------ | | `this` | `MatcherState` | | `received` | `unknown` | | `expected?` | `unknown` | #### Returns `ExpectationResult` *** ### toBeErr ```ts const toBeErr: (this, received, expected?) => ExpectationResult; ``` Defined in: [index.ts:343](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L343) #### Parameters | Parameter | Type | | ------ | ------ | | `this` | `MatcherState` | | `received` | `unknown` | | `expected?` | `unknown` | #### Returns `ExpectationResult` *** ### toBeErrWith ```ts const toBeErrWith: (this, received, expected?) => ExpectationResult; ``` Defined in: [index.ts:350](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L350) #### Parameters | Parameter | Type | | ------ | ------ | | `this` | `MatcherState` | | `received` | `unknown` | | `expected?` | `unknown` | #### Returns `ExpectationResult` *** ### toBeOk ```ts const toBeOk: (this, received, expected?) => ExpectationResult; ``` Defined in: [index.ts:329](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L329) #### Parameters | Parameter | Type | | ------ | ------ | | `this` | `MatcherState` | | `received` | `unknown` | | `expected?` | `unknown` | #### Returns `ExpectationResult` *** ### toBeOkWith ```ts const toBeOkWith: (this, received, expected?) => ExpectationResult; ``` Defined in: [index.ts:336](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L336) #### Parameters | Parameter | Type | | ------ | ------ | | `this` | `MatcherState` | | `received` | `unknown` | | `expected?` | `unknown` | #### Returns `ExpectationResult` ## Functions ### failOnForgottenAwait() ```ts function failOnForgottenAwait(context?): void; ``` Defined in: [index.ts:231](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L231) The check behind the registered `afterEach` hook: when async matcher assertions are still pending at the end of a test — a forgotten `await` — it abandons them (so they cannot late-fire as unhandled rejections) and throws an error naming the un-awaited matchers, failing that test. #### Parameters | Parameter | Type | | ------ | ------ | | `context?` | `HookContext` | #### Returns `void` #### Remarks You never need to call this yourself: importing the package registers it as an `afterEach` hook alongside the matchers. It is exported so the mechanism itself is testable. *** ### toBeErrTagged() ```ts function toBeErrTagged( this, received, tag, expected?): ExpectationResult; ``` Defined in: [index.ts:360](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/vitest/src/index.ts#L360) #### Parameters | Parameter | Type | | ------ | ------ | | `this` | `MatcherState` | | `received` | `unknown` | | `tag` | `string` | | `expected?` | `unknown` | #### Returns `ExpectationResult` --- --- url: /unthrown/api/effect.md --- **@unthrown/effect** *** # @unthrown/effect ## Functions ### fromEffect() ```ts function fromEffect(effect): AsyncResult; ``` Defined in: [index.ts:214](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/effect/src/index.ts#L214) Run an `Effect` and collect its outcome as an `AsyncResult`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `effect` | `Effect`<`T`, `E`> | the effect to run. | #### Returns `AsyncResult`<`T`, `E`> #### Remarks The effect must need no environment (`R = never`). It is run to an `Exit` (which never rejects), then folded with [fromExit](#fromexit): success → `Ok`, a modeled failure → `Err`, a die/interruption → `Defect`. The returned `AsyncResult` never throws when awaited. #### Example ```ts import { Effect } from "effect"; import { fromEffect } from "@unthrown/effect"; const result = await fromEffect(Effect.succeed(1)); result.isOk(); // => true ``` *** ### fromEither() ```ts function fromEither(either): Result; ``` Defined in: [index.ts:150](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/effect/src/index.ts#L150) Convert an Effect `Either` into a `Result`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `either` | `Either`<`T`, `E`> | the either to convert. | #### Returns `Result`<`T`, `E`> #### Remarks `Right → Ok`, `Left → Err`. An `Either` carries no Defect, so the result is never a `Defect`. #### Example ```ts import { Either } from "effect"; import { fromEither } from "@unthrown/effect"; const result = fromEither(Either.right(1)); result.isOk(); // => true ``` *** ### fromExit() ```ts function fromExit(exit): Result; ``` Defined in: [index.ts:80](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/effect/src/index.ts#L80) Convert an Effect `Exit` into a `Result` — the inverse of [toExit](#toexit). #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `exit` | `Exit`<`T`, `E`> | the exit to convert. | #### Returns `Result`<`T`, `E`> #### Remarks `Exit.Success → Ok`. For a failure, the enclosing `Cause` is reduced: * a `Cause.die` becomes a `Defect`, * otherwise a `Cause.fail` becomes the modeled `Err`, * a pure interruption (or empty cause) becomes a `Defect`. A `Defect` **dominates** a modeled failure in a composite cause — the same rule unthrown's `all` uses, on the principle that an unexpected failure is the more severe signal. #### Example ```ts import { Exit } from "effect"; import { fromExit } from "@unthrown/effect"; const result = fromExit(Exit.succeed(1)); result.isOk(); // => true ``` *** ### toEffect() #### Call Signature ```ts function toEffect(source): Effect; ``` Defined in: [index.ts:180](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/effect/src/index.ts#L180) Lift a `Result` or `AsyncResult` into an `Effect`. ##### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | ##### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `source` | `Result`<`T`, `E`> | the result, or async result, to lift. | ##### Returns `Effect`<`T`, `E`> ##### Remarks `Ok → Effect.succeed`, `Err → Effect.fail`, `Defect → Effect.die`. The resulting `Effect` needs no environment (`R = never`). An `AsyncResult` is awaited inside the effect (it never rejects), so this is the `AsyncResult → Effect` direction too. ##### Example ```ts import { Effect } from "effect"; import { Ok } from "unthrown"; import { toEffect } from "@unthrown/effect"; const effect = toEffect(Ok(1)); await Effect.runPromise(effect); // => 1 ``` #### Call Signature ```ts function toEffect(source): Effect; ``` Defined in: [index.ts:181](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/effect/src/index.ts#L181) Lift a `Result` or `AsyncResult` into an `Effect`. ##### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | ##### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `source` | `AsyncResult`<`T`, `E`> | the result, or async result, to lift. | ##### Returns `Effect`<`T`, `E`> ##### Remarks `Ok → Effect.succeed`, `Err → Effect.fail`, `Defect → Effect.die`. The resulting `Effect` needs no environment (`R = never`). An `AsyncResult` is awaited inside the effect (it never rejects), so this is the `AsyncResult → Effect` direction too. ##### Example ```ts import { Effect } from "effect"; import { Ok } from "unthrown"; import { toEffect } from "@unthrown/effect"; const effect = toEffect(Ok(1)); await Effect.runPromise(effect); // => 1 ``` *** ### toEither() ```ts function toEither(result, onDefect): Either; ``` Defined in: [index.ts:121](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/effect/src/index.ts#L121) Convert a `Result` into an Effect `Either`, triaging any Defect. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `result` | `Result`<`T`, `E`> | the result to convert. | | `onDefect` | (`cause`) => `E` | folds a Defect's unknown cause into a modeled `E`. | #### Returns `Either`<`T`, `E`> #### Remarks `Either` has no Defect channel, so a `Defect` cannot pass through silently — `onDefect` **must** fold its cause into a modeled error `E` (a `Left`). This is the boundary-qualification rule (Thesis #3) applied on the way out: `Ok → Right`, `Err → Left`, `Defect → Left(onDefect(cause))`. #### Example ```ts import { fromThrowable } from "unthrown"; import { toEither } from "@unthrown/effect"; // Mint a Defect, then convert: it has no home in Either, so onDefect folds it into E. const defective = fromThrowable((): number => { throw new Error("boom"); }, (cause, defect) => defect(cause))(); const either = toEither(defective, (cause) => `bug: ${String(cause)}`); either._tag; // => "Left" — carrying "bug: Error: boom" ``` *** ### toExit() ```ts function toExit(result): Exit; ``` Defined in: [index.ts:43](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/effect/src/index.ts#L43) Convert a `Result` into an Effect `Exit` — a **bijection**, since both carry three channels. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `result` | `Result`<`T`, `E`> | the result to convert. | #### Returns `Exit`<`T`, `E`> #### Remarks `Ok → Exit.succeed`, `Err → Exit.fail` (a modeled `Cause.fail`), and `Defect → Exit.die` (an unexpected `Cause.die`). Round-trips with [fromExit](#fromexit). #### Example ```ts import { Ok } from "unthrown"; import { toExit } from "@unthrown/effect"; toExit(Ok(1)); // Exit.succeed(1) ``` --- --- url: /unthrown/api/neverthrow.md --- **@unthrown/neverthrow** *** # @unthrown/neverthrow ## Functions ### fromNeverthrow() ```ts function fromNeverthrow(result): Result; ``` Defined in: [index.ts:83](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/neverthrow/src/index.ts#L83) Convert a neverthrow `Result` into a `Result`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `result` | `Result`<`T`, `E`> | the neverthrow result to convert. | #### Returns `Result`<`T`, `E`> #### Remarks `Ok → Ok`, `Err → Err`. neverthrow carries no Defect, so the result is never a `Defect`. #### Example ```ts import { ok } from "neverthrow"; import { fromNeverthrow } from "@unthrown/neverthrow"; const result = fromNeverthrow(ok(1)); result.isOk(); // => true ``` *** ### fromNeverthrowAsync() ```ts function fromNeverthrowAsync(resultAsync): AsyncResult; ``` Defined in: [index.ts:146](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/neverthrow/src/index.ts#L146) Convert a neverthrow `ResultAsync` into an `AsyncResult`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `resultAsync` | `ResultAsync`<`T`, `E`> | the neverthrow async result to convert. | #### Returns `AsyncResult`<`T`, `E`> #### Remarks The async counterpart of [fromNeverthrow](#fromneverthrow). A modeled `Err` stays an `Err`; an *unexpected* rejection inside the neverthrow chain becomes a `Defect`. The returned `AsyncResult` never throws when awaited. #### Example ```ts import { okAsync } from "neverthrow"; import { fromNeverthrowAsync } from "@unthrown/neverthrow"; const result = await fromNeverthrowAsync(okAsync(1)); result.isOk(); // => true ``` *** ### toNeverthrow() ```ts function toNeverthrow(result, onDefect): Result; ``` Defined in: [index.ts:51](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/neverthrow/src/index.ts#L51) Convert a `Result` into a neverthrow `Result`, triaging any Defect. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `result` | `Result`<`T`, `E`> | the result to convert. | | `onDefect` | (`cause`) => `E` | folds a Defect's unknown cause into a modeled `E`. | #### Returns `Result`<`T`, `E`> #### Remarks neverthrow has no Defect channel, so `onDefect` **must** fold a `Defect`'s cause into a modeled error `E` (an `Err`). `Ok → Ok`, `Err → Err`, `Defect → Err(onDefect(cause))`. #### Example ```ts import { fromThrowable } from "unthrown"; import { toNeverthrow } from "@unthrown/neverthrow"; // Mint a Defect, then convert: it has no home in neverthrow, so onDefect folds it into E. const defective = fromThrowable((): number => { throw new Error("boom"); }, (cause, defect) => defect(cause))(); const nt = toNeverthrow(defective, (cause) => `bug: ${String(cause)}`); nt.isErr(); // => true — the Err carries "bug: Error: boom" ``` *** ### toNeverthrowAsync() ```ts function toNeverthrowAsync(asyncResult, onDefect): ResultAsync; ``` Defined in: [index.ts:116](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/neverthrow/src/index.ts#L116) Convert an `AsyncResult` into a neverthrow `ResultAsync`, triaging any Defect. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `asyncResult` | `AsyncResult`<`T`, `E`> | the async result to convert. | | `onDefect` | (`cause`) => `E` | folds a Defect's unknown cause into a modeled `E`. | #### Returns `ResultAsync`<`T`, `E`> #### Remarks The async counterpart of [toNeverthrow](#toneverthrow): `onDefect` is required for the same reason. The `AsyncResult` is awaited (it never rejects) and each settled `Result` is converted. A throwing `onDefect` surfaces as a rejection of the returned `ResultAsync`'s inner promise — neverthrow's own failure mode; do not throw from triage. #### Example ```ts import { fromSafePromise } from "unthrown"; import { toNeverthrowAsync } from "@unthrown/neverthrow"; // A rejection inside fromSafePromise is a Defect; onDefect folds it into E on the way out. const defective = fromSafePromise(Promise.reject(new Error("boom"))); const result = await toNeverthrowAsync(defective, (cause) => `bug: ${String(cause)}`); result.isErr(); // => true — the Err carries "bug: Error: boom" ``` --- --- url: /unthrown/api/boxed.md --- **@unthrown/boxed** *** # @unthrown/boxed ## Functions ### fromBoxed() ```ts function fromBoxed(result): Result; ``` Defined in: [index.ts:78](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/boxed/src/index.ts#L78) Convert a Boxed `Result` into a `Result`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `result` | `Result`<`T`, `E`> | the Boxed result to convert. | #### Returns `Result`<`T`, `E`> #### Remarks `Result.Ok → Ok`, `Result.Error → Err`. Boxed's `Result` carries no Defect, so the result is never a `Defect`. #### Example ```ts import { Result as BoxedResult } from "@bloodyowl/boxed"; import { fromBoxed } from "@unthrown/boxed"; const result = fromBoxed(BoxedResult.Ok(1)); result.isOk(); // => true ``` *** ### fromBoxedFuture() ```ts function fromBoxedFuture(future): AsyncResult; ``` Defined in: [index.ts:164](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/boxed/src/index.ts#L164) Convert a Boxed `Future` into an `AsyncResult`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `future` | `Future`<`Result`<`T`, `E`>> | the Boxed future to convert. | #### Returns `AsyncResult`<`T`, `E`> #### Remarks The async counterpart of [fromBoxed](#fromboxed). A `Result.Error` inside the future stays an `Err`. Boxed's `Future` has no failure channel of its own — `Future.toPromise()` does not reject — so in practice no `Defect` arises here; the `fromSafePromise` boundary is a defensive net that would only capture one if a future somehow rejected. The returned `AsyncResult` never throws when awaited. #### Example ```ts import { Future, Result as BoxedResult } from "@bloodyowl/boxed"; import { fromBoxedFuture } from "@unthrown/boxed"; const result = await fromBoxedFuture(Future.value(BoxedResult.Ok(1))); result.isOk(); // => true ``` *** ### toBoxed() ```ts function toBoxed(result, onDefect): Result; ``` Defined in: [index.ts:46](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/boxed/src/index.ts#L46) Convert a `Result` into a Boxed `Result`, triaging any Defect. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `result` | `Result`<`T`, `E`> | the result to convert. | | `onDefect` | (`cause`) => `E` | folds a Defect's unknown cause into a modeled `E`. | #### Returns `Result`<`T`, `E`> #### Remarks Boxed's `Result` has no Defect channel, so `onDefect` **must** fold a `Defect`'s cause into a modeled error `E` (an `Error`). `Ok → Result.Ok`, `Err → Result.Error`, `Defect → Result.Error(onDefect(cause))`. #### Example ```ts import { fromThrowable } from "unthrown"; import { toBoxed } from "@unthrown/boxed"; // Mint a Defect, then convert: it has no home in Boxed's Result, so onDefect folds it into E. const defective = fromThrowable((): number => { throw new Error("boom"); }, (cause, defect) => defect(cause))(); const boxed = toBoxed(defective, (cause) => `bug: ${String(cause)}`); boxed.isError(); // => true — the Error carries "bug: Error: boom" ``` *** ### toBoxedFuture() ```ts function toBoxedFuture(asyncResult, onDefect): Future>; ``` Defined in: [index.ts:114](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/boxed/src/index.ts#L114) Convert an `AsyncResult` into a Boxed `Future`, triaging any Defect. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `T` | the success value type. | | `E` | the modeled error type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `asyncResult` | `AsyncResult`<`T`, `E`> | the async result to convert. | | `onDefect` | (`cause`) => `E` | folds a Defect's unknown cause into a modeled `E`. | #### Returns `Future`<`Result`<`T`, `E`>> #### Remarks The async counterpart of [toBoxed](#toboxed): `onDefect` is required for the same reason. The `AsyncResult` is awaited (it never rejects) and its settled `Result` is converted, then resolved into the `Future`. `onDefect` must not throw: Boxed's `Future` has no failure channel, so a throw is re-raised out-of-band (uncaught) rather than left as a hung `Future`. #### Example ```ts import { fromSafePromise } from "unthrown"; import { toBoxedFuture } from "@unthrown/boxed"; // A rejection inside fromSafePromise is a Defect; onDefect folds it into E on the way out. const defective = fromSafePromise(Promise.reject(new Error("boom"))); const future = toBoxedFuture(defective, (cause) => `bug: ${String(cause)}`); (await future.toPromise()).isError(); // => true — the Error carries "bug: Error: boom" ``` --- --- url: /unthrown/api/standard-schema.md --- **@unthrown/standard-schema** *** # @unthrown/standard-schema ## Type Aliases ### SchemaIssues ```ts type SchemaIssues = readonly StandardSchemaV1.Issue[]; ``` Defined in: [index.ts:21](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/standard-schema/src/index.ts#L21) The error channel both entry points produce: a schema's validation issues. ## Functions ### fromSchema() ```ts function fromSchema(schema): (input) => Result, SchemaIssues>; ``` Defined in: [index.ts:63](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/standard-schema/src/index.ts#L63) Turn a **synchronous** Standard Schema into a validator returning a `Result`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `S` *extends* `StandardSchemaV1`<`unknown`, `unknown`> | the schema type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `schema` | `S` | a Standard Schema validator. | #### Returns a function mapping an input to `Result`. (`input`) => `Result`<`InferOutput`<`S`>, [`SchemaIssues`](#schemaissues)> #### Remarks Validation issues are the modeled error `E` — `Result` — because a failed validation is an *anticipated* outcome, not a Defect. Works with any Standard Schema implementation (Zod, Valibot, ArkType, …). A validator that **throws** (rather than returning issues) becomes a `Defect` — the same boundary behaviour as `fromThrowable`, so an unexpected crash never escapes as a raw exception. If the schema validates **asynchronously** (its `validate` returns a `Promise`), a synchronous `Result` cannot represent the pending work, so this throws a `TypeError` — a deliberate usage error; use [fromSchemaAsync](#fromschemaasync) instead. #### Example ```ts import { fromSchema } from "@unthrown/standard-schema"; const parse = fromSchema(z.string()); parse("hi").get(); // "hi" parse(42).getErr(); // the issues array ``` *** ### fromSchemaAsync() ```ts function fromSchemaAsync(schema): (input) => AsyncResult, SchemaIssues>; ``` Defined in: [index.ts:122](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/standard-schema/src/index.ts#L122) Turn a Standard Schema (sync **or** async) into a validator returning an `AsyncResult`. #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `S` *extends* `StandardSchemaV1`<`unknown`, `unknown`> | the schema type. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `schema` | `S` | a Standard Schema validator. | #### Returns a function mapping an input to `AsyncResult`. (`input`) => `AsyncResult`<`InferOutput`<`S`>, [`SchemaIssues`](#schemaissues)> #### Remarks The async counterpart of [fromSchema](#fromschema): it awaits the schema's `validate`, so it accepts both synchronous and asynchronous schemas. As with every `AsyncResult`, the returned value never rejects — a validator that *throws* (rather than returning issues) becomes a `Defect`. #### Example ```ts import { fromSchemaAsync } from "@unthrown/standard-schema"; const parse = fromSchemaAsync(asyncSchema); (await parse(input)).match({ ok, errCases, defect }); ``` --- --- url: /unthrown/api/prisma.md --- **@unthrown/prisma** *** # @unthrown/prisma ## Classes ### ForeignKeyViolation Defined in: [packages/prisma/src/index.ts:64](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L64) A foreign key constraint was violated (Prisma error `P2003`). #### Extends * `TaggedErrorInstance`<`"ForeignKeyViolation"`, { `cause`: `unknown`; }> #### Constructors ##### Constructor ```ts new ForeignKeyViolation(args): ForeignKeyViolation; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `object` & `object` | ###### Returns [`ForeignKeyViolation`](#foreignkeyviolation) ###### Inherited from ```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:2011 | | `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:91](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L91) 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(args): InvalidCursor; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `object` & `object` | ###### Returns [`InvalidCursor`](#invalidcursor) ###### Inherited from ```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:2011 | | `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:78](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L78) 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(args): RecordNotFound; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `object` & `object` | ###### Returns [`RecordNotFound`](#recordnotfound) ###### Inherited from ```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:2011 | | `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:58](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L58) 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(args): UniqueConstraintViolation; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `object` & `object` | ###### Returns [`UniqueConstraintViolation`](#uniqueconstraintviolation) ###### Inherited from ```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:2011 | | `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:59](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L59) | | `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 ### 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/374b969ef75956f47e3eb294af83d01ca62523f7/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/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/pagination.ts#L22) | | `hasPreviousPage` | `boolean` | [packages/prisma/src/pagination.ts:21](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/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 = 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:47](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/pagination.ts#L47) 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 `String(row.id)`. | [packages/prisma/src/pagination.ts:49](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/pagination.ts#L49) | | `parseCursor()?` | (`cursor`) => `Cursor` | Parse an opaque cursor back into the model's `cursor` input. | [packages/prisma/src/pagination.ts:51](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/pagination.ts#L51) | #### 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). Provide `getCursor` / `parseCursor` for composite keys, or when the selection omits `id`. *** ### CursorPaginator ```ts type CursorPaginator = object; ``` Defined in: [packages/prisma/src/index.ts:299](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L299) 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:305](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L305) | *** ### PrismaQueryError ```ts type PrismaQueryError = | UniqueConstraintViolation | ForeignKeyViolation | RecordNotFound; ``` Defined in: [packages/prisma/src/index.ts:105](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L105) 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 = Omit; ``` Defined in: [packages/prisma/src/index.ts:348](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L348) 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; 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:285](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L285) 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). ## Variables ### unthrownPrisma ```ts const unthrownPrisma: (client) => PrismaClientExtends, never>; tryCount: AsyncResult, never>; tryCreate: AsyncResult, CreateError>; tryCreateMany: AsyncResult, CreateManyError>; tryCreateManyAndReturn: AsyncResult, CreateManyError>; tryDelete: AsyncResult, DeleteError>; tryDeleteMany: AsyncResult, ForeignKeyViolation>; tryFindFirst: AsyncResult, never>; tryFindFirstOrThrow: AsyncResult, RecordNotFound>; tryFindMany: AsyncResult, never>; tryFindUnique: AsyncResult, never>; tryFindUniqueOrThrow: AsyncResult, RecordNotFound>; tryGroupBy: AsyncResult, never>; tryPaginate: CursorPaginator, NonNullable["cursor"]>>; tryUpdate: AsyncResult, UpdateError>; tryUpdateMany: AsyncResult, UpdateManyError>; tryUpdateManyAndReturn: AsyncResult, UpdateManyError>; tryUpsert: AsyncResult, UpsertError>; }; }, { }, { $tryTransaction: TryTransaction; }>>; ``` Defined in: [packages/prisma/src/index.ts:523](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L523) 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`>; `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"`>, [`ForeignKeyViolation`](#foreignkeyviolation)>; `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`>; `tryUpdateMany`: `AsyncResult`<`Result`<`T`, `A`, `"updateMany"`>, `UpdateManyError`>; `tryUpdateManyAndReturn`: `AsyncResult`<`Result`<`T`, `A`, `"updateManyAndReturn"`>, `UpdateManyError`>; `tryUpsert`: `AsyncResult`<`Result`<`T`, `A`, `"upsert"`>, `UpsertError`>; }; }, { }, { `$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(cause, defect): D | PrismaQueryError; ``` Defined in: [packages/prisma/src/index.ts:171](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/prisma/src/index.ts#L171) 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); ``` --- --- url: /unthrown/api/drizzle.md --- **@unthrown/drizzle** *** # @unthrown/drizzle ## Modules * [index](index-1.md) * [node-postgres](node-postgres.md) --- --- url: /unthrown/api/orpc.md --- **@unthrown/orpc** *** # @unthrown/orpc ## Modules * [client](client.md) * [extensions/result](extensions.result.md) * [server](server.md) --- --- url: /unthrown/examples.md description: >- Small runnable packages — code that compiles and is covered by tests, unlike the snippets in the guide. --- # Examples Annotated tours of the runnable packages under [`examples/`](https://github.com/btravstack/unthrown/tree/main/examples). Three of them model one small checkout between them, each showing a different job `unthrown` does; the fourth stands alone. **Unlike the snippets elsewhere in this guide, this code compiles and is covered by tests.** There is no database and no server to start: ```sh git clone https://github.com/btravstack/unthrown.git cd unthrown pnpm install pnpm turbo run test --filter="@unthrown/example-*" pnpm turbo run typecheck --filter="@unthrown/example-*" ``` ## [Checkout domain](/examples/checkout-domain) The error union, `Do`/`bind` sequencing, exhaustive matching, and the defect channel — a thrown payment-provider outage becomes a `Defect`, never an `Err` a caller might mistake for a modelled outcome. ## [Checkout persistence](/examples/checkout-persistence) `@unthrown/prisma` on in-memory SQLite: why a read infers `E = never` (absence is `null`; a database that will not answer is a defect) and a write carries only the P-codes a caller would actually branch on. ## [Checkout API](/examples/checkout-api) The edge: `placeOrder` served over oRPC with `@unthrown/orpc` — one exhaustive `mapErrCases`, a handler with no `try`/`catch`, a provider outage that collapses to `INTERNAL_SERVER_ERROR` instead of an unhandled rejection, and why oRPC's own input validation is a separate concern from `E`. ## [Existing error types](/examples/existing-errors) The adoption case, with **no `TaggedError` anywhere**: a codebase that already has an error convention — a `kind`-discriminated class hierarchy, a plain `code` union from a generated client, and untagged third-party classes — wired to `Result` without rewriting any of it. ## Why these exist as packages rather than snippets Every fenced block in the rest of this guide is written by hand. It is checked by review and nothing else, so it can drift from the library without any build noticing. These cannot. They are workspace packages: they typecheck, their specs run in CI, and they consume `unthrown` and its satellites through their real published entry points rather than a path alias. If the library changes underneath them, something goes red. --- --- url: /unthrown/examples/checkout-domain.md description: >- Errors as values in a small checkout domain — a TaggedError union, Do/bind sequencing, and the defect channel, in a package that compiles and is tested. --- # Checkout domain [`examples/checkout-domain`](https://github.com/btravstack/unthrown/tree/main/examples/checkout-domain) — the modelling half: the error union, the domain function, and the tests that pin both. ```sh pnpm turbo run test --filter=@unthrown/example-checkout-domain ``` ## The signature is the documentation ```ts placeOrder(deps, cartId): AsyncResult; ``` Four business outcomes, named. A caller can see every way this fails without reading the body, and the compiler will not let them forget one. ## What is deliberately *not* in `E` The payment provider timing out. It throws, the pipeline catches it, and it arrives as a `Defect` — never as an `Err` a caller might mistake for a domain outcome. The test pins it: ```ts await expect(result).toBeDefectWith(boom); ``` The cause is the original throw, not a wrapper — `bind` is a plain combinator, so it mints a `Defect` carrying the thrown value as-is. The rule is "would you branch on it?" Nobody writes business logic for a severed connection; they log it and return 500. Modelling it would force an arm at every call site duplicating that same decision. ## Why `OutOfStock` carries fields, not a string ```ts export class OutOfStock extends TaggedError("OutOfStock")<{ sku: string; requested: number; available: number; }> { override message = `${this.requested} × ${this.sku} requested, ${this.available} available`; } ``` The payload is structured so a caller can *use* it — render `available`, offer a partial fulfilment — and the human string is defined once on the class rather than built at each throw site. See [Model errors](../how-to/model-errors). ## The trap `reserveAll` avoids Reserving every line looks like a job for a loop: ```ts // ✗ WRONG — silently destroys the defect channel for (const line of lines) { const reserved = deps.reserve(line); if (reserved.isErr()) return Err(reserved.error); } return Ok(lines); ``` `isErr()` is **false for a `Defect`**. A `Result` can be in the defect state at runtime — the defect variant is never part of `E` — so a reservation that blew up on its own account falls straight through this loop and gets reported as `Ok`. The failure vanishes. Folding with `flatMap` is both shorter and correct: ```ts lines .reduce>( (acc, line) => acc.flatMap(() => deps.reserve(line)), Ok(), ) .map(() => lines); ``` `flatMap` short-circuits on `Err` **and** passes a `Defect` through untouched, which is the whole reason to reach for the combinator instead of branching by hand. It stays lazy too: after a failure the callback is simply not invoked, so later lines are never reserved — which [`all`](../reference/combinators) could not do, since it takes an already-materialised array. A test pins it: ```ts await expect(result).toBeDefectWith(boom); ``` ## Where to go next * Store and read it back: [Checkout persistence](./checkout-persistence). * Serve it: [Checkout API](./checkout-api). --- --- url: /unthrown/examples/checkout-persistence.md description: >- Storing and reading a checkout with @unthrown/prisma — a read that infers E = never, and a write that carries only the P-codes a caller would branch on. --- # Checkout persistence [`examples/checkout-persistence`](https://github.com/btravstack/unthrown/tree/main/examples/checkout-persistence) — the persistence half: a repository built on `@unthrown/prisma`, storing and reading the cart from [Checkout domain](./checkout-domain) against a real (in-memory) database. ```sh pnpm turbo run test --filter=@unthrown/example-checkout-persistence ``` ## A read infers `E = never` ```ts findCart: (cartId: string): AsyncResult => db.cart .tryFindUnique({ where: { id: cartId }, include: { lines: true } }) .flatMap((row) => row === null ? Err(new CartNotFound({ cartId })) : Ok(/* … */), ); ``` `tryFindUnique` itself is `AsyncResult` — a database that will not answer at all is a `Defect`, not a domain outcome, so there is no error case to name for the query. Absence is `null`. `CartNotFound` is not something Prisma raises; it is something *this repository* introduces by turning that `null` into the modeled error `findCart` promises its caller (matching `CheckoutDeps["findCart"]` from the domain package). The test pins the distinction: ```ts await expect(repo.findCart("nope")).toBeErrTagged("CartNotFound", { cartId: "nope", }); ``` ## A write carries only the P-codes you would branch on ```ts saveOrder: (order: { id: string; total: number; cartId: string }) => db.order.tryCreate({ data: order }); ``` `saveOrder`'s error channel is exactly `UniqueConstraintViolation | ForeignKeyViolation | RecordNotFound` — the P-codes a `create` can actually raise. The schema's `Order.cartId @unique` makes "one order per cart" a real constraint, so a second `saveOrder` for the same cart comes back as a modeled `Err`, not a thrown driver exception: ```ts await expect(repo.saveOrder({ id: "o1", total: 100, cartId: "c1" })).toBeOk(); await expect( repo.saveOrder({ id: "o2", total: 100, cartId: "c1" }), ).toBeErrTagged("UniqueConstraintViolation"); ``` Everything infrastructural — a dropped connection, a pool timeout, a deadlock — is deliberately *not* in either channel. Nobody writes domain logic for those; they are a `Defect`, folded once at the edge. See [the Prisma guide](../how-to/use-with-prisma) for the full per-operation error table. ## Where to go next * The modelling half: [Checkout domain](./checkout-domain). * Serve it: [Checkout API](./checkout-api). --- --- url: /unthrown/examples/checkout-api.md description: >- Serving placeOrder over oRPC with @unthrown/orpc — an exhaustive mapErrCases at the edge, no try/catch, and a provider outage that collapses to INTERNAL_SERVER_ERROR instead of an unhandled rejection. --- # Checkout API [`examples/checkout-api`](https://github.com/btravstack/unthrown/tree/main/examples/checkout-api) — the edge half: [Checkout domain](./checkout-domain)'s `placeOrder` served over oRPC with `@unthrown/orpc`, tested through a real request/response cycle. ```sh pnpm turbo run test --filter=@unthrown/example-checkout-api ``` ## No `try`/`catch` The handler is one `mapErrCases` call — nothing else: ```ts handlerResult(({ input, errors }) => placeOrder(deps, input.cartId).mapErrCases((matcher) => matcher .with(P.tag("CartNotFound"), (e) => errors.NOT_FOUND({ message: e.message }), ) .with(P.tag("CartEmpty"), (e) => errors.BAD_REQUEST({ message: e.message }), ) .with(P.tag("OutOfStock"), (e) => errors.CONFLICT({ message: e.message })) .with(P.tag("PaymentDeclined"), (e) => errors.PAYMENT_REQUIRED({ message: e.message }), ), ), ); ``` That is safe with no surrounding guard because two things already happened upstream. First, `placeOrder`'s own pipeline never lets a thrown callback escape — the throw→defect net converts it to a `Defect` before it reaches this handler. Second, [`handlerResult`](../how-to/use-with-orpc) is the elimination edge: `Ok` becomes the response, a returned `ORPCError` is served as a typed, inferable error, and a `Defect` is rethrown onto oRPC's own defect path. There is nothing left for a `try`/`catch` to do here. ## Every domain case is named `placeOrder`'s error channel is `CartNotFound | CartEmpty | OutOfStock | PaymentDeclined` — four cases, each with its own `.with(P.tag(...), ...)` arm mapping it to a distinct declared `ORPCError`. `P._` is banned by the dogfooded `no-catch-all-pattern` lint rule, so there is no wildcard to quietly absorb a case that was never handled. Add a fifth error to `CheckoutError` and this `mapErrCases` stops compiling — every call site, this one included, must add its own arm before the build is green again. The tests exercise two of the four domain cases end to end — `CartNotFound` and `PaymentDeclined` — each landing on its own distinct `ORPCError` code (`CartEmpty` and `OutOfStock` follow the identical pattern and are covered at the domain layer already; see [Checkout domain](./checkout-domain)): ```ts await expect(caller.placeOrder({ cartId: "nope" })).rejects.toMatchObject({ code: "NOT_FOUND", }); await expect(caller.placeOrder({ cartId: "cart_1" })).rejects.toMatchObject({ code: "PAYMENT_REQUIRED", }); ``` ## The defect arm: an outage, not a 500 with a leaked stack trace The fourth outcome the suite pins is not a domain case at all — it is what happens when the payment provider throws instead of returning a `PaymentDeclined`: ```ts const caller = createCaller( deps({ charge: () => { throw new Error("connect ETIMEDOUT"); }, }), ); await expect(caller.placeOrder({ cartId: "cart_1" })).rejects.toMatchObject({ code: "INTERNAL_SERVER_ERROR", }); ``` Nothing in `router.ts` names this case, because it is not a business outcome — nobody writes domain logic for a severed connection. The throw becomes a `Defect` inside `placeOrder`, `handlerResult` rethrows its cause, and oRPC collapses it to a generic `INTERNAL_SERVER_ERROR` rather than leaking the raw exception. `createCaller` deliberately routes every call through a real `RPCHandler`/`RPCLink` loop (in-memory, no socket) rather than oRPC's in-process shortcut, because that collapse only happens once a call crosses a genuine transport boundary — the same reason [`@unthrown/orpc`'s own suite](https://github.com/btravstack/unthrown/blob/main/packages/orpc/src/index.spec.ts) tests it that way. The payoff: an unmodelled failure still cannot escape as an unhandled rejection — it always arrives as a typed, catchable error, just not one you were meant to handle in `mapErrCases`. See [the oRPC guide](../how-to/use-with-orpc) for the full server/client bridge. ## A fifth outcome, that is not a domain case at all `router.ts` also declares `input(z.object({ cartId: z.string().min(1) }))`. An empty `cartId` never reaches `placeOrder` — oRPC rejects it during its own input validation, before the handler runs at all. The rejection happens to carry the same `BAD_REQUEST` code as `CartEmpty` (both were declared in the same `.errors({...})` call), but it is not one of `E`'s four cases and no arm in `mapErrCases` produced it: ```ts await expect(caller.placeOrder({ cartId: "" })).rejects.toMatchObject({ code: "BAD_REQUEST", message: "Input validation failed", }); ``` The message is the tell — `"Input validation failed"`, not `"cart … has no lines"`. A domain's `E` and a transport's input contract are two different things that can coincidentally share a status code; only `E` is the one `unthrown` makes exhaustive. ## Where to go next * The modelling half: [Checkout domain](./checkout-domain). * The persistence half: [Checkout persistence](./checkout-persistence). --- --- url: /unthrown/examples/existing-errors.md description: >- Adopting unthrown in a codebase that already models its domain errors — a kind-discriminated class hierarchy, a plain code union, and untagged third-party classes, with no TaggedError anywhere. --- # Existing error types [`examples/existing-errors`](https://github.com/btravstack/unthrown/tree/main/examples/existing-errors) — the adoption case. A codebase that already has an error convention, wired to `Result` without rewriting it. **`TaggedError` does not appear once.** ```sh pnpm turbo run test --filter=@unthrown/example-existing-errors ``` ## Why the package exists `Result` is generic in `E` and **unconstrained** — there is no `E extends { _tag: string }` anywhere in core, and `P.tag("X")` is only sugar for the object pattern `{ _tag: "X" }`. Saying so in prose is cheap; the three modules here compile and are tested in CI, so the claim cannot quietly stop being true. Each one takes a different existing convention, matching a section of [Model errors](../how-to/model-errors#use-the-errors-you-already-have). ## `tickets.ts` — your own class hierarchy The convention that was already there: an abstract base carrying a `kind`. ```ts export abstract class AppError extends Error { abstract readonly kind: string; } export class TicketNotFound extends AppError { readonly kind = "TicketNotFound" as const; constructor(readonly ticketId: string) { super(`no ticket ${ticketId}`); } } ``` `mapErrCases` drives the same exhaustive matcher the tagged path uses, dispatching on `kind` through a plain object pattern: ```ts assignTicket(store, ticketId, to).mapErrCases((matcher) => matcher .with({ kind: "TicketNotFound" }, (e) => ({ status: 404, detail: e.ticketId, })) .with({ kind: "TicketLocked" }, (e) => ({ status: 423, detail: e.lockedBy, })), ); ``` Each branch is narrowed to its own class, so `ticketId` and `lockedBy` are reachable without a cast. Add a third `AppError` subclass to the union and this stops compiling until it is named — the guarantee comes from the union's shape, not from `TaggedError`. ## `billing.ts` — a plain union, no classes at all The other extreme: a client generated from an OpenAPI document, whose failures are plain objects with a `code`. `E` does not have to be an `Error` either. ```ts export type BillingError = | { readonly code: "CARD_DECLINED"; readonly declineCode: string } | { readonly code: "INSUFFICIENT_FUNDS" } | { readonly code: "RATE_LIMITED"; readonly retryAfter: number }; ``` Two codes deserve the same response, so they share one arm as a **grouped pattern** — both still named, which is the difference from a wildcard: ```ts client.charge(cents).match({ ok: () => 200, defect: () => 500, errCases: (matcher) => matcher .with( { code: "CARD_DECLINED" }, { code: "INSUFFICIENT_FUNDS" }, () => 402, ) .with({ code: "RATE_LIMITED" }, () => 429), }); ``` The spec pins the `defect` arm too: a socket hang-up in the billing client folds to 500 rather than arriving as a fourth code a caller might branch on. ## `vendor.ts` — untagged third-party classes Two SDK error classes with no shared discriminant, no tag, and no possibility of editing them. The boundary is where the real decision gets made: ```ts export const render = fromThrowable( (source: string): Template => ({ rendered: vendorRender(source) }), (cause, defect) => cause instanceof VendorSyntaxError || cause instanceof VendorTimeoutError ? cause : defect(cause), ); ``` That is the answer to "how does unthrown know which failures are modelled" — not the error's shape, but `qualify`. What you return becomes `E`; what you hand to the injected `defect` leaves the modelled type entirely. The spec asserts both halves, including that a `RangeError` from inside the SDK never reaches `E`. Matching then uses `P.instanceOf`, the pattern for a union with nothing to dispatch on but identity: ```ts result.mapErrCases((matcher) => matcher .with(P.instanceOf(VendorSyntaxError), (e) => ({ detail: `bad syntax at ${e.at}`, })) .with(P.instanceOf(VendorTimeoutError), (e) => ({ detail: `timed out after ${e.afterMs}ms`, })), ); ``` `P.when(guard)` covers whatever neither an object pattern nor `instanceof` can express. ## What you still have to give up Nothing about the error *type* — but `E` must be a union TypeScript can **discriminate**, because exhaustiveness is `Exclude` over it. A `kind`, a `code`, distinct class shapes or a guard all qualify; a widened `Error`, `string` or `unknown` does not, and leaves `P._` as the only arm that terminates the match. That is the same thing a `switch` needs, and what [`no-ambiguous-error-type`](../how-to/lint-your-codebase#no-ambiguous-error-type) is really guarding. ## Where to go next * The guide section this mirrors: [Model errors](../how-to/model-errors#use-the-errors-you-already-have). * Why the boundary decides: [Qualification](../explanation/qualification). * What `TaggedError` buys you when you *don't* have a convention: [Model errors](../how-to/model-errors#define-a-tagged-error). --- --- url: /unthrown/api/orpc/client.md --- [**@unthrown/orpc**](index.md) *** [@unthrown/orpc](index.md) / client # client ## Client ### ResultClient ```ts type ResultClient = T extends Client ? (...rest) => AsyncResult> : { [K in keyof T]: T[K] extends AnyNestedClient ? ResultClient : never }; ``` Defined in: [client.ts:88](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/orpc/src/client.ts#L88) The type of a [createResultClient](#createresultclient) client: every procedure of `T` returns an `AsyncResult` instead of a throwing promise. #### Type Parameters | Type Parameter | | ------ | | `T` *extends* `AnyNestedClient` | *** ### createResultClient() ```ts function createResultClient(client): ResultClient; ``` Defined in: [client.ts:132](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/orpc/src/client.ts#L132) Wrap an oRPC client so every procedure call returns an `AsyncResult` — [fromCall](#fromcall) applied to the whole router. #### Type Parameters | Type Parameter | | ------ | | `T` *extends* `AnyNestedClient` | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `client` | `T` | the oRPC client (or any nested router segment) to wrap. | #### Returns [`ResultClient`](#resultclient)<`T`> #### Remarks The mirror of oRPC's own `createSafeClient`, producing `AsyncResult`s instead of `SafeResult` tuples: inferable errors land in the error channel (the raw `ORPCError` union, discriminated by `code`), everything else is a `Defect`. Call options (`signal`, `context`, `lastEventId`) pass through untouched. Event-iterator (streaming) procedures are out of scope: a stream does not collapse to one `Result`. Keep calling those on the raw client. #### Example ```ts import { createResultClient } from "@unthrown/orpc/client"; const rc = createResultClient(client); const greeting = await rc.planet .find({ id }) .map((planet) => `Hello, ${planet.name}!`) .match({ ok: (msg) => msg, // the `errCases` handler matches the error exhaustively: one arm per // `code` the procedure declares — no catch-all to absorb a new one errCases: (matcher) => matcher .with({ code: "NOT_FOUND" }, () => "Hello, void!") .with({ code: "CONFLICT" }, () => "Hello, again!"), defect: () => "Hello, bug tracker!", }); ``` *** ### fromCall() ```ts function fromCall(promise): AsyncResult>; ``` Defined in: [client.ts:56](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/orpc/src/client.ts#L56) Lift a single oRPC call into an `AsyncResult`. #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `TOutput` | - | the procedure's output type. | | `TError` | `Error` | the call's error union; only its `ORPCError` arm is modeled, the rest is subtracted into the defect channel. | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `promise` | `PromiseWithError`<`TOutput`, `TError`> | the in-flight call to lift. | #### Returns `AsyncResult`<`TOutput`, `Extract`<`TError`, `AnyORPCError`>> #### Remarks The error channel is the call's *inferable* errors — the `ORPCError`s the procedure declares via `.errors({...})` or returns as values, extracted as `Extract` and discriminated by `code`. Any other rejection (network failure, an undeclared throw collapsed to `INTERNAL_SERVER_ERROR`, a malformed response) is a `Defect`: unmodeled, flowing past the error combinators, panicking at `get`. Accepts the promise of a client procedure call or of oRPC's server-side `call(procedure, input)` — anything typed `PromiseWithError`. #### Example ```ts import { fromCall } from "@unthrown/orpc/client"; const planet = await fromCall(client.planet.find({ id })); // planet: Result> if (planet.isErr()) planet.error.code; // "NOT_FOUND" ``` --- --- url: /unthrown/api/orpc/extensions.result.md --- [**@unthrown/orpc**](index.md) *** [@unthrown/orpc](index.md) / extensions/result # extensions/result --- --- url: /unthrown/api/drizzle/index-1.md --- [**@unthrown/drizzle**](index.md) *** [@unthrown/drizzle](index.md) / index # index ## Builders ### PgUnthrownCountBuilder Defined in: [packages/drizzle/src/pg-core/count.ts:37](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/count.ts#L37) A `$count` query that resolves to an `AsyncResult`. #### Remarks The one builder with no `_prepare`: it inherits from drizzle's `PgCountBuilder`, which is itself an `SQL` fragment, so it can be embedded in a larger query as well as run on its own. Running it prepares the count inline. #### Extends * `PgCountBuilder` #### Constructors ##### Constructor ```ts new PgUnthrownCountBuilder(__namedParameters): PgUnthrownCountBuilder; ``` Defined in: [packages/drizzle/src/pg-core/count.ts:42](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/count.ts#L42) ###### Parameters | Parameter | Type | | ------ | ------ | | `__namedParameters` | { `dialect`: `PgDialect`; `filters?`: `SQL`<`unknown`>; `session`: [`PgUnthrownSession`](#abstract-pgunthrownsession)<`unknown`>; `source`: | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `SQLWrapper`<`unknown`>; } | | `__namedParameters.dialect` | `PgDialect` | | `__namedParameters.filters?` | `SQL`<`unknown`> | | `__namedParameters.session` | [`PgUnthrownSession`](#abstract-pgunthrownsession)<`unknown`> | | `__namedParameters.source` | | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `SQLWrapper`<`unknown`> | ###### Returns [`PgUnthrownCountBuilder`](#pgunthrowncountbuilder) ###### Overrides ```ts PgCountBuilder.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `public` | `object` | `undefined` | - | - | `PgCountBuilder._` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:61 | | `_.brand` | `public` | `"SQL"` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:62 | | `_.type` | `public` | `number` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:63 | | `queryChunks` | `readonly` | `SQLChunk`\[] | `undefined` | - | - | `PgCountBuilder.queryChunks` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:59 | | `then` | `readonly` | [`ResultThen`](#resultthen)<`number`, `never`> | `undefined` | The `then` that makes a query builder awaitable, resolving to a `Result`. **Remarks** Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. | - | - | [packages/drizzle/src/pg-core/count.ts:83](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/count.ts#L83) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownCountBuilder"` | - | `PgCountBuilder.[entityKind]` | - | [packages/drizzle/src/pg-core/count.ts:38](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/count.ts#L38) | #### Methods ##### append() ```ts append(query): this; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:66 ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `SQL` | ###### Returns `this` ###### Inherited from ```ts PgCountBuilder.append ``` ##### as() ###### Call Signature ```ts as(alias): Aliased; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:71 ###### Parameters | Parameter | Type | | ------ | ------ | | `alias` | `string` | ###### Returns `Aliased`<`number`> ###### Inherited from ```ts PgCountBuilder.as ``` ###### Call Signature ```ts as(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:76 ###### Type Parameters | Type Parameter | | ------ | | `TData` | ###### Returns `SQL`<`TData`> ###### Deprecated Use ``sql\`query`.as(alias)`` instead. ###### Inherited from ```ts PgCountBuilder.as ``` ###### Call Signature ```ts as(alias): Aliased; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:81 ###### Type Parameters | Type Parameter | | ------ | | `TData` | ###### Parameters | Parameter | Type | | ------ | ------ | | `alias` | `string` | ###### Returns `Aliased`<`TData`> ###### Deprecated Use ``sql\`query`.as(alias)`` instead. ###### Inherited from ```ts PgCountBuilder.as ``` ##### buildQueryFromSourceParams() ```ts buildQueryFromSourceParams(chunks, _config): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:68 ###### Parameters | Parameter | Type | | ------ | ------ | | `chunks` | `SQLChunk`\[] | | `_config` | `BuildQueryConfig` | ###### Returns `Query` ###### Inherited from ```ts PgCountBuilder.buildQueryFromSourceParams ``` ##### execute() ```ts execute(placeholderValues?): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/count.ts:66](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/count.ts#L66) Run the count, resolving to the number of matching rows. The error channel is `never` — a count is a read, so every failure it can hit is a defect. See `runSafeQuery`. ###### Parameters | Parameter | Type | | ------ | ------ | | `placeholderValues?` | `Record`<`string`, `unknown`> | ###### Returns `AsyncResult`<`number`, `never`> ##### getSQL() ```ts getSQL(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:70 ###### Returns `SQL`<`number`> ###### Inherited from ```ts PgCountBuilder.getSQL ``` ##### if() ```ts if(condition): PgUnthrownCountBuilder | undefined; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:91 This method is used to conditionally include a part of the query. ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `condition` | `any` | Condition to check | ###### Returns [`PgUnthrownCountBuilder`](#pgunthrowncountbuilder) | `undefined` itself if the condition is `true`, otherwise `undefined` ###### Inherited from ```ts PgCountBuilder.if ``` ##### inlineParams() ```ts inlineParams(): this; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:84 ###### Returns `this` ###### Inherited from ```ts PgCountBuilder.inlineParams ``` ##### mapWith() ```ts mapWith(decoder): SQL>; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:82 ###### Type Parameters | Type Parameter | | ------ | | `TDecoder` *extends* | `DriverValueDecoder`<`any`, `number`> | `DriverValueDecoderFn`<`any`, `number`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `decoder` | `TDecoder` | ###### Returns `SQL`<`GetDecoderResult`<`TDecoder`>> ###### Inherited from ```ts PgCountBuilder.mapWith ``` ##### nullable() ```ts nullable(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:83 ###### Returns `SQL`<`number` | `null`> ###### Inherited from ```ts PgCountBuilder.nullable ``` ##### toQuery() ```ts toQuery(config): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:67 ###### Parameters | Parameter | Type | | ------ | ------ | | `config` | `BuildQueryConfig` | ###### Returns `Query` ###### Inherited from ```ts PgCountBuilder.toQuery ``` *** ### PgUnthrownDeleteBase Defined in: [packages/drizzle/src/pg-core/delete.ts:58](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/delete.ts#L58) A `delete` query that resolves to an `AsyncResult`. #### Remarks Deleting a row another table still references raises a [ForeignKeyViolation](#foreignkeyviolation), which lands in the error channel rather than as a rejection. #### Extends * `PgDeleteBase`<[`PgUnthrownDeleteHKT`](#pgunthrowndeletehkt), `TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`> #### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TTable` *extends* `PgTable` | - | | `TQueryResult` *extends* `PgQueryResultHKT` | - | | `TSelectedFields` *extends* `ColumnsSelection` | `undefined` | `undefined` | | `TReturning` *extends* `Record`<`string`, `unknown`> | `undefined` | `undefined` | | `TDynamic` *extends* `boolean` | `false` | | `TExcludedMethods` *extends* `string` | `never` | #### Constructors ##### Constructor ```ts new PgUnthrownDeleteBase( table, session, dialect, withList?): PgUnthrownDeleteBase; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:66 ###### Parameters | Parameter | Type | | ------ | ------ | | `table` | `TTable` | | `session` | `PgSession` | | `dialect` | `PgDialect` | | `withList?` | `Subquery`<`string`, `Record`<`string`, `unknown`>>\[] | ###### Returns [`PgUnthrownDeleteBase`](#pgunthrowndeletebase)<`TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`> ###### Inherited from ```ts PgDeleteBase< PgUnthrownDeleteHKT, TTable, TQueryResult, TSelectedFields, TReturning, TDynamic, TExcludedMethods >.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | `PgDeleteBase._` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:49 | | `_.dialect` | `readonly` | `"pg"` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:50 | | `_.dynamic` | `readonly` | `TDynamic` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:56 | | `_.excludedMethods` | `readonly` | `TExcludedMethods` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:57 | | `_.hkt` | `readonly` | [`PgUnthrownDeleteHKT`](#pgunthrowndeletehkt) | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:51 | | `_.queryResult` | `readonly` | `TQueryResult` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:53 | | `_.result` | `readonly` | `TReturning` *extends* `undefined` ? `PgQueryResultKind`<`TQueryResult`, `never`> : `TReturning`\[] | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:58 | | `_.returning` | `readonly` | `TReturning` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:55 | | `_.selectedFields` | `readonly` | `TSelectedFields` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:54 | | `_.table` | `readonly` | `TTable` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:52 | | `then` | `readonly` | [`ResultThen`](#resultthen)<[`DeleteResult`](#deleteresult)<`TQueryResult`, `TReturning`>> | `undefined` | The `then` that makes a query builder awaitable, resolving to a `Result`. **Remarks** Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. | - | - | [packages/drizzle/src/pg-core/delete.ts:121](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/delete.ts#L121) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownDelete"` | - | `PgDeleteBase.[entityKind]` | - | [packages/drizzle/src/pg-core/delete.ts:74](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/delete.ts#L74) | #### Methods ##### $dynamic() ```ts $dynamic(): PgUnthrownDeleteBase>>; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:125 ###### Returns [`PgUnthrownDeleteBase`](#pgunthrowndeletebase)<`Assume`<`TTable`, `PgTable`<`TableConfig`>>> ###### Inherited from ```ts PgDeleteBase.$dynamic ``` ##### comment() ```ts comment(comment): PgDeleteWithout, TDynamic, "comment">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:122 Attach [sqlcommenter](https://google.github.io/sqlcommenter) comment to a query ###### Parameters | Parameter | Type | | ------ | ------ | | `comment` | `CommentInput` | ###### Returns `PgDeleteWithout`<[`PgUnthrownDeleteBase`](#pgunthrowndeletebase)<`TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"comment"`> ###### Inherited from ```ts PgDeleteBase.comment ``` ##### execute() ```ts execute(placeholderValues?): AsyncResult, PgQueryError>; ``` Defined in: [packages/drizzle/src/pg-core/delete.ts:113](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/delete.ts#L113) Run the delete, resolving to its result or a [PgQueryError](#pgqueryerror). ###### Parameters | Parameter | Type | | ------ | ------ | | `placeholderValues?` | `Record`<`string`, `unknown`> | ###### Returns `AsyncResult`<[`DeleteResult`](#deleteresult)<`TQueryResult`, `TReturning`>, [`PgQueryError`](#pgqueryerror)> ##### getSQL() ```ts getSQL(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:123 ###### Returns `SQL` ###### Inherited from ```ts PgDeleteBase.getSQL ``` ##### prepare() ```ts prepare(name): PgUnthrownPreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/delete.ts:104](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/delete.ts#L104) Create a prepared statement for this query. This allows the database to remember this query for the given session and call it by name, rather than specifying the full query. [Postgres prepare documentation](https://www.postgresql.org/docs/current/sql-prepare.html) ###### Parameters | Parameter | Type | | ------ | ------ | | `name` | `string` | ###### Returns [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery)<`PreparedQueryConfig` & `object`> ##### returning() ###### Call Signature ```ts returning(): PgDeleteWithout, TDynamic>; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:117 Adds a `returning` clause to the query. Calling this method will return the specified fields of the deleted rows. If no fields are specified, all fields will be returned. See docs: ###### Returns `PgDeleteWithout`<`PgDeleteKind`<[`PgUnthrownDeleteHKT`](#pgunthrowndeletehkt), `TTable`, `TQueryResult`, `TTable`\[`"_"`]\[`"columns"`], `TTable`\[`"$inferSelect"`], `TDynamic`, `TExcludedMethods`>, `TDynamic`> ###### Example ```ts // Delete all cars with the green color and return all fields const deletedCars: Car[] = await db.delete(cars) .where(eq(cars.color, 'green')) .returning(); // Delete all cars with the green color and return only their id and brand fields const deletedCarsIdsAndBrands: { id: number, brand: string }[] = await db.delete(cars) .where(eq(cars.color, 'green')) .returning({ id: cars.id, brand: cars.brand }); ``` ###### Inherited from ```ts PgDeleteBase.returning ``` ###### Call Signature ```ts returning(fields): PgDeleteWithout }[K] }, TDynamic, TExcludedMethods>, TDynamic, "returning">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:118 Adds a `returning` clause to the query. Calling this method will return the specified fields of the deleted rows. If no fields are specified, all fields will be returned. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelectedFields` *extends* `SelectedFieldsFlat` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelectedFields` | ###### Returns `PgDeleteWithout`<`PgDeleteKind`<[`PgUnthrownDeleteHKT`](#pgunthrowndeletehkt), `TTable`, `TQueryResult`, `TSelectedFields`, { \[K in string | number | symbol]: { \[Key in string | number | symbol]: SelectResultField\ }\[K] }, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"returning"`> ###### Example ```ts // Delete all cars with the green color and return all fields const deletedCars: Car[] = await db.delete(cars) .where(eq(cars.color, 'green')) .returning(); // Delete all cars with the green color and return only their id and brand fields const deletedCarsIdsAndBrands: { id: number, brand: string }[] = await db.delete(cars) .where(eq(cars.color, 'green')) .returning({ id: cars.id, brand: cars.brand }); ``` ###### Inherited from ```ts PgDeleteBase.returning ``` ##### shouldOmitSQLParens()? ```ts optional shouldOmitSQLParens(): boolean; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:49 ###### Returns `boolean` ###### Inherited from ```ts PgDeleteBase.shouldOmitSQLParens ``` ##### toSQL() ```ts toSQL(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:124 ###### Returns `Query` ###### Inherited from ```ts PgDeleteBase.toSQL ``` ##### where() ```ts where(where): PgDeleteWithout, TDynamic, "where">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:96 Adds a `where` clause to the query. Calling this method will delete only those rows that fulfill a specified condition. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `where` | `SQL`<`unknown`> | `undefined` | the `where` clause. | ###### Returns `PgDeleteWithout`<[`PgUnthrownDeleteBase`](#pgunthrowndeletebase)<`TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"where"`> ###### Example You can use conditional operators and `sql function` to filter the rows to be deleted. ```ts // Delete all cars with green color await db.delete(cars).where(eq(cars.color, 'green')); // or await db.delete(cars).where(sql`${cars.color} = 'green'`) ``` You can logically combine conditional operators with `and()` and `or()` operators: ```ts // Delete all BMW cars with a green color await db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); // Delete all cars with the green or blue color await db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); ``` ###### Inherited from ```ts PgDeleteBase.where ``` *** ### PgUnthrownInsertBase Defined in: [packages/drizzle/src/pg-core/insert.ts:57](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/insert.ts#L57) An `insert` query that resolves to an `AsyncResult`. #### Remarks This is where the package earns its keep: a unique index, a foreign key or a `NOT NULL` column turns a write into a modeled [PgQueryError](#pgqueryerror) instead of a rejection, so the caller branches on it exhaustively. #### Extends * `PgInsertBase`<[`PgUnthrownInsertHKT`](#pgunthrowninserthkt), `TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`> #### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TTable` *extends* `PgTable` | - | | `TQueryResult` *extends* `PgQueryResultHKT` | - | | `TSelectedFields` | `undefined` | | `TReturning` | `undefined` | | `TDynamic` *extends* `boolean` | `false` | | `TExcludedMethods` *extends* `string` | `never` | #### Constructors ##### Constructor ```ts new PgUnthrownInsertBase( table, values, session, dialect, withList?, select?, overridingSystemValue_?): PgUnthrownInsertBase; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:114 ###### Parameters | Parameter | Type | | ------ | ------ | | `table` | `TTable` | | `values` | | `SQL`<`unknown`> | `Record`<`string`, `SQL`<`unknown`> | `Param`<`any`, `any`>>\[] | `TypedQueryBuilder`<{ }, `unknown`, `unknown`> | | `session` | `PgSession` | | `dialect` | `PgDialect` | | `withList?` | `Subquery`<`string`, `Record`<`string`, `unknown`>>\[] | | `select?` | `boolean` | | `overridingSystemValue_?` | `boolean` | ###### Returns [`PgUnthrownInsertBase`](#pgunthrowninsertbase)<`TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`> ###### Inherited from ```ts PgInsertBase< PgUnthrownInsertHKT, TTable, TQueryResult, TSelectedFields, TReturning, TDynamic, TExcludedMethods >.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | `PgInsertBase._` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:97 | | `_.dialect` | `readonly` | `"pg"` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:98 | | `_.dynamic` | `readonly` | `TDynamic` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:104 | | `_.excludedMethods` | `readonly` | `TExcludedMethods` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:105 | | `_.hkt` | `readonly` | [`PgUnthrownInsertHKT`](#pgunthrowninserthkt) | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:99 | | `_.queryResult` | `readonly` | `TQueryResult` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:101 | | `_.result` | `readonly` | `TReturning` *extends* `undefined` ? `PgQueryResultKind`<`TQueryResult`, `never`> : `TReturning`\[] | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:106 | | `_.returning` | `readonly` | `TReturning` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:103 | | `_.selectedFields` | `readonly` | `TSelectedFields` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:102 | | `_.table` | `readonly` | `TTable` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:100 | | `then` | `readonly` | [`ResultThen`](#resultthen)<[`InsertResult`](#insertresult)<`TQueryResult`, `TReturning`>> | `undefined` | The `then` that makes a query builder awaitable, resolving to a `Result`. **Remarks** Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. | - | - | [packages/drizzle/src/pg-core/insert.ts:120](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/insert.ts#L120) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownInsert"` | - | `PgInsertBase.[entityKind]` | - | [packages/drizzle/src/pg-core/insert.ts:73](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/insert.ts#L73) | #### Methods ##### $dynamic() ```ts $dynamic(): PgUnthrownInsertBase>>; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:199 ###### Returns [`PgUnthrownInsertBase`](#pgunthrowninsertbase)<`Assume`<`TTable`, `PgTable`<`TableConfig`>>> ###### Inherited from ```ts PgInsertBase.$dynamic ``` ##### comment() ```ts comment(comment): PgInsertWithout, TDynamic, "comment">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:196 Attach [sqlcommenter](https://google.github.io/sqlcommenter) comment to a query ###### Parameters | Parameter | Type | | ------ | ------ | | `comment` | `CommentInput` | ###### Returns `PgInsertWithout`<[`PgUnthrownInsertBase`](#pgunthrowninsertbase)<`TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"comment"`> ###### Inherited from ```ts PgInsertBase.comment ``` ##### execute() ```ts execute(placeholderValues?): AsyncResult, PgQueryError>; ``` Defined in: [packages/drizzle/src/pg-core/insert.ts:112](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/insert.ts#L112) Run the insert, resolving to its result or a [PgQueryError](#pgqueryerror). ###### Parameters | Parameter | Type | | ------ | ------ | | `placeholderValues?` | `Record`<`string`, `unknown`> | ###### Returns `AsyncResult`<[`InsertResult`](#insertresult)<`TQueryResult`, `TReturning`>, [`PgQueryError`](#pgqueryerror)> ##### getSQL() ```ts getSQL(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:197 ###### Returns `SQL` ###### Inherited from ```ts PgInsertBase.getSQL ``` ##### onConflictDoNothing() ```ts onConflictDoNothing(config?): PgInsertWithout, TDynamic, "onConflictDoNothing" | "onConflictDoUpdate">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:159 Adds an `on conflict do nothing` clause to the query. Calling this method simply avoids inserting a row as its alternative action. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `config?` | { `target?`: `IndexColumn` | `IndexColumn`\[]; `where?`: `SQL`<`unknown`>; } | The `target` and `where` clauses. | | `config.target?` | `IndexColumn` | `IndexColumn`\[] | - | | `config.where?` | `SQL`<`unknown`> | - | ###### Returns `PgInsertWithout`<[`PgUnthrownInsertBase`](#pgunthrowninsertbase)<`TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"onConflictDoNothing"` | `"onConflictDoUpdate"`> ###### Example ```ts // Insert one row and cancel the insert if there's a conflict await db.insert(cars) .values({ id: 1, brand: 'BMW' }) .onConflictDoNothing(); // Explicitly specify conflict target await db.insert(cars) .values({ id: 1, brand: 'BMW' }) .onConflictDoNothing({ target: cars.id }); ``` ###### Inherited from ```ts PgInsertBase.onConflictDoNothing ``` ##### onConflictDoUpdate() ```ts onConflictDoUpdate(config): PgInsertWithout, TDynamic, "onConflictDoNothing" | "onConflictDoUpdate">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:192 Adds an `on conflict do update` clause to the query. Calling this method will update the existing row that conflicts with the row proposed for insertion as its alternative action. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `config` | `PgInsertOnConflictDoUpdateConfig`<[`PgUnthrownInsertBase`](#pgunthrowninsertbase)<`TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`>> | The `target`, `set` and `where` clauses. | ###### Returns `PgInsertWithout`<[`PgUnthrownInsertBase`](#pgunthrowninsertbase)<`TTable`, `TQueryResult`, `TSelectedFields`, `TReturning`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"onConflictDoNothing"` | `"onConflictDoUpdate"`> ###### Example ```ts // Update the row if there's a conflict await db.insert(cars) .values({ id: 1, brand: 'BMW' }) .onConflictDoUpdate({ target: cars.id, set: { brand: 'Porsche' } }); // Upsert with 'where' clause await db.insert(cars) .values({ id: 1, brand: 'BMW' }) .onConflictDoUpdate({ target: cars.id, set: { brand: 'newBMW' }, targetWhere: sql`${cars.createdAt} > '2023-01-01'::date`, }); ``` ###### Inherited from ```ts PgInsertBase.onConflictDoUpdate ``` ##### prepare() ```ts prepare(name): PgUnthrownPreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/insert.ts:103](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/insert.ts#L103) Create a prepared statement for this query. This allows the database to remember this query for the given session and call it by name, rather than specifying the full query. [Postgres prepare documentation](https://www.postgresql.org/docs/current/sql-prepare.html) ###### Parameters | Parameter | Type | | ------ | ------ | | `name` | `string` | ###### Returns [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery)<`PreparedQueryConfig` & `object`> ##### returning() ###### Call Signature ```ts returning(): PgInsertWithout, TDynamic>; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:135 Adds a `returning` clause to the query. Calling this method will return the specified fields of the inserted rows. If no fields are specified, all fields will be returned. See docs: ###### Returns `PgInsertWithout`<`PgInsertKind`<[`PgUnthrownInsertHKT`](#pgunthrowninserthkt), `TTable`, `TQueryResult`, `TTable`\[`"_"`]\[`"columns"`], `TTable`\[`"$inferSelect"`], `TDynamic`, `TExcludedMethods`>, `TDynamic`> ###### Example ```ts // Insert one row and return all fields const insertedCar: Car[] = await db.insert(cars) .values({ brand: 'BMW' }) .returning(); // Insert one row and return only the id const insertedCarId: { id: number }[] = await db.insert(cars) .values({ brand: 'BMW' }) .returning({ id: cars.id }); ``` ###### Inherited from ```ts PgInsertBase.returning ``` ###### Call Signature ```ts returning(fields): PgInsertWithout }[K] }, TDynamic, TExcludedMethods>, TDynamic, "returning">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:136 Adds a `returning` clause to the query. Calling this method will return the specified fields of the inserted rows. If no fields are specified, all fields will be returned. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelectedFields` *extends* `SelectedFieldsFlat` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelectedFields` | ###### Returns `PgInsertWithout`<`PgInsertKind`<[`PgUnthrownInsertHKT`](#pgunthrowninserthkt), `TTable`, `TQueryResult`, `TSelectedFields`, { \[K in string | number | symbol]: { \[Key in string | number | symbol]: SelectResultField\ }\[K] }, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"returning"`> ###### Example ```ts // Insert one row and return all fields const insertedCar: Car[] = await db.insert(cars) .values({ brand: 'BMW' }) .returning(); // Insert one row and return only the id const insertedCarId: { id: number }[] = await db.insert(cars) .values({ brand: 'BMW' }) .returning({ id: cars.id }); ``` ###### Inherited from ```ts PgInsertBase.returning ``` ##### shouldOmitSQLParens()? ```ts optional shouldOmitSQLParens(): boolean; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:49 ###### Returns `boolean` ###### Inherited from ```ts PgInsertBase.shouldOmitSQLParens ``` ##### toSQL() ```ts toSQL(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:198 ###### Returns `Query` ###### Inherited from ```ts PgInsertBase.toSQL ``` *** ### PgUnthrownRaw Defined in: [packages/drizzle/src/pg-core/raw.ts:22](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/raw.ts#L22) A raw `db.execute(sql\`…\`)`query that resolves to an`AsyncResult\`. #### Remarks Unlike every other builder, this one is handed an already-prepared query — the database prepared it when building the fragment — so `_prepare` simply returns it and `execute` runs it. #### Extends * `PgRaw`<`TResult`> #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `TResult` | the driver's result for the statement. | #### Constructors ##### Constructor ```ts new PgUnthrownRaw( prepared, sql, query): PgUnthrownRaw; ``` Defined in: [packages/drizzle/src/pg-core/raw.ts:31](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/raw.ts#L31) ###### Parameters | Parameter | Type | | ------ | ------ | | `prepared` | [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery)<{ `execute`: `TResult`; }> | | `sql` | `SQL` | | `query` | `Query` | ###### Returns [`PgUnthrownRaw`](#pgunthrownraw)<`TResult`> ###### Overrides ```ts PgRaw.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | `PgRaw._` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/raw.d.ts:13 | | `_.dialect` | `readonly` | `"pg"` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/raw.d.ts:14 | | `_.result` | `readonly` | `TResult` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/raw.d.ts:15 | | `then` | `readonly` | [`ResultThen`](#resultthen)<`TResult`> | `undefined` | The `then` that makes a query builder awaitable, resolving to a `Result`. **Remarks** Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. | - | - | [packages/drizzle/src/pg-core/raw.ts:46](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/raw.ts#L46) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownRaw"` | - | `PgRaw.[entityKind]` | - | [packages/drizzle/src/pg-core/raw.ts:23](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/raw.ts#L23) | #### Methods ##### \_prepare() ```ts _prepare(): PgUnthrownPreparedQuery<{ execute: TResult; }>; ``` Defined in: [packages/drizzle/src/pg-core/raw.ts:40](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/raw.ts#L40) ###### Returns [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery)<{ `execute`: `TResult`; }> ###### Overrides ```ts PgRaw._prepare ``` ##### execute() ```ts execute(placeholderValues?): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/raw.ts:36](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/raw.ts#L36) Run the statement, resolving to the driver's result. ###### Parameters | Parameter | Type | | ------ | ------ | | `placeholderValues?` | `Record`<`string`, `unknown`> | ###### Returns `AsyncResult`<`TResult`, [`PgQueryError`](#pgqueryerror)> ##### getQuery() ```ts getQuery(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/raw.d.ts:19 ###### Returns `Query` ###### Inherited from ```ts PgRaw.getQuery ``` ##### getSQL() ```ts getSQL(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/raw.d.ts:18 ###### Returns `SQL`<`unknown`> ###### Inherited from ```ts PgRaw.getSQL ``` ##### shouldOmitSQLParens()? ```ts optional shouldOmitSQLParens(): boolean; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:49 ###### Returns `boolean` ###### Inherited from ```ts PgRaw.shouldOmitSQLParens ``` *** ### PgUnthrownRefreshMaterializedView Defined in: [packages/drizzle/src/pg-core/refresh-materialized-view.ts:18](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/refresh-materialized-view.ts#L18) A `refresh materialized view` statement that resolves to an `AsyncResult`. #### Extends * `PgRefreshMaterializedView`<`TQueryResult`> #### Type Parameters | Type Parameter | | ------ | | `TQueryResult` *extends* `PgQueryResultHKT` | #### Constructors ##### Constructor ```ts new PgUnthrownRefreshMaterializedView( view, session, dialect): PgUnthrownRefreshMaterializedView; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/refresh-materialized-view.d.ts:21 ###### Parameters | Parameter | Type | | ------ | ------ | | `view` | `PgMaterializedView` | | `session` | `PgSession` | | `dialect` | `PgDialect` | ###### Returns [`PgUnthrownRefreshMaterializedView`](#pgunthrownrefreshmaterializedview)<`TQueryResult`> ###### Inherited from ```ts PgRefreshMaterializedView.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | `PgRefreshMaterializedView._` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/refresh-materialized-view.d.ts:12 | | `_.dialect` | `readonly` | `"pg"` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/refresh-materialized-view.d.ts:13 | | `_.result` | `readonly` | `PgQueryResultKind`<`TQueryResult`, `never`> | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/refresh-materialized-view.d.ts:14 | | `then` | `readonly` | [`ResultThen`](#resultthen)<`PgQueryResultKind`<`TQueryResult`, `never`>, `never`> | `undefined` | The `then` that makes a query builder awaitable, resolving to a `Result`. **Remarks** Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. | - | - | [packages/drizzle/src/pg-core/refresh-materialized-view.ts:88](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/refresh-materialized-view.ts#L88) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownRefreshMaterializedView"` | - | `PgRefreshMaterializedView.[entityKind]` | - | [packages/drizzle/src/pg-core/refresh-materialized-view.ts:21](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/refresh-materialized-view.ts#L21) | #### Methods ##### concurrently() ```ts concurrently(): this; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/refresh-materialized-view.d.ts:22 ###### Returns `this` ###### Inherited from ```ts PgRefreshMaterializedView.concurrently ``` ##### execute() ```ts execute(placeholderValues?): AsyncResult, never>; ``` Defined in: [packages/drizzle/src/pg-core/refresh-materialized-view.ts:80](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/refresh-materialized-view.ts#L80) Run the refresh, resolving to the driver's result. The error channel is `never`, and here that is a *judgement*, not an impossibility. A refresh **can** raise `23505` — it repopulates a heap, and `REFRESH … CONCURRENTLY` (the inherited `.concurrently()`) requires a unique index, so a view whose own query yields duplicates violates it. It is still a defect, by this package's "would you branch on it?" rule: a materialized view whose query produces duplicates is a bug in the *view definition*, which you log and 500 on — exactly what `match`'s `defect` arm already does. Nobody writes a recovery path for it, and modelling it would put an arm at every refresh call site duplicating that same defect arm. Runtime and type agree either way; see `runSafeQuery`. ###### Parameters | Parameter | Type | | ------ | ------ | | `placeholderValues?` | `Record`<`string`, `unknown`> | ###### Returns `AsyncResult`<`PgQueryResultKind`<`TQueryResult`, `never`>, `never`> ##### prepare() ```ts prepare(name): PgUnthrownSafePreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/refresh-materialized-view.ts:57](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/refresh-materialized-view.ts#L57) Create a prepared statement for this query. This allows the database to remember this query for the given session and call it by name, rather than specifying the full query. Its `execute()` carries the same `never` error channel as this builder's — see [PgUnthrownSafePreparedQuery](#pgunthrownsafepreparedquery). [Postgres prepare documentation](https://www.postgresql.org/docs/current/sql-prepare.html) ###### Parameters | Parameter | Type | | ------ | ------ | | `name` | `string` | ###### Returns [`PgUnthrownSafePreparedQuery`](#pgunthrownsafepreparedquery)<`PreparedQueryConfig` & `object`> ##### toSQL() ```ts toSQL(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/refresh-materialized-view.d.ts:24 ###### Returns `Query` ###### Inherited from ```ts PgRefreshMaterializedView.toSQL ``` ##### withNoData() ```ts withNoData(): this; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/refresh-materialized-view.d.ts:23 ###### Returns `this` ###### Inherited from ```ts PgRefreshMaterializedView.withNoData ``` *** ### PgUnthrownRelationalQuery Defined in: [packages/drizzle/src/pg-core/query.ts:34](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/query.ts#L34) A relational (`db.query.…`) query that resolves to an `AsyncResult`. #### Extends * `PgRelationalQuery`<[`PgUnthrownRelationalQueryHKT`](#pgunthrownrelationalqueryhkt), `TResult`> #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `TResult` | the shape the relational query builds; an array for `findMany`, a single row or `undefined` for `findFirst`. | #### Constructors ##### Constructor ```ts new PgUnthrownRelationalQuery( schema, table, tableConfig, dialect, session, config, mode, parseJson): PgUnthrownRelationalQuery; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/query.d.ts:52 ###### Parameters | Parameter | Type | | ------ | ------ | | `schema` | `TablesRelationalConfig` | | `table` | `PgTable` | | `tableConfig` | `TableRelationalConfig` | | `dialect` | `PgDialect` | | `session` | `PgSession` | | `config` | `true` | `DBQueryConfigWithComment`<`"many"` | `"one"`> | | `mode` | `"many"` | `"first"` | | `parseJson` | `boolean` | ###### Returns [`PgUnthrownRelationalQuery`](#pgunthrownrelationalquery)<`TResult`> ###### Inherited from ```ts PgRelationalQuery< PgUnthrownRelationalQueryHKT, TResult >.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | `PgRelationalQuery._` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/query.d.ts:47 | | `_.dialect` | `readonly` | `"pg"` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/query.d.ts:48 | | `_.hkt` | `readonly` | [`PgUnthrownRelationalQueryHKT`](#pgunthrownrelationalqueryhkt) | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/query.d.ts:49 | | `_.result` | `readonly` | `TResult` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/query.d.ts:50 | | `then` | `readonly` | [`ResultThen`](#resultthen)<`TResult`, `never`> | `undefined` | The `then` that makes a query builder awaitable, resolving to a `Result`. **Remarks** Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. | - | - | [packages/drizzle/src/pg-core/query.ts:95](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/query.ts#L95) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownRelationalQuery"` | - | `PgRelationalQuery.[entityKind]` | - | [packages/drizzle/src/pg-core/query.ts:38](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/query.ts#L38) | #### Methods ##### execute() ```ts execute(placeholderValues?): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/query.ts:89](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/query.ts#L89) Run the relational query, resolving to its rows. The error channel is `never` — `db.query.*` is a read, so every failure it can hit is a defect. See `runSafeQuery`. ###### Parameters | Parameter | Type | | ------ | ------ | | `placeholderValues?` | `Record`<`string`, `unknown`> | ###### Returns `AsyncResult`<`TResult`, `never`> ##### getSQL() ```ts getSQL(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/query.d.ts:54 ###### Returns `SQL` ###### Inherited from ```ts PgRelationalQuery.getSQL ``` ##### prepare() ```ts prepare(name): PgUnthrownSafePreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/query.ts:79](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/query.ts#L79) Create a prepared statement for this query. This allows the database to remember this query for the given session and call it by name, rather than specifying the full query. Its `execute()` carries the same `never` error channel as this builder's — see [PgUnthrownSafePreparedQuery](#pgunthrownsafepreparedquery). [Postgres prepare documentation](https://www.postgresql.org/docs/current/sql-prepare.html) ###### Parameters | Parameter | Type | | ------ | ------ | | `name` | `string` | ###### Returns [`PgUnthrownSafePreparedQuery`](#pgunthrownsafepreparedquery)<`PreparedQueryConfig` & `object`> ##### toSQL() ```ts toSQL(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/query.d.ts:59 ###### Returns `Query` ###### Inherited from ```ts PgRelationalQuery.toSQL ``` *** ### PgUnthrownSelectBase Defined in: [packages/drizzle/src/pg-core/select.ts:71](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/select.ts#L71) A `select` query that resolves to an `AsyncResult`. #### Remarks Every chaining method comes from drizzle's `PgSelectBase`; this subclass adds only the execution half — `_prepare`, `prepare`, `execute` — plus the `then` that makes `await db.select().from(users)` yield a `Result`. The error channel is **`never`**: a read has no modeled failure. A `SELECT` writes nothing, so it cannot violate an integrity constraint; a database that will not answer is an infrastructure failure, which is a defect. That is enforced at runtime as well as declared — see `runSafeQuery`. #### Extends * `PgSelectBase`<[`PgUnthrownSelectHKT`](#pgunthrownselecthkt), `TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`> #### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TTableName` *extends* `string` | `undefined` | - | | `TSelection` *extends* `ColumnsSelection` | `undefined` | - | | `TSelectMode` *extends* `SelectMode` | - | | `TNullabilityMap` *extends* `Record`<`string`, `JoinNullability`> | `TTableName` *extends* `string` ? `Record`<`TTableName`, `"not-null"`> : `Record`<`string`, `never`> | | `TDynamic` *extends* `boolean` | `false` | | `TExcludedMethods` *extends* `string` | `never` | | `TResult` *extends* `unknown`\[] | `SelectResult`<`TSelection`, `TSelectMode`, `TNullabilityMap`>\[] | | `TSelectedFields` *extends* `ColumnsSelection` | `BuildSubquerySelection`<`Assume`<`TSelection`, `ColumnsSelection`>, `TNullabilityMap`> | #### Constructors ##### Constructor ```ts new PgUnthrownSelectBase(config): PgUnthrownSelectBase; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:88 ###### Parameters | Parameter | Type | | ------ | ------ | | `config` | { `dialect`: `PgDialect`; `distinct`: | `boolean` | { `on`: ( | `SQLWrapper`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }>)\[]; } | `undefined`; `fields`: `Record`<`string`, `unknown`>; `isPartialSelect`: `boolean`; `session`: `PgSession` | `undefined`; `table`: | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `Subquery`<`string`, `Record`<`string`, `unknown`>>; `tagged?`: `boolean`; `withList`: `Subquery`<`string`, `Record`<`string`, `unknown`>>\[]; } | | `config.dialect` | `PgDialect` | | `config.distinct` | | `boolean` | { `on`: ( | `SQLWrapper`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }>)\[]; } | `undefined` | | `config.fields` | `Record`<`string`, `unknown`> | | `config.isPartialSelect` | `boolean` | | `config.session` | `PgSession` | `undefined` | | `config.table` | | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `Subquery`<`string`, `Record`<`string`, `unknown`>> | | `config.tagged?` | `boolean` | | `config.withList` | `Subquery`<`string`, `Record`<`string`, `unknown`>>\[] | ###### Returns [`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`> ###### Inherited from ```ts PgSelectBase< PgUnthrownSelectHKT, TTableName, TSelection, TSelectMode, TNullabilityMap, TDynamic, TExcludedMethods, TResult, TSelectedFields >.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | `PgSelectBase._` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:67 | | `_.config` | `readonly` | `PgSelectConfig` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:78 | | `_.dialect` | `readonly` | `"pg"` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:68 | | `_.dynamic` | `readonly` | `TDynamic` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:74 | | `_.excludedMethods` | `readonly` | `TExcludedMethods` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:75 | | `_.hkt` | `readonly` | [`PgUnthrownSelectHKT`](#pgunthrownselecthkt) | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:69 | | `_.nullabilityMap` | `readonly` | `TNullabilityMap` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:73 | | `_.result` | `readonly` | `TResult` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:76 | | `_.selectedFields` | `readonly` | `TSelectedFields` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:77 | | `_.selection` | `readonly` | `TSelection` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:71 | | `_.selectMode` | `readonly` | `TSelectMode` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:72 | | `_.tableName` | `readonly` | `TTableName` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:70 | | `crossJoin` | `public` | `PgSelectCrossJoinFn`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `false`> | `undefined` | Executes a `cross join` operation by combining rows from two tables into a new table. Calling this method retrieves all rows from both main and joined tables, merging all rows from each table. See docs: **Param** **table** the table to join. **Example** `// Select all users, each user with every pet const usersWithPets: { user: User; pets: Pet; }[] = await db.select() .from(users) .crossJoin(pets) // Select userId and petId const usersIdsAndPetIds: { userId: number; petId: number; }[] = await db.select({ userId: users.id, petId: pets.id, }) .from(users) .crossJoin(pets)` | - | `PgSelectBase.crossJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:265 | | `crossJoinLateral` | `public` | `PgSelectCrossJoinFn`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `true`> | `undefined` | Executes a `cross join lateral` operation by combining rows from two queries into a new table. A `lateral` join allows the right-hand expression to refer to columns from the left-hand side. Calling this method retrieves all rows from both main and joined queries, merging all rows from each query. See docs: **Param** **table** the query to join. | - | `PgSelectBase.crossJoinLateral` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:277 | | `except` | `public` | <`TValue`>(`rightSelection`) => `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `PgSetOperatorExcludedMethods`, `true`> | `undefined` | Adds `except` set operator to the query. Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. See docs: **Example** `// Select all courses offered in department A but not in department B await db.select({ courseName: depA.courseName }) .from(depA) .except( db.select({ courseName: depB.courseName }).from(depB) ); // or import { except } from 'drizzle-orm/pg-core' await except( db.select({ courseName: depA.courseName }).from(depA), db.select({ courseName: depB.courseName }).from(depB) );` | - | `PgSelectBase.except` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:423 | | `exceptAll` | `public` | <`TValue`>(`rightSelection`) => `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `PgSetOperatorExcludedMethods`, `true`> | `undefined` | Adds `except all` set operator to the query. Calling this method will retrieve all rows from the left query, except for the rows that are present in the result set of the right query. See docs: **Example** `// Select all products that are ordered by regular customers but not by VIP customers await db.select({ productId: regularCustomerOrders.productId, quantityOrdered: regularCustomerOrders.quantityOrdered, }) .from(regularCustomerOrders) .exceptAll( db.select({ productId: vipCustomerOrders.productId, quantityOrdered: vipCustomerOrders.quantityOrdered, }) .from(vipCustomerOrders) ); // or import { exceptAll } from 'drizzle-orm/pg-core' await exceptAll( db.select({ productId: regularCustomerOrders.productId, quantityOrdered: regularCustomerOrders.quantityOrdered }) .from(regularCustomerOrders), db.select({ productId: vipCustomerOrders.productId, quantityOrdered: vipCustomerOrders.quantityOrdered }) .from(vipCustomerOrders) );` | - | `PgSelectBase.exceptAll` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:464 | | `fullJoin` | `public` | `PgSelectJoinFn`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"full"`, `false`> | `undefined` | Executes a `full join` operation by combining rows from two tables into a new table. Calling this method retrieves all rows from both main and joined tables, merging rows with matching values and filling in `null` for non-matching columns. See docs: **Param** **table** the table to join. **Param** **on** the `on` clause. **Example** `// Select all users and their pets const usersWithPets: { user: User | null; pets: Pet | null; }[] = await db.select() .from(users) .fullJoin(pets, eq(users.id, pets.ownerId)) // Select userId and petId const usersIdsAndPetIds: { userId: number | null; petId: number | null; }[] = await db.select({ userId: users.id, petId: pets.id, }) .from(users) .fullJoin(pets, eq(users.id, pets.ownerId))` | - | `PgSelectBase.fullJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:238 | | `innerJoin` | `public` | `PgSelectJoinFn`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"inner"`, `false`> | `undefined` | Executes an `inner join` operation, creating a new table by combining rows from two tables that have matching values. Calling this method retrieves rows that have corresponding entries in both joined tables. Rows without matching entries in either table are excluded, resulting in a table that includes only matching pairs. See docs: **Param** **table** the table to join. **Param** **on** the `on` clause. **Example** `// Select all users and their pets const usersWithPets: { user: User; pets: Pet; }[] = await db.select() .from(users) .innerJoin(pets, eq(users.id, pets.ownerId)) // Select userId and petId const usersIdsAndPetIds: { userId: number; petId: number; }[] = await db.select({ userId: users.id, petId: pets.id, }) .from(users) .innerJoin(pets, eq(users.id, pets.ownerId))` | - | `PgSelectBase.innerJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:197 | | `innerJoinLateral` | `public` | `PgSelectJoinFn`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"inner"`, `true`> | `undefined` | Executes an `inner join lateral` operation, creating a new table by combining rows from two queries that have matching values. A `lateral` join allows the right-hand expression to refer to columns from the left-hand side. Calling this method retrieves rows that have corresponding entries in both joined tables. Rows without matching entries in either table are excluded, resulting in a table that includes only matching pairs. See docs: **Param** **table** the subquery to join. **Param** **on** the `on` clause. | - | `PgSelectBase.innerJoinLateral` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:210 | | `intersect` | `public` | <`TValue`>(`rightSelection`) => `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `PgSetOperatorExcludedMethods`, `true`> | `undefined` | Adds `intersect` set operator to the query. Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. See docs: **Example** `// Select course names that are offered in both departments A and B await db.select({ courseName: depA.courseName }) .from(depA) .intersect( db.select({ courseName: depB.courseName }).from(depB) ); // or import { intersect } from 'drizzle-orm/pg-core' await intersect( db.select({ courseName: depA.courseName }).from(depA), db.select({ courseName: depB.courseName }).from(depB) );` | - | `PgSelectBase.intersect` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:356 | | `intersectAll` | `public` | <`TValue`>(`rightSelection`) => `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `PgSetOperatorExcludedMethods`, `true`> | `undefined` | Adds `intersect all` set operator to the query. Calling this method will retain only the rows that are present in both result sets including all duplicates. See docs: **Example** `// Select all products and quantities that are ordered by both regular and VIP customers await db.select({ productId: regularCustomerOrders.productId, quantityOrdered: regularCustomerOrders.quantityOrdered }) .from(regularCustomerOrders) .intersectAll( db.select({ productId: vipCustomerOrders.productId, quantityOrdered: vipCustomerOrders.quantityOrdered }) .from(vipCustomerOrders) ); // or import { intersectAll } from 'drizzle-orm/pg-core' await intersectAll( db.select({ productId: regularCustomerOrders.productId, quantityOrdered: regularCustomerOrders.quantityOrdered }) .from(regularCustomerOrders), db.select({ productId: vipCustomerOrders.productId, quantityOrdered: vipCustomerOrders.quantityOrdered }) .from(vipCustomerOrders) );` | - | `PgSelectBase.intersectAll` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:397 | | `leftJoin` | `public` | `PgSelectJoinFn`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"left"`, `false`> | `undefined` | Executes a `left join` operation by adding another table to the current query. Calling this method associates each row of the table with the corresponding row from the joined table, if a match is found. If no matching row exists, it sets all columns of the joined table to null. See docs: **Param** **table** the table to join. **Param** **on** the `on` clause. **Example** `// Select all users and their pets const usersWithPets: { user: User; pets: Pet | null; }[] = await db.select() .from(users) .leftJoin(pets, eq(users.id, pets.ownerId)) // Select userId and petId const usersIdsAndPetIds: { userId: number; petId: number | null; }[] = await db.select({ userId: users.id, petId: pets.id, }) .from(users) .leftJoin(pets, eq(users.id, pets.ownerId))` | - | `PgSelectBase.leftJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:128 | | `leftJoinLateral` | `public` | `PgSelectJoinFn`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"left"`, `true`> | `undefined` | Executes a `left join lateral` operation by adding subquery to the current query. A `lateral` join allows the right-hand expression to refer to columns from the left-hand side. Calling this method associates each row of the table with the corresponding row from the joined table, if a match is found. If no matching row exists, it sets all columns of the joined table to null. See docs: **Param** **table** the subquery to join. **Param** **on** the `on` clause. | - | `PgSelectBase.leftJoinLateral` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:141 | | `rightJoin` | `public` | `PgSelectJoinFn`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"right"`, `false`> | `undefined` | Executes a `right join` operation by adding another table to the current query. Calling this method associates each row of the joined table with the corresponding row from the main table, if a match is found. If no matching row exists, it sets all columns of the main table to null. See docs: **Param** **table** the table to join. **Param** **on** the `on` clause. **Example** `// Select all users and their pets const usersWithPets: { user: User | null; pets: Pet; }[] = await db.select() .from(users) .rightJoin(pets, eq(users.id, pets.ownerId)) // Select userId and petId const usersIdsAndPetIds: { userId: number | null; petId: number; }[] = await db.select({ userId: users.id, petId: pets.id, }) .from(users) .rightJoin(pets, eq(users.id, pets.ownerId))` | - | `PgSelectBase.rightJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:169 | | `then` | `readonly` | [`ResultThen`](#resultthen)<`TResult`, `never`> | `undefined` | The `then` that makes a query builder awaitable, resolving to a `Result`. **Remarks** Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. | - | - | [packages/drizzle/src/pg-core/select.ts:161](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/select.ts#L161) | | `union` | `public` | <`TValue`>(`rightSelection`) => `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `PgSetOperatorExcludedMethods`, `true`> | `undefined` | Adds `union` set operator to the query. Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. See docs: **Example** `// Select all unique names from customers and users tables await db.select({ name: users.name }) .from(users) .union( db.select({ name: customers.name }).from(customers) ); // or import { union } from 'drizzle-orm/pg-core' await union( db.select({ name: users.name }).from(users), db.select({ name: customers.name }).from(customers) );` | - | `PgSelectBase.union` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:304 | | `unionAll` | `public` | <`TValue`>(`rightSelection`) => `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `PgSetOperatorExcludedMethods`, `true`> | `undefined` | Adds `union all` set operator to the query. Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. See docs: **Example** `// Select all transaction ids from both online and in-store sales await db.select({ transaction: onlineSales.transactionId }) .from(onlineSales) .unionAll( db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) ); // or import { unionAll } from 'drizzle-orm/pg-core' await unionAll( db.select({ transaction: onlineSales.transactionId }).from(onlineSales), db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) );` | - | `PgSelectBase.unionAll` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:330 | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownSelect"` | - | `PgSelectBase.[entityKind]` | - | [packages/drizzle/src/pg-core/select.ts:96](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/select.ts#L96) | #### Methods ##### $dynamic() ```ts $dynamic(): PgSelectDynamic>; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:617 ###### Returns `PgSelectDynamic`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>> ###### Inherited from ```ts PgSelectBase.$dynamic ``` ##### $withCache() ```ts $withCache(config?): this; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:618 ###### Parameters | Parameter | Type | | ------ | ------ | | `config?` | | `false` | { `autoInvalidate?`: `boolean`; `config?`: `CacheConfig`; `tag?`: `string`; } | ###### Returns `this` ###### Inherited from ```ts PgSelectBase.$withCache ``` ##### as() ```ts as(alias): SubqueryWithSelection; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:616 ###### Type Parameters | Type Parameter | | ------ | | `TAlias` *extends* `string` | ###### Parameters | Parameter | Type | | ------ | ------ | | `alias` | `TAlias` | ###### Returns `SubqueryWithSelection`<`TSelectedFields`, `TAlias`> ###### Inherited from ```ts PgSelectBase.as ``` ##### comment() ```ts comment(comment): PgSelectWithout, TDynamic, "comment">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:613 Attach [sqlcommenter](https://google.github.io/sqlcommenter) comment to a query ###### Parameters | Parameter | Type | | ------ | ------ | | `comment` | `CommentInput` | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"comment"`> ###### Inherited from ```ts PgSelectBase.comment ``` ##### execute() ```ts execute(placeholderValues?): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/select.ts:155](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/select.ts#L155) Run the query, resolving to the selected rows. The error channel is `never` — every failure a read can hit is a defect, and `runSafeQuery` is what makes that true at runtime, not just in the type. ###### Parameters | Parameter | Type | | ------ | ------ | | `placeholderValues?` | `Record`<`string`, `unknown`> | ###### Returns `AsyncResult`<`TResult`, `never`> ##### for() ```ts for(strength, config?): PgSelectWithout, TDynamic, "for">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:609 Adds a `for` clause to the query. Calling this method will specify a lock strength for this query that controls how strictly it acquires exclusive access to the rows being queried. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `strength` | `LockStrength` | the lock strength. | | `config?` | `LockConfig` | the lock configuration. | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"for"`> ###### Inherited from ```ts PgSelectBase.for ``` ##### getSQL() ```ts getSQL(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:614 ###### Returns `SQL` ###### Inherited from ```ts PgSelectBase.getSQL ``` ##### groupBy() ###### Call Signature ```ts groupBy(builder): PgSelectWithout, TDynamic, "groupBy">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:537 Adds a `group by` clause to the query. Calling this method will group rows that have the same values into summary rows, often used for aggregation purposes. See docs: ###### Parameters | Parameter | Type | | ------ | ------ | | `builder` | (`aliases`) => `ValueOrArray`< | `SQL`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }> | `Aliased`<`unknown`>> | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"groupBy"`> ###### Example ```ts // Group and count people by their last names await db.select({ lastName: people.lastName, count: sql`cast(count(*) as int)` }) .from(people) .groupBy(people.lastName); ``` ###### Inherited from ```ts PgSelectBase.groupBy ``` ###### Call Signature ```ts groupBy(...columns): PgSelectWithout, TDynamic, "groupBy">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:538 Adds a `group by` clause to the query. Calling this method will group rows that have the same values into summary rows, often used for aggregation purposes. See docs: ###### Parameters | Parameter | Type | | ------ | ------ | | ...`columns` | ( | `SQL`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }> | `Aliased`<`unknown`>)\[] | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"groupBy"`> ###### Example ```ts // Group and count people by their last names await db.select({ lastName: people.lastName, count: sql`cast(count(*) as int)` }) .from(people) .groupBy(people.lastName); ``` ###### Inherited from ```ts PgSelectBase.groupBy ``` ##### having() ```ts having(having): PgSelectWithout, TDynamic, "having">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:517 Adds a `having` clause to the query. Calling this method will select only those rows that fulfill a specified condition. It is typically used with aggregate functions to filter the aggregated data based on a specified condition. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `having` | | `SQL`<`unknown`> | ((`aliases`) => `SQL`<`unknown`> | `undefined`) | `undefined` | the `having` clause. | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"having"`> ###### Example ```ts // Select all brands with more than one car await db.select({ brand: cars.brand, count: sql`cast(count(${cars.id}) as int)`, }) .from(cars) .groupBy(cars.brand) .having(({ count }) => gt(count, 1)); ``` ###### Inherited from ```ts PgSelectBase.having ``` ##### limit() ```ts limit(limit): PgSelectWithout, TDynamic, "limit">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:581 Adds a `limit` clause to the query. Calling this method will set the maximum number of rows that will be returned by this query. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `limit` | `number` | `Placeholder`<`string`, `any`> | the `limit` clause. | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"limit"`> ###### Example ```ts // Get the first 10 people from this query. await db.select().from(people).limit(10); ``` ###### Inherited from ```ts PgSelectBase.limit ``` ##### offset() ```ts offset(offset): PgSelectWithout, TDynamic, "offset">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:598 Adds an `offset` clause to the query. Calling this method will skip a number of rows when returning results from this query. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `offset` | `number` | `Placeholder`<`string`, `any`> | the `offset` clause. | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"offset"`> ###### Example ```ts // Get the 10th-20th people from this query. await db.select().from(people).offset(10).limit(10); ``` ###### Inherited from ```ts PgSelectBase.offset ``` ##### orderBy() ###### Call Signature ```ts orderBy(builder): PgSelectWithout, TDynamic, "orderBy">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:563 Adds an `order by` clause to the query. Calling this method will sort the result-set in ascending or descending order. By default, the sort order is ascending. See docs: ###### Parameters | Parameter | Type | | ------ | ------ | | `builder` | (`aliases`) => `ValueOrArray`< | `SQL`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }> | `Aliased`<`unknown`>> | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"orderBy"`> ###### Example ``` // Select cars ordered by year await db.select().from(cars).orderBy(cars.year); ``` You can specify whether results are in ascending or descending order with the `asc()` and `desc()` operators. ```ts // Select cars ordered by year in descending order await db.select().from(cars).orderBy(desc(cars.year)); // Select cars ordered by year and price await db.select().from(cars).orderBy(asc(cars.year), desc(cars.price)); ``` ###### Inherited from ```ts PgSelectBase.orderBy ``` ###### Call Signature ```ts orderBy(...columns): PgSelectWithout, TDynamic, "orderBy">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:564 Adds an `order by` clause to the query. Calling this method will sort the result-set in ascending or descending order. By default, the sort order is ascending. See docs: ###### Parameters | Parameter | Type | | ------ | ------ | | ...`columns` | ( | `SQL`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }> | `Aliased`<`unknown`>)\[] | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"orderBy"`> ###### Example ``` // Select cars ordered by year await db.select().from(cars).orderBy(cars.year); ``` You can specify whether results are in ascending or descending order with the `asc()` and `desc()` operators. ```ts // Select cars ordered by year in descending order await db.select().from(cars).orderBy(desc(cars.year)); // Select cars ordered by year and price await db.select().from(cars).orderBy(asc(cars.year), desc(cars.price)); ``` ###### Inherited from ```ts PgSelectBase.orderBy ``` ##### prepare() ```ts prepare(name): PgUnthrownSafePreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/select.ts:145](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/select.ts#L145) Create a prepared statement for this query. This allows the database to remember this query for the given session and call it by name, rather than specifying the full query. Its `execute()` carries the same `never` error channel as this builder's — see [PgUnthrownSafePreparedQuery](#pgunthrownsafepreparedquery). [Postgres prepare documentation](https://www.postgresql.org/docs/current/sql-prepare.html) ###### Parameters | Parameter | Type | | ------ | ------ | | `name` | `string` | ###### Returns [`PgUnthrownSafePreparedQuery`](#pgunthrownsafepreparedquery)<`PreparedQueryConfig` & `object`> ##### toSQL() ```ts toSQL(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:615 ###### Returns `Query` ###### Inherited from ```ts PgSelectBase.toSQL ``` ##### where() ```ts where(where): PgSelectWithout, TDynamic, "where">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.d.ts:494 Adds a `where` clause to the query. Calling this method will select only those rows that fulfill a specified condition. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `where` | | `SQL`<`unknown`> | ((`aliases`) => `SQL`<`unknown`> | `undefined`) | `undefined` | the `where` clause. | ###### Returns `PgSelectWithout`<[`PgUnthrownSelectBase`](#pgunthrownselectbase)<`TTableName`, `TSelection`, `TSelectMode`, `TNullabilityMap`, `TDynamic`, `TExcludedMethods`, `TResult`, `TSelectedFields`>, `TDynamic`, `"where"`> ###### Example You can use conditional operators and `sql function` to filter the rows to be selected. ```ts // Select all cars with green color await db.select().from(cars).where(eq(cars.color, 'green')); // or await db.select().from(cars).where(sql`${cars.color} = 'green'`) ``` You can logically combine conditional operators with `and()` and `or()` operators: ```ts // Select all BMW cars with a green color await db.select().from(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); // Select all cars with the green or blue color await db.select().from(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); ``` ###### Inherited from ```ts PgSelectBase.where ``` *** ### PgUnthrownUpdateBase Defined in: [packages/drizzle/src/pg-core/update.ts:60](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/update.ts#L60) An `update` query that resolves to an `AsyncResult`. #### Extends * `PgUpdateBase`<[`PgUnthrownUpdateHKT`](#pgunthrownupdatehkt), `TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`> #### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TTable` *extends* `PgTable` | - | | `TQueryResult` *extends* `PgQueryResultHKT` | - | | `TFrom` *extends* `PgTable` | `Subquery` | `PgViewBase` | `SQL` | `undefined` | `undefined` | | `TSelectedFields` *extends* `ColumnsSelection` | `undefined` | `undefined` | | `TReturning` *extends* `Record`<`string`, `unknown`> | `undefined` | `undefined` | | `TNullabilityMap` *extends* `Record`<`string`, `JoinNullability`> | `Record`<`TTable`\[`"_"`]\[`"name"`], `"not-null"`> | | `TJoins` *extends* `Join`\[] | \[] | | `TDynamic` *extends* `boolean` | `false` | | `TExcludedMethods` *extends* `string` | `never` | #### Constructors ##### Constructor ```ts new PgUnthrownUpdateBase( table, set, session, dialect, withList?): PgUnthrownUpdateBase; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:119 ###### Parameters | Parameter | Type | | ------ | ------ | | `table` | `TTable` | | `set` | `UpdateSet` | | `session` | `PgSession` | | `dialect` | `PgDialect` | | `withList?` | `Subquery`<`string`, `Record`<`string`, `unknown`>>\[] | ###### Returns [`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`> ###### Inherited from ```ts PgUpdateBase< PgUnthrownUpdateHKT, TTable, TQueryResult, TFrom, TSelectedFields, TReturning, TNullabilityMap, TJoins, TDynamic, TExcludedMethods >.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | `PgUpdateBase._` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:97 | | `_.dialect` | `readonly` | `"pg"` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:98 | | `_.dynamic` | `readonly` | `TDynamic` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:107 | | `_.excludedMethods` | `readonly` | `TExcludedMethods` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:108 | | `_.from` | `readonly` | `TFrom` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:104 | | `_.hkt` | `readonly` | [`PgUnthrownUpdateHKT`](#pgunthrownupdatehkt) | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:99 | | `_.joins` | `readonly` | `TJoins` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:101 | | `_.nullabilityMap` | `readonly` | `TNullabilityMap` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:102 | | `_.queryResult` | `readonly` | `TQueryResult` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:103 | | `_.result` | `readonly` | `TReturning` *extends* `undefined` ? `PgQueryResultKind`<`TQueryResult`, `never`> : `TReturning`\[] | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:109 | | `_.returning` | `readonly` | `TReturning` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:106 | | `_.selectedFields` | `readonly` | `TSelectedFields` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:105 | | `_.table` | `readonly` | `TTable` | `undefined` | - | - | - | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:100 | | `fullJoin` | `public` | `PgUpdateJoinFn`<[`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"full"`> | `undefined` | - | - | `PgUpdateBase.fullJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:126 | | `innerJoin` | `public` | `PgUpdateJoinFn`<[`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"inner"`> | `undefined` | - | - | `PgUpdateBase.innerJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:125 | | `leftJoin` | `public` | `PgUpdateJoinFn`<[`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"left"`> | `undefined` | - | - | `PgUpdateBase.leftJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:123 | | `rightJoin` | `public` | `PgUpdateJoinFn`<[`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"right"`> | `undefined` | - | - | `PgUpdateBase.rightJoin` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:124 | | `then` | `readonly` | [`ResultThen`](#resultthen)<[`UpdateResult`](#updateresult)<`TQueryResult`, `TReturning`>> | `undefined` | The `then` that makes a query builder awaitable, resolving to a `Result`. **Remarks** Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. | - | - | [packages/drizzle/src/pg-core/update.ts:131](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/update.ts#L131) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownUpdate"` | - | `PgUpdateBase.[entityKind]` | - | [packages/drizzle/src/pg-core/update.ts:82](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/update.ts#L82) | #### Methods ##### $dynamic() ```ts $dynamic(): PgUnthrownUpdateBase>>; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:191 ###### Returns [`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`Assume`<`TTable`, `PgTable`<`TableConfig`>>> ###### Inherited from ```ts PgUpdateBase.$dynamic ``` ##### comment() ```ts comment(comment): PgUpdateWithout, TDynamic, "comment">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:188 Attach [sqlcommenter](https://google.github.io/sqlcommenter) comment to a query ###### Parameters | Parameter | Type | | ------ | ------ | | `comment` | `CommentInput` | ###### Returns `PgUpdateWithout`<[`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"comment"`> ###### Inherited from ```ts PgUpdateBase.comment ``` ##### execute() ```ts execute(placeholderValues?): AsyncResult, PgQueryError>; ``` Defined in: [packages/drizzle/src/pg-core/update.ts:123](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/update.ts#L123) Run the update, resolving to its result or a [PgQueryError](#pgqueryerror). ###### Parameters | Parameter | Type | | ------ | ------ | | `placeholderValues?` | `Record`<`string`, `unknown`> | ###### Returns `AsyncResult`<[`UpdateResult`](#updateresult)<`TQueryResult`, `TReturning`>, [`PgQueryError`](#pgqueryerror)> ##### from() ```ts from(source): PgUpdateWithJoins; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:120 ###### Type Parameters | Type Parameter | | ------ | | `TFrom` *extends* | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `Subquery`<`string`, `Record`<`string`, `unknown`>> | ###### Parameters | Parameter | Type | | ------ | ------ | | `source` | `TableLikeHasEmptySelection`<`TFrom`> *extends* `true` ? `DrizzleTypeError`<``"Cannot reference a data-modifying statement subquery if it doesn't contain a `returning` clause"``> : `TFrom` | ###### Returns `PgUpdateWithJoins`<`this`, `TDynamic`, `TFrom`> ###### Inherited from ```ts PgUpdateBase.from ``` ##### getSQL() ```ts getSQL(): SQL; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:189 ###### Returns `SQL` ###### Inherited from ```ts PgUpdateBase.getSQL ``` ##### prepare() ```ts prepare(name): PgUnthrownPreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/update.ts:114](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/update.ts#L114) Create a prepared statement for this query. This allows the database to remember this query for the given session and call it by name, rather than specifying the full query. [Postgres prepare documentation](https://www.postgresql.org/docs/current/sql-prepare.html) ###### Parameters | Parameter | Type | | ------ | ------ | | `name` | `string` | ###### Returns [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery)<`PreparedQueryConfig` & `object`> ##### returning() ###### Call Signature ```ts returning(): PgUpdateWithout extends true ? TTable["_"]["columns"] : { [K in string | number | symbol]: (Record & { [K in string | number | symbol as (...)[(...)]["table"]["_"]["name"]]: (...)[(...)]["table"]["_"]["columns"] })[K] }, SelectPartialResult, "single", TJoins, GetSelectTableSelection>, TNullabilityMap>, TNullabilityMap, TJoins, TDynamic, TExcludedMethods>, TDynamic>; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:183 Adds a `returning` clause to the query. Calling this method will return the specified fields of the updated rows. If no fields are specified, all fields will be returned. See docs: ###### Returns `PgUpdateWithout`<`PgUpdateKind`<[`PgUnthrownUpdateHKT`](#pgunthrownupdatehkt), `TTable`, `TQueryResult`, `TFrom`, `Equal`<`TJoins`, \[]> *extends* `true` ? `TTable`\[`"_"`]\[`"columns"`] : { \[K in string | number | symbol]: (Record\ & { \[K in string | number | symbol as (...)\[(...)]\["table"]\["\_"]\["name"]]: (...)\[(...)]\["table"]\["\_"]\["columns"] })\[K] }, `SelectPartialResult`<`AccumulateToResult`<[`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `"single"`, `TJoins`, `GetSelectTableSelection`<`TTable`>>, `TNullabilityMap`>, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `TDynamic`> ###### Example ```ts // Update all cars with the green color and return all fields const updatedCars: Car[] = await db.update(cars) .set({ color: 'red' }) .where(eq(cars.color, 'green')) .returning(); // Update all cars with the green color and return only their id and brand fields const updatedCarsIdsAndBrands: { id: number, brand: string }[] = await db.update(cars) .set({ color: 'red' }) .where(eq(cars.color, 'green')) .returning({ id: cars.id, brand: cars.brand }); ``` ###### Inherited from ```ts PgUpdateBase.returning ``` ###### Call Signature ```ts returning(fields): PgUpdateWithout, "partial", TJoins, TSelectedFields>, TNullabilityMap>, TNullabilityMap, TJoins, TDynamic, TExcludedMethods>, TDynamic, "returning">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:184 Adds a `returning` clause to the query. Calling this method will return the specified fields of the updated rows. If no fields are specified, all fields will be returned. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelectedFields` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelectedFields` | ###### Returns `PgUpdateWithout`<`PgUpdateKind`<[`PgUnthrownUpdateHKT`](#pgunthrownupdatehkt), `TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `SelectPartialResult`<`AccumulateToResult`<[`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `"partial"`, `TJoins`, `TSelectedFields`>, `TNullabilityMap`>, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"returning"`> ###### Example ```ts // Update all cars with the green color and return all fields const updatedCars: Car[] = await db.update(cars) .set({ color: 'red' }) .where(eq(cars.color, 'green')) .returning(); // Update all cars with the green color and return only their id and brand fields const updatedCarsIdsAndBrands: { id: number, brand: string }[] = await db.update(cars) .set({ color: 'red' }) .where(eq(cars.color, 'green')) .returning({ id: cars.id, brand: cars.brand }); ``` ###### Inherited from ```ts PgUpdateBase.returning ``` ##### shouldOmitSQLParens()? ```ts optional shouldOmitSQLParens(): boolean; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/sql/sql.d.ts:49 ###### Returns `boolean` ###### Inherited from ```ts PgUpdateBase.shouldOmitSQLParens ``` ##### toSQL() ```ts toSQL(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:190 ###### Returns `Query` ###### Inherited from ```ts PgUpdateBase.toSQL ``` ##### where() ```ts where(where): PgUpdateWithout, TDynamic, "where">; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:160 Adds a 'where' clause to the query. Calling this method will update only those rows that fulfill a specified condition. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `where` | `SQL`<`unknown`> | `undefined` | the 'where' clause. | ###### Returns `PgUpdateWithout`<[`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`TTable`, `TQueryResult`, `TFrom`, `TSelectedFields`, `TReturning`, `TNullabilityMap`, `TJoins`, `TDynamic`, `TExcludedMethods`>, `TDynamic`, `"where"`> ###### Example You can use conditional operators and `sql function` to filter the rows to be updated. ```ts // Update all cars with green color await db.update(cars).set({ color: 'red' }) .where(eq(cars.color, 'green')); // or await db.update(cars).set({ color: 'red' }) .where(sql`${cars.color} = 'green'`) ``` You can logically combine conditional operators with `and()` and `or()` operators: ```ts // Update all BMW cars with a green color await db.update(cars).set({ color: 'red' }) .where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); // Update all cars with the green or blue color await db.update(cars).set({ color: 'red' }) .where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); ``` ###### Inherited from ```ts PgUpdateBase.where ``` *** ### PgUnthrownDeleteHKT Defined in: [packages/drizzle/src/pg-core/delete.ts:37](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/delete.ts#L37) The higher-kinded type that keeps every chained `delete` method returning an unthrown builder rather than drizzle's own. #### Remarks See [PgUnthrownSelectHKT](#pgunthrownselecthkt) for why this is an `interface`. #### Extends * `PgDeleteHKTBase` #### Properties | Property | Type | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `_type` | [`PgUnthrownDeleteBase`](#pgunthrowndeletebase)<`PgTable`<`TableConfig`>, `PgQueryResultHKT`, `ColumnsSelection` | `undefined`, `Record`<`string`, `unknown`> | `undefined`, `boolean`, `string`> | `PgDeleteHKTBase._type` | - | [packages/drizzle/src/pg-core/delete.ts:38](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/delete.ts#L38) | | `dynamic` | `boolean` | - | `PgDeleteHKTBase.dynamic` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:33 | | `excludedMethods` | `string` | - | `PgDeleteHKTBase.excludedMethods` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:34 | | `queryResult` | `unknown` | - | `PgDeleteHKTBase.queryResult` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:30 | | `returning` | `unknown` | - | `PgDeleteHKTBase.returning` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:32 | | `selectedFields` | `unknown` | - | `PgDeleteHKTBase.selectedFields` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:31 | | `table` | `unknown` | - | `PgDeleteHKTBase.table` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/delete.d.ts:29 | *** ### PgUnthrownInsertHKT Defined in: [packages/drizzle/src/pg-core/insert.ts:36](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/insert.ts#L36) The higher-kinded type that keeps every chained `insert` method returning an unthrown builder rather than drizzle's own. #### Remarks See [PgUnthrownSelectHKT](#pgunthrownselecthkt) for why this is an `interface`. #### Extends * `PgInsertHKTBase` #### Properties | Property | Type | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `_type` | [`PgUnthrownInsertBase`](#pgunthrowninsertbase)<`PgTable`<`TableConfig`>, `PgQueryResultHKT`, `unknown`, `unknown`, `boolean`, `string`> | `PgInsertHKTBase._type` | - | [packages/drizzle/src/pg-core/insert.ts:37](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/insert.ts#L37) | | `dynamic` | `boolean` | - | `PgInsertHKTBase.dynamic` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:66 | | `excludedMethods` | `string` | - | `PgInsertHKTBase.excludedMethods` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:67 | | `queryResult` | `unknown` | - | `PgInsertHKTBase.queryResult` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:63 | | `result` | `unknown` | - | `PgInsertHKTBase.result` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:68 | | `returning` | `unknown` | - | `PgInsertHKTBase.returning` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:65 | | `selectedFields` | `unknown` | - | `PgInsertHKTBase.selectedFields` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:64 | | `table` | `unknown` | - | `PgInsertHKTBase.table` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/insert.d.ts:62 | *** ### PgUnthrownRelationalQueryHKT Defined in: [packages/drizzle/src/pg-core/query.ts:22](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/query.ts#L22) The higher-kinded type that makes `db.query.
.findMany()` build an unthrown relational query rather than drizzle's own. #### Remarks See [PgUnthrownSelectHKT](#pgunthrownselecthkt) for why this is an `interface`. #### Extends * `PgRelationalQueryHKTBase` #### Properties | Property | Type | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `_type` | [`PgUnthrownRelationalQuery`](#pgunthrownrelationalquery)<`unknown`> | `PgRelationalQueryHKTBase._type` | - | [packages/drizzle/src/pg-core/query.ts:23](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/query.ts#L23) | | `result` | `unknown` | - | `PgRelationalQueryHKTBase.result` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/query.d.ts:28 | *** ### PgUnthrownSelectHKT Defined in: [packages/drizzle/src/pg-core/select.ts:35](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/select.ts#L35) The higher-kinded type that keeps every chained `select` method returning an unthrown builder rather than drizzle's own. #### Remarks Drizzle's base builders are container-agnostic: `.where()`, `.limit()` and the joins all rebuild `this` through `PgSelectKind`, and the tree the query stays in is decided by this one type. It must be an `interface` — the pattern reads `this["tableName"]` and the polymorphic `this` type only exists inside an interface or class declaration. #### Extends * `PgSelectHKTBase` #### Properties | Property | Type | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `_type` | [`PgUnthrownSelectBase`](#pgunthrownselectbase)<`string` | `undefined`, `ColumnsSelection`, `SelectMode`, `Record`<`string`, `JoinNullability`>, `boolean`, `string`, `unknown`\[], `ColumnsSelection`> | `PgSelectHKTBase._type` | - | [packages/drizzle/src/pg-core/select.ts:36](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/select.ts#L36) | | `dynamic` | `boolean` | - | `PgSelectHKTBase.dynamic` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.types.d.ts:82 | | `excludedMethods` | `string` | - | `PgSelectHKTBase.excludedMethods` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.types.d.ts:83 | | `nullabilityMap` | `unknown` | - | `PgSelectHKTBase.nullabilityMap` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.types.d.ts:81 | | `result` | `unknown` | - | `PgSelectHKTBase.result` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.types.d.ts:84 | | `selectedFields` | `unknown` | - | `PgSelectHKTBase.selectedFields` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.types.d.ts:85 | | `selection` | `unknown` | - | `PgSelectHKTBase.selection` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.types.d.ts:79 | | `selectMode` | `SelectMode` | - | `PgSelectHKTBase.selectMode` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.types.d.ts:80 | | `tableName` | `string` | `undefined` | - | `PgSelectHKTBase.tableName` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/select.types.d.ts:78 | *** ### PgUnthrownUpdateHKT Defined in: [packages/drizzle/src/pg-core/update.ts:41](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/update.ts#L41) The higher-kinded type that keeps every chained `update` method returning an unthrown builder rather than drizzle's own. #### Remarks See [PgUnthrownSelectHKT](#pgunthrownselecthkt) for why this is an `interface`. #### Extends * `PgUpdateHKTBase` #### Properties | Property | Type | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `_type` | [`PgUnthrownUpdateBase`](#pgunthrownupdatebase)<`PgTable`<`TableConfig`>, `PgQueryResultHKT`, | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `Subquery`<`string`, `Record`<`string`, `unknown`>> | `undefined`, `ColumnsSelection` | `undefined`, `Record`<`string`, `unknown`> | `undefined`, `Record`<`string`, `JoinNullability`>, `Join`\[], `boolean`, `string`> | `PgUpdateHKTBase._type` | - | [packages/drizzle/src/pg-core/update.ts:42](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/update.ts#L42) | | `dynamic` | `boolean` | - | `PgUpdateHKTBase.dynamic` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:76 | | `excludedMethods` | `string` | - | `PgUpdateHKTBase.excludedMethods` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:77 | | `from` | `unknown` | - | `PgUpdateHKTBase.from` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:73 | | `joins` | `unknown` | - | `PgUpdateHKTBase.joins` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:70 | | `nullabilityMap` | `unknown` | - | `PgUpdateHKTBase.nullabilityMap` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:71 | | `queryResult` | `unknown` | - | `PgUpdateHKTBase.queryResult` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:72 | | `returning` | `unknown` | - | `PgUpdateHKTBase.returning` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:75 | | `selectedFields` | `unknown` | - | `PgUpdateHKTBase.selectedFields` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:74 | | `table` | `unknown` | - | `PgUpdateHKTBase.table` | node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/query-builders/update.d.ts:69 | *** ### PgUnthrownSelectBuilder ```ts type PgUnthrownSelectBuilder = PgSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/select.ts:53](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/select.ts#L53) The builder `db.select()` returns, before a table has been chosen. #### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | `undefined` | *** ### ResultThen ```ts type ResultThen = (onFulfilled?, onRejected?) => PromiseLike; ``` Defined in: [packages/drizzle/src/pg-core/awaitable.ts:40](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/awaitable.ts#L40) The `then` that makes a query builder awaitable, resolving to a `Result`. #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `T` | - | the value the query succeeds with; the awaited type is `Result`. | | `E` | [`PgQueryError`](#pgqueryerror) | the query's modeled error channel. Defaults to [PgQueryError](#pgqueryerror), which is what a **write** carries; the four read builders pass `never`, because a read has no modeled failure at all — see `runSafeQuery`. | #### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TResult1` | `Result`<`T`, `E`> | | `TResult2` | `never` | #### Parameters | Parameter | Type | | ------ | ------ | | `onFulfilled?` | ((`value`) => `TResult1` | `PromiseLike`<`TResult1`>) | `null` | | `onRejected?` | ((`reason`) => `TResult2` | `PromiseLike`<`TResult2`>) | `null` | #### Returns `PromiseLike`<`TResult1` | `TResult2`> #### Remarks Drizzle's promise and Effect trees each make their builders runnable the same way: the builder carries a `then` that defers to `execute()`. The promise tree gets it from the `QueryPromise` mixin, whose `then` is literally `this.execute().then(onFulfilled, onRejected)`. This package cannot reuse that mixin. `QueryPromise` declares `execute(): Promise`, and ours returns an `AsyncResult` — so merging its type would contradict the very method it delegates to. (Its `applyMixins` helper is `@internal` and absent from drizzle's published `.d.ts` besides.) Each builder therefore declares this `then` itself, built by `resultThen`, with the awaited type it actually produces. Awaiting a builder yields a `Result`, never a rejection: `execute()` returns an `AsyncResult`, whose internal promise never rejects, and the compilation step ahead of it runs inside the same boundary — see `runQuery`. `catch` and `finally` are deliberately not offered: there is no rejection for them to observe. `onRejected` is still forwarded, exactly as `AsyncResult.then` forwards it, so a hypothetical internal rejection settles the `await` instead of hanging it. ## Database ### PgUnthrownDatabase Defined in: [packages/drizzle/src/pg-core/db.ts:55](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L55) A Postgres database whose every query resolves to an `AsyncResult`. #### Remarks The unthrown sibling of drizzle's own `PgAsyncDatabase` (promises) and `PgEffectDatabase` (Effects). The entry points below only *build* queries — every one of them hands back a builder from this package's tree, and nothing touches the database until that builder is awaited or `execute`d. That is why their bodies are drizzle's, unchanged but for the builder classes. #### Extended by * [`NodePgUnthrownDatabase`](node-postgres.md#nodepgunthrowndatabase) * [`NodePgUnthrownTransaction`](node-postgres.md#nodepgunthrowntransaction) #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `TQueryResult` *extends* `PgQueryResultHKT` | - | the driver's result kind, which decides what a write without `.returning()` resolves to. | | `TRelations` *extends* `AnyRelations` | `EmptyRelations` | the relational schema backing [query](#query). | #### Constructors ##### Constructor ```ts new PgUnthrownDatabase( dialect, session, relations, parseRqbJson?, tagged?): PgUnthrownDatabase; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:78](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L78) ###### Parameters | Parameter | Type | Default value | Description | | ------ | ------ | ------ | ------ | | `dialect` | `PgDialect` | `undefined` | - | | `session` | [`PgUnthrownSession`](#abstract-pgunthrownsession)<`unknown`> | `undefined` | - | | `relations` | `TRelations` | `undefined` | - | | `parseRqbJson` | `boolean` | `false` | - | | `tagged` | `boolean` | `false` | - | ###### Returns [`PgUnthrownDatabase`](#pgunthrowndatabase)<`TQueryResult`, `TRelations`> #### Properties | Property | Modifier | Type | Default value | Description | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | [packages/drizzle/src/pg-core/db.ts:61](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L61) | | `_.relations` | `readonly` | `TRelations` | `undefined` | - | [packages/drizzle/src/pg-core/db.ts:62](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L62) | | `_.session` | `readonly` | [`PgUnthrownSession`](#abstract-pgunthrownsession)<`unknown`> | `undefined` | - | [packages/drizzle/src/pg-core/db.ts:63](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L63) | | `$with` | `readonly` | `WithBuilder` | `undefined` | Creates a subquery that defines a temporary named result set as a CTE. It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query. See docs: **Param** **alias** The alias for the subquery. Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries. **Example** `// Create a subquery with alias 'sq' and use it in the select query const sq = db.$with("sq").as(db.select().from(users).where(eq(users.id, 42))); const rows = (await db.with(sq).select().from(sq)).get();` To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them: `// Select an arbitrary SQL value as a field in a CTE and reference it in the main query const sq = db.$with("sq").as( db .select({ name: sql`upper(${users.name})`.as("name"), }) .from(users), ); const rows = (await db.with(sq).select({ name: sq.name }).from(sq)).get();` | [packages/drizzle/src/pg-core/db.ts:173](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L173) | | `query` | `readonly` | { \[K in string | number | symbol]: RelationalQueryBuilder\ } | `undefined` | The relational query API — `db.query.users.findMany(…)`, one entry per table in the relational schema. | [packages/drizzle/src/pg-core/db.ts:70](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L70) | | `tagged` | `readonly` | `boolean` | `false` | - | [packages/drizzle/src/pg-core/db.ts:85](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L85) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownDatabase"` | - | [packages/drizzle/src/pg-core/db.ts:59](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L59) | #### Methods ##### $count() ```ts $count(source, filters?): PgUnthrownCountBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:218](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L218) Count the rows a table, view or subquery yields, optionally filtered. ###### Parameters | Parameter | Type | | ------ | ------ | | `source` | | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `SQLWrapper`<`unknown`> | | `filters?` | `SQL`<`unknown`> | ###### Returns [`PgUnthrownCountBuilder`](#pgunthrowncountbuilder) ###### Example ```ts const total = (await db.$count(users, eq(users.active, true))).get(); // ^? number — a count is a read, so its error channel is `never`. ``` ##### delete() ```ts delete(table): PgUnthrownDeleteBase; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:613](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L613) Creates a delete query. Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. See docs: A write carries the full `PgQueryError` union — a delete can still raise `23505` through an `ON DELETE SET DEFAULT` — so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match`. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to delete from. | ###### Returns [`PgUnthrownDeleteBase`](#pgunthrowndeletebase)<`TTable`, `TQueryResult`> ###### Example ```ts // Delete all rows in the 'cars' table const all = await db.delete(cars); // ^? Result, PgQueryError> // Delete rows with filters and conditions await db.delete(cars).where(eq(cars.color, "green")); // Delete with returning clause const deleted = await db.delete(cars).where(eq(cars.id, 1)).returning(); ``` ##### execute() ```ts execute(query): PgUnthrownRaw>; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:650](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L650) Run a statement drizzle does not model — a raw `SQL` fragment or a string. ###### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TRow` *extends* `Record`<`string`, `unknown`> | `Record`<`string`, `unknown`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `string` | `SQLWrapper`<`unknown`> | ###### Returns [`PgUnthrownRaw`](#pgunthrownraw)<`PgQueryResultKind`<`TQueryResult`, `TRow`>> ###### Remarks Unlike every other entry point, this one compiles its argument **eagerly**, because `PgUnthrownRaw` is defined as holding an already-prepared query (that is what makes its `getSQL`, `getQuery` and `_prepare` synchronous accessors, exactly as in drizzle). Compilation therefore happens here rather than at `await`, and a `SQLWrapper` that cannot compile **throws at this call site** instead of yielding a defect. That is a deliberate line, not an oversight: the contract this package makes is about *running* a query — awaiting a builder, or calling its `execute()` — and `db.execute(…)` is the factory that produces one, not the run itself. The builder it returns is fully guarded. Reaching the throw takes handing in a query builder that is already broken (`db.execute(db.select({ t: other.col }).from(users))`); a string or a `sql` template — the documented use — cannot. Closing the gap would mean deferring compilation, which would cost `PgRaw`'s shape and its synchronous accessors for a case where the argument, not the statement, is the bug. ###### Example ```ts const result = await db.execute(sql`select now()`); ``` ##### insert() ```ts insert(table): PgInsertBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:572](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L572) Creates an insert query. Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert. See docs: A write carries the full `PgQueryError` union, so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match` — never a rejection. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to insert into. | ###### Returns `PgInsertBuilder`<`TTable`, `TQueryResult`, `false`, [`PgUnthrownInsertHKT`](#pgunthrowninserthkt)> ###### Example ```ts // Insert one row const one = await db.insert(cars).values({ brand: "BMW" }); // ^? Result, PgQueryError> // Insert multiple rows await db.insert(cars).values([{ brand: "BMW" }, { brand: "Porsche" }]); // Insert with returning clause const inserted = await db.insert(cars).values({ brand: "BMW" }).returning(); ``` ##### refreshMaterializedView() ```ts refreshMaterializedView(view): PgUnthrownRefreshMaterializedView; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:618](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L618) Rebuild a materialized view's stored rows. ###### Type Parameters | Type Parameter | | ------ | | `TView` *extends* `PgMaterializedView`<`string`, `boolean`, `ColumnsSelection`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `view` | `TView` | ###### Returns [`PgUnthrownRefreshMaterializedView`](#pgunthrownrefreshmaterializedview)<`TQueryResult`> ##### select() ###### Call Signature ```ts select(): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:396](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L396) Creates a select query. Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. Use `.from()` method to specify which table to select from. See docs: Awaiting the builder resolves to a `Result`, never rows directly — a read has no modeled failure, so the error channel is `never` and `.get()` compiles. ###### Returns [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select all columns and all rows from the 'cars' table const allCars = (await db.select().from(cars)).get(); // Select specific columns and all rows from the 'cars' table const carsIdsAndBrands = ( await db .select({ id: cars.id, brand: cars.brand, }) .from(cars) ).get(); ``` ###### Call Signature ```ts select(fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:397](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L397) Creates a select query. Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. Use `.from()` method to specify which table to select from. See docs: Awaiting the builder resolves to a `Result`, never rows directly — a read has no modeled failure, so the error channel is `never` and `.get()` compiles. ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelection` | ###### Returns [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select all columns and all rows from the 'cars' table const allCars = (await db.select().from(cars)).get(); // Select specific columns and all rows from the 'cars' table const carsIdsAndBrands = ( await db .select({ id: cars.id, brand: cars.brand, }) .from(cars) ).get(); ``` ##### selectDistinct() ###### Call Signature ```ts selectDistinct(): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:437](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L437) Adds `distinct` expression to the select query. Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. Use `.from()` method to specify which table to select from. Pass a selection object to specify the columns you want to select. See docs: ###### Returns [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select all unique rows from the 'cars' table const unique = ( await db.selectDistinct().from(cars).orderBy(cars.id, cars.brand, cars.color) ).get(); // Select all unique brands from the 'cars' table const brands = ( await db.selectDistinct({ brand: cars.brand }).from(cars).orderBy(cars.brand) ).get(); ``` ###### Call Signature ```ts selectDistinct(fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:438](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L438) Adds `distinct` expression to the select query. Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. Use `.from()` method to specify which table to select from. Pass a selection object to specify the columns you want to select. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelection` | ###### Returns [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select all unique rows from the 'cars' table const unique = ( await db.selectDistinct().from(cars).orderBy(cars.id, cars.brand, cars.color) ).get(); // Select all unique brands from the 'cars' table const brands = ( await db.selectDistinct({ brand: cars.brand }).from(cars).orderBy(cars.brand) ).get(); ``` ##### selectDistinctOn() ###### Call Signature ```ts selectDistinctOn(on): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:483](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L483) Adds `distinct on` expression to the select query. Calling this method will specify how the unique rows are determined. Use `.from()` method to specify which table to select from. Pass a selection object as the second argument to specify the columns you want to select. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `on` | ( | `SQLWrapper`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }>)\[] | The expression defining uniqueness. | ###### Returns [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select the first row for each unique brand from the 'cars' table const firstPerBrand = ( await db.selectDistinctOn([cars.brand]).from(cars).orderBy(cars.brand) ).get(); // The first occurrence of each unique brand, with its color const brandColors = ( await db .selectDistinctOn([cars.brand], { brand: cars.brand, color: cars.color }) .from(cars) .orderBy(cars.brand, cars.color) ).get(); ``` ###### Call Signature ```ts selectDistinctOn(on, fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:484](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L484) Adds `distinct on` expression to the select query. Calling this method will specify how the unique rows are determined. Use `.from()` method to specify which table to select from. Pass a selection object as the second argument to specify the columns you want to select. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `on` | ( | `SQLWrapper`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }>)\[] | The expression defining uniqueness. | | `fields` | `TSelection` | - | ###### Returns [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select the first row for each unique brand from the 'cars' table const firstPerBrand = ( await db.selectDistinctOn([cars.brand]).from(cars).orderBy(cars.brand) ).get(); // The first occurrence of each unique brand, with its color const brandColors = ( await db .selectDistinctOn([cars.brand], { brand: cars.brand, color: cars.color }) .from(cars) .orderBy(cars.brand, cars.color) ).get(); ``` ##### update() ```ts update(table): PgUpdateBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:538](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L538) Creates an update query. Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. Use `.set()` method to specify which values to update. See docs: A write carries the full `PgQueryError` union, so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match` — never a rejection. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to update. | ###### Returns `PgUpdateBuilder`<`TTable`, `TQueryResult`, [`PgUnthrownUpdateHKT`](#pgunthrownupdatehkt)> ###### Example ```ts // Update all rows in the 'cars' table const all = await db.update(cars).set({ color: "red" }); // ^? Result, PgQueryError> // Update rows with filters and conditions await db.update(cars).set({ color: "red" }).where(eq(cars.brand, "BMW")); // Update with returning clause const updated = await db .update(cars) .set({ color: "red" }) .where(eq(cars.id, 1)) .returning(); ``` ##### with() ```ts with(...queries): object; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:251](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L251) Incorporates a previously defined CTE (using `$with`) into the main query. This method allows the main query to reference a temporary named result set. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | ...`queries` | `WithSubquery`<`string`, `Record`<`string`, `unknown`>>\[] | The CTEs to incorporate into the main query. | ###### Returns `object` | Name | Type | Defined in | | ------ | ------ | ------ | | `delete()` | <`TTable`>(`table`) => [`PgUnthrownDeleteBase`](#pgunthrowndeletebase)<`TTable`, `TQueryResult`> | [packages/drizzle/src/pg-core/db.ts:273](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L273) | | `insert()` | <`TTable`>(`table`) => `PgInsertBuilder`<`TTable`, `TQueryResult`, `false`, [`PgUnthrownInsertHKT`](#pgunthrowninserthkt)> | [packages/drizzle/src/pg-core/db.ts:270](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L270) | | `select()` | { (): [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`fields`): [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:252](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L252) | | `selectDistinct()` | { (): [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`fields`): [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:256](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L256) | | `selectDistinctOn()` | { (`on`): [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`on`, `fields`): [`PgUnthrownSelectBuilder`](#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:260](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L260) | | `update()` | <`TTable`>(`table`) => `PgUpdateBuilder`<`TTable`, `TQueryResult`, [`PgUnthrownUpdateHKT`](#pgunthrownupdatehkt)> | [packages/drizzle/src/pg-core/db.ts:267](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L267) | ###### Example ```ts // Define a subquery 'sq' as a CTE using $with const sq = db.$with("sq").as(db.select().from(users).where(eq(users.id, 42))); // Incorporate the CTE 'sq' into the main query and select from it const rows = (await db.with(sq).select().from(sq)).get(); ``` ## Other ### CheckViolation Defined in: [packages/drizzle/src/errors.ts:29](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L29) A check constraint was violated (SQLSTATE `23514`). #### Extends * `TaggedErrorInstance`<`"CheckViolation"`, `ConstraintFields`> #### Constructors ##### Constructor ```ts new CheckViolation(args): CheckViolation; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `ConstraintFields` & `object` | ###### Returns [`CheckViolation`](#checkviolation) ###### Inherited from ```ts TaggedError("CheckViolation").constructor ``` #### Properties | Property | Modifier | Type | Default value | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_tag` | `readonly` | `"CheckViolation"` | `undefined` | - | `TaggedError("CheckViolation")._tag` | packages/core/dist/index.d.mts:2011 | | `cause` | `public` | `unknown` | `undefined` | - | `TaggedError("CheckViolation").cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 | | `constraint` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("CheckViolation").constraint` | [packages/drizzle/src/errors.ts:10](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L10) | | `detail` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("CheckViolation").detail` | [packages/drizzle/src/errors.ts:12](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L12) | | `message` | `public` | `string` | `"check constraint violated"` | `TaggedError("CheckViolation").message` | - | [packages/drizzle/src/errors.ts:30](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L30) | | `name` | `public` | `string` | `undefined` | - | `TaggedError("CheckViolation").name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 | | `stack?` | `public` | `string` | `undefined` | - | `TaggedError("CheckViolation").stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 | | `table` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("CheckViolation").table` | [packages/drizzle/src/errors.ts:11](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L11) | *** ### ExclusionViolation Defined in: [packages/drizzle/src/errors.ts:34](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L34) An exclusion constraint was violated (SQLSTATE `23P01`). #### Extends * `TaggedErrorInstance`<`"ExclusionViolation"`, `ConstraintFields`> #### Constructors ##### Constructor ```ts new ExclusionViolation(args): ExclusionViolation; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `ConstraintFields` & `object` | ###### Returns [`ExclusionViolation`](#exclusionviolation) ###### Inherited from ```ts TaggedError("ExclusionViolation").constructor ``` #### Properties | Property | Modifier | Type | Default value | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_tag` | `readonly` | `"ExclusionViolation"` | `undefined` | - | `TaggedError("ExclusionViolation")._tag` | packages/core/dist/index.d.mts:2011 | | `cause` | `public` | `unknown` | `undefined` | - | `TaggedError("ExclusionViolation").cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 | | `constraint` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("ExclusionViolation").constraint` | [packages/drizzle/src/errors.ts:10](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L10) | | `detail` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("ExclusionViolation").detail` | [packages/drizzle/src/errors.ts:12](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L12) | | `message` | `public` | `string` | `"exclusion constraint violated"` | `TaggedError("ExclusionViolation").message` | - | [packages/drizzle/src/errors.ts:35](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L35) | | `name` | `public` | `string` | `undefined` | - | `TaggedError("ExclusionViolation").name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 | | `stack?` | `public` | `string` | `undefined` | - | `TaggedError("ExclusionViolation").stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 | | `table` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("ExclusionViolation").table` | [packages/drizzle/src/errors.ts:11](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L11) | *** ### ForeignKeyViolation Defined in: [packages/drizzle/src/errors.ts:24](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L24) A foreign key constraint was violated (SQLSTATE `23503`). #### Extends * `TaggedErrorInstance`<`"ForeignKeyViolation"`, `ConstraintFields`> #### Constructors ##### Constructor ```ts new ForeignKeyViolation(args): ForeignKeyViolation; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `ConstraintFields` & `object` | ###### Returns [`ForeignKeyViolation`](#foreignkeyviolation) ###### Inherited from ```ts TaggedError("ForeignKeyViolation").constructor ``` #### Properties | Property | Modifier | Type | Default value | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_tag` | `readonly` | `"ForeignKeyViolation"` | `undefined` | - | `TaggedError("ForeignKeyViolation")._tag` | packages/core/dist/index.d.mts:2011 | | `cause` | `public` | `unknown` | `undefined` | - | `TaggedError("ForeignKeyViolation").cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 | | `constraint` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("ForeignKeyViolation").constraint` | [packages/drizzle/src/errors.ts:10](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L10) | | `detail` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("ForeignKeyViolation").detail` | [packages/drizzle/src/errors.ts:12](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L12) | | `message` | `public` | `string` | `"foreign key constraint violated"` | `TaggedError("ForeignKeyViolation").message` | - | [packages/drizzle/src/errors.ts:25](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L25) | | `name` | `public` | `string` | `undefined` | - | `TaggedError("ForeignKeyViolation").name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 | | `stack?` | `public` | `string` | `undefined` | - | `TaggedError("ForeignKeyViolation").stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 | | `table` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("ForeignKeyViolation").table` | [packages/drizzle/src/errors.ts:11](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L11) | *** ### NotNullViolation Defined in: [packages/drizzle/src/errors.ts:45](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L45) A `NOT NULL` constraint was violated (SQLSTATE `23502`). #### Remarks Carries `column` rather than `constraint`: `23502` names the offending column and has no constraint name of its own. #### Extends * `TaggedErrorInstance`<`"NotNullViolation"`, { `cause`: `unknown`; `column`: `string` | `undefined`; `detail`: `string` | `undefined`; `table`: `string` | `undefined`; }> #### Constructors ##### Constructor ```ts new NotNullViolation(args): NotNullViolation; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `object` & `object` | ###### Returns [`NotNullViolation`](#notnullviolation) ###### Inherited from ```ts TaggedError("NotNullViolation")<{ column: string | undefined; table: string | undefined; detail: string | undefined; cause: unknown; }>.constructor ``` #### Properties | Property | Modifier | Type | Default value | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_tag` | `readonly` | `"NotNullViolation"` | `undefined` | - | `TaggedError("NotNullViolation")._tag` | packages/core/dist/index.d.mts:2011 | | `cause` | `public` | `unknown` | `undefined` | - | `TaggedError("NotNullViolation").cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 | | `column` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("NotNullViolation").column` | [packages/drizzle/src/errors.ts:46](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L46) | | `detail` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("NotNullViolation").detail` | [packages/drizzle/src/errors.ts:48](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L48) | | `message` | `public` | `string` | `"not-null constraint violated"` | `TaggedError("NotNullViolation").message` | - | [packages/drizzle/src/errors.ts:51](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L51) | | `name` | `public` | `string` | `undefined` | - | `TaggedError("NotNullViolation").name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 | | `stack?` | `public` | `string` | `undefined` | - | `TaggedError("NotNullViolation").stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 | | `table` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError("NotNullViolation").table` | [packages/drizzle/src/errors.ts:47](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L47) | *** ### UniqueConstraintViolation Defined in: [packages/drizzle/src/errors.ts:17](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L17) A unique constraint was violated (SQLSTATE `23505`). #### Extends * `TaggedErrorInstance`<`"UniqueConstraintViolation"`, `ConstraintFields`> #### Constructors ##### Constructor ```ts new UniqueConstraintViolation(args): UniqueConstraintViolation; ``` Defined in: packages/core/dist/index.d.mts:2034 ###### Parameters | Parameter | Type | | ------ | ------ | | `args` | `ConstraintFields` & `object` | ###### Returns [`UniqueConstraintViolation`](#uniqueconstraintviolation) ###### Inherited from ```ts TaggedError( "UniqueConstraintViolation", ).constructor ``` #### Properties | Property | Modifier | Type | Default value | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_tag` | `readonly` | `"UniqueConstraintViolation"` | `undefined` | - | `TaggedError( "UniqueConstraintViolation", )._tag` | packages/core/dist/index.d.mts:2011 | | `cause` | `public` | `unknown` | `undefined` | - | `TaggedError( "UniqueConstraintViolation", ).cause` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 | | `constraint` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError( "UniqueConstraintViolation", ).constraint` | [packages/drizzle/src/errors.ts:10](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L10) | | `detail` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError( "UniqueConstraintViolation", ).detail` | [packages/drizzle/src/errors.ts:12](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L12) | | `message` | `public` | `string` | `"unique constraint violated"` | `TaggedError( "UniqueConstraintViolation", ).message` | - | [packages/drizzle/src/errors.ts:20](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L20) | | `name` | `public` | `string` | `undefined` | - | `TaggedError( "UniqueConstraintViolation", ).name` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1074 | | `stack?` | `public` | `string` | `undefined` | - | `TaggedError( "UniqueConstraintViolation", ).stack` | node\_modules/.pnpm/typescript@6.0.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 | | `table` | `readonly` | `string` | `undefined` | `undefined` | - | `TaggedError( "UniqueConstraintViolation", ).table` | [packages/drizzle/src/errors.ts:11](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L11) | *** ### DeleteResult ```ts type DeleteResult = TReturning extends undefined ? PgQueryResultKind : TReturning[]; ``` Defined in: [packages/drizzle/src/pg-core/delete.ts:22](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/delete.ts#L22) What a `delete` resolves to: the driver's own result object, or the returned rows once `.returning()` has been called. #### Type Parameters | Type Parameter | | ------ | | `TQueryResult` *extends* `PgQueryResultHKT` | | `TReturning` | *** ### InsertResult ```ts type InsertResult = TReturning extends undefined ? PgQueryResultKind : TReturning[]; ``` Defined in: [packages/drizzle/src/pg-core/insert.ts:21](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/insert.ts#L21) What an `insert` resolves to: the driver's own result object, or the returned rows once `.returning()` has been called. #### Type Parameters | Type Parameter | | ------ | | `TQueryResult` *extends* `PgQueryResultHKT` | | `TReturning` | *** ### PgQueryError ```ts type PgQueryError = | UniqueConstraintViolation | ForeignKeyViolation | NotNullViolation | CheckViolation | ExclusionViolation; ``` Defined in: [packages/drizzle/src/errors.ts:61](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L61) The full union of domain errors a Postgres query can surface. #### Remarks Infrastructure failures are deliberately absent — they are defects, not values. See [qualifyPgError](#qualifypgerror). *** ### UpdateResult ```ts type UpdateResult = TReturning extends undefined ? PgQueryResultKind : TReturning[]; ``` Defined in: [packages/drizzle/src/pg-core/update.ts:26](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/update.ts#L26) What an `update` resolves to: the driver's own result object, or the returned rows once `.returning()` has been called. #### Type Parameters | Type Parameter | | ------ | | `TQueryResult` *extends* `PgQueryResultHKT` | | `TReturning` | *** ### qualifyPgError() ```ts function qualifyPgError(cause, defect): D | PgQueryError; ``` Defined in: [packages/drizzle/src/errors.ts:106](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/errors.ts#L106) Triage a Postgres driver failure into the modeled error channel or the defect channel — a `qualify` in the Thesis-#3 sense, so it drops straight into a `fromPromise` at a boundary of your own. #### Type Parameters | Type Parameter | | ------ | | `D` | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `cause` | `unknown` | the rejected value from a Postgres query (a node-postgres `DatabaseError`, a `DrizzleQueryError` wrapping one, or anything else). | | `defect` | (`cause`) => `D` | the defect helper the boundary injects (never import it). | #### Returns `D` | [`PgQueryError`](#pgqueryerror) #### Remarks Only the five `23xxx` integrity-constraint codes are modeled: they are what a request handler branches on. Everything else — serialization failure (`40001`), deadlock (`40P01`), statement timeout (`57014`), connection loss, syntax errors — is a defect. Retry belongs in one `recoverDefect` wrapper that inspects the cause, not an arm at every write call site. #### Example ```ts const rows = fromPromise(pool.query("select 1"), qualifyPgError); ``` ## Session ### PgUnthrownPreparedQuery Defined in: [packages/drizzle/src/pg-core/session.ts:59](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L59) A prepared query whose execution yields an `AsyncResult`. #### Remarks This is the single place in the package where a driver rejection is triaged. Everything above it — the builder tree, the database facade — is type plumbing; the container swap happens here, and only here, because drizzle declares `PgBasePreparedQuery.execute()` as returning `unknown`. Every failure leaves [execute](#execute-4) as either a modeled [PgQueryError](#pgqueryerror) or a defect, so the returned `AsyncResult`'s internal promise never rejects and awaiting it never throws. #### Extends * `PgBasePreparedQuery` #### Extended by * [`PgUnthrownSafePreparedQuery`](#pgunthrownsafepreparedquery) #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `T` *extends* `PreparedQueryConfig` | `PreparedQueryConfig` | drizzle's per-query config, whose `execute` member is the value the query resolves to. | #### Constructors ##### Constructor ```ts new PgUnthrownPreparedQuery( executor, query, mapper, mode, logger): PgUnthrownPreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:73](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L73) ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `executor` | (`params`) => `Promise`<`unknown`> | runs the query against the driver with the given bound parameters. Its rejection is what [execute](#execute-4) triages. | | `query` | `Query` | the compiled SQL and its parameter list. | | `mapper` | [`PgRowMapper`](#pgrowmapper) | `undefined` | maps the driver's rows to the query's declared result, or `undefined` to pass the driver's value through untouched. | | `mode` | [`PgQueryMode`](#pgquerymode) | the row shape the driver was asked for. | | `logger` | `Logger` | drizzle's query logger. | ###### Returns [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery)<`T`> ###### Overrides ```ts PgBasePreparedQuery.constructor ``` #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `mode` | `readonly` | [`PgQueryMode`](#pgquerymode) | `undefined` | the row shape the driver was asked for. | - | [packages/drizzle/src/pg-core/session.ts:77](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L77) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownPreparedQuery"` | - | `PgBasePreparedQuery.[entityKind]` | [packages/drizzle/src/pg-core/session.ts:62](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L62) | #### Methods ##### execute() ```ts execute(placeholderValues?): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:142](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L142) Run the query, triaging any driver failure into the error or defect channel. ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `placeholderValues` | `Record`<`string`, `unknown`> | values for the query's named placeholders. | ###### Returns `AsyncResult`<`T`\[`"execute"`], [`PgQueryError`](#pgqueryerror)> ###### Remarks The promise is started from a thunk so that a synchronous throw — a missing placeholder value, a driver that validates its arguments eagerly — is caught by the same boundary as a rejection. `execute` therefore neither throws nor rejects: awaiting it always yields a `Result`. ###### Overrides ```ts PgBasePreparedQuery.execute ``` ##### getQuery() ```ts getQuery(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/session.d.ts:15 ###### Returns `Query` ###### Inherited from ```ts PgBasePreparedQuery.getQuery ``` *** ### PgUnthrownSafePreparedQuery Defined in: [packages/drizzle/src/pg-core/session.ts:201](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L201) A prepared query whose every failure is a defect — the read builders' half of [PgUnthrownPreparedQuery](#pgunthrownpreparedquery). #### Remarks A read has no modeled failure (see `runSafeQuery`), so the four read builders declare `E = never`. Their `prepare(name)` returns one of these, so running a *prepared* read reaches the same `fromSafePromise` boundary that `execute()` and `await` do — all three routes agree, and none of them can put a value in a channel the type calls empty. This is a subclass rather than a type parameter on [PgUnthrownPreparedQuery](#pgunthrownpreparedquery) deliberately. A parameterised `E` would have to pick its boundary from a constructor-injected function, and the injected default (`fromPromise` + `qualifyPgError`, typed `PgQueryError`) is not assignable to an unresolved `E` — so the single-class form needs a cast exactly where the type and the runtime must not be allowed to drift apart. Overriding `execute` needs none: `AsyncResult` is covariant in `E`, so `AsyncResult` already satisfies the base's declaration, and the narrower type is reachable *only* through this class, whose `execute` is the safe one. The weld is by construction. #### Extends * [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery)<`T`> #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `T` *extends* `PreparedQueryConfig` | `PreparedQueryConfig` | drizzle's per-query config, whose `execute` member is the value the query resolves to. | #### Constructors ##### Constructor ```ts new PgUnthrownSafePreparedQuery( executor, query, mapper, mode, logger): PgUnthrownSafePreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:73](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L73) ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `executor` | (`params`) => `Promise`<`unknown`> | runs the query against the driver with the given bound parameters. Its rejection is what [execute](#execute-8) triages. | | `query` | `Query` | the compiled SQL and its parameter list. | | `mapper` | [`PgRowMapper`](#pgrowmapper) | `undefined` | maps the driver's rows to the query's declared result, or `undefined` to pass the driver's value through untouched. | | `mode` | [`PgQueryMode`](#pgquerymode) | the row shape the driver was asked for. | | `logger` | `Logger` | drizzle's query logger. | ###### Returns [`PgUnthrownSafePreparedQuery`](#pgunthrownsafepreparedquery)<`T`> ###### Inherited from [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery).[`constructor`](#constructor-8) #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `mode` | `readonly` | [`PgQueryMode`](#pgquerymode) | `undefined` | the row shape the driver was asked for. | - | [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery).[`mode`](#mode) | [packages/drizzle/src/pg-core/session.ts:77](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L77) | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownSafePreparedQuery"` | - | [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery).[`[entityKind]`](#entitykind-4) | - | [packages/drizzle/src/pg-core/session.ts:204](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L204) | #### Methods ##### execute() ```ts execute(placeholderValues?): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:213](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L213) Run the query. Every failure — a constraint violation raised by a volatile function the read called included — is a `Defect`; the error channel is `never`. ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `placeholderValues` | `Record`<`string`, `unknown`> | values for the query's named placeholders. | ###### Returns `AsyncResult`<`T`\[`"execute"`], `never`> ###### Overrides [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery).[`execute`](#execute-4) ##### getQuery() ```ts getQuery(): Query; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/session.d.ts:15 ###### Returns `Query` ###### Inherited from [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery).[`getQuery`](#getquery) *** ### `abstract` PgUnthrownSession Defined in: [packages/drizzle/src/pg-core/session.ts:237](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L237) The session every unthrown Postgres driver implements. #### Remarks The mirror of drizzle's own `PgAsyncSession` / `PgEffectSession`: `PgSession` declares `execute` / `arrays` / `objects` as returning `unknown`, which is precisely the seam that lets a fourth execution container — `AsyncResult` — be plugged in alongside promises and Effects. #### Extends * `PgSession` #### Extended by * [`NodePgUnthrownSession`](node-postgres.md#nodepgunthrownsession) #### Type Parameters | Type Parameter | Description | | ------ | ------ | | `TTransaction` | the transaction handle passed to a [PgUnthrownSession.transaction](#transaction) callback. It is a parameter rather than a concrete type because the transaction class is built on top of the database facade, which in turn is built on this session; the driver that owns both supplies it. | #### Constructors ##### Constructor ```ts new PgUnthrownSession(dialect): PgUnthrownSession; ``` Defined in: node\_modules/.pnpm/drizzle-orm@1.0.0-rc.4\_@electric-sql+pglite@0.4.3\_@types+pg@8.20.3\_better-sqlite3@13.0.\_6633ef2f0d5de3d48504df1aac109381/node\_modules/drizzle-orm/pg-core/session.d.ts:26 ###### Parameters | Parameter | Type | | ------ | ------ | | `dialect` | `PgDialect` | ###### Returns [`PgUnthrownSession`](#abstract-pgunthrownsession)<`TTransaction`> ###### Inherited from ```ts PgSession.constructor ``` #### Properties | Property | Modifier | Type | Default value | Overrides | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | | `[entityKind]` | `readonly` | `string` | `"PgUnthrownSession"` | `PgSession.[entityKind]` | [packages/drizzle/src/pg-core/session.ts:238](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L238) | #### Methods ##### arrays() ```ts arrays(query): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:276](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L276) Run a raw `SQL` fragment, returning each row as an array of column values. ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `SQL` | ###### Returns `AsyncResult`<`unknown`, [`PgQueryError`](#pgqueryerror)> ###### Overrides ```ts PgSession.arrays ``` ##### execute() ```ts execute(query): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:271](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L271) Run a raw `SQL` fragment, returning the driver's own result object. ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `SQL` | ###### Returns `AsyncResult`<`unknown`, [`PgQueryError`](#pgqueryerror)> ###### Remarks Compilation runs **inside** the failure boundary — see `runQuery`. `dialect.sqlToQuery` throws for mistakes that are type-legal and reachable, and a throw escaping here would land on a caller who has no `try`/`catch`, because this method's contract is a `Result`. ###### Overrides ```ts PgSession.execute ``` ##### objects() ```ts objects(query): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:281](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L281) Run a raw `SQL` fragment, returning each row as a column-keyed object. ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `SQL` | ###### Returns `AsyncResult`<`unknown`, [`PgQueryError`](#pgqueryerror)> ###### Overrides ```ts PgSession.objects ``` ##### prepareQuery() ```ts abstract prepareQuery( query, mode, name, mapper?, queryMetadata?, cacheConfig?): PgUnthrownPreparedQuery; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:240](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L240) ###### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `T` *extends* `PreparedQueryConfig` | `PreparedQueryConfig` | ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `Query` | | `mode` | [`PgQueryMode`](#pgquerymode) | | `name` | `string` | `boolean` | | `mapper?` | [`PgRowMapper`](#pgrowmapper) | | `queryMetadata?` | { `tables`: `string`\[]; `type`: `"insert"` | `"update"` | `"select"` | `"delete"`; } | | `queryMetadata.tables?` | `string`\[] | | `queryMetadata.type?` | `"insert"` | `"update"` | `"select"` | `"delete"` | | `cacheConfig?` | `WithCacheConfig` | ###### Returns [`PgUnthrownPreparedQuery`](#pgunthrownpreparedquery)<`T`> ###### Overrides ```ts PgSession.prepareQuery ``` ##### transaction() ```ts abstract transaction(fn, config?): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:257](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L257) Run `fn` inside a database transaction. ###### Type Parameters | Type Parameter | | ------ | | `A` | | `E` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fn` | (`tx`) => `AsyncResult`<`A`, `E`> | | `config?` | `PgTransactionConfig` | ###### Returns `AsyncResult`<`A`, [`PgQueryError`](#pgqueryerror) | `E`> ###### Remarks An `Err` from `fn` rolls back and re-surfaces typed; a defect rolls back and stays a defect. The transaction's own control statements can fail too, so [PgQueryError](#pgqueryerror) joins the callback's error channel. *** ### PgQueryMode ```ts type PgQueryMode = "arrays" | "objects" | "raw"; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:22](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L22) The row shapes a prepared query can be asked to produce. *** ### PgRowMapper ```ts type PgRowMapper = (rows) => unknown; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:39](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L39) A row mapper, as handed over by a drizzle query builder. #### Parameters | Parameter | Type | | ------ | ------ | | `rows` | `never`\[] | #### Returns `unknown` #### Remarks The parameter is `never[]` — the bottom array type — deliberately. The session never inspects rows: it forwards whatever the driver produced to the mapper the builder supplied, and each builder asks for a different row shape (`unknown[][]` for a column-array select, `unknown[][] | Record[]` for a relational query). Under `strictFunctionTypes` a parameter is checked contravariantly, so `never[]` is the one parameter type every such mapper is assignable to. Spelling it `any[]` would accept exactly the same set while giving up type-checking inside every mapper that reads it. --- --- url: /unthrown/api/drizzle/node-postgres.md --- [**@unthrown/drizzle**](index.md) *** [@unthrown/drizzle](index.md) / node-postgres # node-postgres ## Database ### NodePgUnthrownDatabase Defined in: [packages/drizzle/src/node-postgres/driver.ts:66](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L66) A node-postgres database whose every query resolves to an `AsyncResult`. #### Remarks The unthrown sibling of drizzle's `NodePgDatabase`. Build one with [drizzle](#drizzle) rather than by hand — the factory is what pairs a dialect, a session and a client. #### Extends * [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase)<`NodePgQueryResultHKT`, `TRelations`> #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `TRelations` *extends* `AnyRelations` | `EmptyRelations` | the relational schema backing `db.query`. | #### Constructors ##### Constructor ```ts new NodePgUnthrownDatabase( dialect, session, relations): NodePgUnthrownDatabase; ``` Defined in: [packages/drizzle/src/node-postgres/driver.ts:83](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L83) ###### Parameters | Parameter | Type | | ------ | ------ | | `dialect` | `PgDialect` | | `session` | [`NodePgUnthrownSession`](#nodepgunthrownsession)<`TRelations`> | | `relations` | `TRelations` | ###### Returns [`NodePgUnthrownDatabase`](#nodepgunthrowndatabase)<`TRelations`> ###### Overrides [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`constructor`](index-1.md#constructor-5) #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`_`](index-1.md#_-1) | [packages/drizzle/src/pg-core/db.ts:61](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L61) | | `_.relations` | `readonly` | `TRelations` | `undefined` | - | - | - | [packages/drizzle/src/pg-core/db.ts:62](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L62) | | `_.session` | `readonly` | [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession)<`unknown`> | `undefined` | - | - | - | [packages/drizzle/src/pg-core/db.ts:63](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L63) | | `$with` | `readonly` | `WithBuilder` | `undefined` | Creates a subquery that defines a temporary named result set as a CTE. It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query. See docs: **Param** **alias** The alias for the subquery. Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries. **Example** `// Create a subquery with alias 'sq' and use it in the select query const sq = db.$with("sq").as(db.select().from(users).where(eq(users.id, 42))); const rows = (await db.with(sq).select().from(sq)).get();` To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them: `// Select an arbitrary SQL value as a field in a CTE and reference it in the main query const sq = db.$with("sq").as( db .select({ name: sql`upper(${users.name})`.as("name"), }) .from(users), ); const rows = (await db.with(sq).select({ name: sq.name }).from(sq)).get();` | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`$with`](index-1.md#with) | [packages/drizzle/src/pg-core/db.ts:173](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L173) | | `query` | `readonly` | { \[K in string | number | symbol]: RelationalQueryBuilder\ } | `undefined` | The relational query API — `db.query.users.findMany(…)`, one entry per table in the relational schema. | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`query`](index-1.md#query) | [packages/drizzle/src/pg-core/db.ts:70](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L70) | | `session` | `readonly` | [`NodePgUnthrownSession`](#nodepgunthrownsession)<`TRelations`> | `undefined` | The node-postgres session this database runs on. **Remarks** Narrows the base's `PgUnthrownSession` — whose transaction handle is deliberately unresolved, because the base facade is built *underneath* the transaction class that extends it — to the one this driver actually holds. `declare` because the base already assigns it; this only restates its type, which is what gives [transaction](#transaction) a typed handle. | `PgUnthrownDatabase.session` | - | [packages/drizzle/src/node-postgres/driver.ts:81](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L81) | | `tagged` | `readonly` | `boolean` | `false` | - | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`tagged`](index-1.md#tagged) | [packages/drizzle/src/pg-core/db.ts:85](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L85) | | `[entityKind]` | `readonly` | `string` | `"NodePgUnthrownDatabase"` | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`[entityKind]`](index-1.md#entitykind-1) | - | [packages/drizzle/src/node-postgres/driver.ts:69](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L69) | #### Methods ##### $count() ```ts $count(source, filters?): PgUnthrownCountBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:218](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L218) Count the rows a table, view or subquery yields, optionally filtered. ###### Parameters | Parameter | Type | | ------ | ------ | | `source` | | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `SQLWrapper`<`unknown`> | | `filters?` | `SQL`<`unknown`> | ###### Returns [`PgUnthrownCountBuilder`](index-1.md#pgunthrowncountbuilder) ###### Example ```ts const total = (await db.$count(users, eq(users.active, true))).get(); // ^? number — a count is a read, so its error channel is `never`. ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`$count`](index-1.md#count) ##### delete() ```ts delete(table): PgUnthrownDeleteBase; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:613](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L613) Creates a delete query. Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. See docs: A write carries the full `PgQueryError` union — a delete can still raise `23505` through an `ON DELETE SET DEFAULT` — so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match`. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to delete from. | ###### Returns [`PgUnthrownDeleteBase`](index-1.md#pgunthrowndeletebase)<`TTable`, `NodePgQueryResultHKT`> ###### Example ```ts // Delete all rows in the 'cars' table const all = await db.delete(cars); // ^? Result, PgQueryError> // Delete rows with filters and conditions await db.delete(cars).where(eq(cars.color, "green")); // Delete with returning clause const deleted = await db.delete(cars).where(eq(cars.id, 1)).returning(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`delete`](index-1.md#delete) ##### execute() ```ts execute(query): PgUnthrownRaw>>; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:650](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L650) Run a statement drizzle does not model — a raw `SQL` fragment or a string. ###### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TRow` *extends* `Record`<`string`, `unknown`> | `Record`<`string`, `unknown`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `string` | `SQLWrapper`<`unknown`> | ###### Returns [`PgUnthrownRaw`](index-1.md#pgunthrownraw)<`QueryResult`<`Assume`<`TRow`, `QueryResultRow`>>> ###### Remarks Unlike every other entry point, this one compiles its argument **eagerly**, because `PgUnthrownRaw` is defined as holding an already-prepared query (that is what makes its `getSQL`, `getQuery` and `_prepare` synchronous accessors, exactly as in drizzle). Compilation therefore happens here rather than at `await`, and a `SQLWrapper` that cannot compile **throws at this call site** instead of yielding a defect. That is a deliberate line, not an oversight: the contract this package makes is about *running* a query — awaiting a builder, or calling its `execute()` — and `db.execute(…)` is the factory that produces one, not the run itself. The builder it returns is fully guarded. Reaching the throw takes handing in a query builder that is already broken (`db.execute(db.select({ t: other.col }).from(users))`); a string or a `sql` template — the documented use — cannot. Closing the gap would mean deferring compilation, which would cost `PgRaw`'s shape and its synchronous accessors for a case where the argument, not the statement, is the bug. ###### Example ```ts const result = await db.execute(sql`select now()`); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`execute`](index-1.md#execute-1) ##### insert() ```ts insert(table): PgInsertBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:572](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L572) Creates an insert query. Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert. See docs: A write carries the full `PgQueryError` union, so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match` — never a rejection. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to insert into. | ###### Returns `PgInsertBuilder`<`TTable`, `NodePgQueryResultHKT`, `false`, [`PgUnthrownInsertHKT`](index-1.md#pgunthrowninserthkt)> ###### Example ```ts // Insert one row const one = await db.insert(cars).values({ brand: "BMW" }); // ^? Result, PgQueryError> // Insert multiple rows await db.insert(cars).values([{ brand: "BMW" }, { brand: "Porsche" }]); // Insert with returning clause const inserted = await db.insert(cars).values({ brand: "BMW" }).returning(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`insert`](index-1.md#insert) ##### refreshMaterializedView() ```ts refreshMaterializedView(view): PgUnthrownRefreshMaterializedView; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:618](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L618) Rebuild a materialized view's stored rows. ###### Type Parameters | Type Parameter | | ------ | | `TView` *extends* `PgMaterializedView`<`string`, `boolean`, `ColumnsSelection`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `view` | `TView` | ###### Returns [`PgUnthrownRefreshMaterializedView`](index-1.md#pgunthrownrefreshmaterializedview)<`NodePgQueryResultHKT`> ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`refreshMaterializedView`](index-1.md#refreshmaterializedview) ##### select() ###### Call Signature ```ts select(): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:396](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L396) Creates a select query. Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. Use `.from()` method to specify which table to select from. See docs: Awaiting the builder resolves to a `Result`, never rows directly — a read has no modeled failure, so the error channel is `never` and `.get()` compiles. ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select all columns and all rows from the 'cars' table const allCars = (await db.select().from(cars)).get(); // Select specific columns and all rows from the 'cars' table const carsIdsAndBrands = ( await db .select({ id: cars.id, brand: cars.brand, }) .from(cars) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`select`](index-1.md#select) ###### Call Signature ```ts select(fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:397](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L397) Creates a select query. Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. Use `.from()` method to specify which table to select from. See docs: Awaiting the builder resolves to a `Result`, never rows directly — a read has no modeled failure, so the error channel is `never` and `.get()` compiles. ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelection` | ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select all columns and all rows from the 'cars' table const allCars = (await db.select().from(cars)).get(); // Select specific columns and all rows from the 'cars' table const carsIdsAndBrands = ( await db .select({ id: cars.id, brand: cars.brand, }) .from(cars) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`select`](index-1.md#select) ##### selectDistinct() ###### Call Signature ```ts selectDistinct(): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:437](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L437) Adds `distinct` expression to the select query. Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. Use `.from()` method to specify which table to select from. Pass a selection object to specify the columns you want to select. See docs: ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select all unique rows from the 'cars' table const unique = ( await db.selectDistinct().from(cars).orderBy(cars.id, cars.brand, cars.color) ).get(); // Select all unique brands from the 'cars' table const brands = ( await db.selectDistinct({ brand: cars.brand }).from(cars).orderBy(cars.brand) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`selectDistinct`](index-1.md#selectdistinct) ###### Call Signature ```ts selectDistinct(fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:438](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L438) Adds `distinct` expression to the select query. Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. Use `.from()` method to specify which table to select from. Pass a selection object to specify the columns you want to select. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelection` | ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select all unique rows from the 'cars' table const unique = ( await db.selectDistinct().from(cars).orderBy(cars.id, cars.brand, cars.color) ).get(); // Select all unique brands from the 'cars' table const brands = ( await db.selectDistinct({ brand: cars.brand }).from(cars).orderBy(cars.brand) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`selectDistinct`](index-1.md#selectdistinct) ##### selectDistinctOn() ###### Call Signature ```ts selectDistinctOn(on): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:483](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L483) Adds `distinct on` expression to the select query. Calling this method will specify how the unique rows are determined. Use `.from()` method to specify which table to select from. Pass a selection object as the second argument to specify the columns you want to select. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `on` | ( | `SQLWrapper`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }>)\[] | The expression defining uniqueness. | ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select the first row for each unique brand from the 'cars' table const firstPerBrand = ( await db.selectDistinctOn([cars.brand]).from(cars).orderBy(cars.brand) ).get(); // The first occurrence of each unique brand, with its color const brandColors = ( await db .selectDistinctOn([cars.brand], { brand: cars.brand, color: cars.color }) .from(cars) .orderBy(cars.brand, cars.color) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`selectDistinctOn`](index-1.md#selectdistincton) ###### Call Signature ```ts selectDistinctOn(on, fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:484](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L484) Adds `distinct on` expression to the select query. Calling this method will specify how the unique rows are determined. Use `.from()` method to specify which table to select from. Pass a selection object as the second argument to specify the columns you want to select. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `on` | ( | `SQLWrapper`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }>)\[] | The expression defining uniqueness. | | `fields` | `TSelection` | - | ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select the first row for each unique brand from the 'cars' table const firstPerBrand = ( await db.selectDistinctOn([cars.brand]).from(cars).orderBy(cars.brand) ).get(); // The first occurrence of each unique brand, with its color const brandColors = ( await db .selectDistinctOn([cars.brand], { brand: cars.brand, color: cars.color }) .from(cars) .orderBy(cars.brand, cars.color) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`selectDistinctOn`](index-1.md#selectdistincton) ##### transaction() ```ts transaction(fn, config?): AsyncResult; ``` Defined in: [packages/drizzle/src/node-postgres/driver.ts:134](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L134) Run `fn` inside a database transaction. ###### Type Parameters | Type Parameter | | ------ | | `A` | | `E` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `fn` | (`tx`) => `AsyncResult`<`A`, `E`> | the work to run inside the transaction. | | `config?` | `PgTransactionConfig` | isolation level, access mode and deferrability, rendered into the `BEGIN`. | ###### Returns `AsyncResult`<`A`, [`PgQueryError`](index-1.md#pgqueryerror) | `E`> ###### Remarks **`Ok` commits; `Err` and `Defect` both roll back.** An `Err` re-surfaces typed in the error channel, so rolling back costs no information — and because rollback *is* returning an `Err`, there is no `tx.rollback()`. [PgQueryError](index-1.md#pgqueryerror) joins the callback's own error channel because the transaction's control statements can fail on their own account: a `DEFERRABLE` constraint is checked at `COMMIT`, so a unique violation can be raised by the commit rather than by any statement the callback ran. The callback owes an `AsyncResult`, so each step ends in `.execute()` — a builder is a thenable that resolves to a `Result`, not an `AsyncResult` itself — and the steps compose with `flatMap` or `DoAsync().bind(…)`. A one-line delegate to [NodePgUnthrownSession.transaction](#transaction-1), exactly as drizzle's own database delegates to its session: the session owns the connection, and a transaction is a property of one connection. ###### Example ```ts const moved = await db.transaction((tx) => tx .update(accounts) .set({ balance: sql`${accounts.balance} - 100` }) .where(eq(accounts.id, from)) .execute() .flatMap(() => tx .update(accounts) .set({ balance: sql`${accounts.balance} + 100` }) .where(eq(accounts.id, to)) .execute(), ), ); ``` ##### update() ```ts update(table): PgUpdateBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:538](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L538) Creates an update query. Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. Use `.set()` method to specify which values to update. See docs: A write carries the full `PgQueryError` union, so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match` — never a rejection. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to update. | ###### Returns `PgUpdateBuilder`<`TTable`, `NodePgQueryResultHKT`, [`PgUnthrownUpdateHKT`](index-1.md#pgunthrownupdatehkt)> ###### Example ```ts // Update all rows in the 'cars' table const all = await db.update(cars).set({ color: "red" }); // ^? Result, PgQueryError> // Update rows with filters and conditions await db.update(cars).set({ color: "red" }).where(eq(cars.brand, "BMW")); // Update with returning clause const updated = await db .update(cars) .set({ color: "red" }) .where(eq(cars.id, 1)) .returning(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`update`](index-1.md#update) ##### with() ```ts with(...queries): object; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:251](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L251) Incorporates a previously defined CTE (using `$with`) into the main query. This method allows the main query to reference a temporary named result set. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | ...`queries` | `WithSubquery`<`string`, `Record`<`string`, `unknown`>>\[] | The CTEs to incorporate into the main query. | ###### Returns `object` | Name | Type | Defined in | | ------ | ------ | ------ | | `delete()` | <`TTable`>(`table`) => [`PgUnthrownDeleteBase`](index-1.md#pgunthrowndeletebase)<`TTable`, `NodePgQueryResultHKT`> | [packages/drizzle/src/pg-core/db.ts:273](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L273) | | `insert()` | <`TTable`>(`table`) => `PgInsertBuilder`<`TTable`, `NodePgQueryResultHKT`, `false`, [`PgUnthrownInsertHKT`](index-1.md#pgunthrowninserthkt)> | [packages/drizzle/src/pg-core/db.ts:270](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L270) | | `select()` | { (): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`fields`): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:252](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L252) | | `selectDistinct()` | { (): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`fields`): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:256](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L256) | | `selectDistinctOn()` | { (`on`): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`on`, `fields`): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:260](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L260) | | `update()` | <`TTable`>(`table`) => `PgUpdateBuilder`<`TTable`, `NodePgQueryResultHKT`, [`PgUnthrownUpdateHKT`](index-1.md#pgunthrownupdatehkt)> | [packages/drizzle/src/pg-core/db.ts:267](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L267) | ###### Example ```ts // Define a subquery 'sq' as a CTE using $with const sq = db.$with("sq").as(db.select().from(users).where(eq(users.id, 42))); // Incorporate the CTE 'sq' into the main query and select from it const rows = (await db.with(sq).select().from(sq)).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`with`](index-1.md#with-1) *** ### UnthrownDrizzleConfig ```ts type UnthrownDrizzleConfig = object; ``` Defined in: [packages/drizzle/src/node-postgres/driver.ts:36](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L36) The options [drizzle](#drizzle) accepts. #### Remarks Drizzle's `DrizzlePgConfig` minus the members this package does not carry: * `schema` — drizzle removed it from the Postgres config in v1; `relations` is the successor. * `cache` — the query cache hangs off `db.$cache` and invalidates on mutation, neither of which this database facade models yet. * `jit` — drizzle's JIT row mappers are gated behind an `@internal` compatibility probe that is stripped from its published `.d.ts`, so it cannot be forwarded without reimplementing the probe. Leaving it out gives drizzle's own default (the premade mappers), so nothing silently changes. #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `TRelations` *extends* `AnyRelations` | `EmptyRelations` | the relational schema backing `db.query`. | #### Properties | Property | Modifier | Type | Description | Defined in | | ------ | ------ | ------ | ------ | ------ | | `codecs?` | `readonly` | `PgCodecs` | Column codecs, overriding node-postgres' own. | [packages/drizzle/src/node-postgres/driver.ts:45](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L45) | | `logger?` | `readonly` | `boolean` | `Logger` | `true` for drizzle's `DefaultLogger` (every statement to the console), a `Logger` of your own, or `false`/absent for none. | [packages/drizzle/src/node-postgres/driver.ts:43](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L43) | | `relations?` | `readonly` | `TRelations` | The relational schema, as built by drizzle's `defineRelations`. | [packages/drizzle/src/node-postgres/driver.ts:38](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L38) | *** ### drizzle() #### Call Signature ```ts function drizzle(connectionString, config?): NodePgUnthrownDatabase & object; ``` Defined in: [packages/drizzle/src/node-postgres/driver.ts:218](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L218) Build a Postgres database whose every query resolves to an `AsyncResult`. ##### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TRelations` *extends* `TablesRelationalConfig` | `EmptyRelations` | ##### Parameters | Parameter | Type | | ------ | ------ | | `connectionString` | `string` | | `config?` | [`UnthrownDrizzleConfig`](#unthrowndrizzleconfig)<`TRelations`> | ##### Returns [`NodePgUnthrownDatabase`](#nodepgunthrowndatabase)<`TRelations`> & `object` ##### Remarks This **replaces** `drizzle-orm/node-postgres`'s own `drizzle()` rather than wrapping its result: migrating a call site is an import change. Every method on the database already speaks `AsyncResult`, so there is no `try*` naming scheme to learn — a query's modeled failures are the [PgQueryError](index-1.md#pgqueryerror) union, and every infrastructure failure (a dropped connection, a deadlock, a statement that will not compile) is a defect rather than a value you branch on. The escape hatch is `db.$client`: it is the very client you passed (or the pool the factory built), so a stock `drizzle-orm/node-postgres` database over the same pool — for a migration runner, or a batch API this package does not model — is one line away. The call forms are **exactly** drizzle's own — a connection string (with an optional [UnthrownDrizzleConfig](#unthrowndrizzleconfig) second argument), or a configuration object carrying a client under `client` or connection details under `connection`. There is deliberately no positional-client form: drizzle has none, and a second spelling of `{ client: pool }` would mean a call site no longer ports back by changing the import. (`@param` is left unspelled deliberately: one doc comment fronts three overloads whose parameters are named differently.) ##### Example ```ts const db = drizzle({ client: pool, relations }); const created = await db .insert(users) .values({ id: 1, email: "ada@example.com" }) .returning() .execute() .mapErrCases((m) => m.with(P.tag("UniqueConstraintViolation"), () => "email already taken" as const) .with( P.tag("ForeignKeyViolation"), P.tag("CheckViolation"), P.tag("ExclusionViolation"), P.tag("NotNullViolation"), (e) => e._tag, ), ); ``` #### Call Signature ```ts function drizzle(config): NodePgUnthrownDatabase & object; ``` Defined in: [packages/drizzle/src/node-postgres/driver.ts:222](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L222) Build a Postgres database whose every query resolves to an `AsyncResult`. ##### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TClient` *extends* [`NodePgClient`](#nodepgclient) | - | | `TRelations` *extends* `TablesRelationalConfig` | `EmptyRelations` | ##### Parameters | Parameter | Type | | ------ | ------ | | `config` | [`UnthrownDrizzleConfig`](#unthrowndrizzleconfig)<`TRelations`> & `object` | ##### Returns [`NodePgUnthrownDatabase`](#nodepgunthrowndatabase)<`TRelations`> & `object` ##### Remarks This **replaces** `drizzle-orm/node-postgres`'s own `drizzle()` rather than wrapping its result: migrating a call site is an import change. Every method on the database already speaks `AsyncResult`, so there is no `try*` naming scheme to learn — a query's modeled failures are the [PgQueryError](index-1.md#pgqueryerror) union, and every infrastructure failure (a dropped connection, a deadlock, a statement that will not compile) is a defect rather than a value you branch on. The escape hatch is `db.$client`: it is the very client you passed (or the pool the factory built), so a stock `drizzle-orm/node-postgres` database over the same pool — for a migration runner, or a batch API this package does not model — is one line away. The call forms are **exactly** drizzle's own — a connection string (with an optional [UnthrownDrizzleConfig](#unthrowndrizzleconfig) second argument), or a configuration object carrying a client under `client` or connection details under `connection`. There is deliberately no positional-client form: drizzle has none, and a second spelling of `{ client: pool }` would mean a call site no longer ports back by changing the import. (`@param` is left unspelled deliberately: one doc comment fronts three overloads whose parameters are named differently.) ##### Example ```ts const db = drizzle({ client: pool, relations }); const created = await db .insert(users) .values({ id: 1, email: "ada@example.com" }) .returning() .execute() .mapErrCases((m) => m.with(P.tag("UniqueConstraintViolation"), () => "email already taken" as const) .with( P.tag("ForeignKeyViolation"), P.tag("CheckViolation"), P.tag("ExclusionViolation"), P.tag("NotNullViolation"), (e) => e._tag, ), ); ``` #### Call Signature ```ts function drizzle(config): NodePgUnthrownDatabase & object; ``` Defined in: [packages/drizzle/src/node-postgres/driver.ts:228](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/driver.ts#L228) Build a Postgres database whose every query resolves to an `AsyncResult`. ##### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TRelations` *extends* `TablesRelationalConfig` | `EmptyRelations` | ##### Parameters | Parameter | Type | | ------ | ------ | | `config` | [`UnthrownDrizzleConfig`](#unthrowndrizzleconfig)<`TRelations`> & `object` | ##### Returns [`NodePgUnthrownDatabase`](#nodepgunthrowndatabase)<`TRelations`> & `object` ##### Remarks This **replaces** `drizzle-orm/node-postgres`'s own `drizzle()` rather than wrapping its result: migrating a call site is an import change. Every method on the database already speaks `AsyncResult`, so there is no `try*` naming scheme to learn — a query's modeled failures are the [PgQueryError](index-1.md#pgqueryerror) union, and every infrastructure failure (a dropped connection, a deadlock, a statement that will not compile) is a defect rather than a value you branch on. The escape hatch is `db.$client`: it is the very client you passed (or the pool the factory built), so a stock `drizzle-orm/node-postgres` database over the same pool — for a migration runner, or a batch API this package does not model — is one line away. The call forms are **exactly** drizzle's own — a connection string (with an optional [UnthrownDrizzleConfig](#unthrowndrizzleconfig) second argument), or a configuration object carrying a client under `client` or connection details under `connection`. There is deliberately no positional-client form: drizzle has none, and a second spelling of `{ client: pool }` would mean a call site no longer ports back by changing the import. (`@param` is left unspelled deliberately: one doc comment fronts three overloads whose parameters are named differently.) ##### Example ```ts const db = drizzle({ client: pool, relations }); const created = await db .insert(users) .values({ id: 1, email: "ada@example.com" }) .returning() .execute() .mapErrCases((m) => m.with(P.tag("UniqueConstraintViolation"), () => "email already taken" as const) .with( P.tag("ForeignKeyViolation"), P.tag("CheckViolation"), P.tag("ExclusionViolation"), P.tag("NotNullViolation"), (e) => e._tag, ), ); ``` ## Session ### NodePgUnthrownSession Defined in: [packages/drizzle/src/node-postgres/session.ts:243](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L243) A node-postgres session whose every query resolves to an `AsyncResult`. #### Remarks The unthrown sibling of drizzle's `NodePgSession`. Everything above it is type plumbing; this is where a real driver is spoken to. #### Extends * [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession)<[`NodePgUnthrownTransaction`](#nodepgunthrowntransaction)<`TRelations`>> #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `TRelations` *extends* `AnyRelations` | `EmptyRelations` | the relational schema backing `db.query`. | #### Constructors ##### Constructor ```ts new NodePgUnthrownSession( client, dialect, relations, logger?): NodePgUnthrownSession; ``` Defined in: [packages/drizzle/src/node-postgres/session.ts:256](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L256) ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `client` | [`NodePgClient`](#nodepgclient) | the pool or client to run statements against. A pool has a connection checked out for the duration of a [transaction](#transaction-1) and released afterwards; a plain client is used as-is. | | `dialect` | `PgDialect` | drizzle's Postgres dialect, which compiles the SQL. | | `relations` | `TRelations` | the relational schema, forwarded to every transaction. | | `logger` | `Logger` | drizzle's query logger. | ###### Returns [`NodePgUnthrownSession`](#nodepgunthrownsession)<`TRelations`> ###### Overrides [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession).[`constructor`](index-1.md#constructor-14) #### Properties | Property | Modifier | Type | Default value | Overrides | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | | `[entityKind]` | `readonly` | `string` | `"NodePgUnthrownSession"` | [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession).[`[entityKind]`](index-1.md#entitykind-10) | [packages/drizzle/src/node-postgres/session.ts:246](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L246) | #### Methods ##### arrays() ```ts arrays(query): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:276](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L276) Run a raw `SQL` fragment, returning each row as an array of column values. ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `SQL` | ###### Returns `AsyncResult`<`unknown`, [`PgQueryError`](index-1.md#pgqueryerror)> ###### Inherited from [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession).[`arrays`](index-1.md#arrays) ##### execute() ```ts execute(query): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:271](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L271) Run a raw `SQL` fragment, returning the driver's own result object. ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `SQL` | ###### Returns `AsyncResult`<`unknown`, [`PgQueryError`](index-1.md#pgqueryerror)> ###### Remarks Compilation runs **inside** the failure boundary — see `runQuery`. `dialect.sqlToQuery` throws for mistakes that are type-legal and reachable, and a throw escaping here would land on a caller who has no `try`/`catch`, because this method's contract is a `Result`. ###### Inherited from [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession).[`execute`](index-1.md#execute-10) ##### objects() ```ts objects(query): AsyncResult; ``` Defined in: [packages/drizzle/src/pg-core/session.ts:281](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/session.ts#L281) Run a raw `SQL` fragment, returning each row as a column-keyed object. ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `SQL` | ###### Returns `AsyncResult`<`unknown`, [`PgQueryError`](index-1.md#pgqueryerror)> ###### Inherited from [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession).[`objects`](index-1.md#objects) ##### prepareQuery() ```ts prepareQuery( query, mode, name, mapper?): PgUnthrownPreparedQuery; ``` Defined in: [packages/drizzle/src/node-postgres/session.ts:265](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L265) ###### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `T` *extends* `PreparedQueryConfig` | `PreparedQueryConfig` | ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `Query` | | `mode` | [`PgQueryMode`](index-1.md#pgquerymode) | | `name` | `string` | `boolean` | | `mapper?` | [`PgRowMapper`](index-1.md#pgrowmapper) | ###### Returns [`PgUnthrownPreparedQuery`](index-1.md#pgunthrownpreparedquery)<`T`> ###### Overrides [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession).[`prepareQuery`](index-1.md#preparequery) ##### transaction() ```ts transaction(fn, config?): AsyncResult; ``` Defined in: [packages/drizzle/src/node-postgres/session.ts:339](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L339) Run `fn` inside a database transaction. ###### Type Parameters | Type Parameter | | ------ | | `A` | | `E` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fn` | (`tx`) => `AsyncResult`<`A`, `E`> | | `config?` | `PgTransactionConfig` | ###### Returns `AsyncResult`<`A`, [`PgQueryError`](index-1.md#pgqueryerror) | `E`> ###### Remarks **`Ok` commits; `Err` and `Defect` both roll back.** An `Err` re-surfaces typed in the error channel, so rolling back costs no information — and because rollback *is* returning an `Err`, there is no `tx.rollback()`. [PgQueryError](index-1.md#pgqueryerror) joins the callback's own error channel because the transaction's control statements can fail on their own account: a `DEFERRABLE` constraint is checked at `COMMIT`, so a unique violation can be raised by the commit rather than by any statement the callback ran. The whole sequence is qualified **once**, here, and nothing inside it is left to a channel that could swallow it: the control statements run on the raw rejecting path (see `PgUnthrownPreparedQuery.runUnqualified`), so a failed `COMMIT` can never be mistaken for a successful one. The callback owes an `AsyncResult`, so each step ends in `.execute()` — a builder is a thenable that resolves to a `Result`, not an `AsyncResult` itself — and the steps compose with `flatMap`. ###### Example ```ts const moved = await db.transaction((tx) => tx .update(accounts) .set({ balance: sql`${accounts.balance} - 100` }) .where(eq(accounts.id, from)) .execute() .flatMap(() => tx .update(accounts) .set({ balance: sql`${accounts.balance} + 100` }) .where(eq(accounts.id, to)) .execute(), ), ); ``` ###### Overrides [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession).[`transaction`](index-1.md#transaction) *** ### NodePgUnthrownTransaction Defined in: [packages/drizzle/src/node-postgres/session.ts:407](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L407) The handle a [NodePgUnthrownSession.transaction](#transaction-1) callback receives: a database whose statements all run inside the open transaction. #### Remarks There is deliberately **no `rollback()`**. Drizzle needs one because its rollback signal is a throw; here the signal is an `Err`, and a second spelling of one concept is exactly what this library does not do. Return an `Err` — from a failed query or one of your own — and the transaction rolls back with that error still in hand. #### Extends * [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase)<`NodePgQueryResultHKT`, `TRelations`> #### Type Parameters | Type Parameter | Default type | Description | | ------ | ------ | ------ | | `TRelations` *extends* `AnyRelations` | `EmptyRelations` | the relational schema backing `tx.query`. | #### Constructors ##### Constructor ```ts new NodePgUnthrownTransaction( dialect, session, relations, savepoints?, parseRqbJson?): NodePgUnthrownTransaction; ``` Defined in: [packages/drizzle/src/node-postgres/session.ts:417](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L417) ###### Parameters | Parameter | Type | Default value | Description | | ------ | ------ | ------ | ------ | | `dialect` | `PgDialect` | `undefined` | - | | `session` | [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession)<`unknown`> | `undefined` | - | | `relations` | `TRelations` | `undefined` | - | | `savepoints` | { `count`: `number`; } | `...` | the savepoint-name counter, **shared by every handle descended from one transaction** (see [transaction](#transaction-2)). Defaults to a fresh one, which is what a root transaction wants. | | `savepoints.count` | `number` | `undefined` | - | | `parseRqbJson` | `boolean` | `false` | - | ###### Returns [`NodePgUnthrownTransaction`](#nodepgunthrowntransaction)<`TRelations`> ###### Overrides [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`constructor`](index-1.md#constructor-5) #### Properties | Property | Modifier | Type | Default value | Description | Overrides | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `_` | `readonly` | `object` | `undefined` | - | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`_`](index-1.md#_-1) | [packages/drizzle/src/pg-core/db.ts:61](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L61) | | `_.relations` | `readonly` | `TRelations` | `undefined` | - | - | - | [packages/drizzle/src/pg-core/db.ts:62](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L62) | | `_.session` | `readonly` | [`PgUnthrownSession`](index-1.md#abstract-pgunthrownsession)<`unknown`> | `undefined` | - | - | - | [packages/drizzle/src/pg-core/db.ts:63](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L63) | | `$with` | `readonly` | `WithBuilder` | `undefined` | Creates a subquery that defines a temporary named result set as a CTE. It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query. See docs: **Param** **alias** The alias for the subquery. Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries. **Example** `// Create a subquery with alias 'sq' and use it in the select query const sq = db.$with("sq").as(db.select().from(users).where(eq(users.id, 42))); const rows = (await db.with(sq).select().from(sq)).get();` To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them: `// Select an arbitrary SQL value as a field in a CTE and reference it in the main query const sq = db.$with("sq").as( db .select({ name: sql`upper(${users.name})`.as("name"), }) .from(users), ); const rows = (await db.with(sq).select({ name: sq.name }).from(sq)).get();` | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`$with`](index-1.md#with) | [packages/drizzle/src/pg-core/db.ts:173](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L173) | | `query` | `readonly` | { \[K in string | number | symbol]: RelationalQueryBuilder\ } | `undefined` | The relational query API — `db.query.users.findMany(…)`, one entry per table in the relational schema. | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`query`](index-1.md#query) | [packages/drizzle/src/pg-core/db.ts:70](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L70) | | `tagged` | `readonly` | `boolean` | `false` | - | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`tagged`](index-1.md#tagged) | [packages/drizzle/src/pg-core/db.ts:85](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L85) | | `[entityKind]` | `readonly` | `string` | `"NodePgUnthrownTransaction"` | - | [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`[entityKind]`](index-1.md#entitykind-1) | - | [packages/drizzle/src/node-postgres/session.ts:410](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L410) | #### Methods ##### $count() ```ts $count(source, filters?): PgUnthrownCountBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:218](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L218) Count the rows a table, view or subquery yields, optionally filtered. ###### Parameters | Parameter | Type | | ------ | ------ | | `source` | | `PgTable`<`TableConfig`> | `PgViewBase`<`string`, `boolean`, `ColumnsSelection`> | `SQL`<`unknown`> | `SQLWrapper`<`unknown`> | | `filters?` | `SQL`<`unknown`> | ###### Returns [`PgUnthrownCountBuilder`](index-1.md#pgunthrowncountbuilder) ###### Example ```ts const total = (await db.$count(users, eq(users.active, true))).get(); // ^? number — a count is a read, so its error channel is `never`. ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`$count`](index-1.md#count) ##### delete() ```ts delete(table): PgUnthrownDeleteBase; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:613](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L613) Creates a delete query. Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. See docs: A write carries the full `PgQueryError` union — a delete can still raise `23505` through an `ON DELETE SET DEFAULT` — so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match`. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to delete from. | ###### Returns [`PgUnthrownDeleteBase`](index-1.md#pgunthrowndeletebase)<`TTable`, `NodePgQueryResultHKT`> ###### Example ```ts // Delete all rows in the 'cars' table const all = await db.delete(cars); // ^? Result, PgQueryError> // Delete rows with filters and conditions await db.delete(cars).where(eq(cars.color, "green")); // Delete with returning clause const deleted = await db.delete(cars).where(eq(cars.id, 1)).returning(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`delete`](index-1.md#delete) ##### execute() ```ts execute(query): PgUnthrownRaw>>; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:650](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L650) Run a statement drizzle does not model — a raw `SQL` fragment or a string. ###### Type Parameters | Type Parameter | Default type | | ------ | ------ | | `TRow` *extends* `Record`<`string`, `unknown`> | `Record`<`string`, `unknown`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `query` | `string` | `SQLWrapper`<`unknown`> | ###### Returns [`PgUnthrownRaw`](index-1.md#pgunthrownraw)<`QueryResult`<`Assume`<`TRow`, `QueryResultRow`>>> ###### Remarks Unlike every other entry point, this one compiles its argument **eagerly**, because `PgUnthrownRaw` is defined as holding an already-prepared query (that is what makes its `getSQL`, `getQuery` and `_prepare` synchronous accessors, exactly as in drizzle). Compilation therefore happens here rather than at `await`, and a `SQLWrapper` that cannot compile **throws at this call site** instead of yielding a defect. That is a deliberate line, not an oversight: the contract this package makes is about *running* a query — awaiting a builder, or calling its `execute()` — and `db.execute(…)` is the factory that produces one, not the run itself. The builder it returns is fully guarded. Reaching the throw takes handing in a query builder that is already broken (`db.execute(db.select({ t: other.col }).from(users))`); a string or a `sql` template — the documented use — cannot. Closing the gap would mean deferring compilation, which would cost `PgRaw`'s shape and its synchronous accessors for a case where the argument, not the statement, is the bug. ###### Example ```ts const result = await db.execute(sql`select now()`); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`execute`](index-1.md#execute-1) ##### insert() ```ts insert(table): PgInsertBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:572](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L572) Creates an insert query. Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert. See docs: A write carries the full `PgQueryError` union, so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match` — never a rejection. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to insert into. | ###### Returns `PgInsertBuilder`<`TTable`, `NodePgQueryResultHKT`, `false`, [`PgUnthrownInsertHKT`](index-1.md#pgunthrowninserthkt)> ###### Example ```ts // Insert one row const one = await db.insert(cars).values({ brand: "BMW" }); // ^? Result, PgQueryError> // Insert multiple rows await db.insert(cars).values([{ brand: "BMW" }, { brand: "Porsche" }]); // Insert with returning clause const inserted = await db.insert(cars).values({ brand: "BMW" }).returning(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`insert`](index-1.md#insert) ##### refreshMaterializedView() ```ts refreshMaterializedView(view): PgUnthrownRefreshMaterializedView; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:618](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L618) Rebuild a materialized view's stored rows. ###### Type Parameters | Type Parameter | | ------ | | `TView` *extends* `PgMaterializedView`<`string`, `boolean`, `ColumnsSelection`> | ###### Parameters | Parameter | Type | | ------ | ------ | | `view` | `TView` | ###### Returns [`PgUnthrownRefreshMaterializedView`](index-1.md#pgunthrownrefreshmaterializedview)<`NodePgQueryResultHKT`> ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`refreshMaterializedView`](index-1.md#refreshmaterializedview) ##### select() ###### Call Signature ```ts select(): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:396](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L396) Creates a select query. Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. Use `.from()` method to specify which table to select from. See docs: Awaiting the builder resolves to a `Result`, never rows directly — a read has no modeled failure, so the error channel is `never` and `.get()` compiles. ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select all columns and all rows from the 'cars' table const allCars = (await db.select().from(cars)).get(); // Select specific columns and all rows from the 'cars' table const carsIdsAndBrands = ( await db .select({ id: cars.id, brand: cars.brand, }) .from(cars) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`select`](index-1.md#select) ###### Call Signature ```ts select(fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:397](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L397) Creates a select query. Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. Use `.from()` method to specify which table to select from. See docs: Awaiting the builder resolves to a `Result`, never rows directly — a read has no modeled failure, so the error channel is `never` and `.get()` compiles. ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelection` | ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select all columns and all rows from the 'cars' table const allCars = (await db.select().from(cars)).get(); // Select specific columns and all rows from the 'cars' table const carsIdsAndBrands = ( await db .select({ id: cars.id, brand: cars.brand, }) .from(cars) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`select`](index-1.md#select) ##### selectDistinct() ###### Call Signature ```ts selectDistinct(): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:437](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L437) Adds `distinct` expression to the select query. Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. Use `.from()` method to specify which table to select from. Pass a selection object to specify the columns you want to select. See docs: ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select all unique rows from the 'cars' table const unique = ( await db.selectDistinct().from(cars).orderBy(cars.id, cars.brand, cars.color) ).get(); // Select all unique brands from the 'cars' table const brands = ( await db.selectDistinct({ brand: cars.brand }).from(cars).orderBy(cars.brand) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`selectDistinct`](index-1.md#selectdistinct) ###### Call Signature ```ts selectDistinct(fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:438](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L438) Adds `distinct` expression to the select query. Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. Use `.from()` method to specify which table to select from. Pass a selection object to specify the columns you want to select. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fields` | `TSelection` | ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select all unique rows from the 'cars' table const unique = ( await db.selectDistinct().from(cars).orderBy(cars.id, cars.brand, cars.color) ).get(); // Select all unique brands from the 'cars' table const brands = ( await db.selectDistinct({ brand: cars.brand }).from(cars).orderBy(cars.brand) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`selectDistinct`](index-1.md#selectdistinct) ##### selectDistinctOn() ###### Call Signature ```ts selectDistinctOn(on): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:483](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L483) Adds `distinct on` expression to the select query. Calling this method will specify how the unique rows are determined. Use `.from()` method to specify which table to select from. Pass a selection object as the second argument to specify the columns you want to select. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `on` | ( | `SQLWrapper`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }>)\[] | The expression defining uniqueness. | ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`> ###### Example ```ts // Select the first row for each unique brand from the 'cars' table const firstPerBrand = ( await db.selectDistinctOn([cars.brand]).from(cars).orderBy(cars.brand) ).get(); // The first occurrence of each unique brand, with its color const brandColors = ( await db .selectDistinctOn([cars.brand], { brand: cars.brand, color: cars.color }) .from(cars) .orderBy(cars.brand, cars.color) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`selectDistinctOn`](index-1.md#selectdistincton) ###### Call Signature ```ts selectDistinctOn(on, fields): PgUnthrownSelectBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:484](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L484) Adds `distinct on` expression to the select query. Calling this method will specify how the unique rows are determined. Use `.from()` method to specify which table to select from. Pass a selection object as the second argument to specify the columns you want to select. See docs: ###### Type Parameters | Type Parameter | | ------ | | `TSelection` *extends* `SelectedFields` | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `on` | ( | `SQLWrapper`<`unknown`> | `PgColumn`<`any`, `PgColumnBaseConfig`<`any`>, { }>)\[] | The expression defining uniqueness. | | `fields` | `TSelection` | - | ###### Returns [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`> ###### Example ```ts // Select the first row for each unique brand from the 'cars' table const firstPerBrand = ( await db.selectDistinctOn([cars.brand]).from(cars).orderBy(cars.brand) ).get(); // The first occurrence of each unique brand, with its color const brandColors = ( await db .selectDistinctOn([cars.brand], { brand: cars.brand, color: cars.color }) .from(cars) .orderBy(cars.brand, cars.color) ).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`selectDistinctOn`](index-1.md#selectdistincton) ##### setTransaction() ```ts setTransaction(config): AsyncResult; ``` Defined in: [packages/drizzle/src/node-postgres/session.ts:440](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L440) Set the characteristics of the transaction already in progress. ###### Parameters | Parameter | Type | | ------ | ------ | | `config` | `PgTransactionConfig` | ###### Returns `AsyncResult`<`unknown`, [`PgQueryError`](index-1.md#pgqueryerror)> ###### Remarks A config that asks for nothing (`{}`) issues no statement: Postgres requires at least one mode after `set transaction`, so the alternative is a syntax error reported as a defect for a call that requested no change. ###### Example ```ts await tx.setTransaction({ isolationLevel: "serializable" }); ``` ##### transaction() ```ts transaction(fn): AsyncResult; ``` Defined in: [packages/drizzle/src/node-postgres/session.ts:484](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L484) Run `fn` inside a nested transaction — a savepoint of the enclosing one. ###### Type Parameters | Type Parameter | | ------ | | `A` | | `E` | ###### Parameters | Parameter | Type | | ------ | ------ | | `fn` | (`tx`) => `AsyncResult`<`A`, `E`> | ###### Returns `AsyncResult`<`A`, [`PgQueryError`](index-1.md#pgqueryerror) | `E`> ###### Remarks The same rule one level down: `Ok` releases the savepoint, `Err` and `Defect` roll back to it. Only the nested scope is undone, so the enclosing transaction stays open and decides for itself — recover the inner `Err` and the outer scope still commits. Savepoint names come from a counter **shared by every handle descended from one transaction**, so no two live savepoints on that connection can share a name. Naming them by nesting depth (drizzle's scheme) is safe only while nested transactions are started one after another; two started concurrently — which `allAsync` makes an easy thing to write — would both be `sp1` on the one connection, and the first `rollback to savepoint sp1` would unwind the other's work. ###### Example ```ts const result = await db.transaction((tx) => tx .transaction((nested) => nested.insert(logs).values({ message: "optional" }).execute()) // The savepoint rolled back; the outer transaction carries on. Every // case is named, so the grouped arm lists the whole PgQueryError union. .recoverErrCases((m) => m.with( P.tag("UniqueConstraintViolation"), P.tag("ForeignKeyViolation"), P.tag("CheckViolation"), P.tag("ExclusionViolation"), P.tag("NotNullViolation"), () => undefined, ), ) .flatMap(() => tx.insert(users).values({ id: 1, name: "ada" }).execute()), ); ``` ##### update() ```ts update(table): PgUpdateBuilder; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:538](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L538) Creates an update query. Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. Use `.set()` method to specify which values to update. See docs: A write carries the full `PgQueryError` union, so awaiting the builder resolves to a `Result` you fold with `mapErrCases` or `match` — never a rejection. ###### Type Parameters | Type Parameter | | ------ | | `TTable` *extends* `PgTable`<`TableConfig`> | ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `table` | `TTable` | The table to update. | ###### Returns `PgUpdateBuilder`<`TTable`, `NodePgQueryResultHKT`, [`PgUnthrownUpdateHKT`](index-1.md#pgunthrownupdatehkt)> ###### Example ```ts // Update all rows in the 'cars' table const all = await db.update(cars).set({ color: "red" }); // ^? Result, PgQueryError> // Update rows with filters and conditions await db.update(cars).set({ color: "red" }).where(eq(cars.brand, "BMW")); // Update with returning clause const updated = await db .update(cars) .set({ color: "red" }) .where(eq(cars.id, 1)) .returning(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`update`](index-1.md#update) ##### with() ```ts with(...queries): object; ``` Defined in: [packages/drizzle/src/pg-core/db.ts:251](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L251) Incorporates a previously defined CTE (using `$with`) into the main query. This method allows the main query to reference a temporary named result set. See docs: ###### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | ...`queries` | `WithSubquery`<`string`, `Record`<`string`, `unknown`>>\[] | The CTEs to incorporate into the main query. | ###### Returns `object` | Name | Type | Defined in | | ------ | ------ | ------ | | `delete()` | <`TTable`>(`table`) => [`PgUnthrownDeleteBase`](index-1.md#pgunthrowndeletebase)<`TTable`, `NodePgQueryResultHKT`> | [packages/drizzle/src/pg-core/db.ts:273](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L273) | | `insert()` | <`TTable`>(`table`) => `PgInsertBuilder`<`TTable`, `NodePgQueryResultHKT`, `false`, [`PgUnthrownInsertHKT`](index-1.md#pgunthrowninserthkt)> | [packages/drizzle/src/pg-core/db.ts:270](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L270) | | `select()` | { (): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`fields`): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:252](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L252) | | `selectDistinct()` | { (): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`fields`): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:256](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L256) | | `selectDistinctOn()` | { (`on`): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`undefined`>; <`TSelection`> (`on`, `fields`): [`PgUnthrownSelectBuilder`](index-1.md#pgunthrownselectbuilder)<`TSelection`>; } | [packages/drizzle/src/pg-core/db.ts:260](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L260) | | `update()` | <`TTable`>(`table`) => `PgUpdateBuilder`<`TTable`, `NodePgQueryResultHKT`, [`PgUnthrownUpdateHKT`](index-1.md#pgunthrownupdatehkt)> | [packages/drizzle/src/pg-core/db.ts:267](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/pg-core/db.ts#L267) | ###### Example ```ts // Define a subquery 'sq' as a CTE using $with const sq = db.$with("sq").as(db.select().from(users).where(eq(users.id, 42))); // Incorporate the CTE 'sq' into the main query and select from it const rows = (await db.with(sq).select().from(sq)).get(); ``` ###### Inherited from [`PgUnthrownDatabase`](index-1.md#pgunthrowndatabase).[`with`](index-1.md#with-1) *** ### NodePgClient ```ts type NodePgClient = pg.Pool | pg.PoolClient | pg.Client; ``` Defined in: [packages/drizzle/src/node-postgres/session.ts:33](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/drizzle/src/node-postgres/session.ts#L33) A node-postgres client this package can drive: a pool, a client checked out of one, or a standalone client. --- --- url: /unthrown/api/orpc/server.md --- [**@unthrown/orpc**](index.md) *** [@unthrown/orpc](index.md) / server # server ## Server ### ResultHandler ```ts type ResultHandler = (opts, input) => | Result | Promise> | AsyncResult; ``` Defined in: [server.ts:36](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/orpc/src/server.ts#L36) A procedure handler that speaks `Result`: same options as a plain oRPC handler (`input`, `context`, `errors`, …), returning a `Result` — synchronous, promised, or as an `AsyncResult`. #### Type Parameters | Type Parameter | | ------ | | `TCurrentContext` *extends* `Context` | | `TInput` | | `TOutput` | | `TError` *extends* `AnyORPCError` | | `TErrorMap` *extends* `ErrorMap` | #### Parameters | Parameter | Type | | ------ | ------ | | `opts` | `ProcedureHandlerOptions`<`TCurrentContext`, `TInput`, `ORPCErrorConstructorMap`<`TErrorMap`>> | | `input` | `TInput` | #### Returns | `Result`<`TOutput`, `TError`> | `Promise`<`Result`<`TOutput`, `TError`>> | `AsyncResult`<`TOutput`, `TError`> *** ### handlerResult() ```ts function handlerResult(handler): ProcedureHandler>; ``` Defined in: [server.ts:87](https://github.com/btravstack/unthrown/blob/374b969ef75956f47e3eb294af83d01ca62523f7/packages/orpc/src/server.ts#L87) Adapt a `Result`-returning handler into a plain oRPC procedure handler. #### Type Parameters | Type Parameter | | ------ | | `TCurrentContext` *extends* `Context` | | `TInput` | | `TOutput` | | `TError` *extends* `AnyORPCError` | | `TErrorMap` *extends* `ErrorMap` | #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `handler` | [`ResultHandler`](#resulthandler)<`TCurrentContext`, `TInput`, `TOutput`, `TError`, `TErrorMap`> | the `Result`-speaking handler to adapt. | #### Returns `ProcedureHandler`<`TCurrentContext`, `TInput`, `TOutput` | `TError`, `ORPCErrorConstructorMap`<`TErrorMap`>> #### Remarks The elimination boundary of the server half: `Ok` becomes the procedure's output; `Err` (constrained to `ORPCError` — build one with the injected `errors.CODE(...)` constructors, or map a domain error via `mapErrCases` first) is returned as a value, which oRPC marks *inferable* so the client sees it fully typed; a `Defect` rethrows its original cause, which oRPC collapses to `INTERNAL_SERVER_ERROR` — a bug stays a defect, never a typed error. Like `match` handlers, the callback may be `async` (an edge elimination is exempt from the no-thenable rule): a rejection or throw inside it cannot skip triage, because oRPC's own boundary already treats it as the defect path. #### Example ```ts import { P } from "unthrown"; import { handlerResult } from "@unthrown/orpc/server"; const find = os .input(z.object({ id: z.string() })) .errors({ NOT_FOUND: {} }) .handler( handlerResult(({ input, errors }) => repo .findPlanet(input.id) .mapErrCases((matcher) => matcher.with(P.tag("NotFound"), () => errors.NOT_FOUND()), ), ), ); ```