orchid-orm 1.38.0 → 1.38.2

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.
@@ -1,6 +1,6 @@
1
1
  import { promptSelect, colors, getSchemaAndTableFromName, getDbTableColumnsChecks, dbColumnToAst, instantiateDbColumn, concatSchemaAndName, encodeColumnDefault, getIndexName, getExcludeName, getConstraintName, tableToAst, getDbStructureTableData, makeDomainsMap, astToMigration, createMigrationInterface, introspectDbSchema, exhaustive, pluralize, makeStructureToAstCtx, makeFileVersion, writeMigrationFile, migrate, structureToAst, saveMigratedVersion, rakeDbCommands } from 'rake-db';
2
2
  export * from 'rake-db';
3
- import { toSnakeCase, deepCompare, toArray, addCode, codeToString, toCamelCase, toPascalCase, getImportPath, singleQuote, quoteObjectKey, pathToLog } from 'orchid-core';
3
+ import { toSnakeCase, deepCompare, emptyArray, toArray, addCode, codeToString, toCamelCase, toPascalCase, getImportPath, singleQuote, quoteObjectKey, pathToLog } from 'orchid-core';
4
4
  import { EnumColumn, ArrayColumn, DomainColumn, RawSQL, VirtualColumn, UnknownColumn, defaultSchemaConfig, columnsShapeToCode, pushTableDataCode, Adapter } from 'pqb';
5
5
  import path from 'node:path';
6
6
  import { pathToFileURL } from 'url';
@@ -14,23 +14,30 @@ const compareSqlExpressions = async (tableExpressions, adapter) => {
14
14
  tableExpressions.map(async ({ source, compare, handle }) => {
15
15
  const viewName = `orchidTmpView${id++}`;
16
16
  const values = [];
17
+ let result;
17
18
  try {
18
- const sql = `CREATE TEMPORARY VIEW ${viewName} AS (SELECT ${compare.map(
19
- ({ inDb: inDb2, inCode }, i) => `${inDb2} AS "*inDb-${i}*", ${inCode.map(
20
- (s, j) => `(${typeof s === "string" ? s : s.toSQL({ values })}) "*inCode-${i}-${j}*"`
21
- ).join(", ")}`
22
- ).join(", ")} FROM ${source})`;
23
- await adapter.query({ text: sql, values });
24
- } catch (err) {
19
+ const results = await adapter.query({
20
+ // It is important to run `CREATE TEMPORARY VIEW` and `DROP VIEW` on the same db connection,
21
+ // that's why SQLs are combined into a single query.
22
+ text: [
23
+ `CREATE TEMPORARY VIEW ${viewName} AS (SELECT ${compare.map(
24
+ ({ inDb: inDb2, inCode }, i) => `${inDb2} AS "*inDb-${i}*", ${inCode.map(
25
+ (s, j) => `(${typeof s === "string" ? s : s.toSQL({ values })}) "*inCode-${i}-${j}*"`
26
+ ).join(", ")}`
27
+ ).join(", ")} FROM ${source})`,
28
+ `SELECT pg_get_viewdef('${viewName}') v`,
29
+ `DROP VIEW ${viewName}`
30
+ ].join("; "),
31
+ values
32
+ });
33
+ result = results[1];
34
+ } catch {
35
+ }
36
+ if (!result) {
25
37
  handle();
26
38
  return;
27
39
  }
28
- const {
29
- rows: [{ v }]
30
- } = await adapter.query(
31
- `SELECT pg_get_viewdef('${viewName}') v`
32
- );
33
- await adapter.query(`DROP VIEW ${viewName}`);
40
+ const v = result.rows[0].v;
34
41
  let pos = 7;
35
42
  const rgx = /\s+AS\s+"\*(inDb-\d+|inCode-\d+-\d+)\*",?/g;
36
43
  let match;
@@ -618,10 +625,10 @@ const processDomains = async (ast, adapter, structureToAstCtx, domainsMap, dbStr
618
625
  typmod: -1
619
626
  }
620
627
  );
621
- if (domain.check) {
622
- dbColumn.data.check = {
623
- sql: new RawSQL([[domain.check]])
624
- };
628
+ if (domain.checks) {
629
+ dbColumn.data.checks = domain.checks.map((check) => ({
630
+ sql: new RawSQL([[check]])
631
+ }));
625
632
  }
626
633
  const dbDomain = makeComparableDomain(
627
634
  currentSchema,
@@ -632,13 +639,13 @@ const processDomains = async (ast, adapter, structureToAstCtx, domainsMap, dbStr
632
639
  const found = codeDomains.filter(
633
640
  (codeDomain) => deepCompare(dbDomain.compare, codeDomain.compare)
634
641
  );
635
- if ((domain.default || domain.check) && found.length) {
642
+ if ((domain.default || domain.checks?.length) && found.length) {
636
643
  for (const codeDomain of found) {
637
644
  holdCodeDomains.add(codeDomain);
638
645
  }
639
646
  const compare = [];
640
- pushCompare(compare, domain, found, "default");
641
- pushCompare(compare, domain, found, "check");
647
+ pushCompareDefault(compare, domain, found);
648
+ pushCompareChecks(compare, domain, found);
642
649
  const source = `(VALUES (NULL::${getColumnDbType(
643
650
  dbColumn,
644
651
  currentSchema
@@ -715,17 +722,16 @@ const makeComparableDomain = (currentSchema, schemaName, name, column) => {
715
722
  dateTimePrecision: inner.data.dateTimePrecision,
716
723
  collate: column.data.collate,
717
724
  hasDefault: column.data.default !== void 0,
718
- hasCheck: column.data.check !== void 0
725
+ hasChecks: !!column.data.checks?.length
719
726
  }
720
727
  };
721
728
  };
722
- const pushCompare = (compare, domain, found, key) => {
723
- const inDb = domain[key];
724
- if (inDb) {
729
+ const pushCompareDefault = (compare, domain, found) => {
730
+ if (domain.default) {
725
731
  compare.push({
726
- inDb,
732
+ inDb: domain.default,
727
733
  inCode: found.map((codeDomain) => {
728
- const value = codeDomain.column.data[key];
734
+ const value = codeDomain.column.data.default;
729
735
  if ("sql" in value) {
730
736
  return value.sql;
731
737
  }
@@ -734,6 +740,21 @@ const pushCompare = (compare, domain, found, key) => {
734
740
  });
735
741
  }
736
742
  };
743
+ const pushCompareChecks = (compare, domain, found) => {
744
+ if (domain.checks?.length) {
745
+ const inCode = found.flatMap(
746
+ (codeDomain) => codeDomain.column.data.checks?.map(
747
+ (check) => typeof check === "string" ? check : check.sql
748
+ ) || emptyArray
749
+ );
750
+ compare.push(
751
+ ...domain.checks.map((check) => ({
752
+ inDb: check,
753
+ inCode
754
+ }))
755
+ );
756
+ }
757
+ };
737
758
  const dropAst = (dbDomain) => ({
738
759
  type: "domain",
739
760
  action: "drop",
@@ -1211,6 +1232,7 @@ const collectCodeComparableItemsType = (config, codeItems, key) => {
1211
1232
  });
1212
1233
  };
1213
1234
  const normalizeItem = (item) => {
1235
+ if (item.using) item.using = item.using.toLowerCase();
1214
1236
  if (item.using === "btree") item.using = void 0;
1215
1237
  if (!item.unique) item.unique = void 0;
1216
1238
  if (item.nullsNotDistinct === false) item.nullsNotDistinct = void 0;
@@ -1619,12 +1641,12 @@ const processChecks = (ast, changeTableData, compareExpressions) => {
1619
1641
  if (!hasDbChecks) {
1620
1642
  if (codeChecks.length) {
1621
1643
  const constraints = add.constraints ?? (add.constraints = []);
1622
- for (const check of codeChecks) {
1623
- if (check.column && changeTableData.changingColumns[check.column]) {
1624
- const column = changeTableData.changingColumns[check.column];
1625
- column.to.data.check = check;
1626
- } else {
1627
- constraints.push({ check: check.sql, name: check.name });
1644
+ for (const codeCheck of codeChecks) {
1645
+ if (!codeCheck.column || !changeTableData.changingColumns[codeCheck.column]) {
1646
+ constraints.push({
1647
+ check: codeCheck.check.sql,
1648
+ name: codeCheck.name
1649
+ });
1628
1650
  }
1629
1651
  }
1630
1652
  }
@@ -1645,20 +1667,40 @@ const processChecks = (ast, changeTableData, compareExpressions) => {
1645
1667
  compare: [
1646
1668
  {
1647
1669
  inDb: dbCheck.expression,
1648
- inCode: codeChecks.map((check) => check.sql)
1670
+ inCode: codeChecks.map(({ check }) => check.sql)
1649
1671
  }
1650
1672
  ],
1651
1673
  handle(i) {
1652
- if (i !== void 0) return;
1653
- dropCheck(changeTableData, dbCheck, name);
1654
- if (--wait === 0 && !changeTableData.pushedAst) {
1674
+ if (i !== void 0) {
1675
+ foundCodeChecks.add(i);
1676
+ } else {
1677
+ dropCheck(changeTableData, dbCheck, name);
1678
+ }
1679
+ if (--wait !== 0) return;
1680
+ const checksToAdd = [];
1681
+ codeChecks.forEach((check, i2) => {
1682
+ if (foundCodeChecks.has(i2)) {
1683
+ if (!check.column) return;
1684
+ const change = changeTableData.changingColumns[check.column];
1685
+ if (!change) return;
1686
+ const columnChecks = change.to.data.checks;
1687
+ if (!columnChecks) return;
1688
+ const i3 = columnChecks.indexOf(check.check);
1689
+ if (i3 !== -1) {
1690
+ columnChecks.splice(i3, 1);
1691
+ }
1692
+ return;
1693
+ }
1694
+ checksToAdd.push({
1695
+ name: check.name,
1696
+ check: check.check.sql
1697
+ });
1698
+ });
1699
+ if (checksToAdd.length) {
1700
+ (add.constraints ?? (add.constraints = [])).push(...checksToAdd);
1701
+ }
1702
+ if (!changeTableData.pushedAst && (changeTableData.changeTableAst.drop.constraints?.length || add.constraints?.length)) {
1655
1703
  changeTableData.pushedAst = true;
1656
- (add.constraints ?? (add.constraints = [])).push(
1657
- ...codeChecks.filter((_, i2) => !foundCodeChecks.has(i2)).map((check) => ({
1658
- name: check.name,
1659
- check: check.sql
1660
- }))
1661
- );
1662
1704
  ast.push(changeTableData.changeTableAst);
1663
1705
  }
1664
1706
  }
@@ -1672,41 +1714,70 @@ const collectCodeChecks = ({
1672
1714
  codeTable,
1673
1715
  changeTableAst: { shape }
1674
1716
  }) => {
1717
+ const names = /* @__PURE__ */ new Set();
1675
1718
  const codeChecks = [];
1676
1719
  for (const key in codeTable.shape) {
1677
1720
  const column = codeTable.shape[key];
1678
- if (!column.data.check) continue;
1679
- const name = column.data.name ?? key;
1680
- if (checkForColumnAddOrDrop(shape, name)) continue;
1681
- codeChecks.push({
1682
- ...column.data.check,
1683
- column: name
1684
- });
1721
+ if (!column.data.checks) continue;
1722
+ const columnName = column.data.name ?? key;
1723
+ if (checkForColumnAddOrDrop(shape, columnName)) continue;
1724
+ const baseName = `${codeTable.table}_${columnName}_check`;
1725
+ codeChecks.push(
1726
+ ...column.data.checks.map((check) => {
1727
+ let name = check.name;
1728
+ if (!name) {
1729
+ name = baseName;
1730
+ let n = 0;
1731
+ while (names.has(name)) {
1732
+ name = baseName + ++n;
1733
+ }
1734
+ }
1735
+ names.add(name);
1736
+ return {
1737
+ check,
1738
+ name,
1739
+ column: columnName
1740
+ };
1741
+ })
1742
+ );
1685
1743
  }
1686
1744
  if (codeTable.internal.tableData.constraints) {
1687
1745
  for (const constraint of codeTable.internal.tableData.constraints) {
1688
1746
  const { check } = constraint;
1689
1747
  if (check) {
1690
- codeChecks.push({ sql: check, name: constraint.name });
1748
+ const baseName = `${codeTable.table}_check`;
1749
+ let name = constraint.name;
1750
+ if (!name) {
1751
+ name = baseName;
1752
+ let n = 0;
1753
+ while (names.has(name)) {
1754
+ name = baseName + ++n;
1755
+ }
1756
+ }
1757
+ names.add(name);
1758
+ codeChecks.push({
1759
+ check: { sql: check, name: constraint.name },
1760
+ name
1761
+ });
1691
1762
  }
1692
1763
  }
1693
1764
  }
1694
1765
  return codeChecks;
1695
1766
  };
1696
1767
  const dropCheck = ({ changeTableAst: { drop }, changingColumns }, dbCheck, name) => {
1697
- const constraints = drop.constraints ?? (drop.constraints = []);
1768
+ var _a;
1698
1769
  const sql = new RawSQL([
1699
1770
  [dbCheck.expression]
1700
1771
  ]);
1701
1772
  if (dbCheck.columns?.length === 1 && changingColumns[dbCheck.columns[0]]) {
1702
1773
  const column = changingColumns[dbCheck.columns[0]];
1703
1774
  column.from.data.name = "i_d";
1704
- column.from.data.check = {
1775
+ ((_a = column.from.data).checks ?? (_a.checks = [])).push({
1705
1776
  name,
1706
1777
  sql
1707
- };
1778
+ });
1708
1779
  } else {
1709
- constraints.push({
1780
+ (drop.constraints ?? (drop.constraints = [])).push({
1710
1781
  name,
1711
1782
  check: sql
1712
1783
  });
@@ -1920,7 +1991,7 @@ const addChangeTable = (dbStructure, changeTables, tableShapes, currentSchema, d
1920
1991
  const shape = {};
1921
1992
  const schema = codeTable.q.schema ?? currentSchema;
1922
1993
  changeTables.push({
1923
- codeTable,
1994
+ codeTable: cloneCodeTableForChange(codeTable),
1924
1995
  dbTable,
1925
1996
  dbTableData: getDbStructureTableData(dbStructure, dbTable),
1926
1997
  schema,
@@ -1938,6 +2009,19 @@ const addChangeTable = (dbStructure, changeTables, tableShapes, currentSchema, d
1938
2009
  });
1939
2010
  tableShapes[`${schema}.${codeTable.table}`] = shape;
1940
2011
  };
2012
+ const cloneCodeTableForChange = (codeTable) => ({
2013
+ ...codeTable,
2014
+ shape: Object.fromEntries(
2015
+ Object.entries(codeTable.shape).map(([key, column]) => {
2016
+ const cloned = Object.create(column);
2017
+ cloned.data = {
2018
+ ...cloned.data,
2019
+ checks: cloned.data.checks && [...cloned.data.checks]
2020
+ };
2021
+ return [key, cloned];
2022
+ })
2023
+ )
2024
+ });
1941
2025
  const createTableAst = (currentSchema, table) => {
1942
2026
  return {
1943
2027
  type: "table",
@@ -2106,8 +2190,8 @@ const report = (ast, config, currentSchema) => {
2106
2190
  if (column.data.foreignKeys) {
2107
2191
  counters["foreign key"] += column.data.foreignKeys.length;
2108
2192
  }
2109
- if (column.data.check) {
2110
- counters.check++;
2193
+ if (column.data.checks) {
2194
+ counters.check += column.data.checks.length;
2111
2195
  }
2112
2196
  }
2113
2197
  const summary = [];
@@ -2140,13 +2224,13 @@ const report = (ast, config, currentSchema) => {
2140
2224
  for (const change of changes) {
2141
2225
  if (change.type === "add" || change.type === "drop") {
2142
2226
  const column = change.item;
2143
- const { primaryKey, indexes, excludes, foreignKeys, check } = column.data;
2227
+ const { primaryKey, indexes, excludes, foreignKeys, checks } = column.data;
2144
2228
  inner.push(
2145
2229
  `${change.type === "add" ? green("+ add column") : red("- drop column")} ${key} ${column.data.alias ?? getColumnDbType(column, currentSchema)}${column.data.isNullable ? " nullable" : ""}${primaryKey ? " primary key" : ""}${foreignKeys ? ` references ${foreignKeys.map((fk) => {
2146
2230
  return `${fnOrTableToString(
2147
2231
  fk.fnOrTable
2148
2232
  )}(${fk.foreignColumns.join(", ")})`;
2149
- }).join(", ")}` : ""}${indexes?.length ? indexes.length === 1 ? ", has index" : `, has ${indexes.length} indexes` : ""}${excludes?.length ? excludes.length === 1 ? ", has exclude" : `, has ${excludes.length} excludes` : ""}${check ? `, checks ${check.sql.toSQL({ values: [] })}` : ""}`
2233
+ }).join(", ")}` : ""}${indexes?.length ? indexes.length === 1 ? ", has index" : `, has ${indexes.length} indexes` : ""}${excludes?.length ? excludes.length === 1 ? ", has exclude" : `, has ${excludes.length} excludes` : ""}${checks?.length ? `, checks ${checks.map((check) => check.sql.toSQL({ values: [] })).join(", ")}` : ""}`
2150
2234
  );
2151
2235
  } else if (change.type === "change") {
2152
2236
  const name = change.from.column?.data.name ?? key;