turbine-orm 0.65.0 → 0.66.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 (142) hide show
  1. package/README.md +34 -32
  2. package/dist/adapters/cockroachdb.js +21 -3
  3. package/dist/adapters/index.d.ts +15 -0
  4. package/dist/adapters/yugabytedb.js +20 -3
  5. package/dist/cjs/adapters/cockroachdb.js +21 -3
  6. package/dist/cjs/adapters/index.d.ts +15 -0
  7. package/dist/cjs/adapters/yugabytedb.js +20 -3
  8. package/dist/cjs/cli/destructive.d.ts +18 -4
  9. package/dist/cjs/cli/destructive.js +230 -122
  10. package/dist/cjs/cli/index.d.ts +21 -4
  11. package/dist/cjs/cli/index.js +119 -22
  12. package/dist/cjs/cli/mcp.d.ts +28 -8
  13. package/dist/cjs/cli/mcp.js +170 -127
  14. package/dist/cjs/cli/migrate.d.ts +134 -13
  15. package/dist/cjs/cli/migrate.js +349 -241
  16. package/dist/cjs/cli/pii-predicate-guard.d.ts +112 -0
  17. package/dist/cjs/cli/pii-predicate-guard.js +390 -0
  18. package/dist/cjs/cli/prisma-resolve.js +75 -4
  19. package/dist/cjs/cli/prisma-schema.d.ts +17 -1
  20. package/dist/cjs/cli/prisma-schema.js +83 -17
  21. package/dist/cjs/cli/sql-statements.d.ts +125 -0
  22. package/dist/cjs/cli/sql-statements.js +378 -0
  23. package/dist/cjs/cli/studio.js +49 -118
  24. package/dist/cjs/cli/ui.d.ts +1 -1
  25. package/dist/cjs/client.d.ts +43 -0
  26. package/dist/cjs/client.js +125 -6
  27. package/dist/cjs/dialect.d.ts +123 -0
  28. package/dist/cjs/dialect.js +33 -0
  29. package/dist/cjs/errors.d.ts +74 -1
  30. package/dist/cjs/errors.js +239 -25
  31. package/dist/cjs/index-advisor.d.ts +33 -1
  32. package/dist/cjs/index-advisor.js +32 -1
  33. package/dist/cjs/introspect.d.ts +48 -0
  34. package/dist/cjs/introspect.js +222 -91
  35. package/dist/cjs/mssql.js +43 -1
  36. package/dist/cjs/mysql.d.ts +5 -2
  37. package/dist/cjs/mysql.js +202 -17
  38. package/dist/cjs/nested-write.js +6 -1
  39. package/dist/cjs/pipeline-submittable.js +17 -3
  40. package/dist/cjs/pipeline.js +75 -9
  41. package/dist/cjs/powdb.d.ts +23 -0
  42. package/dist/cjs/powdb.js +33 -1
  43. package/dist/cjs/powql.d.ts +61 -9
  44. package/dist/cjs/powql.js +186 -49
  45. package/dist/cjs/prisma-compat.js +160 -41
  46. package/dist/cjs/query/aggregates.d.ts +1 -1
  47. package/dist/cjs/query/aggregates.js +80 -18
  48. package/dist/cjs/query/batched-loader.d.ts +10 -0
  49. package/dist/cjs/query/batched-loader.js +268 -7
  50. package/dist/cjs/query/builder.d.ts +73 -0
  51. package/dist/cjs/query/builder.js +225 -28
  52. package/dist/cjs/query/filters.d.ts +162 -0
  53. package/dist/cjs/query/filters.js +250 -1
  54. package/dist/cjs/query/relations.d.ts +10 -10
  55. package/dist/cjs/query/relations.js +93 -12
  56. package/dist/cjs/query/types.d.ts +14 -1
  57. package/dist/cjs/query/utils.d.ts +146 -2
  58. package/dist/cjs/query/utils.js +210 -4
  59. package/dist/cjs/query/warn-registry.d.ts +10 -0
  60. package/dist/cjs/query/warn-registry.js +10 -0
  61. package/dist/cjs/query/where-compile.d.ts +30 -0
  62. package/dist/cjs/query/where-compile.js +41 -0
  63. package/dist/cjs/query/where.d.ts +128 -13
  64. package/dist/cjs/query/where.js +215 -77
  65. package/dist/cjs/query/writes.d.ts +1 -1
  66. package/dist/cjs/query/writes.js +39 -15
  67. package/dist/cjs/schema-builder.d.ts +2 -1
  68. package/dist/cjs/schema-sql.d.ts +94 -4
  69. package/dist/cjs/schema-sql.js +506 -30
  70. package/dist/cjs/schema.d.ts +3 -1
  71. package/dist/cjs/sqlite.d.ts +6 -0
  72. package/dist/cjs/sqlite.js +151 -10
  73. package/dist/cjs/typed-sql.d.ts +29 -1
  74. package/dist/cjs/typed-sql.js +30 -12
  75. package/dist/cli/destructive.d.ts +18 -4
  76. package/dist/cli/destructive.js +229 -121
  77. package/dist/cli/index.d.ts +21 -4
  78. package/dist/cli/index.js +120 -24
  79. package/dist/cli/mcp.d.ts +28 -8
  80. package/dist/cli/mcp.js +172 -129
  81. package/dist/cli/migrate.d.ts +134 -13
  82. package/dist/cli/migrate.js +347 -238
  83. package/dist/cli/pii-predicate-guard.d.ts +112 -0
  84. package/dist/cli/pii-predicate-guard.js +386 -0
  85. package/dist/cli/prisma-resolve.js +75 -4
  86. package/dist/cli/prisma-schema.d.ts +17 -1
  87. package/dist/cli/prisma-schema.js +83 -17
  88. package/dist/cli/sql-statements.d.ts +125 -0
  89. package/dist/cli/sql-statements.js +373 -0
  90. package/dist/cli/studio.js +49 -118
  91. package/dist/cli/ui.d.ts +1 -1
  92. package/dist/client.d.ts +43 -0
  93. package/dist/client.js +126 -7
  94. package/dist/dialect.d.ts +123 -0
  95. package/dist/dialect.js +33 -0
  96. package/dist/errors.d.ts +74 -1
  97. package/dist/errors.js +228 -19
  98. package/dist/index-advisor.d.ts +33 -1
  99. package/dist/index-advisor.js +31 -1
  100. package/dist/introspect.d.ts +48 -0
  101. package/dist/introspect.js +221 -91
  102. package/dist/mssql.js +44 -2
  103. package/dist/mysql.d.ts +5 -2
  104. package/dist/mysql.js +203 -18
  105. package/dist/nested-write.js +7 -2
  106. package/dist/pipeline-submittable.js +18 -4
  107. package/dist/pipeline.js +76 -10
  108. package/dist/powdb.d.ts +23 -0
  109. package/dist/powdb.js +33 -2
  110. package/dist/powql.d.ts +61 -9
  111. package/dist/powql.js +187 -50
  112. package/dist/prisma-compat.js +160 -41
  113. package/dist/query/aggregates.d.ts +1 -1
  114. package/dist/query/aggregates.js +82 -20
  115. package/dist/query/batched-loader.d.ts +10 -0
  116. package/dist/query/batched-loader.js +270 -9
  117. package/dist/query/builder.d.ts +73 -0
  118. package/dist/query/builder.js +226 -30
  119. package/dist/query/filters.d.ts +162 -0
  120. package/dist/query/filters.js +246 -1
  121. package/dist/query/relations.d.ts +10 -10
  122. package/dist/query/relations.js +94 -14
  123. package/dist/query/types.d.ts +14 -1
  124. package/dist/query/utils.d.ts +146 -2
  125. package/dist/query/utils.js +204 -3
  126. package/dist/query/warn-registry.d.ts +10 -0
  127. package/dist/query/warn-registry.js +10 -0
  128. package/dist/query/where-compile.d.ts +30 -0
  129. package/dist/query/where-compile.js +40 -1
  130. package/dist/query/where.d.ts +128 -13
  131. package/dist/query/where.js +216 -80
  132. package/dist/query/writes.d.ts +1 -1
  133. package/dist/query/writes.js +40 -16
  134. package/dist/schema-builder.d.ts +2 -1
  135. package/dist/schema-sql.d.ts +94 -4
  136. package/dist/schema-sql.js +505 -30
  137. package/dist/schema.d.ts +3 -1
  138. package/dist/sqlite.d.ts +6 -0
  139. package/dist/sqlite.js +151 -10
  140. package/dist/typed-sql.d.ts +29 -1
  141. package/dist/typed-sql.js +30 -12
  142. package/package.json +6 -4
@@ -188,7 +188,7 @@ export declare function assertBindableSetValue(qi: BuilderCtx, key: string, valu
188
188
  * Fingerprint SET clauses for update/updateMany.
189
189
  * Captures key names + operator types (set/increment/etc) but not values.
190
190
  */
191
- export declare function fingerprintSet(_qi: BuilderCtx, data: Record<string, unknown>): string;
191
+ export declare function fingerprintSet(qi: BuilderCtx, data: Record<string, unknown>): string;
192
192
  /**
193
193
  * Collect SET params for update/updateMany. Mirrors buildSetClause param order.
194
194
  */
@@ -15,7 +15,7 @@ import { camelToSnake, snakeToCamel } from '../schema.js';
15
15
  import { expandCompoundUniqueWhere } from './compound-unique.js';
16
16
  import { isUnmatchedPlainObject, UPDATE_OPERATOR_KEYS } from './filters.js';
17
17
  import { resolveSkipGlobalFilters, resolveUnsafeFlag } from './types.js';
18
- import { coerceTemporalValue, resolveColumnName } from './utils.js';
18
+ import { canonicalWriteEntries, coerceTemporalValue, resolveColumnName } from './utils.js';
19
19
  import * as whereMod from './where.js';
20
20
  /**
21
21
  * Normalize one `data` value before it is bound as a write param.
@@ -115,7 +115,7 @@ function buildDefaultValuesInsert(qi, rowCount, skipDuplicates) {
115
115
  export function buildCreate(qi, args) {
116
116
  assertWritable(qi, 'create');
117
117
  assertNoGeneratedColumns(qi, args.data, 'create');
118
- const entries = Object.entries(args.data).filter(([, v]) => v !== undefined);
118
+ const entries = writeEntries(qi, args.data);
119
119
  const columns = entries.map(([k]) => qi.toSqlColumn(k));
120
120
  const params = entries.map(([k, v]) => coerceWriteValue(qi, k, v));
121
121
  // Enum columns get an explicit `::"EnumName"` cast (see enumTypeForColumn).
@@ -176,15 +176,39 @@ export function makeCreateReselect(qi, insertSql, insertParams, data) {
176
176
  };
177
177
  }
178
178
  /**
179
- * The fields a write's `data` object actually names.
179
+ * The `[key, value]` pairs a write's `data` object actually names, in the
180
+ * table's own column order.
180
181
  *
181
182
  * A key whose value is `undefined` is NOT named: single-row {@link buildCreate}
182
183
  * filters those out of its column list, so the column takes its declared
183
- * default. `createMany` reads its rows through this same helper, so
184
- * `{ n: undefined }` and `{}` mean the identical thing on both paths.
184
+ * default. `createMany` reads its rows through {@link definedKeys}, which is
185
+ * this function's key half, so `{ n: undefined }` and `{}` mean the identical
186
+ * thing on both paths.
187
+ *
188
+ * THE ORDERING IS A SECURITY BOUND, not tidiness, and it is the whole reason
189
+ * this is one function rather than an `Object.entries` at each site. A write's
190
+ * column list is SQL TEXT: `SET "a" = $1, "b" = $2` and `SET "b" = $1, "a" = $2`
191
+ * are the same write and two different permanently-cached server-side prepared
192
+ * statements. `JSON.parse` preserves insertion order, so
193
+ * `update({ where, data: JSON.parse(reqBody) })` (an ordinary REST handler)
194
+ * lets the request body pick that order, with no array, no arity, and nothing
195
+ * the caller needs to know. Measured on PostgreSQL 16: 720 PATCH bodies
196
+ * carrying the SAME six keys in different orders left 720 prepared statements
197
+ * and 2.8 MB of CachedPlanSource on one connection. See
198
+ * {@link canonicalWriteEntries} for the ordering rule and why duplicates are
199
+ * deliberately preserved.
200
+ *
201
+ * Every consumer of this list must use THIS function: the SET-clause build, the
202
+ * cache fingerprint ({@link fingerprintSet}) and the param collector
203
+ * ({@link collectSetParams}) must enumerate one identical order or the cached
204
+ * statement and its params describe different writes.
185
205
  */
186
- function definedKeys(row) {
187
- return Object.keys(row).filter((k) => row[k] !== undefined);
206
+ function writeEntries(qi, data) {
207
+ return canonicalWriteEntries(qi.tableMeta, Object.entries(data).filter(([, v]) => v !== undefined));
208
+ }
209
+ /** The key half of {@link writeEntries}, for the paths that need names only. */
210
+ function definedKeys(qi, row) {
211
+ return writeEntries(qi, row).map(([k]) => k);
188
212
  }
189
213
  /**
190
214
  * Refuse a `createMany` whose rows do not all name the SAME fields.
@@ -214,7 +238,7 @@ function definedKeys(row) {
214
238
  function assertUniformCreateManyRows(qi, rows, firstKeys) {
215
239
  const expected = new Set(firstKeys);
216
240
  for (let i = 1; i < rows.length; i++) {
217
- const rowKeys = definedKeys(rows[i]);
241
+ const rowKeys = definedKeys(qi, rows[i]);
218
242
  const unexpected = rowKeys.filter((k) => !expected.has(k));
219
243
  // No stranger and the same count means the same set (object keys are unique).
220
244
  if (unexpected.length === 0 && rowKeys.length === expected.size)
@@ -252,7 +276,7 @@ export function buildCreateMany(qi, args) {
252
276
  for (const row of args.data) {
253
277
  assertNoGeneratedColumns(qi, row, 'createMany');
254
278
  }
255
- const keys = definedKeys(args.data[0]);
279
+ const keys = definedKeys(qi, args.data[0]);
256
280
  assertUniformCreateManyRows(qi, args.data, keys);
257
281
  // No column named by the first row: every row is pure defaults (the bulk
258
282
  // counterpart of `create({ data: {} })`, see buildDefaultValuesInsert). The
@@ -360,7 +384,7 @@ export function buildUpdate(qi, args) {
360
384
  const ck = lock ? null : `u:${setFp}|${whereFp}${whereMod.globalFilterCacheSegment(qi)}`;
361
385
  const params = [];
362
386
  const buildSql = (freshParams) => {
363
- const setEntries = Object.entries(dataObj).filter(([, v]) => v !== undefined);
387
+ const setEntries = writeEntries(qi, dataObj);
364
388
  const setClauses = setEntries.map(([k, v]) => buildSetClause(qi, k, v, freshParams));
365
389
  if (lock) {
366
390
  const versionCol = qi.toSqlColumn(lock.field);
@@ -510,7 +534,7 @@ export function buildUpsert(qi, args) {
510
534
  // Prisma compound-unique selector on the conflict target → its member columns.
511
535
  const upsertWhere = expandCompoundUniqueWhere(qi.tableMeta, args.where);
512
536
  // Build the INSERT part from create data
513
- const createEntries = Object.entries(args.create).filter(([, v]) => v !== undefined);
537
+ const createEntries = writeEntries(qi, args.create);
514
538
  const columns = createEntries.map(([k]) => qi.toSqlColumn(k));
515
539
  const createParams = createEntries.map(([k, v]) => coerceWriteValue(qi, k, v));
516
540
  // Enum columns get an explicit `::"EnumName"` cast (see enumTypeForColumn).
@@ -519,7 +543,7 @@ export function buildUpsert(qi, args) {
519
543
  const conflictKeys = Object.keys(upsertWhere).filter((k) => upsertWhere[k] !== undefined);
520
544
  const conflictColumns = conflictKeys.map((k) => qi.toSqlColumn(k));
521
545
  // Build the UPDATE SET part
522
- const updateEntries = Object.entries(args.update).filter(([, v]) => v !== undefined);
546
+ const updateEntries = writeEntries(qi, args.update);
523
547
  let paramIdx = createParams.length + 1;
524
548
  const setClauses = updateEntries.map(([k]) => {
525
549
  const clause = `${qi.toSqlColumn(k)} = ${qi.p(paramIdx)}${whereMod.enumCastSuffix(qi, qi.toColumn(k))}`;
@@ -597,7 +621,7 @@ export function buildUpdateMany(qi, args) {
597
621
  const ck = `um:${setFp}|${whereFp}${whereMod.globalFilterCacheSegment(qi)}`;
598
622
  const params = [];
599
623
  const buildSql = (freshParams) => {
600
- const setEntries = Object.entries(dataObj).filter(([, v]) => v !== undefined);
624
+ const setEntries = writeEntries(qi, dataObj);
601
625
  const setClauses = setEntries.map(([k, v]) => buildSetClause(qi, k, v, freshParams));
602
626
  const whereClause = whereMod.buildWhereClause(qi, whereObj, freshParams);
603
627
  const whereSql = whereClause ? ` WHERE ${whereClause}` : '';
@@ -922,8 +946,8 @@ export function assertBindableSetValue(qi, key, value) {
922
946
  * Fingerprint SET clauses for update/updateMany.
923
947
  * Captures key names + operator types (set/increment/etc) but not values.
924
948
  */
925
- export function fingerprintSet(_qi, data) {
926
- const entries = Object.entries(data).filter(([, v]) => v !== undefined);
949
+ export function fingerprintSet(qi, data) {
950
+ const entries = writeEntries(qi, data);
927
951
  const parts = [];
928
952
  for (const [k, v] of entries) {
929
953
  if (v !== null &&
@@ -945,7 +969,7 @@ export function fingerprintSet(_qi, data) {
945
969
  * Collect SET params for update/updateMany. Mirrors buildSetClause param order.
946
970
  */
947
971
  export function collectSetParams(qi, data, params) {
948
- const entries = Object.entries(data).filter(([, v]) => v !== undefined);
972
+ const entries = writeEntries(qi, data);
949
973
  for (const [k, v] of entries) {
950
974
  if (v !== null &&
951
975
  typeof v === 'object' &&
@@ -70,7 +70,8 @@ export interface ColumnDef {
70
70
  * `schemaDefToMetadata` / codegen, onto
71
71
  * {@link import('./schema.js').ColumnMetadata.pii}. A PII column is excluded
72
72
  * from default projections (read back only via an explicit `select` or
73
- * `includePii: true`) and redacted by Studio. Introspection never auto-tags PII.
73
+ * `includePii: UNSAFE`, the imported sentinel symbol) and redacted by Studio.
74
+ * Introspection never auto-tags PII.
74
75
  */
75
76
  pii?: boolean;
76
77
  /**
@@ -8,7 +8,7 @@ import { type DestructiveStatement } from './cli/destructive.js';
8
8
  import { type Dialect } from './dialect.js';
9
9
  import { ValidationError } from './errors.js';
10
10
  import { type ReferentialAction } from './schema.js';
11
- import { type ColumnIndexDef, type SchemaDef, type TableDef } from './schema-builder.js';
11
+ import { type ColumnConfig, type ColumnIndexDef, type SchemaDef, type TableDef } from './schema-builder.js';
12
12
  export interface SchemaSqlOptions {
13
13
  /** SQL dialect used for DDL generation. Defaults to PostgreSQL. */
14
14
  dialect?: Dialect;
@@ -154,13 +154,92 @@ export declare function diffCheckConstraints(table: string, schemaChecks: readon
154
154
  statements: string[];
155
155
  reverseStatements: string[];
156
156
  };
157
+ /** Options for {@link schemaDiff} and {@link schemaPush}. */
158
+ export interface SchemaDiffOptions {
159
+ /**
160
+ * Postgres NAMESPACE the diff reads (default `public`).
161
+ *
162
+ * Every catalog read here used to hardcode `'public'` while `generate`,
163
+ * `pull`, `doctor`, and `studio` all honored the configured schema. Against a
164
+ * table in a non-public schema the diff therefore saw nothing and emitted
165
+ * `CREATE TABLE "users"` (a duplicate in public); worse, when a legacy copy of
166
+ * the table still sat in `public` (the usual state after moving to a dedicated
167
+ * schema) it read THAT one and emitted ALTER / DROP COLUMN against the wrong
168
+ * table. Defaults to `public`, so a project with no schema configured emits
169
+ * byte-identical SQL.
170
+ */
171
+ schema?: string;
172
+ }
157
173
  /**
158
174
  * Compare a SchemaDef against a live Postgres database and return the diff.
159
175
  *
160
- * Connects to the database, inspects the public schema, and computes what
161
- * DDL is needed to make the database match the schema definition.
176
+ * Connects to the database, inspects `options.schema` (default `public`), and
177
+ * computes what DDL is needed to make the database match the schema definition.
162
178
  */
163
- export declare function schemaDiff(schema: SchemaDef, connectionString: string): Promise<DiffResult>;
179
+ export declare function schemaDiff(schema: SchemaDef, connectionString: string, options?: SchemaDiffOptions): Promise<DiffResult>;
180
+ /** The type-relevant subset of {@link DbColumn}, so {@link planTypeChange} stays testable. */
181
+ export interface DbColumnType {
182
+ udtName: string;
183
+ maxLength: number | null;
184
+ numericPrecision: number | null;
185
+ numericScale: number | null;
186
+ /**
187
+ * `format_type(atttypid, atttypmod)` from pg_catalog: the type exactly as
188
+ * Postgres would write it, e.g. `character varying(255)[]`, `vector(3)`,
189
+ * `numeric(10,2)`, `app."Probe"`. Read alongside information_schema because
190
+ * information_schema cannot express an array element's length modifier or a
191
+ * pgvector dimension count, and because it is the only spelling of an
192
+ * unmapped type that is guaranteed to be valid, correctly quoted and
193
+ * correctly schema-qualified DDL. Null only when a caller builds the value by
194
+ * hand (the live diff always populates it).
195
+ */
196
+ formattedType: string | null;
197
+ }
198
+ /**
199
+ * What the diff should do about one column's type.
200
+ *
201
+ * `alter` carries `needsUsing` (see {@link planTypeChange}) and, when the
202
+ * conversion can lose or reject data, a `loss` sentence naming the SPECIFIC
203
+ * loss. `warn` is for a difference the code-first schema cannot express, where
204
+ * emitting DDL would destroy an intentional database-side constraint.
205
+ */
206
+ export type TypeChangePlan = {
207
+ kind: 'none';
208
+ } | {
209
+ kind: 'alter';
210
+ needsUsing: boolean;
211
+ loss?: string;
212
+ } | {
213
+ kind: 'warn';
214
+ reason: string;
215
+ };
216
+ /**
217
+ * Decide what the diff should emit for one column's type.
218
+ *
219
+ * Two things this deliberately does that the previous `udtName !== expectedUdt`
220
+ * check did not:
221
+ *
222
+ * 1. It compares LENGTH and NUMERIC PRECISION, not just the UDT name. A
223
+ * declared `varchar(10)` against a database `VARCHAR(255)` produced no
224
+ * statement and no warning, so `push` printed "Database is already in
225
+ * sync" for a schema that genuinely differed. The widening direction is
226
+ * the operationally painful one: the schema says 255, the column is 10,
227
+ * push says in sync, and writes fail at runtime with "value too long".
228
+ * 2. It reports `needsUsing` FALSE for a same-family conversion. The old
229
+ * statement always appended `USING col::type`, and an EXPLICIT cast to
230
+ * `varchar(n)` TRUNCATES where the plain assignment cast raises "value too
231
+ * long". Postgres refuses that migration on its own; the generated `USING`
232
+ * converted the refusal into silent data amputation. Same shape for
233
+ * `numeric -> integer` and `timestamptz -> date`. `USING` is emitted only
234
+ * where the conversion genuinely needs it (text to uuid, text to an enum,
235
+ * anything crossing a type family), where no assignment cast exists.
236
+ *
237
+ * Numeric PRECISION drift gets a warning rather than a statement: `defineSchema`
238
+ * has no way to declare `numeric(10, 2)`, so every such column would otherwise
239
+ * get a table-rewriting `ALTER ... TYPE NUMERIC` on every push, discarding a
240
+ * constraint the schema never had the vocabulary to ask for.
241
+ */
242
+ export declare function planTypeChange(config: ColumnConfig, dbCol: DbColumnType, column: string): TypeChangePlan;
164
243
  /**
165
244
  * Scan a set of diff statements for data-destroying operations, using the same
166
245
  * conservative scanner (`scanDestructiveSql`) that gates `migrate up`/`down`.
@@ -204,11 +283,22 @@ export declare class DestructivePushRefusal extends ValidationError {
204
283
  * `allowDestructive: true` is passed. The CLI (`turbine push`) catches this and
205
284
  * prompts for the same typed confirmation as `migrate up`; programmatic callers
206
285
  * must opt in explicitly.
286
+ *
287
+ * `options.schema` (default `public`) scopes BOTH halves: the diff reads that
288
+ * namespace, and the generated DDL (which names tables unqualified) is executed
289
+ * with a transaction-local `search_path` pinned so the target schema resolves
290
+ * FIRST. Without the second half a diff that correctly found nothing in `app`
291
+ * would still emit `CREATE TABLE "users"` into whatever the connection's
292
+ * search_path happens to resolve to. The pin is unconditional (`public` is a
293
+ * target like any other, since a role's own search_path may not lead there),
294
+ * refuses a schema that does not exist, and APPENDS the connection's existing
295
+ * path so types living elsewhere still resolve. See {@link pinSearchPath}.
207
296
  */
208
297
  export declare function schemaPush(schema: SchemaDef, connectionString: string, options?: {
209
298
  dryRun?: boolean;
210
299
  allowDestructive?: boolean;
211
300
  precomputedDiff?: DiffResult;
301
+ schema?: string;
212
302
  }): Promise<PushResult>;
213
303
  /**
214
304
  * Generate the full DDL as a single formatted string.