@vibeorm/sql 4.3.0 → 5.0.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/dist/index.js CHANGED
@@ -317,6 +317,7 @@ var mysqlDecimalCodec = {
317
317
  };
318
318
  var ZONE_LESS_DATETIME = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?$/;
319
319
  var PG_ZONED_DATETIME = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}(?::\d{2})?)(\.\d{1,9})?([+-]\d{2})(?::?(\d{2}))?$/;
320
+ var EXTENDED_DATETIME = /^(\d{4,})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?)?(?:([+-])(\d{2})(?::?(\d{2}))?(?::?(\d{2}))?)?( BC)?$/;
320
321
  function parseDateTimeText(params) {
321
322
  const trimmed = params.text.trim();
322
323
  const date = parseDateTimeInstant({ trimmed });
@@ -341,11 +342,34 @@ function parseDateTimeInstant(params) {
341
342
  if (!Number.isNaN(iso.getTime()))
342
343
  return iso;
343
344
  }
345
+ const extended = parseExtendedDateTimeText({ text: trimmed });
346
+ if (extended !== undefined)
347
+ return extended;
344
348
  const parsed = new Date(trimmed);
345
349
  return Number.isNaN(parsed.getTime()) ? undefined : parsed;
346
350
  }
351
+ function parseExtendedDateTimeText(params) {
352
+ const match = EXTENDED_DATETIME.exec(params.text.trim());
353
+ if (match === null)
354
+ return;
355
+ const [, yearText, month, day, hours, minutes, seconds, fraction, sign, offsetHours, offsetMinutes, offsetSeconds, era] = match;
356
+ if (yearText.length < 5 && era === undefined)
357
+ return;
358
+ const year = era === undefined ? Number(yearText) : 1 - Number(yearText);
359
+ const date = new Date(0);
360
+ date.setUTCFullYear(year, Number(month) - 1, Number(day));
361
+ date.setUTCHours(Number(hours ?? 0), Number(minutes ?? 0), Number(seconds ?? 0), Number((fraction ?? "").padEnd(3, "0").slice(0, 3)));
362
+ if (sign !== undefined) {
363
+ const offset = (Number(offsetHours) * 3600 + Number(offsetMinutes ?? 0) * 60 + Number(offsetSeconds ?? 0)) * 1000;
364
+ date.setTime(date.getTime() - (sign === "-" ? -offset : offset));
365
+ }
366
+ return Number.isNaN(date.getTime()) ? undefined : date;
367
+ }
368
+ function decodedDateTimeRefusal() {
369
+ return new VibeError({ code: "VIBE_DATA_INVALID", message: "DateTime requires a finite timestamp; use an explicit extended timestamp decoder for infinity" });
370
+ }
347
371
  function invalidDecodedDateTime() {
348
- throw new VibeError({ code: "VIBE_DATA_INVALID", message: "DateTime requires a finite timestamp; use an explicit extended timestamp decoder for infinity" });
372
+ throw decodedDateTimeRefusal();
349
373
  }
350
374
  var dateNativeCodec = {
351
375
  encode: (value) => {
@@ -2330,6 +2354,8 @@ var sqliteDialect = {
2330
2354
  keyListStrategy: "values",
2331
2355
  keysetSeekStrategy: "rowValue",
2332
2356
  keyPageStrategy: "inLimit",
2357
+ lateralJson: null,
2358
+ relationStrategyDefault: "query",
2333
2359
  relationFilterStrategy: "inSelect",
2334
2360
  deferredJoinPage: null,
2335
2361
  nativeNullsOrder: "low",
@@ -2842,6 +2868,10 @@ function isDbNowMarker(value) {
2842
2868
  return candidate.__dbNow === true && typeof candidate.offsetSeconds === "number" && Number.isFinite(candidate.offsetSeconds);
2843
2869
  }
2844
2870
  var SQL_DEFAULT_CELL = Object.freeze({ __sqlDefault: true });
2871
+ var SQL_KEEP_CELL = Object.freeze({ __sqlKeep: true });
2872
+ function isSqlKeepCell(value) {
2873
+ return value === SQL_KEEP_CELL;
2874
+ }
2845
2875
  function isSqlDefaultCell(value) {
2846
2876
  return value === SQL_DEFAULT_CELL;
2847
2877
  }
@@ -2979,6 +3009,8 @@ var postgresDialect = {
2979
3009
  keyListStrategy: "unnest",
2980
3010
  keysetSeekStrategy: "rowValue",
2981
3011
  keyPageStrategy: "lateral",
3012
+ lateralJson: { rowArray: "json_build_array", arrayAgg: "json_agg", emptyArray: "'[]'::json", order: "inAggregate", timeOfDayAsText: false, requiresUtcDateTimeWire: false },
3013
+ relationStrategyDefault: "join",
2982
3014
  relationFilterStrategy: "exists",
2983
3015
  deferredJoinPage: { minSkip: 1000, requiresCoveringIndex: true },
2984
3016
  nativeNullsOrder: "high",
@@ -3064,6 +3096,8 @@ var mysqlDialect = {
3064
3096
  keyListStrategy: "rowValue",
3065
3097
  keysetSeekStrategy: "or",
3066
3098
  keyPageStrategy: "window",
3099
+ lateralJson: { rowArray: "JSON_ARRAY", arrayAgg: "JSON_ARRAYAGG", emptyArray: "JSON_ARRAY()", order: "positionSlot", timeOfDayAsText: true, requiresUtcDateTimeWire: true },
3100
+ relationStrategyDefault: "join",
3067
3101
  relationFilterStrategy: "exists",
3068
3102
  deferredJoinPage: { minSkip: 1000, requiresCoveringIndex: false },
3069
3103
  nativeNullsOrder: "low",
@@ -3077,7 +3111,7 @@ var mysqlDialect = {
3077
3111
  duplicatesInOneStatement: "lastWriteWins"
3078
3112
  },
3079
3113
  excludedRowRef: { form: "rowAlias", alias: "new" },
3080
- doNothingForm: "insertIgnore",
3114
+ doNothingForm: "duplicateKeyKeep",
3081
3115
  insensitiveLike: "lower",
3082
3116
  strictMatchStrategy: "binary",
3083
3117
  greatestForm: "wrapped-frame",
@@ -3752,11 +3786,14 @@ function renderRlsPolicy(params) {
3752
3786
  }
3753
3787
  function renderRlsContext(params) {
3754
3788
  requireRls(params);
3755
- if (validateRlsContextIR({ context: params.context }).length !== 0 || Object.keys(params.context).length === 0 || typeof params.values !== "object" || params.values === null || Array.isArray(params.values)) {
3789
+ const extra = params.role !== undefined || params.readOnly === true || params.backend === true;
3790
+ if (validateRlsContextIR({ context: params.context }).length !== 0 || Object.keys(params.context).length === 0 && !extra || typeof params.values !== "object" || params.values === null || Array.isArray(params.values)) {
3756
3791
  throw new RlsContextError({ reason: "invalid" });
3757
3792
  }
3758
3793
  const collector = new ParamCollector(params.dialect);
3759
3794
  const parts = [];
3795
+ if (params.role !== undefined)
3796
+ parts.push(`set_config('role', ${collector.add(runtimeRoleOf({ role: params.role }))}, true)`);
3760
3797
  for (const [key, slot] of Object.entries(params.context)) {
3761
3798
  if (!Object.hasOwn(params.values, key))
3762
3799
  throw new RlsContextError({ reason: "missing", key });
@@ -3770,15 +3807,24 @@ function renderRlsContext(params) {
3770
3807
  if (typeof key !== "string" || !Object.hasOwn(params.context, key))
3771
3808
  throw new RlsContextError({ reason: "invalid" });
3772
3809
  }
3810
+ if (params.readOnly === true)
3811
+ parts.push("set_config('transaction_read_only', 'on', true)");
3812
+ if (params.backend === true) {
3813
+ parts.push(`pg_catalog.pg_backend_pid()::text AS ${identifier2({ dialect: params.dialect, name: "backendPid" })}`, `(SELECT a.backend_start::text FROM pg_catalog.pg_stat_activity a WHERE a.pid = pg_catalog.pg_backend_pid()) AS ${identifier2({ dialect: params.dialect, name: "backendStart" })}`);
3814
+ }
3773
3815
  return query({ text: `SELECT ${parts.join(", ")}`, values: collector.values });
3774
3816
  }
3775
- function renderRlsRole(params) {
3776
- requireRls(params);
3817
+ function runtimeRoleOf(params) {
3777
3818
  if (typeof params.role !== "string" || params.role.trim().length === 0 || params.role.includes("\x00")) {
3778
3819
  throw new VibeError22({ code: "VIBE_CONFIG", message: "PGlite native RLS requires a trusted nonempty runtime role name" });
3779
3820
  }
3821
+ return params.role;
3822
+ }
3823
+ function renderRlsRole(params) {
3824
+ requireRls(params);
3825
+ const role = runtimeRoleOf({ role: params.role });
3780
3826
  const collector = new ParamCollector(params.dialect);
3781
- return query({ text: `SELECT set_config('role', ${collector.add(params.role)}, true)`, values: collector.values });
3827
+ return query({ text: `SELECT set_config('role', ${collector.add(role)}, true)`, values: collector.values });
3782
3828
  }
3783
3829
 
3784
3830
  // packages/sql/src/dialects/postgres-rls-readiness.ts
@@ -4037,7 +4083,7 @@ function renderStatement(params) {
4037
4083
  case "rlsPolicy":
4038
4084
  return renderRlsPolicy({ dialect, ...statement });
4039
4085
  case "rlsContext":
4040
- return renderRlsContext({ dialect, context: statement.context, values: statement.values });
4086
+ return renderRlsContext({ dialect, ...statement });
4041
4087
  case "rlsRole":
4042
4088
  return renderRlsRole({ dialect, role: statement.role });
4043
4089
  }
@@ -4090,9 +4136,13 @@ function quoteProjection(dialect, column) {
4090
4136
  const alias = dialect.quoteIdent({ name: column.alias ?? column.name });
4091
4137
  if (column.transform === "castText")
4092
4138
  return `${textProjection({ dialect, expression: ref })} AS ${alias}`;
4139
+ if (column.transform === "encodeBase64" && dialect.name === "mysql")
4140
+ return `TO_BASE64(${ref}) AS ${alias}`;
4093
4141
  if (dialect.name !== "postgres") {
4094
- throw internalError3({ message: "encodeBase64 is a postgres construct" });
4142
+ throw internalError3({ message: `${column.transform} is a postgres construct` });
4095
4143
  }
4144
+ if (column.transform === "encodeArrayBase64")
4145
+ return `encode(array_send(${ref}), 'base64') AS ${alias}`;
4096
4146
  return `encode(${ref}, 'base64') AS ${alias}`;
4097
4147
  }
4098
4148
  function textProjection(params) {
@@ -4494,6 +4544,35 @@ function renderKeyPage(params) {
4494
4544
  });
4495
4545
  return `SELECT ${[...projection, rank].join(", ")} FROM (VALUES ${tuples.join(", ")}) AS ${keys} INNER JOIN ${rows} ON ${membership}`;
4496
4546
  }
4547
+ function renderKeyRows(params) {
4548
+ const { dialect, statement, keys, collector } = params;
4549
+ if (statement.fromSelect !== undefined || statement.keyPage !== undefined || statement.fromUnion !== undefined || statement.table.alias !== undefined) {
4550
+ throw internalError3({ message: "fromKeys uses table.name as the derived-table alias \u2014 fromSelect, keyPage, fromUnion and table.alias must be unset" });
4551
+ }
4552
+ if (statement.rowLock !== undefined)
4553
+ throw internalError3({ message: "a locking read cannot read from key rows" });
4554
+ const arity = keys.columns.length;
4555
+ if (arity === 0 || keys.members.length !== arity) {
4556
+ throw internalError3({ message: `fromKeys has ${keys.members.length} members for ${arity} columns` });
4557
+ }
4558
+ if (keys.rows.length === 0)
4559
+ throw internalError3({ message: "fromKeys needs at least one key row" });
4560
+ for (const row of keys.rows) {
4561
+ if (row.length !== arity)
4562
+ throw internalError3({ message: `fromKeys row has ${row.length} values for ${arity} columns` });
4563
+ }
4564
+ if (dialect.keyListStrategy !== "unnest" || keyListBindsUntypedRows({ members: keys.members })) {
4565
+ throw unsupportedCapability27({
4566
+ dialect: dialect.name,
4567
+ feature: dialect.keyListStrategy !== "unnest" ? "a key-rows FROM (fromKeys)" : "a key-rows FROM over a DateTime key without a declared native type",
4568
+ hint: "the runtime keeps the per-relation loads for this write"
4569
+ });
4570
+ }
4571
+ const types = keys.members.map((member) => postgresKeyListElementType({ dialect, member }));
4572
+ const arrays = types.map((type, index) => `${collector.add(keys.rows.map((row) => row[index]))}::${type}[]`);
4573
+ const names = keys.columns.map((name) => dialect.quoteIdent({ name }));
4574
+ return `unnest(${arrays.join(", ")}) AS ${dialect.quoteIdent({ name: statement.table.name })} (${names.join(", ")})`;
4575
+ }
4497
4576
  var UNION_BRANCH_MEMBERS = new Set(["kind", "table", "columns", "where", "orderBy", "limit"]);
4498
4577
  function renderUnionPage(params) {
4499
4578
  const { dialect, statement, collector } = params;
@@ -4679,22 +4758,31 @@ function renderSelectExpr(params) {
4679
4758
  }
4680
4759
  function renderPositionalRow(params) {
4681
4760
  const { dialect, join, subAlias } = params;
4682
- if (join.select.columns.length === 0 || join.select.selectExpr !== undefined || (join.select.aggregates?.length ?? 0) > 0 || join.select.rowNumber !== undefined) {
4761
+ const json = lateralJsonOf({ dialect });
4762
+ const position = join.select.rowNumber;
4763
+ const positioned = position !== undefined && json.order === "positionSlot" && join.agg === "jsonArray" && position.partitionBy.length === 0 && position.orderBy.length > 0;
4764
+ if (join.select.columns.length === 0 || join.select.selectExpr !== undefined || (join.select.aggregates?.length ?? 0) > 0 || position !== undefined && !positioned) {
4683
4765
  throw internalError3({ message: "positional lateral rows require an explicit column-only projection" });
4684
4766
  }
4685
- const names = join.select.columns.map((column) => projectionOutputName({ column }));
4767
+ const names = [...join.select.columns.map((column) => projectionOutputName({ column })), ...positioned ? [position.alias] : []];
4686
4768
  if (new Set(names).size !== names.length) {
4687
4769
  throw internalError3({ message: "positional lateral projection has duplicate output names" });
4688
4770
  }
4689
4771
  const values = names.map((name) => `${subAlias}.${dialect.quoteIdent({ name })}`);
4690
4772
  const chunks = [];
4691
4773
  for (let index = 0;index < values.length; index += JSON_TRANSPORT.chunkSize) {
4692
- chunks.push(`json_build_array(${values.slice(index, index + JSON_TRANSPORT.chunkSize).join(", ")})`);
4774
+ chunks.push(`${json.rowArray}(${values.slice(index, index + JSON_TRANSPORT.chunkSize).join(", ")})`);
4693
4775
  }
4694
4776
  if (chunks.length > JSON_TRANSPORT.chunkSize) {
4695
4777
  throw internalError3({ message: "positional lateral projection exceeds the transport width limit" });
4696
4778
  }
4697
- return chunks.length === 1 ? chunks[0] : `json_build_array(${chunks.join(", ")})`;
4779
+ return chunks.length === 1 ? chunks[0] : `${json.rowArray}(${chunks.join(", ")})`;
4780
+ }
4781
+ function lateralJsonOf(params) {
4782
+ const json = params.dialect.lateralJson;
4783
+ if (json === null)
4784
+ throw internalError3({ message: "lateral JSON rendering on a dialect without LATERAL" });
4785
+ return json;
4698
4786
  }
4699
4787
  function renderLateralJoin(params) {
4700
4788
  const { dialect, join, collector } = params;
@@ -4707,8 +4795,9 @@ function renderLateralJoin(params) {
4707
4795
  }
4708
4796
  const columnAlias = dialect.quoteIdent({ name: join.columnAlias });
4709
4797
  const subAlias = dialect.quoteIdent({ name: "__sub" });
4798
+ const json = lateralJsonOf({ dialect });
4710
4799
  let aggOrder = "";
4711
- if (join.agg === "jsonArray" && join.select.orderBy !== undefined && join.select.orderBy.length > 0) {
4800
+ if (json.order === "inAggregate" && join.agg === "jsonArray" && join.select.orderBy !== undefined && join.select.orderBy.length > 0) {
4712
4801
  const projected = new Set(join.select.columns.filter((column) => column.transform === undefined && column.castReal !== true).map((column) => column.name));
4713
4802
  const terms = join.select.orderBy;
4714
4803
  const columnTerms = terms.filter((term) => ("column" in term));
@@ -4724,8 +4813,11 @@ function renderLateralJoin(params) {
4724
4813
  aggOrder = ` ORDER BY ${rendered.join(", ")}`;
4725
4814
  }
4726
4815
  }
4816
+ if (join.rowFormat !== "positional" && json.order !== "inAggregate") {
4817
+ throw unsupportedCapability27({ dialect: dialect.name, feature: "object-format lateral rows", hint: 'lateral relation rows render positional (rowFormat "positional") on this dialect' });
4818
+ }
4727
4819
  const rowJson = join.rowFormat === "positional" ? renderPositionalRow({ dialect, join, subAlias }) : `to_json(${subAlias}.*)`;
4728
- const projection = join.agg === "jsonArray" ? `COALESCE(json_agg(${rowJson}${aggOrder}), '[]'::json) AS ${columnAlias}` : `${rowJson} AS ${columnAlias}`;
4820
+ const projection = join.agg === "jsonArray" ? `COALESCE(${json.arrayAgg}(${rowJson}${aggOrder}), ${json.emptyArray}) AS ${columnAlias}` : `${rowJson} AS ${columnAlias}`;
4729
4821
  const alias = dialect.quoteIdent({ name: join.alias });
4730
4822
  return `LEFT JOIN LATERAL (SELECT ${projection} FROM (${inner.text}) AS ${subAlias}) AS ${alias} ON true`;
4731
4823
  }
@@ -4848,12 +4940,12 @@ function renderSelect(params) {
4848
4940
  }
4849
4941
  if (statement.rowNumber !== undefined) {
4850
4942
  const rowNumber = statement.rowNumber;
4851
- if (rowNumber.partitionBy.length === 0) {
4852
- throw internalError3({ message: "rowNumber needs at least one partition column" });
4943
+ if (rowNumber.partitionBy.length === 0 && rowNumber.orderBy.length === 0) {
4944
+ throw internalError3({ message: "rowNumber needs a partition column or an order" });
4853
4945
  }
4854
- const partition = rowNumber.partitionBy.map((column) => quoteCol(dialect, column)).join(", ");
4855
- const order = rowNumber.orderBy.length === 0 ? "" : ` ORDER BY ${rowNumber.orderBy.map((term) => renderOrderTerm({ dialect, term, collector })).join(", ")}`;
4856
- columnList.push(`ROW_NUMBER() OVER (PARTITION BY ${partition}${order}) AS ${dialect.quoteIdent({ name: rowNumber.alias })}`);
4946
+ const partition = rowNumber.partitionBy.length === 0 ? "" : `PARTITION BY ${rowNumber.partitionBy.map((column) => quoteCol(dialect, column)).join(", ")}`;
4947
+ const order = rowNumber.orderBy.length === 0 ? "" : `${partition === "" ? "" : " "}ORDER BY ${rowNumber.orderBy.map((term) => renderOrderTerm({ dialect, term, collector })).join(", ")}`;
4948
+ columnList.push(`ROW_NUMBER() OVER (${partition}${order}) AS ${dialect.quoteIdent({ name: rowNumber.alias })}`);
4857
4949
  }
4858
4950
  let distinctPrefix = statement.distinct === true ? "DISTINCT " : "";
4859
4951
  if (statement.distinct === true && statement.distinctOn !== undefined) {
@@ -4871,7 +4963,9 @@ function renderSelect(params) {
4871
4963
  }
4872
4964
  const columns = columnList.length === 0 ? "*" : columnList.join(", ");
4873
4965
  let from;
4874
- if (statement.fromUnion !== undefined) {
4966
+ if (statement.fromKeys !== undefined) {
4967
+ from = renderKeyRows({ dialect, statement, keys: statement.fromKeys, collector });
4968
+ } else if (statement.fromUnion !== undefined) {
4875
4969
  from = `(${renderUnionPage({ dialect, statement, collector })}) AS ${dialect.quoteIdent({ name: statement.table.name })}`;
4876
4970
  } else if (statement.keyPage !== undefined) {
4877
4971
  if (statement.fromSelect !== undefined || statement.table.alias !== undefined) {
@@ -4909,7 +5003,7 @@ function renderSelect(params) {
4909
5003
  }
4910
5004
  }
4911
5005
  if (statement.lateralJoins !== undefined && statement.lateralJoins.length > 0) {
4912
- if (!dialect.capabilities.lateralJoin) {
5006
+ if (!dialect.capabilities.lateralJoin || dialect.lateralJson === null) {
4913
5007
  throw unsupportedCapability27({
4914
5008
  dialect: dialect.name,
4915
5009
  feature: "LATERAL JOIN relation loading",
@@ -5029,8 +5123,7 @@ function renderInsert(params) {
5029
5123
  }
5030
5124
  }
5031
5125
  const onConflict = statement.onConflict;
5032
- const skipConflicts = onConflict !== undefined && "doNothing" in onConflict;
5033
- const insertKeyword = skipConflicts && dialect.doNothingForm === "insertIgnore" ? "INSERT IGNORE INTO" : "INSERT INTO";
5126
+ const insertKeyword = "INSERT INTO";
5034
5127
  const columnList = statement.columns.map((name) => dialect.quoteIdent({ name })).join(", ");
5035
5128
  const unnestSource = statement.unnest === undefined ? undefined : renderUnnestRows({ dialect, statement, members: statement.unnest, collector });
5036
5129
  const rowsSql = unnestSource !== undefined ? "" : statement.rows.map((row) => `(${row.map((value) => {
@@ -5072,12 +5165,25 @@ function renderInsert(params) {
5072
5165
  }
5073
5166
  }
5074
5167
  text += ` ON CONFLICT${target} DO NOTHING`;
5075
- } else if (onConflict.constraint !== undefined || onConflict.conflictWhere !== undefined) {
5076
- throw unsupportedCapability27({
5077
- dialect: dialect.name,
5078
- feature: "a refined conflict target (constraint / partial-index predicate) on INSERT IGNORE",
5079
- hint: "mysql skips on any duplicate key \u2014 drop the refinement or gate the call per dialect"
5080
- });
5168
+ } else {
5169
+ if (onConflict.constraint !== undefined || onConflict.conflictWhere !== undefined) {
5170
+ throw unsupportedCapability27({
5171
+ dialect: dialect.name,
5172
+ feature: "a refined conflict target (constraint / partial-index predicate) on ON DUPLICATE KEY UPDATE",
5173
+ hint: "mysql skips on any duplicate key \u2014 drop the refinement or gate the call per dialect"
5174
+ });
5175
+ }
5176
+ const keepName = onConflict.keepColumn ?? statement.columns[0];
5177
+ if (keepName === undefined) {
5178
+ throw internalError3({ message: "a skip-duplicates insert of an all-default row must name its keepColumn" });
5179
+ }
5180
+ const keep = dialect.quoteIdent({ name: keepName });
5181
+ const current = `${dialect.quoteIdent({ name: statement.table.name })}.${keep}`;
5182
+ const flag = onConflict.duplicateFlag;
5183
+ if (flag !== undefined && !/^\d{1,20}$/.test(flag)) {
5184
+ throw internalError3({ message: `duplicateFlag must be a decimal literal, got ${JSON.stringify(flag)}` });
5185
+ }
5186
+ text += flag === undefined ? ` ON DUPLICATE KEY UPDATE ${keep} = ${current}` : ` ON DUPLICATE KEY UPDATE ${keep} = IF(LAST_INSERT_ID(${flag}), ${current}, ${current})`;
5081
5187
  }
5082
5188
  } else {
5083
5189
  const updates = Object.entries(onConflict.update);
@@ -5134,7 +5240,7 @@ function renderUpdate(params) {
5134
5240
  if (assignments.length === 0) {
5135
5241
  throw internalError3({ message: "update must set at least one column" });
5136
5242
  }
5137
- const setSql = renderAssignments({ dialect, entries: assignments, collector });
5243
+ const setSql = renderAssignments({ dialect, entries: assignments, collector, ...params.earlier === undefined ? {} : { steps: params.earlier } });
5138
5244
  let text = `UPDATE ${renderTable(dialect, statement.table)} SET ${setSql}`;
5139
5245
  if (statement.where !== undefined) {
5140
5246
  text += ` WHERE ${renderExpr({ dialect, expr: statement.where, collector })}`;
@@ -5153,6 +5259,12 @@ function renderAssignments(params) {
5153
5259
  return entries.map(([name, value]) => {
5154
5260
  const column = dialect.quoteIdent({ name });
5155
5261
  const read = selfRef === undefined ? column : `${selfRef}.${column}`;
5262
+ if (isStepColumnRef(value)) {
5263
+ if (params.steps === undefined || !params.steps.has(value.step)) {
5264
+ throw internalError3({ message: `an UPDATE set value reads step "${value.step}", which is not an earlier chain step` });
5265
+ }
5266
+ return `${column} = (SELECT ${dialect.quoteIdent({ name: value.column })} FROM ${dialect.quoteIdent({ name: value.step })})`;
5267
+ }
5156
5268
  if (isSqlFragment(value)) {
5157
5269
  if (params.allowExcluded !== true || selfRef === undefined)
5158
5270
  throw internalError3({ message: "SQL assignment fragments require a conflict update" });
@@ -5166,6 +5278,11 @@ function renderAssignments(params) {
5166
5278
  }
5167
5279
  return `${column} = ${renderIncomingRowColumn({ dialect, column: value.column })}`;
5168
5280
  }
5281
+ if (isSqlKeepCell(value)) {
5282
+ if (params.allowExcluded !== true || selfRef === undefined)
5283
+ throw internalError3({ message: "a keep-column cell is only meaningful inside an upsert's update arm" });
5284
+ return `${column} = ${read}`;
5285
+ }
5169
5286
  if (isJsonParamCell(value)) {
5170
5287
  return `${column} = ${collector.add(value.text)}${jsonCellCast(dialect, value)}`;
5171
5288
  }
@@ -5259,7 +5376,7 @@ function renderChainStep(params) {
5259
5376
  case "insertSelect":
5260
5377
  return renderInsertSelect({ dialect, statement, collector, earlier: params.earlier });
5261
5378
  case "update":
5262
- return renderUpdate({ dialect, statement, collector }).text;
5379
+ return renderUpdate({ dialect, statement, collector, earlier: params.earlier }).text;
5263
5380
  case "delete":
5264
5381
  return renderDelete({ dialect, statement, collector }).text;
5265
5382
  }
@@ -5360,6 +5477,19 @@ function renderInsertSelect(params) {
5360
5477
  if (statement.where !== undefined) {
5361
5478
  text += ` WHERE ${renderExpr({ dialect, expr: statement.where, collector })}`;
5362
5479
  }
5480
+ const conflict = statement.conflictDoNothing;
5481
+ if (conflict !== undefined) {
5482
+ if (conflict.columns.length === 0)
5483
+ throw internalError3({ message: "an INSERT \u2026 SELECT conflict clause needs at least one column" });
5484
+ if (dialect.doNothingForm !== "onConflictDoNothing") {
5485
+ throw unsupportedCapability27({
5486
+ dialect: dialect.name,
5487
+ feature: "ON CONFLICT DO NOTHING on an INSERT \u2026 SELECT chain step",
5488
+ hint: "gate on SqlDialect.statementChain and keep the multi-statement path"
5489
+ });
5490
+ }
5491
+ text += ` ON CONFLICT (${conflict.columns.map((name) => dialect.quoteIdent({ name })).join(", ")}) DO NOTHING`;
5492
+ }
5363
5493
  return text + applyReturning({ dialect, requested: statement.returning }).suffix;
5364
5494
  }
5365
5495
  // packages/sql/src/dialects/postgres-type-identity.ts
@@ -5504,31 +5634,54 @@ function sqliteTableConstraints(params) {
5504
5634
  return result;
5505
5635
  }
5506
5636
  // packages/sql/src/dialects/migration-visibility.ts
5507
- import { unsupportedCapability as unsupportedCapability32 } from "@vibeorm/schema";
5508
- function renderMigrationVisibility(params) {
5509
- if (params.dialect.name !== "mysql")
5510
- throw unsupportedCapability32({ dialect: params.dialect.name, feature: "mysqlCatalogVisibility" });
5511
- const collector = new ParamCollector(params.dialect);
5512
- const grantee = "CONCAT(QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)), '@', QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', -1)))";
5513
- return { text: `SELECT PRIVILEGE_TYPE AS privilege FROM information_schema.USER_PRIVILEGES WHERE GRANTEE = ${grantee} UNION SELECT PRIVILEGE_TYPE AS privilege FROM information_schema.SCHEMA_PRIVILEGES WHERE GRANTEE = ${grantee} AND ${collector.add(params.namespace)} LIKE TABLE_SCHEMA`, values: collector.values, returning: "none" };
5514
- }
5515
- // packages/sql/src/dialects/migration-inventory.ts
5516
5637
  import { unsupportedCapability as unsupportedCapability33 } from "@vibeorm/schema";
5638
+
5639
+ // packages/sql/src/dialects/migration-inventory.ts
5640
+ import { unsupportedCapability as unsupportedCapability32 } from "@vibeorm/schema";
5641
+ var MYSQL_NO_ROW_LIMIT = " LIMIT 18446744073709551615";
5517
5642
  function renderSqliteColumnInventory(params) {
5518
5643
  if (params.dialect.name !== "sqlite")
5519
- throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteColumnInventory" });
5644
+ throw unsupportedCapability32({ dialect: params.dialect.name, feature: "sqliteColumnInventory" });
5520
5645
  const collector = new ParamCollector(params.dialect);
5521
5646
  return { text: `SELECT name, hidden, pk, dflt_value AS definition FROM pragma_table_xinfo(${collector.add(params.table)}, ${collector.add(params.namespace)}) ORDER BY cid`, values: collector.values, returning: "none" };
5522
5647
  }
5523
5648
  function renderSqliteForeignKeyInventory(params) {
5524
5649
  if (params.dialect.name !== "sqlite")
5525
- throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteForeignKeyInventory" });
5650
+ throw unsupportedCapability32({ dialect: params.dialect.name, feature: "sqliteForeignKeyInventory" });
5526
5651
  const collector = new ParamCollector(params.dialect);
5527
5652
  return { text: `SELECT id, seq, "from", "to", "table", on_update, on_delete, match FROM pragma_foreign_key_list(${collector.add(params.table)}, ${collector.add(params.namespace)}) ORDER BY id, seq`, values: collector.values, returning: "none" };
5528
5653
  }
5654
+ function renderSqliteColumnInventoryBatch(params) {
5655
+ if (params.dialect.name !== "sqlite")
5656
+ throw unsupportedCapability32({ dialect: params.dialect.name, feature: "sqliteColumnInventory" });
5657
+ const collector = new ParamCollector(params.dialect);
5658
+ const request = params.dialect.quoteIdent({ name: "vibe_request" });
5659
+ return { text: `SELECT j.key AS ${request}, x.name AS name, x.hidden AS hidden, x.pk AS pk, x.dflt_value AS definition FROM json_each(${collector.add(JSON.stringify(params.tables))}) j LEFT JOIN pragma_table_xinfo(j.value, ${collector.add(params.namespace)}) x ORDER BY j.key, x.cid`, values: collector.values, returning: "none" };
5660
+ }
5661
+ function renderSqliteForeignKeyInventoryBatch(params) {
5662
+ if (params.dialect.name !== "sqlite")
5663
+ throw unsupportedCapability32({ dialect: params.dialect.name, feature: "sqliteForeignKeyInventory" });
5664
+ const collector = new ParamCollector(params.dialect);
5665
+ const request = params.dialect.quoteIdent({ name: "vibe_request" });
5666
+ return { text: `SELECT j.key AS ${request}, f.id AS id, f.seq AS seq, f."from" AS "from", f."to" AS "to", f."table" AS "table", f.on_update AS on_update, f.on_delete AS on_delete, f.match AS match FROM json_each(${collector.add(JSON.stringify(params.tables))}) j LEFT JOIN pragma_foreign_key_list(j.value, ${collector.add(params.namespace)}) f ORDER BY j.key, f.id, f.seq`, values: collector.values, returning: "none" };
5667
+ }
5668
+ var SQLITE_INTROSPECTION_PRAGMA_ORDER = Object.freeze({
5669
+ table_xinfo: "p.cid",
5670
+ index_list: "p.seq",
5671
+ index_xinfo: "p.seqno",
5672
+ foreign_key_list: "p.id, p.seq"
5673
+ });
5674
+ function renderSqliteIntrospectionPragmaBatch(params) {
5675
+ if (params.dialect.name !== "sqlite")
5676
+ throw unsupportedCapability32({ dialect: params.dialect.name, feature: "sqliteIntrospectionPragmaBatch" });
5677
+ const order = SQLITE_INTROSPECTION_PRAGMA_ORDER[params.pragma];
5678
+ if (order === undefined)
5679
+ throw unsupportedCapability32({ dialect: "sqlite", feature: `introspectionPragma:${String(params.pragma)}` });
5680
+ return { text: `SELECT j.key AS ${params.dialect.quoteIdent({ name: "vibe_request" })}, p.* FROM json_each(${params.dialect.quoteStringLiteral({ value: JSON.stringify(params.names) })}) j LEFT JOIN pragma_${params.pragma}(j.value) p ORDER BY j.key, ${order}`, values: [], returning: "none" };
5681
+ }
5529
5682
  function renderSqliteRebuildObjects(params) {
5530
5683
  if (params.dialect.name !== "sqlite")
5531
- throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteRebuildObjects" });
5684
+ throw unsupportedCapability32({ dialect: params.dialect.name, feature: "sqliteRebuildObjects" });
5532
5685
  return { text: "SELECT name, tbl_name, type, sql FROM main.sqlite_schema WHERE type IN ('index', 'trigger') AND sql IS NOT NULL ORDER BY type, name", values: [], returning: "none" };
5533
5686
  }
5534
5687
  function renderMigrationInventory(params) {
@@ -5561,11 +5714,20 @@ UNION ALL SELECT 'trigger', TRIGGER_NAME, EVENT_OBJECT_TABLE, NULL, NULL, NULL F
5561
5714
  UNION ALL SELECT 'column', COLUMN_NAME, TABLE_NAME, NULL, NULL, NULL FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${n()} AND TABLE_NAME <> '_vibe_migrations'
5562
5715
  UNION ALL SELECT CASE WHEN GENERATION_EXPRESSION <> '' THEN 'generatedColumn' ELSE 'columnDefault' END, COLUMN_NAME, TABLE_NAME, NULL, NULL, NULL FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${n()} AND TABLE_NAME <> '_vibe_migrations' AND (COLUMN_DEFAULT IS NOT NULL OR GENERATION_EXPRESSION <> '')
5563
5716
  UNION ALL SELECT 'function', ROUTINE_NAME, NULL, NULL, '[]', NULL FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ${n()} AND ROUTINE_TYPE = 'FUNCTION'
5564
- ORDER BY kind, parent, name`, values: collector.values, returning: "none" };
5717
+ ORDER BY kind, parent, name${MYSQL_NO_ROW_LIMIT}`, values: collector.values, returning: "none" };
5565
5718
  }
5566
5719
  const schema = params.dialect.quoteIdent({ name: params.namespace });
5567
5720
  return { text: `SELECT type AS kind, name, tbl_name AS parent, sql AS definition FROM ${schema}.sqlite_schema WHERE name NOT LIKE 'sqlite\\_%' ESCAPE '\\' AND name <> '_vibe_migrations' ORDER BY type, tbl_name, name`, values: [], returning: "none" };
5568
5721
  }
5722
+
5723
+ // packages/sql/src/dialects/migration-visibility.ts
5724
+ function renderMigrationVisibility(params) {
5725
+ if (params.dialect.name !== "mysql")
5726
+ throw unsupportedCapability33({ dialect: params.dialect.name, feature: "mysqlCatalogVisibility" });
5727
+ const collector = new ParamCollector(params.dialect);
5728
+ const grantee = "CONCAT(QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)), '@', QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', -1)))";
5729
+ return { text: `SELECT PRIVILEGE_TYPE AS privilege FROM information_schema.USER_PRIVILEGES WHERE GRANTEE = ${grantee} UNION SELECT PRIVILEGE_TYPE AS privilege FROM information_schema.SCHEMA_PRIVILEGES WHERE GRANTEE = ${grantee} AND ${collector.add(params.namespace)} LIKE TABLE_SCHEMA${MYSQL_NO_ROW_LIMIT}`, values: collector.values, returning: "none" };
5730
+ }
5569
5731
  // packages/sql/src/dialects/migration-objects.ts
5570
5732
  import { internalError as internalError4, unsupportedCapability as unsupportedCapability34 } from "@vibeorm/schema";
5571
5733
  function renderMigrationObjectQuery(params) {
@@ -5622,35 +5784,12 @@ function objectQuery(params) {
5622
5784
  break;
5623
5785
  }
5624
5786
  } else if (dialect.name === "mysql") {
5625
- switch (object.kind) {
5626
- case "view":
5627
- text = `SELECT VIEW_DEFINITION AS definition, CHECK_OPTION AS checkOption, SECURITY_TYPE AS securityType, DEFINER AS definer FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name}`;
5628
- break;
5629
- case "trigger":
5630
- text = `SELECT ACTION_STATEMENT AS definition, ACTION_TIMING AS timing, EVENT_MANIPULATION AS event, ACTION_ORDER AS actionOrder, SQL_MODE AS sqlMode, DEFINER AS definer FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = ${namespace} AND EVENT_OBJECT_TABLE = ${name} AND TRIGGER_NAME = ${collector.add(object.name)}`;
5631
- break;
5632
- case "function":
5633
- text = `SELECT ROUTINE_DEFINITION AS definition, DTD_IDENTIFIER AS result, IS_DETERMINISTIC AS deterministic, SQL_DATA_ACCESS AS dataAccess, SECURITY_TYPE AS securityType, SQL_MODE AS sqlMode, DEFINER AS definer FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ${namespace} AND ROUTINE_NAME = ${name} AND ROUTINE_TYPE = 'FUNCTION'`;
5634
- break;
5635
- case "column":
5636
- case "columnDefault":
5637
- case "generatedColumn":
5638
- text = `SELECT COLUMN_TYPE AS type, IS_NULLABLE AS nullable, COLUMN_DEFAULT AS definition, GENERATION_EXPRESSION AS ${dialect.quoteIdent({ name: "generated" })}, EXTRA AS extra, COLLATION_NAME AS collation FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND COLUMN_NAME = ${collector.add(object.column)}`;
5639
- break;
5640
- case "constraint":
5641
- if (object.constraintType === "exclusion")
5642
- throw unsupportedCapability34({ dialect: "mysql", feature: "exclusionConstraints" });
5643
- text = `SELECT tc.CONSTRAINT_TYPE AS type, tc.ENFORCED AS enforced, cc.CHECK_CLAUSE AS definition, rc.UPDATE_RULE AS onUpdate, rc.DELETE_RULE AS onDelete, rc.MATCH_OPTION AS matchOption FROM information_schema.TABLE_CONSTRAINTS tc LEFT JOIN information_schema.CHECK_CONSTRAINTS cc ON cc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND cc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME LEFT JOIN information_schema.REFERENTIAL_CONSTRAINTS rc ON rc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND rc.TABLE_NAME = tc.TABLE_NAME AND rc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME WHERE tc.TABLE_SCHEMA = ${namespace} AND tc.TABLE_NAME = ${name} AND tc.CONSTRAINT_NAME = ${collector.add(object.name)}`;
5644
- break;
5645
- case "index":
5646
- text = `SELECT INDEX_NAME AS name, NON_UNIQUE AS nonUnique, INDEX_TYPE AS method, IS_VISIBLE AS visible FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND INDEX_NAME = ${collector.add(object.name)} GROUP BY INDEX_NAME, NON_UNIQUE, INDEX_TYPE, IS_VISIBLE`;
5647
- break;
5648
- case "table":
5649
- text = `SELECT TABLE_TYPE AS type, ENGINE AS engine, TABLE_COLLATION AS collation FROM information_schema.TABLES WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name}`;
5650
- break;
5651
- default:
5652
- throw unsupportedCapability34({ dialect: "mysql", feature: `inspect:${object.kind}` });
5653
- }
5787
+ if (object.kind === "constraint" && object.constraintType === "exclusion")
5788
+ throw unsupportedCapability34({ dialect: "mysql", feature: "exclusionConstraints" });
5789
+ const mysql = mysqlFactsText({ dialect, identity: object, namespace, name, collector });
5790
+ if (mysql === undefined)
5791
+ throw unsupportedCapability34({ dialect: "mysql", feature: `inspect:${object.kind}` });
5792
+ text = mysql;
5654
5793
  } else {
5655
5794
  if (physical.namespace !== "main" && physical.namespace !== "temp")
5656
5795
  throw unsupportedCapability34({ dialect: "sqlite", feature: "attachedSchemaInspection" });
@@ -5669,18 +5808,103 @@ function objectQuery(params) {
5669
5808
  }
5670
5809
  return { text, values: collector.values, returning: "none" };
5671
5810
  }
5672
- function renderMysqlObjectMembers(params) {
5673
- if (params.dialect.name !== "mysql")
5674
- return;
5675
- const object = params.identity;
5811
+ function mysqlFactsText(params) {
5812
+ const { dialect, identity: object, namespace, name, collector } = params;
5813
+ switch (object.kind) {
5814
+ case "view":
5815
+ return `SELECT VIEW_DEFINITION AS definition, CHECK_OPTION AS checkOption, SECURITY_TYPE AS securityType, DEFINER AS definer FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name}`;
5816
+ case "trigger":
5817
+ return `SELECT ACTION_STATEMENT AS definition, ACTION_TIMING AS timing, EVENT_MANIPULATION AS event, ACTION_ORDER AS actionOrder, SQL_MODE AS sqlMode, DEFINER AS definer FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = ${namespace} AND EVENT_OBJECT_TABLE = ${name} AND TRIGGER_NAME = ${collector.add(object.name)}`;
5818
+ case "function":
5819
+ return `SELECT ROUTINE_DEFINITION AS definition, DTD_IDENTIFIER AS result, IS_DETERMINISTIC AS deterministic, SQL_DATA_ACCESS AS dataAccess, SECURITY_TYPE AS securityType, SQL_MODE AS sqlMode, DEFINER AS definer FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ${namespace} AND ROUTINE_NAME = ${name} AND ROUTINE_TYPE = 'FUNCTION'`;
5820
+ case "column":
5821
+ case "columnDefault":
5822
+ case "generatedColumn":
5823
+ return `SELECT COLUMN_TYPE AS type, IS_NULLABLE AS nullable, COLUMN_DEFAULT AS definition, GENERATION_EXPRESSION AS ${dialect.quoteIdent({ name: "generated" })}, EXTRA AS extra, COLLATION_NAME AS collation FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND COLUMN_NAME = ${collector.add(object.column)}`;
5824
+ case "constraint":
5825
+ if (object.constraintType === "exclusion")
5826
+ return;
5827
+ return `SELECT tc.CONSTRAINT_TYPE AS type, tc.ENFORCED AS enforced, cc.CHECK_CLAUSE AS definition, rc.UPDATE_RULE AS onUpdate, rc.DELETE_RULE AS onDelete, rc.MATCH_OPTION AS matchOption FROM information_schema.TABLE_CONSTRAINTS tc LEFT JOIN information_schema.CHECK_CONSTRAINTS cc ON cc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND cc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME LEFT JOIN information_schema.REFERENTIAL_CONSTRAINTS rc ON rc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND rc.TABLE_NAME = tc.TABLE_NAME AND rc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME WHERE tc.TABLE_SCHEMA = ${namespace} AND tc.TABLE_NAME = ${name} AND tc.CONSTRAINT_NAME = ${collector.add(object.name)}`;
5828
+ case "index":
5829
+ return `SELECT INDEX_NAME AS name, NON_UNIQUE AS nonUnique, INDEX_TYPE AS method, IS_VISIBLE AS visible FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND INDEX_NAME = ${collector.add(object.name)} GROUP BY INDEX_NAME, NON_UNIQUE, INDEX_TYPE, IS_VISIBLE`;
5830
+ case "table":
5831
+ return `SELECT TABLE_TYPE AS type, ENGINE AS engine, TABLE_COLLATION AS collation FROM information_schema.TABLES WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name}`;
5832
+ default:
5833
+ return;
5834
+ }
5835
+ }
5836
+ function mysqlMemberParts(params) {
5837
+ const { identity: object, collector } = params;
5676
5838
  if (object.kind !== "function" && object.kind !== "index" && object.kind !== "constraint")
5677
5839
  return;
5678
- const collector = new ParamCollector(params.dialect);
5679
5840
  const physical = "table" in object ? object.table : object.name;
5680
5841
  const namespace = collector.add(physical.namespace);
5681
5842
  const name = collector.add(physical.name);
5682
- const text = object.kind === "function" ? `SELECT PARAMETER_MODE AS mode, PARAMETER_NAME AS name, DTD_IDENTIFIER AS type, CHARACTER_SET_NAME AS characterSet, COLLATION_NAME AS collation FROM information_schema.PARAMETERS WHERE SPECIFIC_SCHEMA = ${namespace} AND SPECIFIC_NAME = ${name} ORDER BY ORDINAL_POSITION` : object.kind === "index" ? `SELECT COLUMN_NAME AS name, EXPRESSION AS expression, SUB_PART AS prefixLength, COLLATION AS collation FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND INDEX_NAME = ${collector.add(object.name)} ORDER BY SEQ_IN_INDEX` : `SELECT COLUMN_NAME AS name, REFERENCED_TABLE_SCHEMA AS referenceNamespace, REFERENCED_TABLE_NAME AS referenceTable, REFERENCED_COLUMN_NAME AS referenceColumn FROM information_schema.KEY_COLUMN_USAGE WHERE CONSTRAINT_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND CONSTRAINT_NAME = ${collector.add(object.name)} ORDER BY ORDINAL_POSITION`;
5683
- return { text, values: collector.values, returning: "none" };
5843
+ return object.kind === "function" ? { columns: "PARAMETER_MODE AS mode, PARAMETER_NAME AS name, DTD_IDENTIFIER AS type, CHARACTER_SET_NAME AS characterSet, COLLATION_NAME AS collation", source: `information_schema.PARAMETERS WHERE SPECIFIC_SCHEMA = ${namespace} AND SPECIFIC_NAME = ${name}`, ordinal: "ORDINAL_POSITION" } : object.kind === "index" ? { columns: "COLUMN_NAME AS name, EXPRESSION AS expression, SUB_PART AS prefixLength, COLLATION AS collation", source: `information_schema.STATISTICS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND INDEX_NAME = ${collector.add(object.name)}`, ordinal: "SEQ_IN_INDEX" } : { columns: "COLUMN_NAME AS name, REFERENCED_TABLE_SCHEMA AS referenceNamespace, REFERENCED_TABLE_NAME AS referenceTable, REFERENCED_COLUMN_NAME AS referenceColumn", source: `information_schema.KEY_COLUMN_USAGE WHERE CONSTRAINT_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND CONSTRAINT_NAME = ${collector.add(object.name)}`, ordinal: "ORDINAL_POSITION" };
5844
+ }
5845
+ function renderMysqlObjectMembers(params) {
5846
+ if (params.dialect.name !== "mysql")
5847
+ return;
5848
+ const collector = new ParamCollector(params.dialect);
5849
+ const parts = mysqlMemberParts({ identity: params.identity, collector });
5850
+ if (parts === undefined)
5851
+ return;
5852
+ return { text: `SELECT ${parts.columns} FROM ${parts.source} ORDER BY ${parts.ordinal}`, values: collector.values, returning: "none" };
5853
+ }
5854
+ var MYSQL_OBJECT_BATCH_SIZE = 100;
5855
+ var MYSQL_BATCH_NO_ROW_LIMIT = " LIMIT 18446744073709551615";
5856
+ function mysqlBatches(params) {
5857
+ const batches = [];
5858
+ for (const group of params.groups.values()) {
5859
+ for (let offset = 0;offset < group.length; offset += MYSQL_OBJECT_BATCH_SIZE) {
5860
+ const chunk = group.slice(offset, offset + MYSQL_OBJECT_BATCH_SIZE);
5861
+ batches.push({
5862
+ text: `${chunk.map((entry, index) => entry.branch(index)).join(" UNION ALL ")}${params.suffix}${MYSQL_BATCH_NO_ROW_LIMIT}`,
5863
+ values: chunk.flatMap((entry) => entry.values),
5864
+ returning: "none",
5865
+ positions: chunk.map((entry) => entry.position)
5866
+ });
5867
+ }
5868
+ }
5869
+ return batches;
5870
+ }
5871
+ function renderMysqlObjectBatch(params) {
5872
+ const { dialect } = params;
5873
+ if (dialect.name !== "mysql")
5874
+ throw unsupportedCapability34({ dialect: dialect.name, feature: "batchedMigrationInspection" });
5875
+ const position = dialect.quoteIdent({ name: "vibe_position" });
5876
+ const groups = new Map;
5877
+ for (const [index, identity] of params.identities.entries()) {
5878
+ if (identity.kind === "namespace")
5879
+ continue;
5880
+ const physical = "table" in identity ? identity.table : identity.name;
5881
+ const collector = new ParamCollector(dialect);
5882
+ const text = mysqlFactsText({ dialect, identity, namespace: collector.add(physical.namespace), name: collector.add(physical.name), collector });
5883
+ if (text === undefined)
5884
+ continue;
5885
+ const group = groups.get(text) ?? [];
5886
+ group.push({ position: index, branch: (branch) => `SELECT ${branch} AS ${position}, q.* FROM (${text}) q`, values: collector.values });
5887
+ groups.set(text, group);
5888
+ }
5889
+ return mysqlBatches({ groups, suffix: "" });
5890
+ }
5891
+ function renderMysqlObjectMembersBatch(params) {
5892
+ const { dialect } = params;
5893
+ if (dialect.name !== "mysql")
5894
+ throw unsupportedCapability34({ dialect: dialect.name, feature: "batchedMigrationInspection" });
5895
+ const position = dialect.quoteIdent({ name: "vibe_position" });
5896
+ const ordinal = dialect.quoteIdent({ name: "vibe_ordinal" });
5897
+ const groups = new Map;
5898
+ for (const [index, identity] of params.identities.entries()) {
5899
+ const collector = new ParamCollector(dialect);
5900
+ const parts = mysqlMemberParts({ identity, collector });
5901
+ if (parts === undefined)
5902
+ continue;
5903
+ const group = groups.get(identity.kind) ?? [];
5904
+ group.push({ position: index, branch: (branch) => `SELECT ${branch} AS ${position}, ${parts.ordinal} AS ${ordinal}, ${parts.columns} FROM ${parts.source}`, values: collector.values });
5905
+ groups.set(identity.kind, group);
5906
+ }
5907
+ return mysqlBatches({ groups, suffix: ` ORDER BY ${position}, ${ordinal}` });
5684
5908
  }
5685
5909
  function renderMigrationDependencies(params) {
5686
5910
  return dependencyQuery({ ...params, collector: new ParamCollector(params.dialect) });
@@ -5919,6 +6143,7 @@ export {
5919
6143
  SQLITE_SESSION_SQL,
5920
6144
  SQL_DEFAULT_CELL,
5921
6145
  SQL_DIALECTS,
6146
+ SQL_KEEP_CELL,
5922
6147
  assertIndexExpressionVersion,
5923
6148
  assertSqlParamBuilding,
5924
6149
  chainVetoToken,
@@ -5940,6 +6165,7 @@ export {
5940
6165
  dbNowMarker,
5941
6166
  decode,
5942
6167
  decodeIsNoop,
6168
+ decodedDateTimeRefusal,
5943
6169
  describeRowLock,
5944
6170
  encode,
5945
6171
  endsWithPattern,
@@ -5966,6 +6192,7 @@ export {
5966
6192
  isSqlCommand,
5967
6193
  isSqlDefaultCell,
5968
6194
  isSqlFragment,
6195
+ isSqlKeepCell,
5969
6196
  isSqlParam,
5970
6197
  isSqlQuery,
5971
6198
  isStepColumnRef,
@@ -5977,6 +6204,7 @@ export {
5977
6204
  mysqlDialect,
5978
6205
  nativeEnumArrayParameter,
5979
6206
  parseDateTimeText,
6207
+ parseExtendedDateTimeText,
5980
6208
  parseJsonText,
5981
6209
  parsePgArrayLiteral,
5982
6210
  parsePgArrayLiteralNested,
@@ -6024,7 +6252,9 @@ export {
6024
6252
  renderModuleJournal,
6025
6253
  renderMysqlCheckProbe,
6026
6254
  renderMysqlGeneratedColumnProbe,
6255
+ renderMysqlObjectBatch,
6027
6256
  renderMysqlObjectMembers,
6257
+ renderMysqlObjectMembersBatch,
6028
6258
  renderPostgresDefaultFunctionIdentity,
6029
6259
  renderPostgresDropGeneratedExpression,
6030
6260
  renderPostgresExplain,
@@ -6059,8 +6289,11 @@ export {
6059
6289
  renderShadowOperation,
6060
6290
  renderSqlFragment,
6061
6291
  renderSqliteColumnInventory,
6292
+ renderSqliteColumnInventoryBatch,
6062
6293
  renderSqliteForeignKeyInventory,
6294
+ renderSqliteForeignKeyInventoryBatch,
6063
6295
  renderSqliteFtsUpdateTrigger,
6296
+ renderSqliteIntrospectionPragmaBatch,
6064
6297
  renderSqliteRebuildObjects,
6065
6298
  renderStatement,
6066
6299
  resolveIndexKeys,
@@ -6089,4 +6322,4 @@ export {
6089
6322
  toPgArrayLiteral
6090
6323
  };
6091
6324
 
6092
- //# debugId=75BF4FE272330AE564756E2164756E21
6325
+ //# debugId=0FD86C4E8226D05064756E2164756E21