@vibeorm/runtime 1.3.0 → 2.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +50 -107
  2. package/dist/adapter.d.ts +124 -0
  3. package/dist/adapter.d.ts.map +1 -0
  4. package/dist/client.d.ts +152 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/codecs.d.ts +170 -0
  7. package/dist/codecs.d.ts.map +1 -0
  8. package/dist/computed.d.ts +43 -0
  9. package/dist/computed.d.ts.map +1 -0
  10. package/dist/extensions.d.ts +102 -0
  11. package/dist/extensions.d.ts.map +1 -0
  12. package/dist/index.d.ts +29 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +6625 -0
  15. package/dist/index.js.map +21 -0
  16. package/dist/model-meta.d.ts +156 -0
  17. package/dist/model-meta.d.ts.map +1 -0
  18. package/dist/nested-writes.d.ts +100 -0
  19. package/dist/nested-writes.d.ts.map +1 -0
  20. package/dist/query-builder.d.ts +250 -0
  21. package/dist/query-builder.d.ts.map +1 -0
  22. package/dist/relation-loader.d.ts +75 -0
  23. package/dist/relation-loader.d.ts.map +1 -0
  24. package/dist/relation-plan.d.ts +103 -0
  25. package/dist/relation-plan.d.ts.map +1 -0
  26. package/dist/render-cache.d.ts +48 -0
  27. package/dist/render-cache.d.ts.map +1 -0
  28. package/dist/views.d.ts +97 -0
  29. package/dist/views.d.ts.map +1 -0
  30. package/package.json +31 -26
  31. package/src/adapter.ts +0 -146
  32. package/src/client.ts +0 -2172
  33. package/src/coerce.ts +0 -184
  34. package/src/count-loader.ts +0 -152
  35. package/src/errors.ts +0 -492
  36. package/src/id-generators.ts +0 -151
  37. package/src/index.ts +0 -55
  38. package/src/lateral-join-builder.ts +0 -1053
  39. package/src/query-builder.ts +0 -1832
  40. package/src/relation-loader.ts +0 -534
  41. package/src/retry.ts +0 -183
  42. package/src/types.ts +0 -317
  43. package/src/view.ts +0 -629
  44. package/src/where-builder.ts +0 -772
package/README.md CHANGED
@@ -1,141 +1,84 @@
1
1
  # @vibeorm/runtime
2
2
 
3
- Driver-agnostic query engine and client runtime for VibeORM. This package contains the SQL query builder, WHERE clause compiler, relation loading strategies, and client factory. It does **not** include any database driver — use an adapter package to connect to PostgreSQL.
3
+ > Part of **[VibeORM](https://github.com/vibeorm/vibeorm)** — a type-safe TypeScript ORM for Bun and Node. Prisma-schema or TypeScript-DSL input, a canonical schema IR, a generated client, and a dialect-aware SQL layer over PostgreSQL, PGlite, SQLite and MySQL.
4
4
 
5
- ## Installation
5
+ The query engine behind the generated client: it turns delegate calls into SQL statements, loads relations, runs nested writes and moves values across the wire through the codec table. It is its own package because it is driver-agnostic — it talks to databases only through the `DatabaseAdapter` contract, so adapters and the generator can depend on it without depending on each other.
6
6
 
7
7
  ```bash
8
- bun add @vibeorm/runtime
8
+ bun add @vibeorm/runtime@alpha
9
9
  ```
10
10
 
11
- You also need an adapter:
11
+ > **Pre-release.** `2.0.0-alpha.x`, published under the `alpha` dist-tag. `npm i vibeorm` still resolves to the stable v1 line.
12
12
 
13
- ```bash
14
- bun add @vibeorm/adapter-bun # for bun:sql
15
- # or
16
- bun add @vibeorm/adapter-pg pg # for node-postgres
17
- ```
13
+ Most users never install this directly — it ships as a dependency of [`vibeorm`](https://www.npmjs.com/package/vibeorm) and of the generated client. Reach for it when you are writing an adapter or tooling against the runtime.
18
14
 
19
- ## Usage
15
+ ## What it does
20
16
 
21
- This package is consumed by the generated client. You typically don't import from it directly — the generated `index.ts` calls `createClient()` internally.
17
+ `createClient({ schema, adapter, options })` builds a `DynamicClient` from the Schema IR at runtime: model delegates keyed by both camelCase client name and model name (`$models`), plus `$transaction`, `$queryRaw`, `$executeRaw`, `$queryRawUnsafe`, `$executeRawUnsafe`, `$on`, `$connect` and `$disconnect`. The delegates are deliberately broad here (`ClientRow` in, `ClientRow` out); the generated `.d.ts` declares the precise per-model types on top.
22
18
 
23
- ```ts
24
- // The generated client wires everything together:
25
- import { VibeClient } from "./generated/vibeorm/index.ts";
26
-
27
- const db = VibeClient({
28
- relationStrategy: "query",
29
- log: false,
30
- });
31
- ```
19
+ Each `ModelDelegate` implements 16 methods:
32
20
 
33
- ## API
21
+ | Group | Methods |
22
+ |---|---|
23
+ | Read | `findMany` · `findFirst` · `findFirstOrThrow` · `findUnique` · `findUniqueOrThrow` |
24
+ | Create | `create` · `createMany` · `createManyAndReturn` |
25
+ | Update | `update` · `updateMany` · `upsert` |
26
+ | Delete | `delete` · `deleteMany` |
27
+ | Aggregate | `count` · `aggregate` · `groupBy` |
34
28
 
35
- ### `createClient({ options, modelMeta, schemas? })`
29
+ The statement-building pieces are exported too, for tooling that needs SQL without executing it: `buildQuery`, `compileWhere`, `compileSelect`, `compileOrderBy`, `resolveResultShape`, and the runtime metadata builders `buildRuntimeMeta`, `getModelMeta`, `getFieldMeta`.
36
30
 
37
- Creates a VibeORM client instance. Called by generated code — takes model metadata, optional Zod schemas, and client options.
31
+ ## The adapter contract
38
32
 
39
- `countStrategy` can be set globally in client options and overridden per count call:
33
+ `DatabaseAdapter` is frozen. Implement it and any driver works with the whole ORM:
40
34
 
41
35
  ```ts
42
- await db.user.count({
43
- where: { isActive: true },
44
- countStrategy: "subquery",
45
- });
36
+ import type { DatabaseAdapter, QueryResult, TransactionOptions } from "@vibeorm/runtime";
37
+
38
+ const adapter: DatabaseAdapter = {
39
+ dialect: "postgres",
40
+ provider: "postgresql",
41
+ async execute(params: { text: string; values: unknown[] }): Promise<Record<string, unknown>[]> { /* … */ },
42
+ async executeUnsafe(params: { text: string; values?: unknown[] }): Promise<QueryResult> { /* … */ },
43
+ async transaction<T>(fn: (tx: DatabaseAdapter) => Promise<T>, options?: TransactionOptions): Promise<T> { /* … */ },
44
+ async connect(): Promise<void> { /* … */ },
45
+ async disconnect(): Promise<void> { /* … */ },
46
+ formatArrayParam(values: unknown[]): unknown { /* … */ },
47
+ };
46
48
  ```
47
49
 
48
- Per-operation `countStrategy` takes precedence over the client default.
49
-
50
- ### Mutation RETURNING behavior
51
-
52
- `create`, `update`, `delete`, and `upsert` now narrow SQL `RETURNING` columns when `select` is provided, reducing row payload size.
53
-
54
- - Default behavior: full scalar row is returned (same as before)
55
- - With `select`: only selected scalar columns are returned (plus internal keys when needed)
56
- - With `returning: true`: force full scalar `RETURNING` payload even when `select` is present
50
+ - `execute` is the ORM hot path (row-returning, statement-cached by the adapter). `executeUnsafe` is the raw/DDL path and is the only place `affectedRows` surfaces.
51
+ - `transaction` nests: an inner call creates a savepoint. `isolationLevel` and `timeout` are top-level only — a nested call must refuse both with `VIBE_VALIDATION`.
52
+ - Adapters never let raw driver errors escape. Each maps its driver's failures to `VibeError` codes (`VIBE_UNIQUE_VIOLATION`, `VIBE_FK_VIOLATION`, `VIBE_TRANSACTION`, `VIBE_ADAPTER`) through a per-driver table, with the driver error as `cause`.
53
+ - `formatArrayParam` converts a JS array into the driver's preferred scalar-array representation; the ORM path binds arrays through it, the raw path does not.
54
+ - The optional `wire` declaration (`WireFidelity`) tells the runtime what the driver already delivers for non-list scalars, so provably no-op decoders can be skipped.
57
55
 
58
- ### `toSqlExecutor({ adapter })`
56
+ `toSqlExecutor({ adapter })` bridges an adapter to the `SqlExecutor` shape `@vibeorm/migrate` runs on.
59
57
 
60
- Bridges a `DatabaseAdapter` to a `SqlExecutor` for use with the migrate package.
61
-
62
- ### `withRetry(fn, options?)`
63
-
64
- Retry utility with exponential backoff and jitter. Only retries `VibeTransientError` instances (connection failures, deadlocks, serialization conflicts, statement timeouts, pool exhaustion). Deterministic errors (`VibeRequestError`) are never retried.
58
+ ## Relation strategies
65
59
 
66
60
  ```ts
67
- import { withRetry } from "@vibeorm/runtime";
68
-
69
- // Basic — 3 retries, exponential backoff with jitter
70
- const users = await withRetry(() =>
71
- db.user.findMany({ where: { active: true } })
72
- );
73
-
74
- // Custom options
75
- const user = await withRetry(
76
- () => db.user.create({ data: { email: "new@example.com" } }),
77
- { maxRetries: 5, baseDelay: 100, maxDelay: 10000 },
78
- );
79
-
80
- // Retry only specific error codes
81
- const result = await withRetry(
82
- () => db.$transaction(async (tx) => {
83
- /* ... */
84
- }, { isolationLevel: "Serializable" }),
85
- { retryOn: ["SERIALIZATION_FAILURE", "DEADLOCK"] },
86
- );
87
-
88
- // With abort signal
89
- const controller = new AbortController();
90
- const result = await withRetry(
91
- () => db.user.findFirst({ where: { id: 1 } }),
92
- { signal: controller.signal },
93
- );
61
+ const db = createClient({ schema, adapter, options: { relationStrategy: "join" } });
94
62
  ```
95
63
 
96
- **Options (`RetryOptions`):**
97
-
98
- | Option | Default | Description |
99
- |--------|---------|-------------|
100
- | `maxRetries` | `3` | Max retry attempts (total executions = maxRetries + 1) |
101
- | `baseDelay` | `50` | Base delay in ms for exponential backoff |
102
- | `maxDelay` | `5000` | Maximum delay cap in ms |
103
- | `maxJitter` | `50` | Random jitter added per retry to prevent thundering herd |
104
- | `signal` | — | `AbortSignal` to cancel pending retries |
105
- | `retryOn` | — | Filter to retry only specific `VibeTransientErrorCode`s |
106
- | `onRetry` | — | Callback `({ error, attempt, delay }) => void` for logging/metrics |
107
-
108
- Backoff formula: `min(baseDelay * 2^attempt + random(0, maxJitter), maxDelay)`
109
-
110
- ### `VibeValidationError`
64
+ - `"query"` (default): one query per relation, batched with `WHERE ... IN`. Works on every dialect.
65
+ - `"join"`: a single statement using `LEFT JOIN LATERAL` with JSON aggregation. PostgreSQL and PGlite only; other dialects throw `VibeError` with code `VIBE_UNSUPPORTED_CAPABILITY`.
111
66
 
112
- Custom error class thrown when Zod validation fails on input or output data.
67
+ A `relationStrategy` argument on a find overrides the client default. Relation trees are resolved by `resolveRelationSelection` / `resolveRelationLink` and attached by `attachRelations` (query strategy) or `attachLateralRelations` (join strategy).
113
68
 
114
- ### `DatabaseAdapter` interface
69
+ ## Codecs
115
70
 
116
- The contract that adapter packages implement:
71
+ Value encoding and decoding lives in one table per dialect: `POSTGRES_CODECS`, `SQLITE_CODECS`, `MYSQL_CODECS`, indexed by `DIALECT_CODECS` and reachable through `getCodec({ dialect, type })`. Nothing else in the codebase coerces values — scattered coercion is what produced v1's BigInt, enum-array and timestamp bugs.
117
72
 
118
73
  ```ts
119
- type DatabaseAdapter = {
120
- execute(params: { text: string; values: unknown[] }): Promise<Record<string, unknown>[]>;
121
- executeRaw(params: { text: string; values: unknown[] }): Promise<QueryResult>;
122
- transaction<T>(params: { fn: (adapter: DatabaseAdapter) => Promise<T> }): Promise<T>;
123
- connect(): Promise<void>;
124
- disconnect(): Promise<void>;
125
- };
74
+ import { decodeRows, encodeValue, getCodec } from "@vibeorm/runtime";
126
75
  ```
127
76
 
128
- ### Relation Loading Strategies
129
-
130
- | Strategy | Method | Best for |
131
- |----------|--------|----------|
132
- | `"query"` | Parent query + batched `WHERE IN` queries | Deep/nested includes |
133
- | `"join"` | `LEFT JOIN LATERAL` + JSON aggregation | Flat includes, fewer round-trips |
134
-
135
- ### Exported Types
136
-
137
- `DatabaseAdapter`, `QueryResult`, `SqlExecutor`, `VibeClientOptions`, `ModelMeta`, `ModelMetaMap`, `ModelSchemas`, `ValidationSchema`, `QueryProfile`, `RelationProfile`, `ScalarFieldMeta`, `RelationFieldMeta`, `SqlQuery`, `Operation`, `RetryOptions`.
77
+ `encodeValue` runs on every parameter, `decodeValue` / `decodeRow` / `decodeRows` on every row materialization point — including relation children and join-strategy rows, not only top-level parents. `decodeAggregateValue` handles aggregate columns, whose result type differs from the underlying field's.
138
78
 
139
- ## License
79
+ ## Links
140
80
 
141
- [MIT](../../LICENSE)
81
+ - [Documentation](https://github.com/vibeorm/vibeorm/tree/master/docs)
82
+ - [Query API](https://github.com/vibeorm/vibeorm/blob/master/docs/queries.md)
83
+ - [Repository and issues](https://github.com/vibeorm/vibeorm)
84
+ - MIT licensed
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Database adapter contract for VibeORM v2. FROZEN INTERFACE — the runtime is
3
+ * driver-agnostic and talks to databases exclusively through this type;
4
+ * adapter packages (adapter-bun, adapter-pg, adapter-pglite, adapter-sqlite,
5
+ * adapter-mysql) implement it.
6
+ *
7
+ * ERROR CONTRACT: adapters never let raw driver errors escape. Every failure
8
+ * is mapped to a VibeError with a stable code via a per-driver table
9
+ * (unique violation → VIBE_UNIQUE_VIOLATION, FK violation → VIBE_FK_VIOLATION,
10
+ * serialization/deadlock → VIBE_TRANSACTION, connection/other → VIBE_ADAPTER),
11
+ * with the driver error attached as `cause`.
12
+ */
13
+ import type { Dialect, Provider } from "@vibeorm/schema";
14
+ import type { WireFidelity } from "@vibeorm/sql";
15
+ /** Transaction isolation levels (mapped per dialect by the adapter). */
16
+ export type IsolationLevel = "ReadCommitted" | "RepeatableRead" | "Serializable";
17
+ /**
18
+ * Options for `$transaction` / `adapter.transaction`.
19
+ *
20
+ * `timeout` is milliseconds, enforced database-side where the engine can
21
+ * genuinely cancel a running statement (postgres servers via `SET LOCAL
22
+ * statement_timeout`, mysql's SELECT-only `MAX_EXECUTION_TIME`). Dialect
23
+ * honesty: an adapter whose engine CANNOT enforce it refuses loudly instead
24
+ * of no-opping — sqlite adapters throw `VIBE_VALIDATION` (busy_timeout only
25
+ * bounds lock acquisition), pglite throws `VIBE_UNSUPPORTED_CAPABILITY` (the
26
+ * WASM build accepts statement_timeout but never fires it).
27
+ *
28
+ * Options are TOP-LEVEL only: a nested `transaction()` call (a savepoint)
29
+ * refuses BOTH fields with `VIBE_VALIDATION` on every adapter — a savepoint
30
+ * cannot change the isolation level of the transaction it joins, and a
31
+ * nested timeout is not enforceable.
32
+ */
33
+ export type TransactionOptions = {
34
+ isolationLevel?: IsolationLevel;
35
+ timeout?: number;
36
+ };
37
+ /** Result of an unsafe/raw execution: rows plus affected-row count. */
38
+ export type QueryResult = {
39
+ rows: Record<string, unknown>[];
40
+ affectedRows: number;
41
+ };
42
+ /**
43
+ * The primary interface every database adapter implements. Adapters own
44
+ * connection management, statement caching, transactions (including nested →
45
+ * savepoints), driver-specific parameter formatting and driver-error mapping.
46
+ */
47
+ export type DatabaseAdapter = {
48
+ /** SQL dialect this adapter's database speaks (selects the @vibeorm/sql dialect). */
49
+ readonly dialect: Dialect;
50
+ /** Concrete provider (pglite and postgresql both speak `postgres`). */
51
+ readonly provider: Provider;
52
+ /**
53
+ * What this DRIVER actually delivers for non-list scalar columns on the
54
+ * result path (board #30) — lets the runtime's decode plans skip decoders
55
+ * that are provably no-ops for this driver (e.g. node-postgres already hands
56
+ * `Date` for timestamptz and parsed values for jsonb). OPTIONAL and purely
57
+ * an optimization contract: an adapter that declares nothing gets the full
58
+ * idempotency-guarded decode path. Declare only what the driver verifiably
59
+ * does; transactional adapters must carry the same declaration.
60
+ */
61
+ readonly wire?: WireFidelity;
62
+ /**
63
+ * Execute a parameterized query on the ORM hot path and return rows.
64
+ * The adapter owns prepared-statement caching and ORM-path parameter
65
+ * serialization (e.g. tagged scalar-list params vs JSON values).
66
+ */
67
+ execute(params: {
68
+ text: string;
69
+ values: unknown[];
70
+ }): Promise<Record<string, unknown>[]>;
71
+ /**
72
+ * Execute a raw query (`$queryRaw*`, `$executeRaw*`, DDL). No statement
73
+ * caching; raw-path parameter serialization (arrays pass through to the
74
+ * driver where it supports them — see LEARNINGS: raw vs ORM paths differ).
75
+ *
76
+ * OMITTING `values` changes semantics on the sqlite adapters (board #31):
77
+ * `adapter-sqlite` and `adapter-better-sqlite3` route no-`values` text
78
+ * through the driver's multi-statement script mode (`db.run`/`exec` — the
79
+ * shape @vibeorm/migrate emits for DDL/PRAGMA batches), which CANNOT return
80
+ * rows: a parameterless SELECT yields `rows: []` there, while pg/pglite/
81
+ * mysql/bun return its result set either way. Callers that want rows from a
82
+ * single parameterless statement must pass `values: []` — the client's
83
+ * `$queryRawUnsafe` always does. Rule of thumb: `values` present (even
84
+ * empty) = one prepared statement with rows; `values` absent = script mode,
85
+ * rows not guaranteed.
86
+ */
87
+ executeUnsafe(params: {
88
+ text: string;
89
+ values?: unknown[];
90
+ }): Promise<QueryResult>;
91
+ /**
92
+ * Run `fn` inside a transaction; the callback receives a transactional
93
+ * adapter with this same interface. Nested calls create savepoints. Throwing
94
+ * rolls back (the savepoint or the whole transaction) and rethrows.
95
+ *
96
+ * `options` is honored on TOP-LEVEL calls only. A NESTED call refuses any
97
+ * `isolationLevel` or `timeout` with `VIBE_VALIDATION` (`meta.nested:
98
+ * true`), identically on every adapter: a savepoint cannot change the
99
+ * isolation level of the transaction it joins, and a nested timeout is not
100
+ * enforceable. Silently dropping the option was the pre-#3 behaviour of the
101
+ * pg/pglite/mysql/bun adapters and is forbidden by constitution rule 4.
102
+ */
103
+ transaction<T>(fn: (txAdapter: DatabaseAdapter) => Promise<T>, options?: TransactionOptions): Promise<T>;
104
+ /** Eagerly open/verify connectivity (pool warm-up or first connection). */
105
+ connect(): Promise<void>;
106
+ /** Gracefully close all connections. */
107
+ disconnect(): Promise<void>;
108
+ /**
109
+ * Convert a JS array into the driver's preferred representation for a
110
+ * scalar-array parameter (postgres `= ANY($n)`): PG array literal string for
111
+ * drivers that send strings, the raw array for drivers with native support.
112
+ */
113
+ formatArrayParam(values: unknown[]): unknown;
114
+ };
115
+ /** Minimal SQL execution interface used by @vibeorm/migrate. */
116
+ export type SqlExecutor = (params: {
117
+ text: string;
118
+ values?: unknown[];
119
+ }) => Promise<Record<string, unknown>[]>;
120
+ /** Bridge a DatabaseAdapter to the migrate package's SqlExecutor shape. */
121
+ export declare function toSqlExecutor(params: {
122
+ adapter: DatabaseAdapter;
123
+ }): SqlExecutor;
124
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAEjF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAIF,uEAAuE;AACvE,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAIF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAE5B;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;IAE7B;;;;OAIG;IACH,OAAO,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAEzF;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAElF;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEzG,2EAA2E;IAC3E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB,wCAAwC;IACxC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;CAC9C,CAAC;AAIF,gEAAgE;AAChE,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;AAEzC,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,eAAe,CAAA;CAAE,GAAG,WAAW,CAS/E"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * The dynamic client: model delegates over a `DatabaseAdapter`, built from the
3
+ * Schema IR at runtime.
4
+ *
5
+ * This is the engine the generated client wraps in P2 proper. It is deliberately
6
+ * untyped-per-model — the generator emits a `.d.ts` that declares each delegate
7
+ * with precise argument and result types, and casts to it. Nothing about the
8
+ * shape of a query lives here: `query-builder.ts` builds statements,
9
+ * `@vibeorm/sql` renders them, `codecs.ts` moves values across the wire,
10
+ * `relation-loader.ts` attaches included relations, `nested-writes.ts`
11
+ * orchestrates relation verbs inside create/update data.
12
+ *
13
+ * Execution split:
14
+ * - row-returning statements use `adapter.execute` (the cached hot path),
15
+ * - count-returning mutations (createMany/updateMany/deleteMany) use
16
+ * `adapter.executeUnsafe`, the only place the frozen adapter contract
17
+ * surfaces `affectedRows`.
18
+ */
19
+ import type { SchemaIR } from "@vibeorm/schema";
20
+ import type { DatabaseAdapter, TransactionOptions } from "./adapter.ts";
21
+ import type { RelationStrategy } from "./query-builder.ts";
22
+ import type { ClientComputedOptions } from "./computed.ts";
23
+ import type { ClientExtensionsOptions } from "./extensions.ts";
24
+ import type { DefineViewFn } from "./views.ts";
25
+ /** One executed statement, reported to `ClientOptions.onQuery`. */
26
+ export type QueryEvent = {
27
+ /** Model name, or `null` for raw queries. */
28
+ readonly model: string | null;
29
+ /** ORM method, or `"$queryRaw"` / `"$executeRaw"`. */
30
+ readonly method: string;
31
+ readonly text: string;
32
+ readonly values: readonly unknown[];
33
+ readonly durationMs: number;
34
+ };
35
+ export type ClientOptions = {
36
+ /** Called after every statement — logging, tracing, test assertions. */
37
+ readonly onQuery?: (event: QueryEvent) => void;
38
+ /**
39
+ * Default relation-loading strategy: `"query"` (batched WHERE-IN, portable,
40
+ * the default) or `"join"` (LATERAL + JSON aggregation, postgres/pglite
41
+ * only). A per-query `relationStrategy` argument overrides it.
42
+ */
43
+ readonly relationStrategy?: RelationStrategy;
44
+ /**
45
+ * Append the primary key to ORDER BY when a find has no explicit orderBy
46
+ * (default false) — deterministic row order at the cost of a sort. v1 parity.
47
+ */
48
+ readonly defaultOrderByPk?: boolean;
49
+ /**
50
+ * Append the primary key as a tie-breaker to `distinct` ordering (default
51
+ * TRUE) — without it, WHICH row represents each distinct key is unspecified.
52
+ * v1 parity.
53
+ */
54
+ readonly distinctOrderByPk?: boolean;
55
+ };
56
+ /** Rows are plain objects keyed by field name; the generated client narrows them. */
57
+ export type ClientRow = Record<string, unknown>;
58
+ /** Result of the count-returning batch methods. */
59
+ export type BatchResult = {
60
+ readonly count: number;
61
+ };
62
+ /**
63
+ * A model's methods. Arguments and results are intentionally broad here — the
64
+ * generated `.d.ts` replaces this surface with precise per-model types, and
65
+ * keeping the runtime free of inference is what holds the type-cost budget
66
+ * (constitution rule 2).
67
+ */
68
+ export type ModelDelegate = {
69
+ readonly findMany: (args?: ClientRow) => Promise<ClientRow[]>;
70
+ readonly findFirst: (args?: ClientRow) => Promise<ClientRow | null>;
71
+ readonly findFirstOrThrow: (args?: ClientRow) => Promise<ClientRow>;
72
+ readonly findUnique: (args: ClientRow) => Promise<ClientRow | null>;
73
+ readonly findUniqueOrThrow: (args: ClientRow) => Promise<ClientRow>;
74
+ readonly create: (args: ClientRow) => Promise<ClientRow>;
75
+ readonly createMany: (args: ClientRow) => Promise<BatchResult>;
76
+ readonly createManyAndReturn: (args: ClientRow) => Promise<ClientRow[]>;
77
+ readonly update: (args: ClientRow) => Promise<ClientRow>;
78
+ readonly updateMany: (args: ClientRow) => Promise<BatchResult>;
79
+ readonly upsert: (args: ClientRow) => Promise<ClientRow>;
80
+ readonly delete: (args: ClientRow) => Promise<ClientRow>;
81
+ readonly deleteMany: (args?: ClientRow) => Promise<BatchResult>;
82
+ /** Plain form returns a number; `{ select: { _all, field } }` returns per-key counts. */
83
+ readonly count: (args?: ClientRow) => Promise<number | Record<string, number>>;
84
+ readonly aggregate: (args: ClientRow) => Promise<ClientRow>;
85
+ readonly groupBy: (args: ClientRow) => Promise<ClientRow[]>;
86
+ };
87
+ /**
88
+ * The client. Delegates are also attached as own properties under their
89
+ * camelCase names (`client.user.findMany()`); the type surfaces them through
90
+ * `$models` because a plain index signature would erase the `$`-methods.
91
+ * Model names can never collide with those: every reserved client name is
92
+ * `$`-prefixed (see `RESERVED_CLIENT_NAMES` in @vibeorm/schema).
93
+ */
94
+ export type DynamicClient = {
95
+ /** Delegates keyed by BOTH camelCase client name and model name. */
96
+ readonly $models: Readonly<Record<string, ModelDelegate>>;
97
+ /**
98
+ * Subscribe to client events (`"query"` fires after every statement, with
99
+ * the same payload as `ClientOptions.onQuery` — both fire). Returns an
100
+ * unsubscribe function. Transaction clients share the parent's listeners.
101
+ */
102
+ readonly $on: (event: "query", listener: (event: QueryEvent) => void) => () => void;
103
+ /**
104
+ * Run work in ONE transaction. Callback form: `fn` receives a transaction
105
+ * client; everything it runs rides the same BEGIN/COMMIT and a throw rolls
106
+ * back. Array form (Prisma parity): UN-AWAITED delegate calls — delegate
107
+ * methods return LAZY query promises that only dispatch on await — run
108
+ * SEQUENTIALLY inside one transaction, results returned positionally.
109
+ */
110
+ readonly $transaction: {
111
+ <T>(fn: (tx: DynamicClient) => Promise<T>, options?: TransactionOptions): Promise<T>;
112
+ <T extends readonly unknown[]>(operations: readonly [...T], options?: TransactionOptions): Promise<{
113
+ -readonly [K in keyof T]: Awaited<T[K]>;
114
+ }>;
115
+ };
116
+ /** Tagged template — interpolations become bound parameters, never text. */
117
+ readonly $queryRaw: (strings: TemplateStringsArray, ...values: unknown[]) => Promise<ClientRow[]>;
118
+ /** Tagged template returning the affected-row count. */
119
+ readonly $executeRaw: (strings: TemplateStringsArray, ...values: unknown[]) => Promise<number>;
120
+ readonly $queryRawUnsafe: (text: string, ...values: unknown[]) => Promise<ClientRow[]>;
121
+ readonly $executeRawUnsafe: (text: string, ...values: unknown[]) => Promise<number>;
122
+ readonly $connect: () => Promise<void>;
123
+ readonly $disconnect: () => Promise<void>;
124
+ /**
125
+ * Field-masking views (v1 `defineView` parity, board #11) — a read-only
126
+ * scoped client restricted to the definition's models and fields. Attached
127
+ * by `attachDefineView` after construction (hence optional in the type);
128
+ * it is always present on a built client, transaction clients included.
129
+ */
130
+ readonly $defineView?: DefineViewFn;
131
+ };
132
+ /**
133
+ * Build a client for a schema over an adapter.
134
+ *
135
+ * The adapter chooses the dialect: the same IR runs on postgres, sqlite or
136
+ * mysql, and every dialect difference is resolved by `@vibeorm/sql` and the
137
+ * codec table rather than by branching here.
138
+ *
139
+ * @example
140
+ * const db = createClient({ schema, adapter });
141
+ * const users = await db.$models.user.findMany({ where: { active: true } });
142
+ */
143
+ export declare function createClient(params: {
144
+ schema: SchemaIR;
145
+ adapter: DatabaseAdapter;
146
+ options?: ClientOptions;
147
+ /** Extension wiring — baked mounts + manifest from the generated client, live instances from the caller. */
148
+ extensions?: ClientExtensionsOptions;
149
+ /** Computed-field wiring — baked manifest from the generated client, live specs from the caller. */
150
+ computed?: ClientComputedOptions;
151
+ }): DynamicClient;
152
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * The codec entry points — constitution rule 6.
3
+ *
4
+ * The PURE per-dialect tables (dialect × scalar type) live in @vibeorm/sql
5
+ * (`codecs.ts` there) and are re-exported here so consumers keep one import
6
+ * site. This module owns the FieldMeta-aware entry points: list handling,
7
+ * enum-to-String routing and row materialization.
8
+ *
9
+ * The two rules that make it work:
10
+ * - EVERY parameter bound by the query builder passes through `encodeValue`.
11
+ * - EVERY row materialized by the client passes through `decodeRow`/
12
+ * `decodeRows` — including every relation-loaded child row, at every
13
+ * materialization point (the v1 lesson: BigInt-as-string and enum-array
14
+ * bugs came from children skipping coercion).
15
+ */
16
+ import type { Dialect, FieldType } from "@vibeorm/schema";
17
+ import type { ScalarCodec, WireFidelity } from "@vibeorm/sql";
18
+ import type { FieldMeta, ModelMeta } from "./model-meta.ts";
19
+ export { DIALECT_CODECS, MYSQL_CODECS, POSTGRES_CODECS, SQLITE_CODECS, decodeIsNoop, } from "@vibeorm/sql";
20
+ export type { CodecTable, ScalarCodec, WireFidelity } from "@vibeorm/sql";
21
+ /** The codec for a field type on a dialect. Enum references use the String codec. */
22
+ export declare function getCodec(params: {
23
+ dialect: Dialect;
24
+ type: FieldType;
25
+ }): ScalarCodec;
26
+ /**
27
+ * Encode one value for parameter binding. `null`/`undefined` pass through
28
+ * untouched (SQL NULL). List fields encode element-wise; the adapter's
29
+ * `formatArrayParam` then owns the array's wire representation — except for
30
+ * postgres ENUM arrays, which become an array literal here (no driver can
31
+ * serialize them, see {@link isPostgresEnumList}).
32
+ */
33
+ export declare function encodeValue(params: {
34
+ dialect: Dialect;
35
+ field: FieldMeta;
36
+ value: unknown;
37
+ }): unknown;
38
+ /**
39
+ * Decode one driver value. List fields decode element-wise.
40
+ *
41
+ * postgres returns ENUM arrays as a raw array literal string, because no driver
42
+ * knows a user-defined enum's array OID (LEARNINGS.md) — that literal is parsed
43
+ * here, next to the other coercion rules.
44
+ */
45
+ export declare function decodeValue(params: {
46
+ dialect: Dialect;
47
+ field: FieldMeta;
48
+ value: unknown;
49
+ }): unknown;
50
+ /**
51
+ * Encode one COMPARISON operand (WHERE / cursor bounds). Identical to
52
+ * {@link encodeValue} everywhere except sqlite Decimal (SQL review B4):
53
+ * Decimal STORES as exact TEXT there, but text comparison is lexicographic —
54
+ * so every compare site casts the column (`CAST(col AS REAL)`) and binds the
55
+ * operand as a NUMBER. Comparison precision is float64-bounded on sqlite
56
+ * (docs/dialects.md); storage and read-back stay exact.
57
+ */
58
+ export declare function encodeFilterValue(params: {
59
+ dialect: Dialect;
60
+ field: FieldMeta;
61
+ value: unknown;
62
+ }): unknown;
63
+ /**
64
+ * Encode one AGGREGATE-predicate operand (HAVING). On sqlite an aggregate
65
+ * expression has NO column affinity, so a TEXT operand never converts and the
66
+ * predicate is constant-false (SQL review M5, live-proven) — operands bind in
67
+ * raw numeric form there: Decimal as a number (the aggregate is over
68
+ * `CAST(col AS REAL)`), BigInt as a bigint (bun:sqlite binds int64 natively).
69
+ * Other dialects keep the field codec's wire form.
70
+ */
71
+ export declare function encodeAggregateOperand(params: {
72
+ dialect: Dialect;
73
+ field: FieldMeta;
74
+ value: unknown;
75
+ }): unknown;
76
+ /** Decode one non-null driver value (list handling prebound). */
77
+ type RowDecoder = (value: unknown) => unknown;
78
+ /**
79
+ * The prebound encoder for one field on one dialect, or `null` when its codec
80
+ * encode is the identity. Mirrors `encodeValue` exactly (see `fieldDecoder`).
81
+ */
82
+ export declare function fieldEncoder(params: {
83
+ dialect: Dialect;
84
+ field: FieldMeta;
85
+ }): RowDecoder | null;
86
+ /**
87
+ * The prebound decoder for one field on one dialect, or `null` when its codec
88
+ * decode is the identity (nothing to do). Mirrors `decodeValue` exactly:
89
+ * elements of a list decode element-wise (null elements pass), a non-array
90
+ * value on a list field goes through the element decoder as-is.
91
+ *
92
+ * With a `wire` declaration (board #30 — the ADAPTER's promise about what its
93
+ * driver delivers), decoders that are provably no-ops for that wire are pruned
94
+ * too ({@link decodeIsNoop}): non-list DateTime/Json/Int/Float columns on
95
+ * drivers that already deliver native forms. Without a declaration the full
96
+ * idempotency-guarded decoder set applies — exactly the pre-#30 behaviour.
97
+ */
98
+ export declare function fieldDecoder(params: {
99
+ dialect: Dialect;
100
+ field: FieldMeta;
101
+ wire?: WireFidelity;
102
+ }): RowDecoder | null;
103
+ /**
104
+ * Materialize one driver row: column names become field names, values pass
105
+ * through their codecs. Columns the model does not know (aggregate aliases, raw
106
+ * extras) are carried over verbatim.
107
+ */
108
+ export declare function decodeRow(params: {
109
+ dialect: Dialect;
110
+ model: ModelMeta;
111
+ row: Record<string, unknown>;
112
+ /** The executing adapter's wire declaration — prunes provably-no-op decoders (board #30). */
113
+ wire?: WireFidelity;
114
+ }): Record<string, unknown>;
115
+ /** `decodeRow` over a result set. */
116
+ export declare function decodeRows(params: {
117
+ dialect: Dialect;
118
+ model: ModelMeta;
119
+ rows: readonly Record<string, unknown>[];
120
+ /** The executing adapter's wire declaration — prunes provably-no-op decoders (board #30). */
121
+ wire?: WireFidelity;
122
+ }): Record<string, unknown>[];
123
+ /**
124
+ * `decodeRows` for rows the caller OWNS (fresh driver output): when no column
125
+ * is renamed the rows are decoded in place — only columns whose codec does
126
+ * something are touched — and the same array returns. With renames it falls
127
+ * back to rebuilding rows. Every decoder is idempotent (each checks its input
128
+ * type), so re-materializing an already-decoded row is harmless.
129
+ *
130
+ * Internal to the runtime (client + relation loader) — the exported
131
+ * `decodeRow`/`decodeRows` keep their copy semantics.
132
+ */
133
+ export declare function materializeRows(params: {
134
+ dialect: Dialect;
135
+ model: ModelMeta;
136
+ rows: Record<string, unknown>[];
137
+ /** The executing adapter's wire declaration — prunes provably-no-op decoders (board #30). */
138
+ wire?: WireFidelity;
139
+ }): Record<string, unknown>[];
140
+ /**
141
+ * `materializeRows` for JSON-transport rows — the join strategy's child rows
142
+ * after `JSON.parse`. Postgres-only by construction (lateral joins are).
143
+ */
144
+ export declare function materializeJsonRows(params: {
145
+ model: ModelMeta;
146
+ rows: Record<string, unknown>[];
147
+ }): Record<string, unknown>[];
148
+ /**
149
+ * Normalize one aggregate value — the contract, tested live on PGlite:
150
+ *
151
+ * | aggregate | field type | JS result |
152
+ * |-----------|-----------------|-------------------------------|
153
+ * | `_count` | any / `_all` | `number` (0 over an empty set)|
154
+ * | `_avg` | Int/BigInt/Float| `number` (pg numeric → Number)|
155
+ * | `_avg` | Decimal | `string` (no float rounding) |
156
+ * | `_sum` | Int / Float | `number` |
157
+ * | `_sum` | BigInt | `bigint` |
158
+ * | `_sum` | Decimal | `string` |
159
+ * | `_min/_max`| any | the field's own codec type |
160
+ *
161
+ * Every non-`_count` aggregate over an empty set is `null` (SQL semantics,
162
+ * kept deliberately — 0 would be a lie for MIN/AVG).
163
+ */
164
+ export declare function decodeAggregateValue(params: {
165
+ dialect: Dialect;
166
+ key: "_count" | "_avg" | "_sum" | "_min" | "_max";
167
+ field: FieldMeta | null;
168
+ value: unknown;
169
+ }): unknown;
170
+ //# sourceMappingURL=codecs.d.ts.map