@prisma/orm-family-sql 8.0.0-rc.17-dev.37 → 8.0.0-rc.17-dev.39
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/{authoring-type-constructors-0Iv2zdwS-CjonPCuf.mjs → authoring-type-constructors-0Iv2zdwS-ZTBL7w8X.mjs} +2 -2
- package/dist/{authoring-type-constructors-0Iv2zdwS-CjonPCuf.mjs.map → authoring-type-constructors-0Iv2zdwS-ZTBL7w8X.mjs.map} +1 -1
- package/dist/{config-types-B-cnVdoD.mjs → config-types-DiCetrJe.mjs} +2 -2
- package/dist/{config-types-B-cnVdoD.mjs.map → config-types-DiCetrJe.mjs.map} +1 -1
- package/dist/{contract-builder-B1KNtOiJ.mjs → contract-builder-D84f__Oc.mjs} +2 -2
- package/dist/{contract-builder-B1KNtOiJ.mjs.map → contract-builder-D84f__Oc.mjs.map} +1 -1
- package/dist/contract-prisma7__provider.mjs +4 -4
- package/dist/contract-psl.mjs +1 -1
- package/dist/contract-psl__attribute-specs.mjs +1 -1
- package/dist/contract-psl__provider.mjs +2 -2
- package/dist/contract-ts.mjs +3 -3
- package/dist/contract-ts__config-types.mjs +1 -1
- package/dist/contract-ts__contract-builder.mjs +2 -2
- package/dist/contract.d.mts +2 -2
- package/dist/contract.mjs +2 -2
- package/dist/contract__data-type.d.mts +2 -2
- package/dist/contract__data-type.mjs +2 -2
- package/dist/{control-D4PHWMpB.d.mts → control-Bs-0JljW.d.mts} +199 -10
- package/dist/{control-D4PHWMpB.d.mts.map → control-Bs-0JljW.d.mts.map} +1 -1
- package/dist/{control-uICV4VAt.mjs → control-Bvnz4Uk4.mjs} +337 -17
- package/dist/control-Bvnz4Uk4.mjs.map +1 -0
- package/dist/{data-type-C_PI_Jsa.mjs → data-type-BgP6Wv48.mjs} +27 -5
- package/dist/{data-type-C_PI_Jsa.mjs.map → data-type-BgP6Wv48.mjs.map} +1 -1
- package/dist/{data-type-CpqSDmR_.d.mts → data-type-gKl5DBHw.d.mts} +9 -2
- package/dist/{data-type-CpqSDmR_.d.mts.map → data-type-gKl5DBHw.d.mts.map} +1 -1
- package/dist/{derived-checks-CYz041Ol-CFhXTA9K.mjs → derived-checks-CYz041Ol-TjL7rPxe.mjs} +2 -2
- package/dist/{derived-checks-CYz041Ol-CFhXTA9K.mjs.map → derived-checks-CYz041Ol-TjL7rPxe.mjs.map} +1 -1
- package/dist/family.d.mts +2 -2
- package/dist/family.mjs +3 -3
- package/dist/family__control.d.mts +2 -2
- package/dist/family__control.mjs +3 -3
- package/dist/family__diff.mjs +1 -1
- package/dist/family__pack.mjs +2 -2
- package/dist/{interpreter-0z4AxG0I-CCbqh8XA.mjs → interpreter-0z4AxG0I-CM9DULu1.mjs} +3 -3
- package/dist/{interpreter-0z4AxG0I-CCbqh8XA.mjs.map → interpreter-0z4AxG0I-CM9DULu1.mjs.map} +1 -1
- package/dist/{psl-field-resolution-D4jnVVTd-CyGA5a3e.mjs → psl-field-resolution-D4jnVVTd-B396sZmO.mjs} +2 -2
- package/dist/{psl-field-resolution-D4jnVVTd-CyGA5a3e.mjs.map → psl-field-resolution-D4jnVVTd-B396sZmO.mjs.map} +1 -1
- package/dist/{schema-verify-DIfHSB4I-Bbek1093.mjs → schema-verify-DIfHSB4I-Du0-5I8k.mjs} +2 -2
- package/dist/{schema-verify-DIfHSB4I-Bbek1093.mjs.map → schema-verify-DIfHSB4I-Du0-5I8k.mjs.map} +1 -1
- package/package.json +18 -18
- 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,
|
|
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-
|
|
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-
|
|
12
|
-
import { c as verifySqlSchemaByDiff, n as classifyDiffSubjectGranularity, o as enforceSqlDataTypeInvariants, t as classifyDiffEntityKind } from "./schema-verify-DIfHSB4I-
|
|
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
|
-
|
|
1832
|
-
dataLoss.push(keepDataAdvice === void 0 ? {
|
|
1833
|
-
operationIndex,
|
|
1834
|
-
subject
|
|
1835
|
-
} : {
|
|
1920
|
+
dataLoss.push({
|
|
1836
1921
|
operationIndex,
|
|
1837
1922
|
subject,
|
|
1838
|
-
|
|
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 {
|
|
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-
|
|
2424
|
+
//# sourceMappingURL=control-Bvnz4Uk4.mjs.map
|