@prisma/orm-family-sql 8.0.0-rc.17-dev.37 → 8.0.0-rc.17-dev.38

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 (41) hide show
  1. package/dist/{authoring-type-constructors-0Iv2zdwS-CjonPCuf.mjs → authoring-type-constructors-0Iv2zdwS-ZTBL7w8X.mjs} +2 -2
  2. package/dist/{authoring-type-constructors-0Iv2zdwS-CjonPCuf.mjs.map → authoring-type-constructors-0Iv2zdwS-ZTBL7w8X.mjs.map} +1 -1
  3. package/dist/{config-types-B-cnVdoD.mjs → config-types-DiCetrJe.mjs} +2 -2
  4. package/dist/{config-types-B-cnVdoD.mjs.map → config-types-DiCetrJe.mjs.map} +1 -1
  5. package/dist/{contract-builder-B1KNtOiJ.mjs → contract-builder-D84f__Oc.mjs} +2 -2
  6. package/dist/{contract-builder-B1KNtOiJ.mjs.map → contract-builder-D84f__Oc.mjs.map} +1 -1
  7. package/dist/contract-prisma7__provider.mjs +4 -4
  8. package/dist/contract-psl.mjs +1 -1
  9. package/dist/contract-psl__attribute-specs.mjs +1 -1
  10. package/dist/contract-psl__provider.mjs +2 -2
  11. package/dist/contract-ts.mjs +3 -3
  12. package/dist/contract-ts__config-types.mjs +1 -1
  13. package/dist/contract-ts__contract-builder.mjs +2 -2
  14. package/dist/contract.d.mts +2 -2
  15. package/dist/contract.mjs +2 -2
  16. package/dist/contract__data-type.d.mts +2 -2
  17. package/dist/contract__data-type.mjs +2 -2
  18. package/dist/{control-D4PHWMpB.d.mts → control-Bs-0JljW.d.mts} +199 -10
  19. package/dist/{control-D4PHWMpB.d.mts.map → control-Bs-0JljW.d.mts.map} +1 -1
  20. package/dist/{control-uICV4VAt.mjs → control-Bvnz4Uk4.mjs} +337 -17
  21. package/dist/control-Bvnz4Uk4.mjs.map +1 -0
  22. package/dist/{data-type-C_PI_Jsa.mjs → data-type-BgP6Wv48.mjs} +27 -5
  23. package/dist/{data-type-C_PI_Jsa.mjs.map → data-type-BgP6Wv48.mjs.map} +1 -1
  24. package/dist/{data-type-CpqSDmR_.d.mts → data-type-gKl5DBHw.d.mts} +9 -2
  25. package/dist/{data-type-CpqSDmR_.d.mts.map → data-type-gKl5DBHw.d.mts.map} +1 -1
  26. package/dist/{derived-checks-CYz041Ol-CFhXTA9K.mjs → derived-checks-CYz041Ol-TjL7rPxe.mjs} +2 -2
  27. package/dist/{derived-checks-CYz041Ol-CFhXTA9K.mjs.map → derived-checks-CYz041Ol-TjL7rPxe.mjs.map} +1 -1
  28. package/dist/family.d.mts +2 -2
  29. package/dist/family.mjs +3 -3
  30. package/dist/family__control.d.mts +2 -2
  31. package/dist/family__control.mjs +3 -3
  32. package/dist/family__diff.mjs +1 -1
  33. package/dist/family__pack.mjs +2 -2
  34. package/dist/{interpreter-0z4AxG0I-CCbqh8XA.mjs → interpreter-0z4AxG0I-CM9DULu1.mjs} +3 -3
  35. package/dist/{interpreter-0z4AxG0I-CCbqh8XA.mjs.map → interpreter-0z4AxG0I-CM9DULu1.mjs.map} +1 -1
  36. package/dist/{psl-field-resolution-D4jnVVTd-CyGA5a3e.mjs → psl-field-resolution-D4jnVVTd-B396sZmO.mjs} +2 -2
  37. package/dist/{psl-field-resolution-D4jnVVTd-CyGA5a3e.mjs.map → psl-field-resolution-D4jnVVTd-B396sZmO.mjs.map} +1 -1
  38. package/dist/{schema-verify-DIfHSB4I-Bbek1093.mjs → schema-verify-DIfHSB4I-Du0-5I8k.mjs} +2 -2
  39. package/dist/{schema-verify-DIfHSB4I-Bbek1093.mjs.map → schema-verify-DIfHSB4I-Du0-5I8k.mjs.map} +1 -1
  40. package/package.json +18 -18
  41. package/dist/control-uICV4VAt.mjs.map +0 -1
@@ -1,15 +1,15 @@
1
1
  import { u as namingOf } from "./naming-CT8tRisJ-DLHKo0Hm.mjs";
2
2
  import { t as sqlContractCanonicalizationHooks } from "./canonicalization-hooks-dmXkOR4a.mjs";
3
- import { a as renderSqlTypeName, l as sqlDataTypeOfCodec, t as dataTypeParams, u as unquotedSqlBaseName } from "./data-type-C_PI_Jsa.mjs";
3
+ import { a as renderSqlTypeName, d as unquotedSqlBaseName, t as dataTypeParams, u as sqlDataTypeOfCodec } from "./data-type-BgP6Wv48.mjs";
4
4
  import { c as StorageTable } from "./storage-table-B7OSPl3G-p1j6AjMS.mjs";
5
5
  import { c as SqlSchemaIR, n as RelationalSchemaNodeKind, u as SqlTableIR } from "./types-D0GFxty0-CP8b4dR3.mjs";
6
6
  import { p as sqlExpressionRegistration } from "./sql-expression-DSRILiU2.mjs";
7
7
  import { u as isStorageTypeInstance } from "./types-DXrO0fxT.mjs";
8
8
  import { g as valueObjectStorageTypeMissingMessage } from "./validators-BMWQ7-5D.mjs";
9
- import { S as sqlAttributeSpecs, a as describeUnsupportedSqlAttribute } from "./psl-field-resolution-D4jnVVTd-CyGA5a3e.mjs";
9
+ import { S as sqlAttributeSpecs, a as describeUnsupportedSqlAttribute } from "./psl-field-resolution-D4jnVVTd-B396sZmO.mjs";
10
10
  import { t as sqlEmission } from "./dist-D8EkCena.mjs";
11
- import { i as sqlFamilyPslBlockDescriptors, n as sqlFamilyAuthoringTypes, r as sqlFamilyEntityTypes, t as sqlFamilyAuthoringFieldPresets } from "./authoring-type-constructors-0Iv2zdwS-CjonPCuf.mjs";
12
- import { c as verifySqlSchemaByDiff, n as classifyDiffSubjectGranularity, o as enforceSqlDataTypeInvariants, t as classifyDiffEntityKind } from "./schema-verify-DIfHSB4I-Bbek1093.mjs";
11
+ import { i as sqlFamilyPslBlockDescriptors, n as sqlFamilyAuthoringTypes, r as sqlFamilyEntityTypes, t as sqlFamilyAuthoringFieldPresets } from "./authoring-type-constructors-0Iv2zdwS-ZTBL7w8X.mjs";
12
+ import { c as verifySqlSchemaByDiff, n as classifyDiffSubjectGranularity, o as enforceSqlDataTypeInvariants, t as classifyDiffEntityKind } from "./schema-verify-DIfHSB4I-Du0-5I8k.mjs";
13
13
  import { t as sqlFamilyError } from "./errors-B5g0xWro-mWH2C07F.mjs";
14
14
  import { t as SqlContractSerializer } from "./sql-contract-serializer-DDaAVCQr-BAb4jKvV.mjs";
15
15
  import { t as collectSupportedCodecTypeIds } from "./verify-BVk5bjdH-dq5M4iIh.mjs";
@@ -21,10 +21,12 @@ import { UNBOUND_NAMESPACE_ID, isPlainRecord } from "@prisma/orm-framework/compo
21
21
  import { assembleDataTypes, canonicalFormOf } from "@prisma/orm-framework/components/codec";
22
22
  import { blindCast } from "@prisma/orm-framework/utils/casts";
23
23
  import { InternalError } from "@prisma/orm-framework/utils/internal-error";
24
+ import { type } from "arktype";
24
25
  import { asNamespaceId, effectiveControlPolicy } from "@prisma/orm-framework/contract/types";
25
26
  import { notOk, ok } from "@prisma/orm-framework/utils/result";
26
- import { APP_SPACE_ID, SchemaTreeNode, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_TARGET_MISMATCH, assembleAuthoringContributions, describeMigrationStatement, extractCodecLookup, issueOutcome, modelDisplayName, sameMarkerHashes } from "@prisma/orm-framework/components/control";
27
+ import { APP_SPACE_ID, SchemaTreeNode, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_TARGET_MISMATCH, assembleAuthoringContributions, describeMigrationStatement, extractCodecLookup, fieldStatementText, issueOutcome, modelDisplayName, sameMarkerHashes } from "@prisma/orm-framework/components/control";
27
28
  import { assertDescriptorSelfConsistency } from "@prisma/orm-toolchain/migration-tools/spaces";
29
+ import { jsonToTsSource } from "@prisma/orm-framework/ts-render";
28
30
  //#region ../../../2-sql/9-family/dist/control.mjs
29
31
  function tablesOf(storage) {
30
32
  return Object.entries(storage.namespaces).flatMap(([namespaceId, namespace]) => Object.entries(namespace.entries["table"] ?? {}).map(([tableName, table]) => ({
@@ -1700,6 +1702,84 @@ function planStatements(input) {
1700
1702
  appliedStatements
1701
1703
  });
1702
1704
  }
1705
+ /**
1706
+ * The column of each field a convert or backfill statement names, as the destination contract
1707
+ * stores it. These statements rename nothing, so the strategies that plan a field's change read
1708
+ * them instead of the working schema. A field with no column has none to list.
1709
+ */
1710
+ function fieldStatementColumns(statements, contract) {
1711
+ const columnsOf = (kind) => statements.flatMap((statement) => {
1712
+ if (statement.kind !== kind) return [];
1713
+ const table = modelTable(contract, statement.field);
1714
+ const column = fieldColumn(contract, statement.field);
1715
+ return table === void 0 || column === void 0 ? [] : [{
1716
+ ...table,
1717
+ column,
1718
+ field: statement.field,
1719
+ text: fieldStatementText(contract, statement.field)
1720
+ }];
1721
+ });
1722
+ return {
1723
+ convert: columnsOf("convert"),
1724
+ backfill: columnsOf("backfill")
1725
+ };
1726
+ }
1727
+ /**
1728
+ * A conflict for the first backfill statement that names a field the origin model does not have and
1729
+ * whose column has a default: the default fills the existing rows when the column is added, so the
1730
+ * statement has nothing to fill. A field already in the origin keeps its backfill, since a default
1731
+ * does not fill the rows that hold NULL when the column becomes required.
1732
+ */
1733
+ function backfillOfDefaultedField(statements, fromContract, contract) {
1734
+ for (const statement of statements) {
1735
+ if (statement.kind !== "backfill" || fromContract === null) continue;
1736
+ const originModel = sqlModelStorage(fromContract, statement.field);
1737
+ if (originModel === void 0 || Object.hasOwn(originModel.fields, statement.field.field)) continue;
1738
+ const table = modelTable(contract, statement.field);
1739
+ const column = fieldColumn(contract, statement.field);
1740
+ if (table === void 0 || column === void 0) continue;
1741
+ if ((contract.storage.namespaces[table.namespaceId]?.entries.table?.[table.table]?.columns[column])?.default === void 0) continue;
1742
+ return statementRefused(statement, `${describeMigrationStatement(statement, fromContract, contract)}: the field is new and has a default`, "The default fills the existing rows when the column is added, so there is nothing to backfill. Leave out the --backfill statement.", {
1743
+ namespaceId: table.namespaceId,
1744
+ table: table.table,
1745
+ column
1746
+ });
1747
+ }
1748
+ }
1749
+ /**
1750
+ * Every statement of a plan in the order given, with the operations it accounts for: a rename's
1751
+ * from `renames`, and none yet for any other statement.
1752
+ */
1753
+ function appliedStatementsInOrder(statements, renames) {
1754
+ return statements.map((statement) => renames.find((applied) => applied.statement === statement) ?? {
1755
+ statement,
1756
+ operationIndexes: []
1757
+ });
1758
+ }
1759
+ /**
1760
+ * The field of `contract` that stores `column` of `table`, or undefined when no field stores it or
1761
+ * tables of two storage namespaces share the table's name.
1762
+ */
1763
+ function fieldOfColumn(contract, table, column) {
1764
+ const fields = Object.entries(contract.domain.namespaces).flatMap(([namespaceId, namespace]) => Object.entries(namespace.models).flatMap(([model, definition]) => {
1765
+ const { storage } = definition;
1766
+ if (!isSqlModelStorage(storage) || storage.table !== table) return [];
1767
+ const field = Object.entries(storage.fields).find(([, stored]) => stored.column === column);
1768
+ if (field === void 0) return [];
1769
+ return [{
1770
+ storageNamespace: storage.namespaceId,
1771
+ isRoot: definition.base === void 0,
1772
+ subject: {
1773
+ kind: "field",
1774
+ namespaceId: asNamespaceId(namespaceId),
1775
+ model,
1776
+ field: field[0]
1777
+ }
1778
+ }];
1779
+ }));
1780
+ if (new Set(fields.map(({ storageNamespace }) => storageNamespace)).size !== 1) return void 0;
1781
+ return (fields.find(({ isRoot }) => isRoot) ?? fields[0])?.subject;
1782
+ }
1703
1783
  /** What a codec hook's call is about: the column of the field event it was returned for. */
1704
1784
  function fieldEventStorage(field) {
1705
1785
  return {
@@ -1731,7 +1811,7 @@ function unknownCallNames(calls) {
1731
1811
  }
1732
1812
  function originTable(context, namespaceId, table) {
1733
1813
  for (const statement of context.statements) {
1734
- if (statement.entity !== "model") continue;
1814
+ if (statement.kind !== "rename" || statement.entity !== "model") continue;
1735
1815
  const effect = modelRenameStorageEffect(statement, context.fromContract, context.contract);
1736
1816
  if (!effect.ok || effect.value.kind !== "renameTable") continue;
1737
1817
  const { rename } = effect.value;
@@ -1741,7 +1821,7 @@ function originTable(context, namespaceId, table) {
1741
1821
  }
1742
1822
  function originColumn(context, namespaceId, table, column) {
1743
1823
  for (const statement of context.statements) {
1744
- if (statement.entity !== "field") continue;
1824
+ if (statement.kind !== "rename" || statement.entity !== "field") continue;
1745
1825
  const effect = fieldRenameStorageEffect(statement, context.fromContract, context.contract);
1746
1826
  if (!effect.ok || effect.value.kind !== "renameColumn") continue;
1747
1827
  const rename = effect.value;
@@ -1824,18 +1904,25 @@ function keepTableAdvice(target, subject, context) {
1824
1904
  function subjectsOfCalls(calls, context) {
1825
1905
  const dataLoss = [];
1826
1906
  const accessWidening = [];
1907
+ const temporaryValues = [];
1827
1908
  let operationIndex = 0;
1828
1909
  for (const call of calls) {
1910
+ for (const { table, column, value } of call.temporaryValues) temporaryValues.push({
1911
+ operationIndex,
1912
+ subject: fieldOfColumn(context.contract, table, column) ?? {
1913
+ kind: "storage",
1914
+ name: `${table}.${column}`
1915
+ },
1916
+ value
1917
+ });
1829
1918
  for (const target of call.dataLoss) {
1830
1919
  const subject = subjectOf(target, context);
1831
- const keepDataAdvice = keepTableAdvice(target, subject, context);
1832
- dataLoss.push(keepDataAdvice === void 0 ? {
1833
- operationIndex,
1834
- subject
1835
- } : {
1920
+ dataLoss.push({
1836
1921
  operationIndex,
1837
1922
  subject,
1838
- keepDataAdvice
1923
+ loss: target.loss,
1924
+ label: call.label,
1925
+ ...ifDefined("keepDataAdvice", keepTableAdvice(target, subject, context))
1839
1926
  });
1840
1927
  }
1841
1928
  for (const target of call.accessWidening) accessWidening.push({
@@ -1847,7 +1934,8 @@ function subjectsOfCalls(calls, context) {
1847
1934
  }
1848
1935
  return {
1849
1936
  dataLoss,
1850
- accessWidening
1937
+ accessWidening,
1938
+ temporaryValues
1851
1939
  };
1852
1940
  }
1853
1941
  const readOnlyEmptyObject = Object.freeze({});
@@ -1912,6 +2000,7 @@ function plannerSuccess(plan, appliedStatements, subjects, warnings) {
1912
2000
  appliedStatements: Object.freeze([...appliedStatements]),
1913
2001
  dataLoss: Object.freeze([...subjects.dataLoss]),
1914
2002
  accessWidening: Object.freeze([...subjects.accessWidening]),
2003
+ temporaryValues: Object.freeze([...subjects.temporaryValues]),
1915
2004
  ...warnings && warnings.length > 0 ? { warnings: Object.freeze(warnings.map((conflict) => Object.freeze({
1916
2005
  kind: conflict.kind,
1917
2006
  summary: conflict.summary,
@@ -1954,13 +2043,206 @@ function runnerFailure(code, summary, options) {
1954
2043
  code,
1955
2044
  summary,
1956
2045
  ...options?.why ? { why: options.why } : {},
1957
- ...options?.meta ? { meta: cloneRecord(options.meta) } : {}
2046
+ ...options?.meta ? { meta: cloneRecord(options.meta) } : {},
2047
+ ...ifDefined("failedTypeChange", options?.failedTypeChange),
2048
+ ...ifDefined("rowsWithoutValue", options?.rowsWithoutValue)
1958
2049
  }));
1959
2050
  }
1960
2051
  /**
1961
2052
  * Policy used by `db init`: additive-only operations, no widening/destructive steps.
1962
2053
  */
1963
2054
  const INIT_ADDITIVE_POLICY = Object.freeze({ allowedOperationClasses: Object.freeze(["additive"]) });
2055
+ const RequiredColumnMeta = type({ requiredColumn: {
2056
+ table: "string",
2057
+ column: "string",
2058
+ reason: "'nullValues' | 'newField' | 'backfillMissedRows'"
2059
+ } });
2060
+ /**
2061
+ * The meta of a step that fails when rows have no value for a column that is to become required:
2062
+ * rows hold NULL in it, or, for a new column that can be added to an empty table only, the table
2063
+ * has rows. When the step fails, the runner counts those rows.
2064
+ */
2065
+ function requiredColumnMeta(table, column, reason) {
2066
+ return { requiredColumn: {
2067
+ table,
2068
+ column,
2069
+ reason
2070
+ } };
2071
+ }
2072
+ /** The column a step checks before it becomes required, as {@link requiredColumnMeta} marks it. */
2073
+ function requiredColumnOf(step) {
2074
+ const meta = RequiredColumnMeta(step.meta ?? {});
2075
+ return meta instanceof type.errors ? void 0 : meta.requiredColumn;
2076
+ }
2077
+ /** What a runner failure says of the rows a column that is to become required has no value in. */
2078
+ function rowsWithoutValueSummary(required, rows) {
2079
+ const { table, column } = required;
2080
+ if (required.reason === "newField") return `"${table}" has ${rows} ${rows === 1 ? "row" : "rows"}, so the new required column "${column}" cannot be added: it can be added to an empty table only.`;
2081
+ const counted = `${rows} ${rows === 1 ? "row" : "rows"} of "${table}"`;
2082
+ if (required.reason === "backfillMissedRows") return `${counted} still ${rows === 1 ? "holds" : "hold"} NULL in "${column}" after its backfill step, so it cannot become required.`;
2083
+ return `${counted} ${rows === 1 ? "holds" : "hold"} NULL in "${column}", so it cannot become required.`;
2084
+ }
2085
+ function migrationRange(edges, operationIndex, operationCount) {
2086
+ let start = 0;
2087
+ for (const edge of edges) {
2088
+ const end = start + edge.operationCount;
2089
+ if (operationIndex < end) return {
2090
+ start,
2091
+ end
2092
+ };
2093
+ start = end;
2094
+ }
2095
+ return {
2096
+ start: 0,
2097
+ end: operationCount
2098
+ };
2099
+ }
2100
+ /**
2101
+ * The marks of the steps of `operations` that belong to the same migration as the operation at
2102
+ * `operationIndex`, in plan order: `edges` say how many operations each migration of the plan has.
2103
+ */
2104
+ function requiredColumnsOfMigration(operations, edges, operationIndex) {
2105
+ const { start, end } = migrationRange(edges, operationIndex, operations.length);
2106
+ return operations.slice(start, end).flatMap((operation, offset) => [
2107
+ ...operation.precheck,
2108
+ ...operation.execute,
2109
+ ...operation.postcheck
2110
+ ].flatMap((step) => {
2111
+ const required = requiredColumnOf(step);
2112
+ return required === void 0 ? [] : [{
2113
+ operation,
2114
+ operationIndex: start + offset,
2115
+ required
2116
+ }];
2117
+ }));
2118
+ }
2119
+ /**
2120
+ * A runner failure's summary and reports for the rows that columns becoming required have no value
2121
+ * in. The failed operation's marks are counted first, and the first of them with such rows is the
2122
+ * one the summary names; undefined when none has any. The other marks of the same migration are
2123
+ * counted after it, until a count fails, such as for a column an earlier operation adds, so that
2124
+ * the advice can name every field that needs a value.
2125
+ */
2126
+ async function rowsWithoutValueFailure(input) {
2127
+ const report = (mark, rows) => ({
2128
+ field: fieldOfColumn(input.contract, mark.required.table, mark.required.column),
2129
+ reason: mark.required.reason,
2130
+ rows,
2131
+ operationIndex: mark.operationIndex
2132
+ });
2133
+ for (const mark of input.failed) {
2134
+ const rows = await input.count(mark);
2135
+ if (rows === 0) continue;
2136
+ const reports = [report(mark, rows)];
2137
+ for (const other of input.others) {
2138
+ if (other.required.table === mark.required.table && other.required.column === mark.required.column) continue;
2139
+ let otherRows;
2140
+ try {
2141
+ otherRows = await input.count(other);
2142
+ } catch {
2143
+ break;
2144
+ }
2145
+ if (otherRows > 0) reports.push(report(other, otherRows));
2146
+ }
2147
+ return {
2148
+ summary: rowsWithoutValueSummary(mark.required, rows),
2149
+ reports
2150
+ };
2151
+ }
2152
+ }
2153
+ /** Keywords that end an expression and continue the statement around it. */
2154
+ const STATEMENT_KEYWORDS = /* @__PURE__ */ new Set([
2155
+ "FROM",
2156
+ "WHERE",
2157
+ "UNION",
2158
+ "INTERSECT",
2159
+ "EXCEPT",
2160
+ "GROUP",
2161
+ "ORDER",
2162
+ "HAVING",
2163
+ "LIMIT",
2164
+ "RETURNING",
2165
+ "WINDOW"
2166
+ ]);
2167
+ const WORD = /[A-Za-z_][A-Za-z0-9_$]*/y;
2168
+ const DOLLAR_QUOTE = /\$[A-Za-z_]*\$/y;
2169
+ function quoteAt(text, index, quoting) {
2170
+ return quoting.find((quote) => text.slice(index, index + quote.open.length).toUpperCase() === quote.open.toUpperCase());
2171
+ }
2172
+ function endOfQuote(text, start, quote) {
2173
+ let index = start + quote.open.length;
2174
+ while (index < text.length) {
2175
+ if (quote.backslashEscapes && text[index] === "\\") {
2176
+ index += 2;
2177
+ continue;
2178
+ }
2179
+ if (text.startsWith(quote.close, index)) {
2180
+ const after = index + quote.close.length;
2181
+ if (!quote.doubledCloseEscapes || !text.startsWith(quote.close, after)) return after;
2182
+ index = after + quote.close.length;
2183
+ continue;
2184
+ }
2185
+ index += 1;
2186
+ }
2187
+ }
2188
+ /**
2189
+ * Returns what in `text` could end or extend the statement a migration writes it into, such as the
2190
+ * conversion of an `ALTER COLUMN … USING` clause or a column of an `INSERT … SELECT` list, or
2191
+ * undefined when it finds nothing. Text inside the quotes of `quoting` may hold anything; outside
2192
+ * them the text may not hold a semicolon, a SQL comment, dollar quoting, or, outside parentheses
2193
+ * and brackets, a comma or a keyword that would end the expression. `FROM` directly after
2194
+ * `DISTINCT`, as in `IS DISTINCT FROM`, belongs to the expression. It checks for these mistakes
2195
+ * only; it does not parse the SQL.
2196
+ */
2197
+ function checkSqlExpressionText(text, quoting) {
2198
+ let depth = 0;
2199
+ let index = 0;
2200
+ let previousWord;
2201
+ while (index < text.length) {
2202
+ const character = text[index] ?? "";
2203
+ const quote = quoteAt(text, index, quoting);
2204
+ if (quote !== void 0) {
2205
+ const end = endOfQuote(text, index, quote);
2206
+ if (end === void 0) return "a quote that is not closed";
2207
+ index = end;
2208
+ previousWord = void 0;
2209
+ continue;
2210
+ }
2211
+ if (character === ";") return "a semicolon outside a quoted literal";
2212
+ if (text.startsWith("--", index) || text.startsWith("/*", index)) return "a SQL comment";
2213
+ DOLLAR_QUOTE.lastIndex = index;
2214
+ if (character === "$" && DOLLAR_QUOTE.test(text)) return "dollar quoting";
2215
+ if (character === "," && depth === 0) return "a comma outside parentheses";
2216
+ if (character === "(" || character === "[") depth += 1;
2217
+ if (character === ")" || character === "]") {
2218
+ depth -= 1;
2219
+ if (depth < 0) return "parentheses that do not match";
2220
+ }
2221
+ WORD.lastIndex = index;
2222
+ const word = /[A-Za-z_]/.test(character) ? WORD.exec(text)?.[0].toUpperCase() : void 0;
2223
+ if (word !== void 0) {
2224
+ if (depth === 0 && STATEMENT_KEYWORDS.has(word) && !(word === "FROM" && previousWord === "DISTINCT")) return `the keyword ${word} outside parentheses`;
2225
+ previousWord = word;
2226
+ index += word.length;
2227
+ continue;
2228
+ }
2229
+ if (!/\s/.test(character)) previousWord = void 0;
2230
+ index += 1;
2231
+ }
2232
+ return depth === 0 ? void 0 : "parentheses that do not match";
2233
+ }
2234
+ /** Whether `slot` is a placeholder the user has not filled yet. */
2235
+ function isUnfilledSlot(slot) {
2236
+ return slot?.kind === "placeholder";
2237
+ }
2238
+ /** The SQL of a written slot; undefined for an unfilled one or none. */
2239
+ function sqlOfSlot(slot) {
2240
+ return slot?.kind === "sql" ? slot.sql : void 0;
2241
+ }
2242
+ /** The slot as `migration.ts` writes it: SQL text written through `sql`, or a `placeholder(...)` call. */
2243
+ function slotSource(slot, sql) {
2244
+ return slot.kind === "placeholder" ? `placeholder(${jsonToTsSource(slot.slot)})` : sql.source(slot.sql);
2245
+ }
1964
2246
  /** `moduleSpecifier` is the module the generated file imports `sql` from. */
1965
2247
  function createSqlTextSources(moduleSpecifier) {
1966
2248
  let usesTag = false;
@@ -2052,6 +2334,44 @@ function detectTableNameCaseChanges(input) {
2052
2334
  }
2053
2335
  return conflicts;
2054
2336
  }
2337
+ /**
2338
+ * Whether a required column the plan adds to a table with rows may take one temporary value in
2339
+ * every row. Not when it is in the primary key, a unique constraint or a foreign key, which one
2340
+ * value in every row would break, and not when its values come from a value set, since no one value
2341
+ * stands for every member. Such a column is added for an empty table only.
2342
+ */
2343
+ function columnTakesTemporaryValue(table, column) {
2344
+ return table.columns[column]?.valueSet === void 0 && !(table.primaryKey?.columns.includes(column) ?? false) && !table.uniques.some(({ columns }) => columns.includes(column)) && !table.foreignKeys.some(({ source }) => source.columns.includes(column));
2345
+ }
2346
+ const ConvertedColumnMeta = type({ convertedColumn: {
2347
+ table: "string",
2348
+ column: "string",
2349
+ by: "'cast' | 'conversion'"
2350
+ } });
2351
+ /**
2352
+ * The meta of a step that converts the values of `column` in `table` to the column's new type, or
2353
+ * checks that it did. When the step fails, the runner names the field that stores the column.
2354
+ */
2355
+ function convertedColumnMeta(table, column, by) {
2356
+ return { convertedColumn: {
2357
+ table,
2358
+ column,
2359
+ by
2360
+ } };
2361
+ }
2362
+ /** The column a step converts to its new type, as {@link convertedColumnMeta} marks it. */
2363
+ function convertedColumnOf(step) {
2364
+ const meta = ConvertedColumnMeta(step.meta ?? {});
2365
+ return meta instanceof type.errors ? void 0 : meta.convertedColumn;
2366
+ }
2367
+ /**
2368
+ * The field of `contract` whose column a failed step converts, or undefined when the step
2369
+ * converts no column, no field stores the column, or tables of two storage namespaces share its name.
2370
+ */
2371
+ function unconvertedFieldOf(step, contract) {
2372
+ const converted = convertedColumnOf(step);
2373
+ return converted === void 0 ? void 0 : fieldOfColumn(contract, converted.table, converted.column);
2374
+ }
2055
2375
  function temporalStringAuthoringPresets(input) {
2056
2376
  const presets = temporalAuthoringPresets(input);
2057
2377
  return {
@@ -2099,6 +2419,6 @@ function temporalCodecPresetWithPrecision(input) {
2099
2419
  }
2100
2420
  var control_default = new SqlFamilyDescriptor();
2101
2421
  //#endregion
2102
- export { temporalCodecPresetWithPrecision as A, resolveColumnRenameAgainst as C, sqlTypeLookupsOf as D, runnerSuccess as E, unknownCallNames as M, unmatchedColumnRename as N, storageNameOfOperation as O, unmatchedTableRename as P, plannerSuccess as S, runnerFailure as T, partitionIssuesByControlPolicy as _, contractNamespaceToSchemaIR as a, planStatements as b, control_default as c, detectDestructiveChanges as d, detectTableNameCaseChanges as f, partitionCallsByControlPolicy as g, modelRenameStorageEffect as h, assembleAuthoringContributions as i, temporalStringAuthoringPresets as j, subjectsOfCalls as k, createMigrationPlan as l, fieldRenameStorageEffect as m, INIT_ADDITIVE_POLICY as n, contractToSchemaIR as o, fieldEventStorage as p, TABLE_NAME_CASE_CHANGED_CODE as r, controlPolicyForCall as s, COLUMN_RENAME_UNMATCHED_CODE as t, createSqlTextSources as u, planFieldEventCalls as v, resolveTableRenameAgainst as w, plannerFailure as x, planFieldEventOperations as y };
2422
+ export { plannerFailure as A, runnerSuccess as B, isUnfilledSlot as C, planFieldEventCalls as D, partitionIssuesByControlPolicy as E, resolveColumnRenameAgainst as F, subjectsOfCalls as G, sqlOfSlot as H, resolveTableRenameAgainst as I, unconvertedFieldOf as J, temporalCodecPresetWithPrecision as K, rowsWithoutValueFailure as L, requiredColumnMeta as M, requiredColumnOf as N, planFieldEventOperations as O, requiredColumnsOfMigration as P, rowsWithoutValueSummary as R, fieldStatementColumns as S, partitionCallsByControlPolicy as T, sqlTypeLookupsOf as U, slotSource as V, storageNameOfOperation as W, unmatchedColumnRename as X, unknownCallNames as Y, unmatchedTableRename as Z, detectDestructiveChanges as _, assembleAuthoringContributions as a, fieldOfColumn as b, columnTakesTemporaryValue as c, controlPolicyForCall as d, control_default as f, createSqlTextSources as g, createMigrationPlan as h, appliedStatementsInOrder as i, plannerSuccess as j, planStatements as k, contractNamespaceToSchemaIR as l, convertedColumnOf as m, INIT_ADDITIVE_POLICY as n, backfillOfDefaultedField as o, convertedColumnMeta as p, temporalStringAuthoringPresets as q, TABLE_NAME_CASE_CHANGED_CODE as r, checkSqlExpressionText as s, COLUMN_RENAME_UNMATCHED_CODE as t, contractToSchemaIR as u, detectTableNameCaseChanges as v, modelRenameStorageEffect as w, fieldRenameStorageEffect as x, fieldEventStorage as y, runnerFailure as z };
2103
2423
 
2104
- //# sourceMappingURL=control-uICV4VAt.mjs.map
2424
+ //# sourceMappingURL=control-Bvnz4Uk4.mjs.map