rake-db 2.3.10 → 2.3.12

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # rake-db
2
2
 
3
+ ## 2.3.12
4
+
5
+ ### Patch Changes
6
+
7
+ - Handle table ordering by foreign key when pulling db
8
+ - Updated dependencies
9
+ - pqb@0.9.7
10
+
11
+ ## 2.3.11
12
+
13
+ ### Patch Changes
14
+
15
+ - Add generating extension to db pull
16
+
3
17
  ## 2.3.10
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -311,7 +311,7 @@ declare class MigrationBase {
311
311
  }
312
312
  declare const runCodeUpdater: (migration: MigrationBase, ast: RakeDbAst) => Promise<void> | undefined;
313
313
 
314
- declare type RakeDbAst = RakeDbAst.Table | RakeDbAst.ChangeTable | RakeDbAst.RenameTable | RakeDbAst.Schema | RakeDbAst.Extension;
314
+ declare type RakeDbAst = RakeDbAst.Table | RakeDbAst.ChangeTable | RakeDbAst.RenameTable | RakeDbAst.Schema | RakeDbAst.Extension | RakeDbAst.ForeignKey;
315
315
  declare namespace RakeDbAst {
316
316
  type Table = {
317
317
  type: 'table';
@@ -387,6 +387,12 @@ declare namespace RakeDbAst {
387
387
  ifExists?: boolean;
388
388
  ifNotExists?: boolean;
389
389
  };
390
+ type ForeignKey = {
391
+ type: 'foreignKey';
392
+ action: 'create';
393
+ tableSchema?: string;
394
+ tableName: string;
395
+ } & TableData.ForeignKey;
390
396
  }
391
397
 
392
398
  declare type Db = DbResult<typeof columnTypes>;
package/dist/index.js CHANGED
@@ -1030,10 +1030,10 @@ class MigrationBase {
1030
1030
  return createSchema$1(this, !this.up, schemaName);
1031
1031
  }
1032
1032
  createExtension(name, options = {}) {
1033
- return createExtension(this, this.up, name, options);
1033
+ return createExtension$1(this, this.up, name, options);
1034
1034
  }
1035
1035
  dropExtension(name, options = {}) {
1036
- return createExtension(this, !this.up, name, options);
1036
+ return createExtension$1(this, !this.up, name, options);
1037
1037
  }
1038
1038
  async tableExists(tableName) {
1039
1039
  return queryExists(this, {
@@ -1095,7 +1095,7 @@ const createSchema$1 = async (migration, up, name) => {
1095
1095
  );
1096
1096
  await runCodeUpdater(migration, ast);
1097
1097
  };
1098
- const createExtension = async (migration, up, name, options) => {
1098
+ const createExtension$1 = async (migration, up, name, options) => {
1099
1099
  const ast = __spreadValues$2({
1100
1100
  type: "extension",
1101
1101
  action: up ? "create" : "drop",
@@ -1718,24 +1718,8 @@ const fkeyActionMap = {
1718
1718
  };
1719
1719
  const structureToAst = async (db) => {
1720
1720
  const ast = [];
1721
- const [
1722
- schemas,
1723
- tables,
1724
- allColumns,
1725
- allPrimaryKeys,
1726
- allIndexes,
1727
- allForeignKeys,
1728
- extensions
1729
- ] = await Promise.all([
1730
- db.getSchemas(),
1731
- db.getTables(),
1732
- db.getColumns(),
1733
- db.getPrimaryKeys(),
1734
- db.getIndexes(),
1735
- db.getForeignKeys(),
1736
- db.getExtensions()
1737
- ]);
1738
- for (const name of schemas) {
1721
+ const data = await getData(db);
1722
+ for (const name of data.schemas) {
1739
1723
  if (name === "public")
1740
1724
  continue;
1741
1725
  ast.push({
@@ -1744,108 +1728,51 @@ const structureToAst = async (db) => {
1744
1728
  name
1745
1729
  });
1746
1730
  }
1747
- for (const table of tables) {
1748
- const { schemaName, name } = table;
1749
- if (name === "schemaMigrations")
1750
- continue;
1751
- const belongsToTable = makeBelongsToTable(schemaName, name);
1752
- const columns = allColumns.filter(belongsToTable);
1753
- const primaryKey = allPrimaryKeys.find(belongsToTable);
1754
- const tableIndexes = allIndexes.filter(belongsToTable);
1755
- const tableForeignKeys = allForeignKeys.filter(belongsToTable);
1756
- const shape = {};
1757
- for (let item of columns) {
1758
- const isSerial = getIsSerial(item);
1759
- if (isSerial) {
1760
- item = __spreadProps(__spreadValues({}, item), { default: void 0 });
1761
- }
1762
- const klass = pqb.columnsByType[getColumnType(item, isSerial)];
1763
- if (!klass) {
1764
- throw new Error(`Column type \`${item.type}\` is not supported`);
1731
+ const pendingTables = {};
1732
+ for (const table of data.tables) {
1733
+ const key = `${table.schemaName}.${table.name}`;
1734
+ const dependsOn = /* @__PURE__ */ new Set();
1735
+ for (const fk of data.foreignKeys) {
1736
+ if (fk.schemaName !== table.schemaName || fk.tableName !== table.name)
1737
+ continue;
1738
+ const otherKey = `${fk.foreignTableSchemaName}.${fk.foreignTableName}`;
1739
+ if (otherKey !== key) {
1740
+ dependsOn.add(otherKey);
1765
1741
  }
1766
- let column = pqb.instantiateColumn(klass, item);
1767
- if ((primaryKey == null ? void 0 : primaryKey.columnNames.length) === 1 && (primaryKey == null ? void 0 : primaryKey.columnNames[0]) === item.name) {
1768
- column = column.primaryKey();
1769
- }
1770
- const indexes = tableIndexes.filter(
1771
- (it) => it.columns.length === 1 && "column" in it.columns[0] && it.columns[0].column === item.name
1772
- );
1773
- for (const index of indexes) {
1774
- const options = index.columns[0];
1775
- column = column.index({
1776
- collate: options.collate,
1777
- opclass: options.opclass,
1778
- order: options.order,
1779
- name: index.name !== getIndexName(name, index.columns) ? index.name : void 0,
1780
- using: index.using === "btree" ? void 0 : index.using,
1781
- unique: index.isUnique,
1782
- include: index.include,
1783
- with: index.with,
1784
- tablespace: index.tablespace,
1785
- where: index.where
1786
- });
1787
- }
1788
- const foreignKeys = tableForeignKeys.filter(
1789
- (it) => it.columnNames.length === 1 && it.columnNames[0] === item.name
1790
- );
1791
- for (const foreignKey of foreignKeys) {
1792
- column = column.foreignKey(
1793
- foreignKey.foreignTableName,
1794
- foreignKey.foreignColumnNames[0],
1795
- {
1796
- name: foreignKey.name && foreignKey.name !== getForeignKeyName(name, foreignKey.columnNames) ? foreignKey.name : void 0,
1797
- match: matchMap[foreignKey.match],
1798
- onUpdate: fkeyActionMap[foreignKey.onUpdate],
1799
- onDelete: fkeyActionMap[foreignKey.onDelete]
1800
- }
1801
- );
1742
+ }
1743
+ pendingTables[key] = { table, dependsOn };
1744
+ }
1745
+ for (const key in pendingTables) {
1746
+ const { table, dependsOn } = pendingTables[key];
1747
+ if (!dependsOn.size) {
1748
+ pushTableAst(ast, data, table, pendingTables);
1749
+ }
1750
+ }
1751
+ const outerFKeys = [];
1752
+ for (const key in pendingTables) {
1753
+ const innerFKeys = [];
1754
+ const { table } = pendingTables[key];
1755
+ for (const fkey of data.foreignKeys) {
1756
+ if (fkey.schemaName !== table.schemaName || fkey.tableName !== table.name)
1757
+ continue;
1758
+ const otherKey = `${fkey.foreignTableSchemaName}.${fkey.foreignTableName}`;
1759
+ if (!pendingTables[otherKey] || otherKey === key) {
1760
+ innerFKeys.push(fkey);
1761
+ } else {
1762
+ outerFKeys.push([fkey, table]);
1802
1763
  }
1803
- shape[item.name] = column;
1804
1764
  }
1805
- ast.push({
1806
- type: "table",
1765
+ pushTableAst(ast, data, table, pendingTables, innerFKeys);
1766
+ }
1767
+ for (const [fkey, table] of outerFKeys) {
1768
+ ast.push(__spreadProps(__spreadValues({}, foreignKeyToAst(fkey)), {
1769
+ type: "foreignKey",
1807
1770
  action: "create",
1808
- schema: schemaName === "public" ? void 0 : schemaName,
1809
- comment: table.comment,
1810
- name,
1811
- shape,
1812
- noPrimaryKey: primaryKey ? "error" : "ignore",
1813
- primaryKey: primaryKey && primaryKey.columnNames.length > 1 ? {
1814
- columns: primaryKey.columnNames,
1815
- options: primaryKey.name === `${name}_pkey` ? void 0 : { name: primaryKey.name }
1816
- } : void 0,
1817
- indexes: tableIndexes.filter(
1818
- (index) => index.columns.length > 1 || index.columns.some((it) => "expression" in it)
1819
- ).map((index) => ({
1820
- columns: index.columns.map((it) => __spreadProps(__spreadValues({}, "column" in it ? { column: it.column } : { expression: it.expression }), {
1821
- collate: it.collate,
1822
- opclass: it.opclass,
1823
- order: it.order
1824
- })),
1825
- options: {
1826
- name: index.name !== getIndexName(name, index.columns) ? index.name : void 0,
1827
- using: index.using === "btree" ? void 0 : index.using,
1828
- unique: index.isUnique,
1829
- include: index.include,
1830
- with: index.with,
1831
- tablespace: index.tablespace,
1832
- where: index.where
1833
- }
1834
- })),
1835
- foreignKeys: tableForeignKeys.filter((it) => it.columnNames.length > 1).map((it) => ({
1836
- columns: it.columnNames,
1837
- fnOrTable: it.foreignTableName,
1838
- foreignColumns: it.foreignColumnNames,
1839
- options: {
1840
- name: it.name && it.name !== getForeignKeyName(name, it.columnNames) ? it.name : void 0,
1841
- match: matchMap[it.match],
1842
- onUpdate: fkeyActionMap[it.onUpdate],
1843
- onDelete: fkeyActionMap[it.onDelete]
1844
- }
1845
- }))
1846
- });
1771
+ tableSchema: table.schemaName === "public" ? void 0 : table.schemaName,
1772
+ tableName: fkey.tableName
1773
+ }));
1847
1774
  }
1848
- for (const it of extensions) {
1775
+ for (const it of data.extensions) {
1849
1776
  ast.push({
1850
1777
  type: "extension",
1851
1778
  action: "create",
@@ -1856,6 +1783,34 @@ const structureToAst = async (db) => {
1856
1783
  }
1857
1784
  return ast;
1858
1785
  };
1786
+ const getData = async (db) => {
1787
+ const [
1788
+ schemas,
1789
+ tables,
1790
+ columns,
1791
+ primaryKeys,
1792
+ indexes,
1793
+ foreignKeys,
1794
+ extensions
1795
+ ] = await Promise.all([
1796
+ db.getSchemas(),
1797
+ db.getTables(),
1798
+ db.getColumns(),
1799
+ db.getPrimaryKeys(),
1800
+ db.getIndexes(),
1801
+ db.getForeignKeys(),
1802
+ db.getExtensions()
1803
+ ]);
1804
+ return {
1805
+ schemas,
1806
+ tables,
1807
+ columns,
1808
+ primaryKeys,
1809
+ indexes,
1810
+ foreignKeys,
1811
+ extensions
1812
+ };
1813
+ };
1859
1814
  const makeBelongsToTable = (schema, table) => (item) => item.schemaName === schema && item.tableName === table;
1860
1815
  const getIsSerial = (item) => {
1861
1816
  if (item.type === "int2" || item.type === "int4" || item.type === "int8") {
@@ -1873,16 +1828,134 @@ const getColumnType = (item, isSerial) => {
1873
1828
  }
1874
1829
  return item.type;
1875
1830
  };
1831
+ const pushTableAst = (ast, data, table, pendingTables, innerFKeys = data.foreignKeys) => {
1832
+ const { schemaName, name } = table;
1833
+ const key = `${schemaName}.${table.name}`;
1834
+ delete pendingTables[key];
1835
+ if (name === "schemaMigrations")
1836
+ return;
1837
+ const belongsToTable = makeBelongsToTable(schemaName, name);
1838
+ const columns = data.columns.filter(belongsToTable);
1839
+ const primaryKey = data.primaryKeys.find(belongsToTable);
1840
+ const tableIndexes = data.indexes.filter(belongsToTable);
1841
+ const tableForeignKeys = innerFKeys.filter(belongsToTable);
1842
+ const shape = {};
1843
+ for (let item of columns) {
1844
+ const isSerial = getIsSerial(item);
1845
+ if (isSerial) {
1846
+ item = __spreadProps(__spreadValues({}, item), { default: void 0 });
1847
+ }
1848
+ const klass = pqb.columnsByType[getColumnType(item, isSerial)];
1849
+ if (!klass) {
1850
+ throw new Error(`Column type \`${item.type}\` is not supported`);
1851
+ }
1852
+ let column = pqb.instantiateColumn(klass, item);
1853
+ if ((primaryKey == null ? void 0 : primaryKey.columnNames.length) === 1 && (primaryKey == null ? void 0 : primaryKey.columnNames[0]) === item.name) {
1854
+ column = column.primaryKey();
1855
+ }
1856
+ const indexes = tableIndexes.filter(
1857
+ (it) => it.columns.length === 1 && "column" in it.columns[0] && it.columns[0].column === item.name
1858
+ );
1859
+ for (const index of indexes) {
1860
+ const options = index.columns[0];
1861
+ column = column.index({
1862
+ collate: options.collate,
1863
+ opclass: options.opclass,
1864
+ order: options.order,
1865
+ name: index.name !== getIndexName(name, index.columns) ? index.name : void 0,
1866
+ using: index.using === "btree" ? void 0 : index.using,
1867
+ unique: index.isUnique,
1868
+ include: index.include,
1869
+ with: index.with,
1870
+ tablespace: index.tablespace,
1871
+ where: index.where
1872
+ });
1873
+ }
1874
+ const foreignKeys = tableForeignKeys.filter(
1875
+ (it) => it.columnNames.length === 1 && it.columnNames[0] === item.name
1876
+ );
1877
+ for (const foreignKey of foreignKeys) {
1878
+ column = column.foreignKey(
1879
+ foreignKey.foreignTableName,
1880
+ foreignKey.foreignColumnNames[0],
1881
+ {
1882
+ name: foreignKey.name && foreignKey.name !== getForeignKeyName(name, foreignKey.columnNames) ? foreignKey.name : void 0,
1883
+ match: matchMap[foreignKey.match],
1884
+ onUpdate: fkeyActionMap[foreignKey.onUpdate],
1885
+ onDelete: fkeyActionMap[foreignKey.onDelete]
1886
+ }
1887
+ );
1888
+ }
1889
+ shape[item.name] = column;
1890
+ }
1891
+ ast.push({
1892
+ type: "table",
1893
+ action: "create",
1894
+ schema: schemaName === "public" ? void 0 : schemaName,
1895
+ comment: table.comment,
1896
+ name,
1897
+ shape,
1898
+ noPrimaryKey: primaryKey ? "error" : "ignore",
1899
+ primaryKey: primaryKey && primaryKey.columnNames.length > 1 ? {
1900
+ columns: primaryKey.columnNames,
1901
+ options: primaryKey.name === `${name}_pkey` ? void 0 : { name: primaryKey.name }
1902
+ } : void 0,
1903
+ indexes: tableIndexes.filter(
1904
+ (index) => index.columns.length > 1 || index.columns.some((it) => "expression" in it)
1905
+ ).map((index) => ({
1906
+ columns: index.columns.map((it) => __spreadProps(__spreadValues({}, "column" in it ? { column: it.column } : { expression: it.expression }), {
1907
+ collate: it.collate,
1908
+ opclass: it.opclass,
1909
+ order: it.order
1910
+ })),
1911
+ options: {
1912
+ name: index.name !== getIndexName(name, index.columns) ? index.name : void 0,
1913
+ using: index.using === "btree" ? void 0 : index.using,
1914
+ unique: index.isUnique,
1915
+ include: index.include,
1916
+ with: index.with,
1917
+ tablespace: index.tablespace,
1918
+ where: index.where
1919
+ }
1920
+ })),
1921
+ foreignKeys: tableForeignKeys.filter((it) => it.columnNames.length > 1).map(foreignKeyToAst)
1922
+ });
1923
+ for (const otherKey in pendingTables) {
1924
+ const item = pendingTables[otherKey];
1925
+ if (item.dependsOn.delete(key) && item.dependsOn.size === 0) {
1926
+ pushTableAst(ast, data, item.table, pendingTables);
1927
+ }
1928
+ }
1929
+ };
1930
+ const foreignKeyToAst = (fkey) => ({
1931
+ columns: fkey.columnNames,
1932
+ fnOrTable: fkey.foreignTableName,
1933
+ foreignColumns: fkey.foreignColumnNames,
1934
+ options: {
1935
+ name: fkey.name && fkey.name !== getForeignKeyName(fkey.tableName, fkey.columnNames) ? fkey.name : void 0,
1936
+ match: matchMap[fkey.match],
1937
+ onUpdate: fkeyActionMap[fkey.onUpdate],
1938
+ onDelete: fkeyActionMap[fkey.onDelete]
1939
+ }
1940
+ });
1876
1941
 
1877
1942
  const astToMigration = (ast) => {
1878
1943
  const code = [];
1879
1944
  for (const item of ast) {
1880
1945
  if (item.type === "schema" && item.action === "create") {
1881
1946
  code.push(createSchema(item));
1947
+ } else if (item.type === "extension" && item.action === "create") {
1948
+ if (code.length)
1949
+ code.push([]);
1950
+ code.push(...createExtension(item));
1882
1951
  } else if (item.type === "table" && item.action === "create") {
1883
1952
  if (code.length)
1884
1953
  code.push([]);
1885
1954
  code.push(...createTable(item));
1955
+ } else if (item.type === "foreignKey") {
1956
+ if (code.length)
1957
+ code.push([]);
1958
+ code.push(...createForeignKey(item));
1886
1959
  }
1887
1960
  }
1888
1961
  if (!code.length)
@@ -1897,6 +1970,21 @@ ${pqb.codeToString(code, " ", " ")}
1897
1970
  const createSchema = (ast) => {
1898
1971
  return `await db.createSchema(${pqb.singleQuote(ast.name)});`;
1899
1972
  };
1973
+ const createExtension = (ast) => {
1974
+ const code = [`await db.createExtension(${pqb.singleQuote(ast.name)}`];
1975
+ if (ast.schema || ast.version) {
1976
+ pqb.addCode(code, ", {");
1977
+ if (ast.schema) {
1978
+ code.push([`schema: ${pqb.singleQuote(ast.schema)},`]);
1979
+ }
1980
+ if (ast.version) {
1981
+ code.push([`version: ${pqb.singleQuote(ast.version)},`]);
1982
+ }
1983
+ pqb.addCode(code, "}");
1984
+ }
1985
+ pqb.addCode(code, ")");
1986
+ return code;
1987
+ };
1900
1988
  const createTable = (ast) => {
1901
1989
  const code = [];
1902
1990
  pqb.addCode(code, `await db.createTable(${quoteSchemaTable(ast)}, (t) => ({`);
@@ -1932,6 +2020,19 @@ const isTimestamp = (column) => {
1932
2020
  const { default: def } = column.data;
1933
2021
  return column instanceof pqb.TimestampColumn && !column.data.isNullable && def && typeof def === "object" && pqb.isRaw(def) && def.__raw === "now()";
1934
2022
  };
2023
+ const createForeignKey = (item) => {
2024
+ return [
2025
+ `await db.addForeignKey(`,
2026
+ [
2027
+ `${quoteSchemaTable({
2028
+ schema: item.tableSchema,
2029
+ name: item.tableName
2030
+ })},`,
2031
+ ...pqb.foreignKeyArgsToCode(item)
2032
+ ],
2033
+ ");"
2034
+ ];
2035
+ };
1935
2036
 
1936
2037
  const pullDbStructure = async (options, config) => {
1937
2038
  const adapter = new pqb.Adapter(options);