rake-db 2.4.8 → 2.4.9

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.d.ts CHANGED
@@ -85,14 +85,16 @@ declare class MigrationBase {
85
85
  dropSchema(schemaName: string): Promise<void>;
86
86
  createExtension(name: string, options?: Omit<RakeDbAst.Extension, 'type' | 'action' | 'name'>): Promise<void>;
87
87
  dropExtension(name: string, options?: Omit<RakeDbAst.Extension, 'type' | 'action' | 'name' | 'values'>): Promise<void>;
88
- createEnum(name: string, values: [string, ...string[]], options?: Omit<RakeDbAst.Enum, 'type' | 'action' | 'name' | 'values'>): Promise<void>;
89
- dropEnum(name: string, values: [string, ...string[]], options?: Omit<RakeDbAst.Enum, 'type' | 'action' | 'name' | 'values'>): Promise<void>;
88
+ createEnum(name: string, values: [string, ...string[]], options?: Omit<RakeDbAst.Enum, 'type' | 'action' | 'name' | 'values' | 'schema'>): Promise<void>;
89
+ dropEnum(name: string, values: [string, ...string[]], options?: Omit<RakeDbAst.Enum, 'type' | 'action' | 'name' | 'values' | 'schema'>): Promise<void>;
90
+ createDomain(name: string, fn: (t: ColumnTypes) => ColumnType, options?: Omit<RakeDbAst.Domain, 'type' | 'action' | 'schema' | 'name' | 'baseType'>): Promise<void>;
91
+ dropDomain(name: string, fn: (t: ColumnTypes) => ColumnType, options?: Omit<RakeDbAst.Domain, 'type' | 'action' | 'schema' | 'name' | 'baseType'>): Promise<void>;
90
92
  tableExists(tableName: string): Promise<boolean>;
91
93
  columnExists(tableName: string, columnName: string): Promise<boolean>;
92
94
  constraintExists(constraintName: string): Promise<boolean>;
93
95
  }
94
96
 
95
- declare type RakeDbAst = RakeDbAst.Table | RakeDbAst.ChangeTable | RakeDbAst.RenameTable | RakeDbAst.Schema | RakeDbAst.Extension | RakeDbAst.Enum | RakeDbAst.ForeignKey;
97
+ declare type RakeDbAst = RakeDbAst.Table | RakeDbAst.ChangeTable | RakeDbAst.RenameTable | RakeDbAst.Schema | RakeDbAst.Extension | RakeDbAst.Enum | RakeDbAst.Domain | RakeDbAst.ForeignKey;
96
98
  declare namespace RakeDbAst {
97
99
  type Table = {
98
100
  type: 'table';
@@ -179,6 +181,18 @@ declare namespace RakeDbAst {
179
181
  cascade?: boolean;
180
182
  dropIfExists?: boolean;
181
183
  };
184
+ type Domain = {
185
+ type: 'domain';
186
+ action: 'create' | 'drop';
187
+ schema?: string;
188
+ name: string;
189
+ baseType: ColumnType;
190
+ notNull?: boolean;
191
+ collation?: string;
192
+ default?: RawExpression;
193
+ check?: RawExpression;
194
+ cascade?: boolean;
195
+ };
182
196
  type EnumOptions = {
183
197
  createIfNotExists?: boolean;
184
198
  dropIfExists?: boolean;
package/dist/index.js CHANGED
@@ -302,8 +302,11 @@ var __spreadValues$5 = (a, b) => {
302
302
  return a;
303
303
  };
304
304
  var __spreadProps$4 = (a, b) => __defProps$4(a, __getOwnPropDescs$4(b));
305
+ const columnTypeToSql = (item) => {
306
+ return item.data.isOfCustomType ? `"${item.toSQL()}"` : item.toSQL();
307
+ };
305
308
  const columnToSql = (key, item, values, hasMultiplePrimaryKeys) => {
306
- const line = [`"${item.data.name || key}" ${item.toSQL()}`];
309
+ const line = [`"${item.data.name || key}" ${columnTypeToSql(item)}`];
307
310
  if (item.data.compression) {
308
311
  line.push(`COMPRESSION ${item.data.compression}`);
309
312
  }
@@ -508,7 +511,7 @@ var __spreadValues$4 = (a, b) => {
508
511
  return a;
509
512
  };
510
513
  var __spreadProps$3 = (a, b) => __defProps$3(a, __getOwnPropDescs$3(b));
511
- var __objRest = (source, exclude) => {
514
+ var __objRest$1 = (source, exclude) => {
512
515
  var target = {};
513
516
  for (var prop in source)
514
517
  if (__hasOwnProp$4.call(source, prop) && exclude.indexOf(prop) < 0)
@@ -536,7 +539,7 @@ const createTable$1 = async (migration, up, tableName, options, fn) => {
536
539
  validatePrimaryKey(ast);
537
540
  const queries = astToQueries$1(ast);
538
541
  for (const _a of queries) {
539
- const _b = _a, { then } = _b, query = __objRest(_b, ["then"]);
542
+ const _b = _a, { then } = _b, query = __objRest$1(_b, ["then"]);
540
543
  const result = await migration.adapter.arrays(query);
541
544
  then == null ? void 0 : then(result);
542
545
  }
@@ -917,8 +920,9 @@ const astToQueries = (ast) => {
917
920
  } else if (item.type === "change") {
918
921
  const { from, to } = item;
919
922
  if (to.type && (from.type !== to.type || from.collate !== to.collate)) {
923
+ const type = !to.column || to.column.data.isOfCustomType ? `"${to.type}"` : to.type;
920
924
  alterTable.push(
921
- `ALTER COLUMN "${item.name || key}" TYPE ${to.type}${to.collate ? ` COLLATE ${pqb.quote(to.collate)}` : ""}${item.using ? ` USING ${pqb.getRaw(item.using, values)}` : ""}`
925
+ `ALTER COLUMN "${item.name || key}" TYPE ${type}${to.collate ? ` COLLATE ${pqb.quote(to.collate)}` : ""}${item.using ? ` USING ${pqb.getRaw(item.using, values)}` : ""}`
922
926
  );
923
927
  }
924
928
  if (from.default !== to.default) {
@@ -1186,6 +1190,12 @@ class MigrationBase {
1186
1190
  dropEnum(name, values, options) {
1187
1191
  return createEnum$1(this, !this.up, name, values, options);
1188
1192
  }
1193
+ createDomain(name, fn, options) {
1194
+ return createDomain$1(this, this.up, name, fn, options);
1195
+ }
1196
+ dropDomain(name, fn, options) {
1197
+ return createDomain$1(this, !this.up, name, fn, options);
1198
+ }
1189
1199
  async tableExists(tableName) {
1190
1200
  return queryExists(this, {
1191
1201
  text: `SELECT 1 FROM "information_schema"."tables" WHERE "table_name" = $1`,
@@ -1280,6 +1290,34 @@ const createEnum$1 = async (migration, up, name, values, options = {}) => {
1280
1290
  await migration.adapter.query(query);
1281
1291
  migration.migratedAsts.push(ast);
1282
1292
  };
1293
+ const createDomain$1 = async (migration, up, name, fn, options) => {
1294
+ const [schema, domainName] = getSchemaAndTableFromName(name);
1295
+ const ast = __spreadValues$2({
1296
+ type: "domain",
1297
+ action: up ? "create" : "drop",
1298
+ schema,
1299
+ name: domainName,
1300
+ baseType: fn(pqb.columnTypes)
1301
+ }, options);
1302
+ let query;
1303
+ const values = [];
1304
+ const quotedName = quoteWithSchema(ast);
1305
+ if (ast.action === "create") {
1306
+ query = `CREATE DOMAIN ${quotedName} AS ${columnTypeToSql(ast.baseType)}${ast.collation ? `
1307
+ COLLATION ${orchidCore.singleQuote(ast.collation)}` : ""}${ast.default ? `
1308
+ DEFAULT ${pqb.getRaw(ast.default, values)}` : ""}${ast.notNull || ast.check ? "\n" : ""}${[
1309
+ ast.notNull && "NOT NULL",
1310
+ ast.check && `CHECK ${pqb.getRaw(ast.check, values)}`
1311
+ ].filter(Boolean).join(" ")}`;
1312
+ } else {
1313
+ query = `DROP DOMAIN ${quotedName}${ast.cascade ? " CASCADE" : ""}`;
1314
+ }
1315
+ await migration.adapter.query({
1316
+ text: query,
1317
+ values
1318
+ });
1319
+ migration.migratedAsts.push(ast);
1320
+ };
1283
1321
  const queryExists = (db, sql) => {
1284
1322
  return db.adapter.query(sql).then(({ rowCount }) => rowCount > 0);
1285
1323
  };
@@ -1923,6 +1961,38 @@ ORDER BY c.conname`);
1923
1961
  }
1924
1962
  return rows;
1925
1963
  }
1964
+ async getDomains() {
1965
+ const { rows } = await this.db.query(`SELECT
1966
+ n.nspname AS "schemaName",
1967
+ d.typname AS "name",
1968
+ t.typname AS "type",
1969
+ s.nspname AS "typeSchema",
1970
+ .typnotnull AS "notNull",
1971
+ d.typcategory = 'A' AS "isArray",
1972
+ character_maximum_length AS "maxChars",
1973
+ numeric_precision AS "numericPrecision",
1974
+ numeric_scale AS "numericScale",
1975
+ datetime_precision AS "dateTimePrecision",
1976
+ collation_name AS "collation",
1977
+ domain_default AS "default",
1978
+ pg_get_expr(conbin, conrelid) AS "expression"
1979
+ FROM pg_catalog.pg_type d
1980
+ JOIN pg_catalog.pg_namespace n ON n.oid = d.typnamespace
1981
+ JOIN information_schema.domains i
1982
+ ON i.domain_schema = nspname
1983
+ AND i.domain_name = d.typname
1984
+ JOIN pg_catalog.pg_type t
1985
+ ON (
1986
+ CASE WHEN d.typcategory = 'A'
1987
+ THEN t.typarray
1988
+ ELSE t.oid
1989
+ END
1990
+ ) = d.typbasetype
1991
+ JOIN pg_catalog.pg_namespace s ON s.oid = t.typnamespace
1992
+ LEFT JOIN pg_catalog.pg_constraint c ON c.contypid = d.oid
1993
+ WHERE d.typtype = 'd' AND ${filterSchema("n.nspname")}`);
1994
+ return rows;
1995
+ }
1926
1996
  }
1927
1997
 
1928
1998
  var __defProp = Object.defineProperty;
@@ -1944,6 +2014,18 @@ var __spreadValues = (a, b) => {
1944
2014
  return a;
1945
2015
  };
1946
2016
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
2017
+ var __objRest = (source, exclude) => {
2018
+ var target = {};
2019
+ for (var prop in source)
2020
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
2021
+ target[prop] = source[prop];
2022
+ if (source != null && __getOwnPropSymbols)
2023
+ for (var prop of __getOwnPropSymbols(source)) {
2024
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
2025
+ target[prop] = source[prop];
2026
+ }
2027
+ return target;
2028
+ };
1947
2029
  class RakeDbEnumColumn extends pqb.EnumColumn {
1948
2030
  toCode(t) {
1949
2031
  return pqb.columnCode(this, t, `enum('${this.enumName}')`);
@@ -1987,10 +2069,21 @@ const structureToAst = async (db) => {
1987
2069
  }
1988
2070
  pendingTables[key] = { table, dependsOn };
1989
2071
  }
2072
+ const domains = {};
2073
+ for (const it of data.domains) {
2074
+ domains[`${it.schemaName}.${it.name}`] = getColumn(data, domains, {
2075
+ schemaName: it.schemaName,
2076
+ name: it.name,
2077
+ type: it.type,
2078
+ typeSchema: it.typeSchema,
2079
+ isArray: it.isArray,
2080
+ isSerial: false
2081
+ });
2082
+ }
1990
2083
  for (const key in pendingTables) {
1991
2084
  const { table, dependsOn } = pendingTables[key];
1992
2085
  if (!dependsOn.size) {
1993
- pushTableAst(ast, data, table, pendingTables);
2086
+ pushTableAst(ast, data, domains, table, pendingTables);
1994
2087
  }
1995
2088
  }
1996
2089
  const outerFKeys = [];
@@ -2012,6 +2105,19 @@ const structureToAst = async (db) => {
2012
2105
  values: it.values
2013
2106
  });
2014
2107
  }
2108
+ for (const it of data.domains) {
2109
+ ast.push({
2110
+ type: "domain",
2111
+ action: "create",
2112
+ schema: it.schemaName === "public" ? void 0 : it.schemaName,
2113
+ name: it.name,
2114
+ baseType: domains[`${it.schemaName}.${it.name}`],
2115
+ notNull: it.notNull,
2116
+ collation: it.collation,
2117
+ default: it.default ? orchidCore.raw(it.default) : void 0,
2118
+ check: it.check ? orchidCore.raw(it.check) : void 0
2119
+ });
2120
+ }
2015
2121
  for (const key in pendingTables) {
2016
2122
  const innerFKeys = [];
2017
2123
  const { table } = pendingTables[key];
@@ -2025,7 +2131,7 @@ const structureToAst = async (db) => {
2025
2131
  outerFKeys.push([fkey, table]);
2026
2132
  }
2027
2133
  }
2028
- pushTableAst(ast, data, table, pendingTables, innerFKeys);
2134
+ pushTableAst(ast, data, domains, table, pendingTables, innerFKeys);
2029
2135
  }
2030
2136
  for (const [fkey, table] of outerFKeys) {
2031
2137
  ast.push(__spreadProps(__spreadValues({}, foreignKeyToAst(fkey)), {
@@ -2047,7 +2153,8 @@ const getData = async (db) => {
2047
2153
  foreignKeys,
2048
2154
  extensions,
2049
2155
  enums,
2050
- checks
2156
+ checks,
2157
+ domains
2051
2158
  ] = await Promise.all([
2052
2159
  db.getSchemas(),
2053
2160
  db.getTables(),
@@ -2057,7 +2164,8 @@ const getData = async (db) => {
2057
2164
  db.getForeignKeys(),
2058
2165
  db.getExtensions(),
2059
2166
  db.getEnums(),
2060
- db.getChecks()
2167
+ db.getChecks(),
2168
+ db.getDomains()
2061
2169
  ]);
2062
2170
  return {
2063
2171
  schemas,
@@ -2068,7 +2176,8 @@ const getData = async (db) => {
2068
2176
  foreignKeys,
2069
2177
  extensions,
2070
2178
  enums,
2071
- checks
2179
+ checks,
2180
+ domains
2072
2181
  };
2073
2182
  };
2074
2183
  const makeBelongsToTable = (schema, table) => (item) => item.schemaName === schema && item.tableName === table;
@@ -2082,12 +2191,52 @@ const getIsSerial = (item) => {
2082
2191
  }
2083
2192
  return false;
2084
2193
  };
2194
+ const getColumn = (data, domains, _a) => {
2195
+ var _b = _a, {
2196
+ schemaName,
2197
+ tableName,
2198
+ name,
2199
+ type,
2200
+ typeSchema,
2201
+ isArray,
2202
+ isSerial
2203
+ } = _b, params = __objRest(_b, [
2204
+ "schemaName",
2205
+ "tableName",
2206
+ "name",
2207
+ "type",
2208
+ "typeSchema",
2209
+ "isArray",
2210
+ "isSerial"
2211
+ ]);
2212
+ let column;
2213
+ const klass = pqb.columnsByType[getColumnType(type, isSerial)];
2214
+ if (klass) {
2215
+ column = pqb.instantiateColumn(klass, params);
2216
+ } else {
2217
+ const domainColumn = domains[`${typeSchema}.${type}`];
2218
+ if (domainColumn) {
2219
+ column = new pqb.DomainColumn({}, type).as(domainColumn);
2220
+ } else {
2221
+ const enumType = data.enums.find(
2222
+ (item) => item.name === type && item.schemaName === typeSchema
2223
+ );
2224
+ if (!enumType) {
2225
+ throw new Error(
2226
+ `Cannot handle ${tableName ? "column" : "domain"} ${schemaName}${tableName ? `.${tableName}` : ""}.${name}: column type \`${type}\` is not supported`
2227
+ );
2228
+ }
2229
+ column = new RakeDbEnumColumn({}, type, enumType.values);
2230
+ }
2231
+ }
2232
+ return isArray ? new pqb.ArrayColumn({}, column) : column;
2233
+ };
2085
2234
  const getColumnType = (type, isSerial) => {
2086
2235
  if (!isSerial)
2087
2236
  return type;
2088
2237
  return type === "int2" ? "smallserial" : type === "int4" ? "serial" : "bigserial";
2089
2238
  };
2090
- const pushTableAst = (ast, data, table, pendingTables, innerFKeys = data.foreignKeys) => {
2239
+ const pushTableAst = (ast, data, domains, table, pendingTables, innerFKeys = data.foreignKeys) => {
2091
2240
  const { schemaName, name } = table;
2092
2241
  const key = `${schemaName}.${table.name}`;
2093
2242
  delete pendingTables[key];
@@ -2110,26 +2259,12 @@ const pushTableAst = (ast, data, table, pendingTables, innerFKeys = data.foreign
2110
2259
  if (isSerial) {
2111
2260
  item = __spreadProps(__spreadValues({}, item), { default: void 0 });
2112
2261
  }
2113
- let column;
2114
2262
  const isArray = item.dataType === "ARRAY";
2115
- const type = isArray ? item.type.slice(1) : item.type;
2116
- const klass = pqb.columnsByType[getColumnType(type, isSerial)];
2117
- if (klass) {
2118
- column = pqb.instantiateColumn(klass, item);
2119
- } else {
2120
- const { type: type2, typeSchema } = item;
2121
- const enumType = data.enums.find(
2122
- (item2) => item2.name === type2 && item2.schemaName === typeSchema
2123
- );
2124
- if (!enumType) {
2125
- throw new Error(
2126
- `Cannot handle column ${item.schemaName}.${item.tableName}.${item.name}: column type \`${item.type}\` is not supported`
2127
- );
2128
- }
2129
- column = new RakeDbEnumColumn({}, type2, enumType.values);
2130
- }
2131
- if (isArray)
2132
- column = new pqb.ArrayColumn({}, column);
2263
+ let column = getColumn(data, domains, __spreadProps(__spreadValues({}, item), {
2264
+ type: isArray ? item.type.slice(1) : item.type,
2265
+ isArray,
2266
+ isSerial
2267
+ }));
2133
2268
  if ((primaryKey == null ? void 0 : primaryKey.columnNames.length) === 1 && (primaryKey == null ? void 0 : primaryKey.columnNames[0]) === item.name) {
2134
2269
  column = column.primaryKey();
2135
2270
  }
@@ -2208,7 +2343,7 @@ const pushTableAst = (ast, data, table, pendingTables, innerFKeys = data.foreign
2208
2343
  for (const otherKey in pendingTables) {
2209
2344
  const item = pendingTables[otherKey];
2210
2345
  if (item.dependsOn.delete(key) && item.dependsOn.size === 0) {
2211
- pushTableAst(ast, data, item.table, pendingTables);
2346
+ pushTableAst(ast, data, domains, item.table, pendingTables);
2212
2347
  }
2213
2348
  }
2214
2349
  };
@@ -2238,7 +2373,11 @@ const astToMigration = (config, ast) => {
2238
2373
  } else if (item.type === "enum" && item.action === "create") {
2239
2374
  if (first.length)
2240
2375
  first.push([]);
2241
- first.push(...createEnum(item));
2376
+ first.push(createEnum(item));
2377
+ } else if (item.type === "domain" && item.action === "create") {
2378
+ if (first.length)
2379
+ first.push([]);
2380
+ first.push(...createDomain(item));
2242
2381
  } else if (item.type === "table" && item.action === "create") {
2243
2382
  tables.push(createTable(config, item));
2244
2383
  } else if (item.type === "foreignKey") {
@@ -2295,12 +2434,26 @@ const createExtension = (ast) => {
2295
2434
  return code;
2296
2435
  };
2297
2436
  const createEnum = (ast) => {
2437
+ return `await db.createEnum(${quoteSchemaTable(ast)}, [${ast.values.map(orchidCore.singleQuote).join(", ")}]);`;
2438
+ };
2439
+ const createDomain = (ast) => {
2298
2440
  const code = [
2299
- `await db.createEnum(${orchidCore.singleQuote(ast.name)}, [${ast.values.map(orchidCore.singleQuote).join(", ")}]`
2441
+ `await db.createDomain(${quoteSchemaTable(
2442
+ ast
2443
+ )}, (t) => ${ast.baseType.toCode("t")}`
2300
2444
  ];
2301
- if (ast.schema) {
2445
+ if (ast.notNull || ast.collation || ast.default || ast.check) {
2446
+ const props = [];
2447
+ if (ast.notNull)
2448
+ props.push(`notNull: true,`);
2449
+ if (ast.collation)
2450
+ props.push(`collation: ${orchidCore.singleQuote(ast.collation)},`);
2451
+ if (ast.default)
2452
+ props.push(`default: ${pqb.rawToCode("db", ast.default)},`);
2453
+ if (ast.check)
2454
+ props.push(`check: ${pqb.rawToCode("db", ast.check)},`);
2302
2455
  orchidCore.addCode(code, ", {");
2303
- code.push([`schema: ${orchidCore.singleQuote(ast.schema)},`]);
2456
+ code.push(props);
2304
2457
  orchidCore.addCode(code, "}");
2305
2458
  }
2306
2459
  orchidCore.addCode(code, ");");