rake-db 2.3.10 → 2.3.13

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { singleQuote, quote, isRaw, getRaw, toArray, columnTypes, raw, getColumnTypes, getTableData, resetTableData, ColumnType, emptyObject, TransactionAdapter, logParamToLogObject, createDb as createDb$1, Adapter, columnsByType, instantiateColumn, codeToString, addCode, quoteObjectKey, primaryKeyToCode, indexToCode, foreignKeyToCode, TimestampColumn } from 'pqb';
1
+ import { singleQuote, quote, isRaw, getRaw, toArray, columnTypes, raw, getColumnTypes, getTableData, resetTableData, ColumnType, emptyObject, TransactionAdapter, logParamToLogObject, createDb as createDb$1, Adapter, columnsByType, instantiateColumn, codeToString, addCode, quoteObjectKey, primaryKeyToCode, indexToCode, foreignKeyToCode, TimestampColumn, foreignKeyArgsToCode } from 'pqb';
2
2
  import Enquirer from 'enquirer';
3
3
  import path from 'path';
4
4
  import { readdir, mkdir, writeFile } from 'fs/promises';
@@ -901,7 +901,7 @@ const createMigrationInterface = (tx, up, options, adapterOptions, appCodeUpdate
901
901
  adapter.arrays = (q, types) => {
902
902
  return wrapWithLog(log, q, () => arrays.call(adapter, q, types));
903
903
  };
904
- const db = createDb$1({ adapter, columnTypes });
904
+ const db = createDb$1({ adapter });
905
905
  const { prototype: proto } = MigrationBase;
906
906
  for (const key of Object.getOwnPropertyNames(proto)) {
907
907
  db[key] = proto[key];
@@ -1003,10 +1003,10 @@ class MigrationBase {
1003
1003
  return createSchema$1(this, !this.up, schemaName);
1004
1004
  }
1005
1005
  createExtension(name, options = {}) {
1006
- return createExtension(this, this.up, name, options);
1006
+ return createExtension$1(this, this.up, name, options);
1007
1007
  }
1008
1008
  dropExtension(name, options = {}) {
1009
- return createExtension(this, !this.up, name, options);
1009
+ return createExtension$1(this, !this.up, name, options);
1010
1010
  }
1011
1011
  async tableExists(tableName) {
1012
1012
  return queryExists(this, {
@@ -1068,7 +1068,7 @@ const createSchema$1 = async (migration, up, name) => {
1068
1068
  );
1069
1069
  await runCodeUpdater(migration, ast);
1070
1070
  };
1071
- const createExtension = async (migration, up, name, options) => {
1071
+ const createExtension$1 = async (migration, up, name, options) => {
1072
1072
  const ast = __spreadValues$2({
1073
1073
  type: "extension",
1074
1074
  action: up ? "create" : "drop",
@@ -1111,7 +1111,7 @@ var __spreadValues$1 = (a, b) => {
1111
1111
  }
1112
1112
  return a;
1113
1113
  };
1114
- const getDb = (adapter) => createDb$1({ adapter, columnTypes });
1114
+ const getDb = (adapter) => createDb$1({ adapter });
1115
1115
  const migrateOrRollback = async (options, config, args, up) => {
1116
1116
  var _a, _b, _c, _d, _e;
1117
1117
  config = __spreadValues$1({}, config);
@@ -1691,24 +1691,8 @@ const fkeyActionMap = {
1691
1691
  };
1692
1692
  const structureToAst = async (db) => {
1693
1693
  const ast = [];
1694
- const [
1695
- schemas,
1696
- tables,
1697
- allColumns,
1698
- allPrimaryKeys,
1699
- allIndexes,
1700
- allForeignKeys,
1701
- extensions
1702
- ] = await Promise.all([
1703
- db.getSchemas(),
1704
- db.getTables(),
1705
- db.getColumns(),
1706
- db.getPrimaryKeys(),
1707
- db.getIndexes(),
1708
- db.getForeignKeys(),
1709
- db.getExtensions()
1710
- ]);
1711
- for (const name of schemas) {
1694
+ const data = await getData(db);
1695
+ for (const name of data.schemas) {
1712
1696
  if (name === "public")
1713
1697
  continue;
1714
1698
  ast.push({
@@ -1717,108 +1701,51 @@ const structureToAst = async (db) => {
1717
1701
  name
1718
1702
  });
1719
1703
  }
1720
- for (const table of tables) {
1721
- const { schemaName, name } = table;
1722
- if (name === "schemaMigrations")
1723
- continue;
1724
- const belongsToTable = makeBelongsToTable(schemaName, name);
1725
- const columns = allColumns.filter(belongsToTable);
1726
- const primaryKey = allPrimaryKeys.find(belongsToTable);
1727
- const tableIndexes = allIndexes.filter(belongsToTable);
1728
- const tableForeignKeys = allForeignKeys.filter(belongsToTable);
1729
- const shape = {};
1730
- for (let item of columns) {
1731
- const isSerial = getIsSerial(item);
1732
- if (isSerial) {
1733
- item = __spreadProps(__spreadValues({}, item), { default: void 0 });
1704
+ const pendingTables = {};
1705
+ for (const table of data.tables) {
1706
+ const key = `${table.schemaName}.${table.name}`;
1707
+ const dependsOn = /* @__PURE__ */ new Set();
1708
+ for (const fk of data.foreignKeys) {
1709
+ if (fk.schemaName !== table.schemaName || fk.tableName !== table.name)
1710
+ continue;
1711
+ const otherKey = `${fk.foreignTableSchemaName}.${fk.foreignTableName}`;
1712
+ if (otherKey !== key) {
1713
+ dependsOn.add(otherKey);
1734
1714
  }
1735
- const klass = columnsByType[getColumnType(item, isSerial)];
1736
- if (!klass) {
1737
- throw new Error(`Column type \`${item.type}\` is not supported`);
1738
- }
1739
- let column = instantiateColumn(klass, item);
1740
- if ((primaryKey == null ? void 0 : primaryKey.columnNames.length) === 1 && (primaryKey == null ? void 0 : primaryKey.columnNames[0]) === item.name) {
1741
- column = column.primaryKey();
1742
- }
1743
- const indexes = tableIndexes.filter(
1744
- (it) => it.columns.length === 1 && "column" in it.columns[0] && it.columns[0].column === item.name
1745
- );
1746
- for (const index of indexes) {
1747
- const options = index.columns[0];
1748
- column = column.index({
1749
- collate: options.collate,
1750
- opclass: options.opclass,
1751
- order: options.order,
1752
- name: index.name !== getIndexName(name, index.columns) ? index.name : void 0,
1753
- using: index.using === "btree" ? void 0 : index.using,
1754
- unique: index.isUnique,
1755
- include: index.include,
1756
- with: index.with,
1757
- tablespace: index.tablespace,
1758
- where: index.where
1759
- });
1760
- }
1761
- const foreignKeys = tableForeignKeys.filter(
1762
- (it) => it.columnNames.length === 1 && it.columnNames[0] === item.name
1763
- );
1764
- for (const foreignKey of foreignKeys) {
1765
- column = column.foreignKey(
1766
- foreignKey.foreignTableName,
1767
- foreignKey.foreignColumnNames[0],
1768
- {
1769
- name: foreignKey.name && foreignKey.name !== getForeignKeyName(name, foreignKey.columnNames) ? foreignKey.name : void 0,
1770
- match: matchMap[foreignKey.match],
1771
- onUpdate: fkeyActionMap[foreignKey.onUpdate],
1772
- onDelete: fkeyActionMap[foreignKey.onDelete]
1773
- }
1774
- );
1715
+ }
1716
+ pendingTables[key] = { table, dependsOn };
1717
+ }
1718
+ for (const key in pendingTables) {
1719
+ const { table, dependsOn } = pendingTables[key];
1720
+ if (!dependsOn.size) {
1721
+ pushTableAst(ast, data, table, pendingTables);
1722
+ }
1723
+ }
1724
+ const outerFKeys = [];
1725
+ for (const key in pendingTables) {
1726
+ const innerFKeys = [];
1727
+ const { table } = pendingTables[key];
1728
+ for (const fkey of data.foreignKeys) {
1729
+ if (fkey.schemaName !== table.schemaName || fkey.tableName !== table.name)
1730
+ continue;
1731
+ const otherKey = `${fkey.foreignTableSchemaName}.${fkey.foreignTableName}`;
1732
+ if (!pendingTables[otherKey] || otherKey === key) {
1733
+ innerFKeys.push(fkey);
1734
+ } else {
1735
+ outerFKeys.push([fkey, table]);
1775
1736
  }
1776
- shape[item.name] = column;
1777
1737
  }
1778
- ast.push({
1779
- type: "table",
1738
+ pushTableAst(ast, data, table, pendingTables, innerFKeys);
1739
+ }
1740
+ for (const [fkey, table] of outerFKeys) {
1741
+ ast.push(__spreadProps(__spreadValues({}, foreignKeyToAst(fkey)), {
1742
+ type: "foreignKey",
1780
1743
  action: "create",
1781
- schema: schemaName === "public" ? void 0 : schemaName,
1782
- comment: table.comment,
1783
- name,
1784
- shape,
1785
- noPrimaryKey: primaryKey ? "error" : "ignore",
1786
- primaryKey: primaryKey && primaryKey.columnNames.length > 1 ? {
1787
- columns: primaryKey.columnNames,
1788
- options: primaryKey.name === `${name}_pkey` ? void 0 : { name: primaryKey.name }
1789
- } : void 0,
1790
- indexes: tableIndexes.filter(
1791
- (index) => index.columns.length > 1 || index.columns.some((it) => "expression" in it)
1792
- ).map((index) => ({
1793
- columns: index.columns.map((it) => __spreadProps(__spreadValues({}, "column" in it ? { column: it.column } : { expression: it.expression }), {
1794
- collate: it.collate,
1795
- opclass: it.opclass,
1796
- order: it.order
1797
- })),
1798
- options: {
1799
- name: index.name !== getIndexName(name, index.columns) ? index.name : void 0,
1800
- using: index.using === "btree" ? void 0 : index.using,
1801
- unique: index.isUnique,
1802
- include: index.include,
1803
- with: index.with,
1804
- tablespace: index.tablespace,
1805
- where: index.where
1806
- }
1807
- })),
1808
- foreignKeys: tableForeignKeys.filter((it) => it.columnNames.length > 1).map((it) => ({
1809
- columns: it.columnNames,
1810
- fnOrTable: it.foreignTableName,
1811
- foreignColumns: it.foreignColumnNames,
1812
- options: {
1813
- name: it.name && it.name !== getForeignKeyName(name, it.columnNames) ? it.name : void 0,
1814
- match: matchMap[it.match],
1815
- onUpdate: fkeyActionMap[it.onUpdate],
1816
- onDelete: fkeyActionMap[it.onDelete]
1817
- }
1818
- }))
1819
- });
1744
+ tableSchema: table.schemaName === "public" ? void 0 : table.schemaName,
1745
+ tableName: fkey.tableName
1746
+ }));
1820
1747
  }
1821
- for (const it of extensions) {
1748
+ for (const it of data.extensions) {
1822
1749
  ast.push({
1823
1750
  type: "extension",
1824
1751
  action: "create",
@@ -1829,6 +1756,34 @@ const structureToAst = async (db) => {
1829
1756
  }
1830
1757
  return ast;
1831
1758
  };
1759
+ const getData = async (db) => {
1760
+ const [
1761
+ schemas,
1762
+ tables,
1763
+ columns,
1764
+ primaryKeys,
1765
+ indexes,
1766
+ foreignKeys,
1767
+ extensions
1768
+ ] = await Promise.all([
1769
+ db.getSchemas(),
1770
+ db.getTables(),
1771
+ db.getColumns(),
1772
+ db.getPrimaryKeys(),
1773
+ db.getIndexes(),
1774
+ db.getForeignKeys(),
1775
+ db.getExtensions()
1776
+ ]);
1777
+ return {
1778
+ schemas,
1779
+ tables,
1780
+ columns,
1781
+ primaryKeys,
1782
+ indexes,
1783
+ foreignKeys,
1784
+ extensions
1785
+ };
1786
+ };
1832
1787
  const makeBelongsToTable = (schema, table) => (item) => item.schemaName === schema && item.tableName === table;
1833
1788
  const getIsSerial = (item) => {
1834
1789
  if (item.type === "int2" || item.type === "int4" || item.type === "int8") {
@@ -1846,16 +1801,134 @@ const getColumnType = (item, isSerial) => {
1846
1801
  }
1847
1802
  return item.type;
1848
1803
  };
1804
+ const pushTableAst = (ast, data, table, pendingTables, innerFKeys = data.foreignKeys) => {
1805
+ const { schemaName, name } = table;
1806
+ const key = `${schemaName}.${table.name}`;
1807
+ delete pendingTables[key];
1808
+ if (name === "schemaMigrations")
1809
+ return;
1810
+ const belongsToTable = makeBelongsToTable(schemaName, name);
1811
+ const columns = data.columns.filter(belongsToTable);
1812
+ const primaryKey = data.primaryKeys.find(belongsToTable);
1813
+ const tableIndexes = data.indexes.filter(belongsToTable);
1814
+ const tableForeignKeys = innerFKeys.filter(belongsToTable);
1815
+ const shape = {};
1816
+ for (let item of columns) {
1817
+ const isSerial = getIsSerial(item);
1818
+ if (isSerial) {
1819
+ item = __spreadProps(__spreadValues({}, item), { default: void 0 });
1820
+ }
1821
+ const klass = columnsByType[getColumnType(item, isSerial)];
1822
+ if (!klass) {
1823
+ throw new Error(`Column type \`${item.type}\` is not supported`);
1824
+ }
1825
+ let column = instantiateColumn(klass, item);
1826
+ if ((primaryKey == null ? void 0 : primaryKey.columnNames.length) === 1 && (primaryKey == null ? void 0 : primaryKey.columnNames[0]) === item.name) {
1827
+ column = column.primaryKey();
1828
+ }
1829
+ const indexes = tableIndexes.filter(
1830
+ (it) => it.columns.length === 1 && "column" in it.columns[0] && it.columns[0].column === item.name
1831
+ );
1832
+ for (const index of indexes) {
1833
+ const options = index.columns[0];
1834
+ column = column.index({
1835
+ collate: options.collate,
1836
+ opclass: options.opclass,
1837
+ order: options.order,
1838
+ name: index.name !== getIndexName(name, index.columns) ? index.name : void 0,
1839
+ using: index.using === "btree" ? void 0 : index.using,
1840
+ unique: index.isUnique,
1841
+ include: index.include,
1842
+ with: index.with,
1843
+ tablespace: index.tablespace,
1844
+ where: index.where
1845
+ });
1846
+ }
1847
+ const foreignKeys = tableForeignKeys.filter(
1848
+ (it) => it.columnNames.length === 1 && it.columnNames[0] === item.name
1849
+ );
1850
+ for (const foreignKey of foreignKeys) {
1851
+ column = column.foreignKey(
1852
+ foreignKey.foreignTableName,
1853
+ foreignKey.foreignColumnNames[0],
1854
+ {
1855
+ name: foreignKey.name && foreignKey.name !== getForeignKeyName(name, foreignKey.columnNames) ? foreignKey.name : void 0,
1856
+ match: matchMap[foreignKey.match],
1857
+ onUpdate: fkeyActionMap[foreignKey.onUpdate],
1858
+ onDelete: fkeyActionMap[foreignKey.onDelete]
1859
+ }
1860
+ );
1861
+ }
1862
+ shape[item.name] = column;
1863
+ }
1864
+ ast.push({
1865
+ type: "table",
1866
+ action: "create",
1867
+ schema: schemaName === "public" ? void 0 : schemaName,
1868
+ comment: table.comment,
1869
+ name,
1870
+ shape,
1871
+ noPrimaryKey: primaryKey ? "error" : "ignore",
1872
+ primaryKey: primaryKey && primaryKey.columnNames.length > 1 ? {
1873
+ columns: primaryKey.columnNames,
1874
+ options: primaryKey.name === `${name}_pkey` ? void 0 : { name: primaryKey.name }
1875
+ } : void 0,
1876
+ indexes: tableIndexes.filter(
1877
+ (index) => index.columns.length > 1 || index.columns.some((it) => "expression" in it)
1878
+ ).map((index) => ({
1879
+ columns: index.columns.map((it) => __spreadProps(__spreadValues({}, "column" in it ? { column: it.column } : { expression: it.expression }), {
1880
+ collate: it.collate,
1881
+ opclass: it.opclass,
1882
+ order: it.order
1883
+ })),
1884
+ options: {
1885
+ name: index.name !== getIndexName(name, index.columns) ? index.name : void 0,
1886
+ using: index.using === "btree" ? void 0 : index.using,
1887
+ unique: index.isUnique,
1888
+ include: index.include,
1889
+ with: index.with,
1890
+ tablespace: index.tablespace,
1891
+ where: index.where
1892
+ }
1893
+ })),
1894
+ foreignKeys: tableForeignKeys.filter((it) => it.columnNames.length > 1).map(foreignKeyToAst)
1895
+ });
1896
+ for (const otherKey in pendingTables) {
1897
+ const item = pendingTables[otherKey];
1898
+ if (item.dependsOn.delete(key) && item.dependsOn.size === 0) {
1899
+ pushTableAst(ast, data, item.table, pendingTables);
1900
+ }
1901
+ }
1902
+ };
1903
+ const foreignKeyToAst = (fkey) => ({
1904
+ columns: fkey.columnNames,
1905
+ fnOrTable: fkey.foreignTableName,
1906
+ foreignColumns: fkey.foreignColumnNames,
1907
+ options: {
1908
+ name: fkey.name && fkey.name !== getForeignKeyName(fkey.tableName, fkey.columnNames) ? fkey.name : void 0,
1909
+ match: matchMap[fkey.match],
1910
+ onUpdate: fkeyActionMap[fkey.onUpdate],
1911
+ onDelete: fkeyActionMap[fkey.onDelete]
1912
+ }
1913
+ });
1849
1914
 
1850
1915
  const astToMigration = (ast) => {
1851
1916
  const code = [];
1852
1917
  for (const item of ast) {
1853
1918
  if (item.type === "schema" && item.action === "create") {
1854
1919
  code.push(createSchema(item));
1920
+ } else if (item.type === "extension" && item.action === "create") {
1921
+ if (code.length)
1922
+ code.push([]);
1923
+ code.push(...createExtension(item));
1855
1924
  } else if (item.type === "table" && item.action === "create") {
1856
1925
  if (code.length)
1857
1926
  code.push([]);
1858
1927
  code.push(...createTable(item));
1928
+ } else if (item.type === "foreignKey") {
1929
+ if (code.length)
1930
+ code.push([]);
1931
+ code.push(...createForeignKey(item));
1859
1932
  }
1860
1933
  }
1861
1934
  if (!code.length)
@@ -1870,6 +1943,21 @@ ${codeToString(code, " ", " ")}
1870
1943
  const createSchema = (ast) => {
1871
1944
  return `await db.createSchema(${singleQuote(ast.name)});`;
1872
1945
  };
1946
+ const createExtension = (ast) => {
1947
+ const code = [`await db.createExtension(${singleQuote(ast.name)}`];
1948
+ if (ast.schema || ast.version) {
1949
+ addCode(code, ", {");
1950
+ if (ast.schema) {
1951
+ code.push([`schema: ${singleQuote(ast.schema)},`]);
1952
+ }
1953
+ if (ast.version) {
1954
+ code.push([`version: ${singleQuote(ast.version)},`]);
1955
+ }
1956
+ addCode(code, "}");
1957
+ }
1958
+ addCode(code, ")");
1959
+ return code;
1960
+ };
1873
1961
  const createTable = (ast) => {
1874
1962
  const code = [];
1875
1963
  addCode(code, `await db.createTable(${quoteSchemaTable(ast)}, (t) => ({`);
@@ -1905,6 +1993,19 @@ const isTimestamp = (column) => {
1905
1993
  const { default: def } = column.data;
1906
1994
  return column instanceof TimestampColumn && !column.data.isNullable && def && typeof def === "object" && isRaw(def) && def.__raw === "now()";
1907
1995
  };
1996
+ const createForeignKey = (item) => {
1997
+ return [
1998
+ `await db.addForeignKey(`,
1999
+ [
2000
+ `${quoteSchemaTable({
2001
+ schema: item.tableSchema,
2002
+ name: item.tableName
2003
+ })},`,
2004
+ ...foreignKeyArgsToCode(item)
2005
+ ],
2006
+ ");"
2007
+ ];
2008
+ };
1908
2009
 
1909
2010
  const pullDbStructure = async (options, config) => {
1910
2011
  const adapter = new Adapter(options);