turbine-orm 0.49.0 → 0.50.0
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.
- package/README.md +122 -39
- package/dist/cjs/adapters/cockroachdb.d.ts +39 -0
- package/dist/cjs/adapters/index.d.ts +110 -0
- package/dist/cjs/adapters/yugabytedb.d.ts +51 -0
- package/dist/cjs/cli/config.d.ts +181 -0
- package/dist/cjs/cli/config.js +32 -6
- package/dist/cjs/cli/destructive.d.ts +38 -0
- package/dist/cjs/cli/index.d.ts +359 -0
- package/dist/cjs/cli/index.js +228 -56
- package/dist/cjs/cli/loader.d.ts +61 -0
- package/dist/cjs/cli/mcp.d.ts +42 -0
- package/dist/cjs/cli/migrate.d.ts +356 -0
- package/dist/cjs/cli/migrate.js +131 -40
- package/dist/cjs/cli/observe-ui.d.ts +1 -0
- package/dist/cjs/cli/observe-ui.js +14 -5
- package/dist/cjs/cli/observe.d.ts +25 -0
- package/dist/cjs/cli/observe.js +49 -12
- package/dist/cjs/cli/pii-tags.d.ts +53 -0
- package/dist/cjs/cli/prisma-report.d.ts +33 -0
- package/dist/cjs/cli/prisma-report.js +73 -0
- package/dist/cjs/cli/prisma-resolve.d.ts +106 -0
- package/dist/cjs/cli/prisma-resolve.js +1 -0
- package/dist/cjs/cli/prisma-schema.d.ts +176 -0
- package/dist/cjs/cli/prisma-schema.js +82 -4
- package/dist/cjs/cli/rate-limit.d.ts +32 -0
- package/dist/cjs/cli/rate-limit.js +45 -0
- package/dist/cjs/cli/studio-demo.d.ts +43 -0
- package/dist/cjs/cli/studio-ui.generated.d.ts +1 -0
- package/dist/cjs/cli/studio.d.ts +207 -0
- package/dist/cjs/cli/studio.js +136 -71
- package/dist/cjs/cli/ui.d.ts +73 -0
- package/dist/cjs/cli/ui.js +51 -9
- package/dist/cjs/client.d.ts +837 -0
- package/dist/cjs/client.js +3 -0
- package/dist/cjs/dialect.d.ts +516 -0
- package/dist/cjs/dialect.js +37 -12
- package/dist/cjs/errors.d.ts +370 -0
- package/dist/cjs/generate.d.ts +137 -0
- package/dist/cjs/generate.js +39 -6
- package/dist/cjs/index-advisor.d.ts +153 -0
- package/dist/cjs/index-stats.d.ts +384 -0
- package/dist/cjs/index.d.ts +55 -0
- package/dist/cjs/index.js +7 -2
- package/dist/cjs/introspect.d.ts +269 -0
- package/dist/cjs/mssql.d.ts +232 -0
- package/dist/cjs/mssql.js +6 -0
- package/dist/cjs/mysql.d.ts +173 -0
- package/dist/cjs/mysql.js +16 -0
- package/dist/cjs/nested-write.d.ts +96 -0
- package/dist/cjs/nested-write.js +414 -24
- package/dist/cjs/observe.d.ts +115 -0
- package/dist/cjs/optional-peer-import.d.cts +72 -0
- package/dist/cjs/pipeline-submittable.d.ts +93 -0
- package/dist/cjs/pipeline.d.ts +71 -0
- package/dist/cjs/powdb-introspect.d.ts +84 -0
- package/dist/cjs/powdb.d.ts +931 -0
- package/dist/cjs/powdb.js +106 -21
- package/dist/cjs/powql.d.ts +592 -0
- package/dist/cjs/powql.js +42 -6
- package/dist/cjs/prisma-compat.d.ts +283 -0
- package/dist/cjs/prisma-compat.js +167 -9
- package/dist/cjs/query/aggregates.d.ts +92 -0
- package/dist/cjs/query/aggregates.js +7 -3
- package/dist/cjs/query/batched-loader.d.ts +193 -0
- package/dist/cjs/query/builder.d.ts +849 -0
- package/dist/cjs/query/builder.js +571 -65
- package/dist/cjs/query/compound-unique.d.ts +51 -0
- package/dist/cjs/query/deferred.d.ts +223 -0
- package/dist/cjs/query/filters.d.ts +201 -0
- package/dist/cjs/query/index.d.ts +14 -0
- package/dist/cjs/query/index.js +6 -1
- package/dist/cjs/query/relations.d.ts +609 -0
- package/dist/cjs/query/relations.js +693 -46
- package/dist/cjs/query/types.d.ts +1300 -0
- package/dist/cjs/query/utils.d.ts +209 -0
- package/dist/cjs/query/utils.js +208 -1
- package/dist/cjs/query/warn-registry.d.ts +68 -0
- package/dist/cjs/query/warn-registry.js +9 -0
- package/dist/cjs/query/where-compile.d.ts +139 -0
- package/dist/cjs/query/where.d.ts +548 -0
- package/dist/cjs/query/where.js +58 -22
- package/dist/cjs/query/writes.d.ts +172 -0
- package/dist/cjs/query/writes.js +105 -12
- package/dist/cjs/realtime.d.ts +70 -0
- package/dist/cjs/schema-builder.d.ts +354 -0
- package/dist/cjs/schema-metadata.d.ts +83 -0
- package/dist/cjs/schema-sql.d.ts +217 -0
- package/dist/cjs/schema-sql.js +23 -5
- package/dist/cjs/schema.d.ts +356 -0
- package/dist/cjs/schema.js +125 -0
- package/dist/cjs/seed.d.ts +15 -0
- package/dist/cjs/serverless.d.ts +142 -0
- package/dist/cjs/sqlite.d.ts +143 -0
- package/dist/cjs/sqlite.js +4 -0
- package/dist/cjs/typed-sql.d.ts +102 -0
- package/dist/cli/config.d.ts +18 -4
- package/dist/cli/config.js +31 -6
- package/dist/cli/index.d.ts +123 -0
- package/dist/cli/index.js +223 -58
- package/dist/cli/migrate.d.ts +59 -10
- package/dist/cli/migrate.js +128 -41
- package/dist/cli/observe-ui.d.ts +1 -1
- package/dist/cli/observe-ui.js +14 -5
- package/dist/cli/observe.d.ts +7 -1
- package/dist/cli/observe.js +48 -12
- package/dist/cli/prisma-report.d.ts +14 -0
- package/dist/cli/prisma-report.js +72 -0
- package/dist/cli/prisma-resolve.d.ts +6 -0
- package/dist/cli/prisma-resolve.js +1 -0
- package/dist/cli/prisma-schema.d.ts +62 -2
- package/dist/cli/prisma-schema.js +81 -4
- package/dist/cli/rate-limit.d.ts +32 -0
- package/dist/cli/rate-limit.js +40 -0
- package/dist/cli/studio.d.ts +5 -5
- package/dist/cli/studio.js +135 -70
- package/dist/cli/ui.d.ts +1 -1
- package/dist/cli/ui.js +51 -9
- package/dist/client.d.ts +40 -0
- package/dist/client.js +3 -0
- package/dist/dialect.d.ts +17 -1
- package/dist/dialect.js +37 -12
- package/dist/generate.js +40 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mssql.js +6 -0
- package/dist/mysql.js +16 -0
- package/dist/nested-write.d.ts +2 -0
- package/dist/nested-write.js +415 -25
- package/dist/powdb.d.ts +4 -2
- package/dist/powdb.js +106 -21
- package/dist/powql.d.ts +5 -0
- package/dist/powql.js +42 -6
- package/dist/prisma-compat.d.ts +2 -0
- package/dist/prisma-compat.js +166 -8
- package/dist/query/aggregates.js +7 -3
- package/dist/query/builder.d.ts +292 -21
- package/dist/query/builder.js +570 -64
- package/dist/query/deferred.d.ts +39 -0
- package/dist/query/index.d.ts +1 -1
- package/dist/query/index.js +1 -1
- package/dist/query/relations.d.ts +173 -5
- package/dist/query/relations.js +688 -47
- package/dist/query/types.d.ts +123 -39
- package/dist/query/utils.d.ts +116 -0
- package/dist/query/utils.js +198 -0
- package/dist/query/warn-registry.d.ts +9 -0
- package/dist/query/warn-registry.js +9 -0
- package/dist/query/where.d.ts +38 -1
- package/dist/query/where.js +58 -23
- package/dist/query/writes.d.ts +42 -1
- package/dist/query/writes.js +104 -13
- package/dist/schema-sql.d.ts +14 -0
- package/dist/schema-sql.js +23 -5
- package/dist/schema.d.ts +38 -0
- package/dist/schema.js +123 -0
- package/dist/sqlite.js +4 -0
- package/package.json +77 -28
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm/mysql — MySQL 8 engine (driver-injected, optional peer)
|
|
3
|
+
*
|
|
4
|
+
* Binds Turbine to MySQL 8 via the `mysql2` driver. `mysql2` is **not** a root
|
|
5
|
+
* dependency — it is an **optional peer**: `npm i turbine-orm` pulls nothing
|
|
6
|
+
* extra, and only consumers who `import 'turbine-orm/mysql'` install `mysql2`
|
|
7
|
+
* themselves. The factory loads it through a dynamic `import('mysql2/promise')`
|
|
8
|
+
* so importing this module never crashes when `mysql2` is absent for a consumer
|
|
9
|
+
* who does not use it. Turbine's root runtime dependency stays exactly `pg`.
|
|
10
|
+
*
|
|
11
|
+
* ## The two hard MySQL realities this engine solves
|
|
12
|
+
*
|
|
13
|
+
* 1. **No `RETURNING`.** `INSERT`/`UPDATE`/`DELETE` cannot return the affected
|
|
14
|
+
* rows. `mysqlDialect.resultStrategy = 'reselect'`: the executor runs the
|
|
15
|
+
* write, then issues a follow-up `SELECT` by primary key (using mysql2's
|
|
16
|
+
* `insertId` for auto-increment PKs) / by the `where` predicate, so
|
|
17
|
+
* `create`/`update`/`upsert`/`delete` still return real rows. This is the
|
|
18
|
+
* first shipped engine to exercise the Phase-0 `reselect` path.
|
|
19
|
+
* 2. **Positional `?` is broken for this builder.** Turbine pushes params in
|
|
20
|
+
* 1-indexed generation order but EMITS them in a different SQL-text position
|
|
21
|
+
* (e.g. a `with`-relation `LIMIT` lands in the SELECT list, ahead of the
|
|
22
|
+
* outer `WHERE`). Postgres reconciles this via numbered `$N`; positional `?`
|
|
23
|
+
* silently mis-binds. So `mysqlDialect` uses **mysql2 named placeholders**
|
|
24
|
+
* (`:p1`, `:p2`, …) and the driver shim binds via a `{ p1, p2, … }` object —
|
|
25
|
+
* exactly mirroring `$N` semantics regardless of text order. (See
|
|
26
|
+
* `turbine-orm/sqlite` for the same fix.)
|
|
27
|
+
*
|
|
28
|
+
* ## Capabilities & limits (vs PostgreSQL)
|
|
29
|
+
*
|
|
30
|
+
* - **Single query nested relations preserved** via MySQL 8 `JSON_OBJECT` /
|
|
31
|
+
* `JSON_ARRAYAGG` with `COALESCE(…, JSON_ARRAY())`. `JSON_ARRAYAGG` has no
|
|
32
|
+
* inline `ORDER BY` argument, so every ordered to-many relation is forced
|
|
33
|
+
* through the inner-subquery rewrite (`aggSupportsInlineOrderBy = false`).
|
|
34
|
+
* Nested subresults are `CAST(… AS JSON)`-wrapped so MySQL embeds them as real
|
|
35
|
+
* nested JSON instead of double-encoding a scalar subquery result as a string.
|
|
36
|
+
* - **`createMany` returns an empty array** (count-not-rows). MySQL has no
|
|
37
|
+
* `RETURNING` and the bulk-insert `insertId` is only the first generated id, so
|
|
38
|
+
* re-selecting N rows reliably is unsafe. The rows ARE inserted; re-query if you
|
|
39
|
+
* need them back. (Plan §4 documented divergence.)
|
|
40
|
+
* - **Unsupported (throw `UnsupportedFeatureError`):** pgvector distance ops,
|
|
41
|
+
* LISTEN/NOTIFY (`$listen`/`$notify`), RLS `sessionContext` (no GUCs).
|
|
42
|
+
* - **Advisory-lock migration locking** is available in principle via
|
|
43
|
+
* `GET_LOCK`/`RELEASE_LOCK` (`supportsAdvisoryLock = true`); the migrate CLI is
|
|
44
|
+
* still PostgreSQL-only, so this flag documents intent for a future adapter.
|
|
45
|
+
* - **Case-insensitive matching** uses `LOWER(col) LIKE LOWER(ref)` — note this
|
|
46
|
+
* can defeat indexes unless a functional/generated index exists.
|
|
47
|
+
* - **bignum:** mysql2 is configured `supportBigNumbers:true, bigNumberStrings:false`
|
|
48
|
+
* — the same safe-int policy Turbine uses for Postgres `int8` (number when it
|
|
49
|
+
* fits, decimal string otherwise). `DECIMAL` comes back as a string; `TINYINT(1)`
|
|
50
|
+
* binds booleans as 1/0. No global parser state is mutated.
|
|
51
|
+
* - **Version:** MySQL **8.0+** required (5.7 lacks `JSON_ARRAYAGG`); MariaDB is
|
|
52
|
+
* unsupported. The factory probes `SELECT VERSION()` and fails fast otherwise.
|
|
53
|
+
*
|
|
54
|
+
* ## Example
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { turbineMysql } from 'turbine-orm/mysql';
|
|
58
|
+
* import { SCHEMA } from './generated/turbine/metadata.js';
|
|
59
|
+
*
|
|
60
|
+
* const db = await turbineMysql('mysql://user:pass@localhost:3306/app', SCHEMA);
|
|
61
|
+
* const users = await db.users.findMany({ with: { posts: true }, limit: 10 });
|
|
62
|
+
* await db.disconnect();
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
import { type PgCompatPool, type PgCompatPoolClient, TurbineClient, type TurbineConfig } from './client.js';
|
|
66
|
+
import { type Dialect, type IntrospectOptions } from './dialect.js';
|
|
67
|
+
import { type SchemaMetadata } from './schema.js';
|
|
68
|
+
/** mysql2's `[result, fields]` tuple. `result` is rows (SELECT) or a header (write). */
|
|
69
|
+
type Mysql2Result = [unknown, unknown];
|
|
70
|
+
interface Mysql2Queryable {
|
|
71
|
+
query(sql: string, values?: unknown): Promise<Mysql2Result>;
|
|
72
|
+
execute(sql: string, values?: unknown): Promise<Mysql2Result>;
|
|
73
|
+
}
|
|
74
|
+
interface Mysql2Connection extends Mysql2Queryable {
|
|
75
|
+
release(): void;
|
|
76
|
+
}
|
|
77
|
+
interface Mysql2Pool extends Mysql2Queryable {
|
|
78
|
+
getConnection(): Promise<Mysql2Connection>;
|
|
79
|
+
end(): Promise<void>;
|
|
80
|
+
on?(event: string, listener: (...args: any[]) => void): unknown;
|
|
81
|
+
}
|
|
82
|
+
/** pg-style query argument: a SQL string or a `{ text, values }` config object. */
|
|
83
|
+
type QueryArg = string | {
|
|
84
|
+
name?: string;
|
|
85
|
+
text: string;
|
|
86
|
+
values?: unknown[];
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* A {@link PgCompatPool} backed by a `mysql2` pool. Non-transaction queries run
|
|
90
|
+
* on the pool directly (any connection); `connect()` checks out a dedicated
|
|
91
|
+
* connection so a transaction's `START TRANSACTION` / `COMMIT` / `ROLLBACK` /
|
|
92
|
+
* `SAVEPOINT` nesting all run on the same physical connection.
|
|
93
|
+
*/
|
|
94
|
+
export declare class MysqlPool implements PgCompatPool {
|
|
95
|
+
/** The underlying mysql2 pool — exposed as an escape hatch (seed / DDL / advanced ops). */
|
|
96
|
+
readonly pool: Mysql2Pool;
|
|
97
|
+
private closed;
|
|
98
|
+
constructor(pool: Mysql2Pool);
|
|
99
|
+
query(text: QueryArg, values?: unknown[]): Promise<any>;
|
|
100
|
+
connect(): Promise<PgCompatPoolClient>;
|
|
101
|
+
end(): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Map a MySQL column type to a TypeScript type. `dialectType` is the
|
|
105
|
+
* `information_schema.COLUMNS.DATA_TYPE` (e.g. `bigint`, `varchar`, `datetime`);
|
|
106
|
+
* `columnType` is the full `COLUMN_TYPE` (e.g. `tinyint(1)`, `enum('a','b')`)
|
|
107
|
+
* used to detect `TINYINT(1)` booleans.
|
|
108
|
+
*/
|
|
109
|
+
export declare function mysqlTypeToTs(dialectType: string, nullable: boolean, columnType?: string): string;
|
|
110
|
+
/**
|
|
111
|
+
* MySQL 8 implementation of the {@link Dialect} contract. Backtick identifier
|
|
112
|
+
* quoting, named `:pN` placeholders (NOT positional `?` — see the module
|
|
113
|
+
* docstring), `JSON_OBJECT` / `JSON_ARRAYAGG` for the single-query nested
|
|
114
|
+
* relation engine (`CAST(… AS JSON)`-wrapped nested subresults), no `RETURNING`
|
|
115
|
+
* (`resultStrategy = 'reselect'`), `INSERT … ON DUPLICATE KEY UPDATE` upserts,
|
|
116
|
+
* and the Postgres-only capabilities disabled (vector / LISTEN-NOTIFY / RLS).
|
|
117
|
+
*/
|
|
118
|
+
export declare const mysqlDialect: Dialect;
|
|
119
|
+
/** Async executor that returns plain row objects for a parameterized query. */
|
|
120
|
+
export type MysqlRowExecutor = (sql: string, params: unknown[]) => Promise<Record<string, unknown>[]>;
|
|
121
|
+
/**
|
|
122
|
+
* Introspect a MySQL database into the same {@link SchemaMetadata} shape the
|
|
123
|
+
* Postgres catalog introspector produces, using a caller-supplied query
|
|
124
|
+
* executor (so tests can dogfood an already-open mysql2 pool/connection).
|
|
125
|
+
*
|
|
126
|
+
* @param exec Runs a parameterized (`:p1`, `:p2`, …) query and returns rows.
|
|
127
|
+
* @param schema The MySQL database (schema) name to introspect.
|
|
128
|
+
* @param options Optional include / exclude table-name filters.
|
|
129
|
+
*/
|
|
130
|
+
export declare function introspectMysqlWith(exec: MysqlRowExecutor, schema: string, options?: {
|
|
131
|
+
include?: string[];
|
|
132
|
+
exclude?: string[];
|
|
133
|
+
}): Promise<SchemaMetadata>;
|
|
134
|
+
/**
|
|
135
|
+
* Open a short-lived mysql2 connection from `options.connectionString`,
|
|
136
|
+
* introspect the database (schema = `options.schema` or the connection's current
|
|
137
|
+
* database), and close it. Wraps {@link introspectMysqlWith} for the
|
|
138
|
+
* {@link DialectIntrospector} seam used by `introspect()` / `npx turbine generate`.
|
|
139
|
+
*/
|
|
140
|
+
export declare function introspectMysql(options: IntrospectOptions): Promise<SchemaMetadata>;
|
|
141
|
+
interface MysqlConnectionConfig {
|
|
142
|
+
host?: string;
|
|
143
|
+
port?: number;
|
|
144
|
+
user?: string;
|
|
145
|
+
password?: string;
|
|
146
|
+
database?: string;
|
|
147
|
+
}
|
|
148
|
+
/** Options for {@link turbineMysql}. Mirrors the relevant {@link TurbineConfig} fields. */
|
|
149
|
+
export interface TurbineMysqlOptions extends Pick<TurbineConfig, 'logging' | 'defaultLimit' | 'warnOnUnlimited'> {
|
|
150
|
+
/** Maximum number of pooled connections (when Turbine builds the pool). Default: 10. */
|
|
151
|
+
connectionLimit?: number;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Create a {@link TurbineClient} bound to MySQL 8 via `mysql2`.
|
|
155
|
+
*
|
|
156
|
+
* Pass one of:
|
|
157
|
+
* - a connection string (`'mysql://user:pass@host:3306/db'`),
|
|
158
|
+
* - a mysql2 connection config object (`{ host, user, password, database }`), or
|
|
159
|
+
* - an existing mysql2 pool / {@link MysqlPool} (injection — you own its lifecycle,
|
|
160
|
+
* `disconnect()` is a no-op, advanced config like SSL lives here).
|
|
161
|
+
*
|
|
162
|
+
* When Turbine builds the pool (string/config), it pins the correct mysql2 flags
|
|
163
|
+
* (named placeholders, bignum, UTC dates, JSON-as-string), probes `SELECT VERSION()`
|
|
164
|
+
* to reject MySQL < 8.0 / MariaDB, and `disconnect()` closes the pool it created.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* import { turbineMysql } from 'turbine-orm/mysql';
|
|
169
|
+
* const db = await turbineMysql('mysql://root:root@localhost:3306/app', SCHEMA);
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export declare function turbineMysql(target: string | MysqlConnectionConfig | Mysql2Pool | MysqlPool, schema: SchemaMetadata, options?: TurbineMysqlOptions): Promise<TurbineClient>;
|
|
173
|
+
export {};
|
package/dist/cjs/mysql.js
CHANGED
|
@@ -375,6 +375,10 @@ exports.mysqlDialect = {
|
|
|
375
375
|
// No RETURNING → run the write, then re-SELECT by PK/where (Phase-0 reselect).
|
|
376
376
|
resultStrategy: 'reselect',
|
|
377
377
|
supportsReturning: false,
|
|
378
|
+
// `ON DUPLICATE KEY UPDATE` has no predicate slot, so `buildUpsertStatement`
|
|
379
|
+
// below cannot emit `input.updateWhere`. Reporting false keeps the builder
|
|
380
|
+
// from compiling one (and from binding its now-orphaned parameters).
|
|
381
|
+
supportsUpsertUpdateWhere: false,
|
|
378
382
|
supportsILike: false,
|
|
379
383
|
supportsVector: false,
|
|
380
384
|
// MySQL full-text is `MATCH(col) AGAINST(...)` over a FULLTEXT index: a
|
|
@@ -414,6 +418,18 @@ exports.mysqlDialect = {
|
|
|
414
418
|
quoteIdentifier(name) {
|
|
415
419
|
return `\`${name.replace(/`/g, '``')}\``;
|
|
416
420
|
},
|
|
421
|
+
/**
|
|
422
|
+
* MySQL is NOT Postgres here: unless the server runs with
|
|
423
|
+
* `NO_BACKSLASH_ESCAPES`, `\` is an escape character inside a string literal,
|
|
424
|
+
* so doubling only `'` (the inherited Postgres rule) leaves a value ending in
|
|
425
|
+
* a backslash able to escape its own closing quote. Escape the backslash
|
|
426
|
+
* first, then the quote; every other byte is safe raw. The only caller is
|
|
427
|
+
* `buildJsonObject` (relation / column names from schema metadata), so this
|
|
428
|
+
* is defence in depth rather than a user-value path.
|
|
429
|
+
*/
|
|
430
|
+
escapeStringLiteral(value) {
|
|
431
|
+
return value.replace(/\\/g, '\\\\').replace(/'/g, "''");
|
|
432
|
+
},
|
|
417
433
|
buildJsonObject(pairs) {
|
|
418
434
|
const args = pairs.map(([key, expr]) => `'${this.escapeStringLiteral(key)}', ${expr}`);
|
|
419
435
|
return `JSON_OBJECT(${args.join(', ')})`;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm — Nested write engine
|
|
3
|
+
*
|
|
4
|
+
* Tree-walking create/update that resolves relation fields in `data` into
|
|
5
|
+
* batched SQL operations within a transaction. Supports create, connect,
|
|
6
|
+
* connectOrCreate, disconnect, set, delete, update, and upsert on related
|
|
7
|
+
* records at arbitrary depth (capped at 10).
|
|
8
|
+
*
|
|
9
|
+
* This module is imported by `query/builder.ts` when the `data` argument
|
|
10
|
+
* of `create()` or `update()` contains relation fields. It never imports
|
|
11
|
+
* `client.ts` directly — the transaction handle is passed in via
|
|
12
|
+
* `NestedWriteContext`.
|
|
13
|
+
*/
|
|
14
|
+
import type { RelationDef, SchemaMetadata, TableMetadata } from './schema.js';
|
|
15
|
+
export interface ExtractedFields {
|
|
16
|
+
scalars: Record<string, unknown>;
|
|
17
|
+
relations: Record<string, Record<string, unknown>>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Transaction context for nested write operations.
|
|
21
|
+
* Matches the subset of TransactionClient that we actually use.
|
|
22
|
+
*/
|
|
23
|
+
export interface NestedWriteContext {
|
|
24
|
+
schema: SchemaMetadata;
|
|
25
|
+
tx: {
|
|
26
|
+
table<T extends object>(name: string): {
|
|
27
|
+
create(args: {
|
|
28
|
+
data: Partial<T>;
|
|
29
|
+
}): Promise<T>;
|
|
30
|
+
createMany(args: {
|
|
31
|
+
data: Partial<T>[];
|
|
32
|
+
skipDuplicates?: boolean;
|
|
33
|
+
}): Promise<T[]>;
|
|
34
|
+
update(args: {
|
|
35
|
+
where: Record<string, unknown>;
|
|
36
|
+
data: Record<string, unknown>;
|
|
37
|
+
}): Promise<T>;
|
|
38
|
+
updateMany(args: {
|
|
39
|
+
where: Record<string, unknown>;
|
|
40
|
+
data: Record<string, unknown>;
|
|
41
|
+
allowFullTableScan?: boolean;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
count: number;
|
|
44
|
+
}>;
|
|
45
|
+
delete(args: {
|
|
46
|
+
where: Record<string, unknown>;
|
|
47
|
+
}): Promise<T>;
|
|
48
|
+
deleteMany(args: {
|
|
49
|
+
where: Record<string, unknown>;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
count: number;
|
|
52
|
+
}>;
|
|
53
|
+
findMany(args: {
|
|
54
|
+
where: Record<string, unknown>;
|
|
55
|
+
warnOnUnlimited?: boolean;
|
|
56
|
+
}): Promise<T[]>;
|
|
57
|
+
findUnique(args: {
|
|
58
|
+
where: Record<string, unknown>;
|
|
59
|
+
with?: Record<string, unknown>;
|
|
60
|
+
}): Promise<T | null>;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Separates scalar data fields from relation operation fields.
|
|
66
|
+
*
|
|
67
|
+
* A key is treated as a relation field only when:
|
|
68
|
+
* 1. It matches a relation name in `tableMeta.relations`
|
|
69
|
+
* 2. Its value is a non-null, non-array, non-Date plain object
|
|
70
|
+
*
|
|
71
|
+
* Everything else goes into `scalars`.
|
|
72
|
+
*/
|
|
73
|
+
export declare function extractRelationFields(data: Record<string, unknown>, tableMeta: TableMetadata): ExtractedFields;
|
|
74
|
+
/**
|
|
75
|
+
* Quick check: does `data` contain any relation fields that would trigger
|
|
76
|
+
* the nested write path? Used by QueryInterface to decide whether to
|
|
77
|
+
* delegate to the nested write engine or take the fast scalar-only path.
|
|
78
|
+
*/
|
|
79
|
+
export declare function hasRelationFields(data: Record<string, unknown>, tableMeta: TableMetadata): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Inject the parent row's PK value(s) as FK field(s) into child data.
|
|
82
|
+
* Handles composite keys. Returns a new object (does not mutate input).
|
|
83
|
+
*/
|
|
84
|
+
export declare function injectForeignKey(childData: Record<string, unknown>, relation: RelationDef, parentRow: Record<string, unknown>, schema: SchemaMetadata): Record<string, unknown>;
|
|
85
|
+
/**
|
|
86
|
+
* Tree-walking create: inserts the parent row, then processes each relation
|
|
87
|
+
* operation (create, connect, connectOrCreate), and finally reads back the
|
|
88
|
+
* full tree using `findUnique` with an auto-built `with` clause.
|
|
89
|
+
*/
|
|
90
|
+
export declare function executeNestedCreate(ctx: NestedWriteContext, tableName: string, data: Record<string, unknown>, depth?: number, path?: string[]): Promise<Record<string, unknown>>;
|
|
91
|
+
/**
|
|
92
|
+
* Tree-walking update: updates the parent row with scalar data, then
|
|
93
|
+
* processes each relation operation (create, connect, connectOrCreate,
|
|
94
|
+
* disconnect, set, delete), and reads back the full tree.
|
|
95
|
+
*/
|
|
96
|
+
export declare function executeNestedUpdate(ctx: NestedWriteContext, tableName: string, where: Record<string, unknown>, data: Record<string, unknown>, depth?: number, path?: string[]): Promise<Record<string, unknown>>;
|