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.
Files changed (157) hide show
  1. package/README.md +122 -39
  2. package/dist/cjs/adapters/cockroachdb.d.ts +39 -0
  3. package/dist/cjs/adapters/index.d.ts +110 -0
  4. package/dist/cjs/adapters/yugabytedb.d.ts +51 -0
  5. package/dist/cjs/cli/config.d.ts +181 -0
  6. package/dist/cjs/cli/config.js +32 -6
  7. package/dist/cjs/cli/destructive.d.ts +38 -0
  8. package/dist/cjs/cli/index.d.ts +359 -0
  9. package/dist/cjs/cli/index.js +228 -56
  10. package/dist/cjs/cli/loader.d.ts +61 -0
  11. package/dist/cjs/cli/mcp.d.ts +42 -0
  12. package/dist/cjs/cli/migrate.d.ts +356 -0
  13. package/dist/cjs/cli/migrate.js +131 -40
  14. package/dist/cjs/cli/observe-ui.d.ts +1 -0
  15. package/dist/cjs/cli/observe-ui.js +14 -5
  16. package/dist/cjs/cli/observe.d.ts +25 -0
  17. package/dist/cjs/cli/observe.js +49 -12
  18. package/dist/cjs/cli/pii-tags.d.ts +53 -0
  19. package/dist/cjs/cli/prisma-report.d.ts +33 -0
  20. package/dist/cjs/cli/prisma-report.js +73 -0
  21. package/dist/cjs/cli/prisma-resolve.d.ts +106 -0
  22. package/dist/cjs/cli/prisma-resolve.js +1 -0
  23. package/dist/cjs/cli/prisma-schema.d.ts +176 -0
  24. package/dist/cjs/cli/prisma-schema.js +82 -4
  25. package/dist/cjs/cli/rate-limit.d.ts +32 -0
  26. package/dist/cjs/cli/rate-limit.js +45 -0
  27. package/dist/cjs/cli/studio-demo.d.ts +43 -0
  28. package/dist/cjs/cli/studio-ui.generated.d.ts +1 -0
  29. package/dist/cjs/cli/studio.d.ts +207 -0
  30. package/dist/cjs/cli/studio.js +136 -71
  31. package/dist/cjs/cli/ui.d.ts +73 -0
  32. package/dist/cjs/cli/ui.js +51 -9
  33. package/dist/cjs/client.d.ts +837 -0
  34. package/dist/cjs/client.js +3 -0
  35. package/dist/cjs/dialect.d.ts +516 -0
  36. package/dist/cjs/dialect.js +37 -12
  37. package/dist/cjs/errors.d.ts +370 -0
  38. package/dist/cjs/generate.d.ts +137 -0
  39. package/dist/cjs/generate.js +39 -6
  40. package/dist/cjs/index-advisor.d.ts +153 -0
  41. package/dist/cjs/index-stats.d.ts +384 -0
  42. package/dist/cjs/index.d.ts +55 -0
  43. package/dist/cjs/index.js +7 -2
  44. package/dist/cjs/introspect.d.ts +269 -0
  45. package/dist/cjs/mssql.d.ts +232 -0
  46. package/dist/cjs/mssql.js +6 -0
  47. package/dist/cjs/mysql.d.ts +173 -0
  48. package/dist/cjs/mysql.js +16 -0
  49. package/dist/cjs/nested-write.d.ts +96 -0
  50. package/dist/cjs/nested-write.js +414 -24
  51. package/dist/cjs/observe.d.ts +115 -0
  52. package/dist/cjs/optional-peer-import.d.cts +72 -0
  53. package/dist/cjs/pipeline-submittable.d.ts +93 -0
  54. package/dist/cjs/pipeline.d.ts +71 -0
  55. package/dist/cjs/powdb-introspect.d.ts +84 -0
  56. package/dist/cjs/powdb.d.ts +931 -0
  57. package/dist/cjs/powdb.js +106 -21
  58. package/dist/cjs/powql.d.ts +592 -0
  59. package/dist/cjs/powql.js +42 -6
  60. package/dist/cjs/prisma-compat.d.ts +283 -0
  61. package/dist/cjs/prisma-compat.js +167 -9
  62. package/dist/cjs/query/aggregates.d.ts +92 -0
  63. package/dist/cjs/query/aggregates.js +7 -3
  64. package/dist/cjs/query/batched-loader.d.ts +193 -0
  65. package/dist/cjs/query/builder.d.ts +849 -0
  66. package/dist/cjs/query/builder.js +571 -65
  67. package/dist/cjs/query/compound-unique.d.ts +51 -0
  68. package/dist/cjs/query/deferred.d.ts +223 -0
  69. package/dist/cjs/query/filters.d.ts +201 -0
  70. package/dist/cjs/query/index.d.ts +14 -0
  71. package/dist/cjs/query/index.js +6 -1
  72. package/dist/cjs/query/relations.d.ts +609 -0
  73. package/dist/cjs/query/relations.js +693 -46
  74. package/dist/cjs/query/types.d.ts +1300 -0
  75. package/dist/cjs/query/utils.d.ts +209 -0
  76. package/dist/cjs/query/utils.js +208 -1
  77. package/dist/cjs/query/warn-registry.d.ts +68 -0
  78. package/dist/cjs/query/warn-registry.js +9 -0
  79. package/dist/cjs/query/where-compile.d.ts +139 -0
  80. package/dist/cjs/query/where.d.ts +548 -0
  81. package/dist/cjs/query/where.js +58 -22
  82. package/dist/cjs/query/writes.d.ts +172 -0
  83. package/dist/cjs/query/writes.js +105 -12
  84. package/dist/cjs/realtime.d.ts +70 -0
  85. package/dist/cjs/schema-builder.d.ts +354 -0
  86. package/dist/cjs/schema-metadata.d.ts +83 -0
  87. package/dist/cjs/schema-sql.d.ts +217 -0
  88. package/dist/cjs/schema-sql.js +23 -5
  89. package/dist/cjs/schema.d.ts +356 -0
  90. package/dist/cjs/schema.js +125 -0
  91. package/dist/cjs/seed.d.ts +15 -0
  92. package/dist/cjs/serverless.d.ts +142 -0
  93. package/dist/cjs/sqlite.d.ts +143 -0
  94. package/dist/cjs/sqlite.js +4 -0
  95. package/dist/cjs/typed-sql.d.ts +102 -0
  96. package/dist/cli/config.d.ts +18 -4
  97. package/dist/cli/config.js +31 -6
  98. package/dist/cli/index.d.ts +123 -0
  99. package/dist/cli/index.js +223 -58
  100. package/dist/cli/migrate.d.ts +59 -10
  101. package/dist/cli/migrate.js +128 -41
  102. package/dist/cli/observe-ui.d.ts +1 -1
  103. package/dist/cli/observe-ui.js +14 -5
  104. package/dist/cli/observe.d.ts +7 -1
  105. package/dist/cli/observe.js +48 -12
  106. package/dist/cli/prisma-report.d.ts +14 -0
  107. package/dist/cli/prisma-report.js +72 -0
  108. package/dist/cli/prisma-resolve.d.ts +6 -0
  109. package/dist/cli/prisma-resolve.js +1 -0
  110. package/dist/cli/prisma-schema.d.ts +62 -2
  111. package/dist/cli/prisma-schema.js +81 -4
  112. package/dist/cli/rate-limit.d.ts +32 -0
  113. package/dist/cli/rate-limit.js +40 -0
  114. package/dist/cli/studio.d.ts +5 -5
  115. package/dist/cli/studio.js +135 -70
  116. package/dist/cli/ui.d.ts +1 -1
  117. package/dist/cli/ui.js +51 -9
  118. package/dist/client.d.ts +40 -0
  119. package/dist/client.js +3 -0
  120. package/dist/dialect.d.ts +17 -1
  121. package/dist/dialect.js +37 -12
  122. package/dist/generate.js +40 -7
  123. package/dist/index.d.ts +1 -1
  124. package/dist/index.js +1 -1
  125. package/dist/mssql.js +6 -0
  126. package/dist/mysql.js +16 -0
  127. package/dist/nested-write.d.ts +2 -0
  128. package/dist/nested-write.js +415 -25
  129. package/dist/powdb.d.ts +4 -2
  130. package/dist/powdb.js +106 -21
  131. package/dist/powql.d.ts +5 -0
  132. package/dist/powql.js +42 -6
  133. package/dist/prisma-compat.d.ts +2 -0
  134. package/dist/prisma-compat.js +166 -8
  135. package/dist/query/aggregates.js +7 -3
  136. package/dist/query/builder.d.ts +292 -21
  137. package/dist/query/builder.js +570 -64
  138. package/dist/query/deferred.d.ts +39 -0
  139. package/dist/query/index.d.ts +1 -1
  140. package/dist/query/index.js +1 -1
  141. package/dist/query/relations.d.ts +173 -5
  142. package/dist/query/relations.js +688 -47
  143. package/dist/query/types.d.ts +123 -39
  144. package/dist/query/utils.d.ts +116 -0
  145. package/dist/query/utils.js +198 -0
  146. package/dist/query/warn-registry.d.ts +9 -0
  147. package/dist/query/warn-registry.js +9 -0
  148. package/dist/query/where.d.ts +38 -1
  149. package/dist/query/where.js +58 -23
  150. package/dist/query/writes.d.ts +42 -1
  151. package/dist/query/writes.js +104 -13
  152. package/dist/schema-sql.d.ts +14 -0
  153. package/dist/schema-sql.js +23 -5
  154. package/dist/schema.d.ts +38 -0
  155. package/dist/schema.js +123 -0
  156. package/dist/sqlite.js +4 -0
  157. 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>>;