rake-db 2.27.18 → 2.27.19

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
@@ -322,6 +322,9 @@ interface PickRenameMigrations {
322
322
  interface PickMigrationsTable {
323
323
  migrationsTable: string;
324
324
  }
325
+ interface PickTransactionSetting {
326
+ transaction: 'single' | 'per-migration';
327
+ }
325
328
  interface PickMigrationCallbacks {
326
329
  beforeChange?: ChangeCallback$1;
327
330
  afterChange?: ChangeCallback$1;
@@ -344,7 +347,7 @@ interface RakeDbBaseConfig<SchemaConfig extends ColumnSchemaConfig, CT = Default
344
347
  noPrimaryKey?: NoPrimaryKeyOption;
345
348
  baseTable?: RakeDbBaseTable<CT>;
346
349
  }
347
- interface RakeDbConfig<SchemaConfig extends ColumnSchemaConfig, CT = DefaultColumnTypes<DefaultSchemaConfig>> extends RakeDbBaseConfig<SchemaConfig, CT>, PickBasePath {
350
+ interface RakeDbConfig<SchemaConfig extends ColumnSchemaConfig, CT = DefaultColumnTypes<DefaultSchemaConfig>> extends RakeDbBaseConfig<SchemaConfig, CT>, PickBasePath, PickTransactionSetting {
348
351
  columnTypes: CT;
349
352
  dbScript: string;
350
353
  recurrentPath: string;
@@ -489,7 +492,7 @@ interface RakeDbRenameMigrationsInput {
489
492
  map: RakeDbRenameMigrationsMap;
490
493
  }
491
494
  declare const migrationConfigDefaults: RakeDbBaseConfig<ColumnSchemaConfig>;
492
- declare const processRakeDbConfig: <SchemaConfig extends ColumnSchemaConfig<pqb.ColumnTypeBase<pqb.ColumnTypeSchemaArg, unknown, any, any, unknown, unknown, any, unknown, any, pqb.ColumnDataBase>>, CT>(config: InputRakeDbConfig<SchemaConfig, CT>) => RakeDbConfig<SchemaConfig, CT>;
495
+ declare const processRakeDbConfig: <SchemaConfig extends ColumnSchemaConfig<pqb.ColumnTypeBase<pqb.ColumnTypeSchemaArg, unknown, any, any, unknown, unknown, any, unknown, any, pqb.ColumnDataBase>>, CT>(config: InputRakeDbConfig<SchemaConfig, CT>, args?: string[]) => RakeDbConfig<SchemaConfig, CT>;
493
496
 
494
497
  type DropMode = 'CASCADE' | 'RESTRICT';
495
498
  type TableOptions = {
@@ -1521,15 +1524,16 @@ declare const promptSelect: ({ message, options, active, inactive, }: {
1521
1524
 
1522
1525
  declare const saveMigratedVersion: (db: SilentQueries, version: string, name: string, config: PickMigrationsTable) => Promise<void>;
1523
1526
 
1524
- interface MigrateFnConfig extends MigrateOrRollbackConfig, PickAfterChangeCommit, PickBasePath, PickImport, PickMigrationsPath {
1527
+ interface MigrateFnConfig extends MigrateOrRollbackConfig, PickAfterChangeCommit, PickBasePath, PickImport, PickMigrationsPath, PickTransactionSetting {
1525
1528
  }
1526
- type MigrateFn = (params: {
1529
+ interface MigrateFnParams {
1527
1530
  ctx?: RakeDbCtx;
1528
1531
  adapter: AdapterBase;
1529
1532
  config: MigrateFnConfig;
1530
1533
  count?: number;
1531
1534
  force?: boolean;
1532
- }) => Promise<void>;
1535
+ }
1536
+ type MigrateFn = (params: MigrateFnParams) => Promise<void>;
1533
1537
  /**
1534
1538
  * Will run all pending yet migrations, sequentially in order,
1535
1539
  * will apply `change` functions top-to-bottom.
@@ -1540,7 +1544,7 @@ type MigrateFn = (params: {
1540
1544
  */
1541
1545
  declare const migrate: MigrateFn;
1542
1546
  declare const migrateAndClose: MigrateFn;
1543
- interface MigrateOrRollbackConfig extends PickMigrationCallbacks, PickMigrationId, QueryLogOptions, PickForceDefaultExports, PickMigrationsTable {
1547
+ interface MigrateOrRollbackConfig extends PickMigrationCallbacks, PickMigrationId, QueryLogOptions, PickForceDefaultExports, PickMigrationsTable, PickTransactionSetting {
1544
1548
  columnTypes: unknown;
1545
1549
  }
1546
1550
 
package/dist/index.js CHANGED
@@ -17,154 +17,6 @@ const clearChanges = () => {
17
17
  const getCurrentChanges = () => currentChanges;
18
18
  const pushChange = (change) => currentChanges.push(change);
19
19
 
20
- const migrationConfigDefaults = {
21
- schemaConfig: pqb.defaultSchemaConfig,
22
- migrationsPath: path.join("src", "db", "migrations"),
23
- migrationId: { serial: 4 },
24
- migrationsTable: "schemaMigrations",
25
- snakeCase: false,
26
- commands: {},
27
- log: true,
28
- logger: console,
29
- import() {
30
- throw new Error(
31
- "Add `import: (path) => import(path),` setting to `rakeDb` config"
32
- );
33
- }
34
- };
35
- const ensureMigrationsPath = (config) => {
36
- if (!config.migrationsPath) {
37
- config.migrationsPath = migrationConfigDefaults.migrationsPath;
38
- }
39
- if (!path.isAbsolute(config.migrationsPath)) {
40
- config.migrationsPath = path.resolve(
41
- config.basePath,
42
- config.migrationsPath
43
- );
44
- }
45
- return config;
46
- };
47
- const ensureBasePathAndDbScript = (config, intermediateCallers = 0) => {
48
- if (config.basePath && config.dbScript) return config;
49
- let filePath = pqb.getStackTrace()?.[3 + intermediateCallers].getFileName();
50
- if (!filePath) {
51
- throw new Error(
52
- "Failed to determine path to db script. Please set basePath option of rakeDb"
53
- );
54
- }
55
- if (filePath.startsWith("file://")) {
56
- filePath = node_url.fileURLToPath(filePath);
57
- }
58
- const ext = path.extname(filePath);
59
- if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
60
- throw new Error(
61
- `Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
62
- );
63
- }
64
- config.basePath = path.dirname(filePath);
65
- config.dbScript = path.basename(filePath);
66
- return config;
67
- };
68
- const processRakeDbConfig = (config) => {
69
- const result = { ...migrationConfigDefaults, ...config };
70
- if (!result.log) {
71
- delete result.logger;
72
- }
73
- ensureBasePathAndDbScript(result, 1);
74
- ensureMigrationsPath(result);
75
- if (!result.recurrentPath) {
76
- result.recurrentPath = path.join(
77
- result.migrationsPath,
78
- "recurrent"
79
- );
80
- }
81
- if ("recurrentPath" in result && !path.isAbsolute(result.recurrentPath)) {
82
- result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
83
- }
84
- if ("baseTable" in config && config.baseTable) {
85
- const { types, snakeCase, language } = config.baseTable.prototype;
86
- result.columnTypes = types || pqb.makeColumnTypes(pqb.defaultSchemaConfig);
87
- if (snakeCase) result.snakeCase = true;
88
- if (language) result.language = language;
89
- } else {
90
- const ct = "columnTypes" in config && config.columnTypes;
91
- result.columnTypes = (typeof ct === "function" ? ct(
92
- pqb.makeColumnTypes(pqb.defaultSchemaConfig)
93
- ) : ct) || pqb.makeColumnTypes(pqb.defaultSchemaConfig);
94
- }
95
- if (config.migrationId === "serial") {
96
- result.migrationId = { serial: 4 };
97
- }
98
- return result;
99
- };
100
-
101
- const getFirstWordAndRest = (input) => {
102
- const i = input.search(/(?=[A-Z])|[-_ ]/);
103
- if (i !== -1) {
104
- const restStart = input[i] === "-" || input[i] === "_" || input[i] === " " ? i + 1 : i;
105
- const rest = input.slice(restStart);
106
- return [input.slice(0, i), rest[0].toLowerCase() + rest.slice(1)];
107
- } else {
108
- return [input];
109
- }
110
- };
111
- const getTextAfterRegExp = (input, regex, length) => {
112
- let i = input.search(regex);
113
- if (i === -1) return;
114
- if (input[i] === "-" || input[i] === "_" || input[i] === " ") i++;
115
- i += length;
116
- const start = input[i] == "-" || input[i] === "_" || input[i] === " " ? i + 1 : i;
117
- const text = input.slice(start);
118
- return text[0].toLowerCase() + text.slice(1);
119
- };
120
- const getTextAfterTo = (input) => {
121
- return getTextAfterRegExp(input, /(To|-to|_to| to)[A-Z-_ ]/, 2);
122
- };
123
- const getTextAfterFrom = (input) => {
124
- return getTextAfterRegExp(input, /(From|-from|_from| from)[A-Z-_ ]/, 4);
125
- };
126
- const joinColumns = (columns) => {
127
- return columns.map((column) => `"${column}"`).join(", ");
128
- };
129
- const quoteWithSchema = ({
130
- schema,
131
- name
132
- }) => quoteTable(schema, name);
133
- const quoteTable = (schema, table) => schema ? `"${schema}"."${table}"` : `"${table}"`;
134
- const getSchemaAndTableFromName = (name) => {
135
- const i = name.indexOf(".");
136
- return i !== -1 ? [name.slice(0, i), name.slice(i + 1)] : [void 0, name];
137
- };
138
- const quoteNameFromString = (string) => {
139
- return quoteTable(...getSchemaAndTableFromName(string));
140
- };
141
- const quoteCustomType = (s) => {
142
- const [schema, type] = getSchemaAndTableFromName(s);
143
- return schema ? '"' + schema + '".' + type : type;
144
- };
145
- const quoteSchemaTable = (arg) => {
146
- return pqb.singleQuote(concatSchemaAndName(arg));
147
- };
148
- const concatSchemaAndName = ({
149
- schema,
150
- name
151
- }) => {
152
- return schema ? `${schema}.${name}` : name;
153
- };
154
- const makePopulateEnumQuery = (item) => {
155
- const [schema, name] = getSchemaAndTableFromName(item.enumName);
156
- return {
157
- text: `SELECT unnest(enum_range(NULL::${quoteTable(schema, name)}))::text`,
158
- then(result) {
159
- item.options.push(...result.rows.map(([value]) => value));
160
- }
161
- };
162
- };
163
- const transaction = (adapter, fn) => {
164
- return adapter.transaction(void 0, fn);
165
- };
166
- const queryLock = (trx) => trx.query(`SELECT pg_advisory_xact_lock('${RAKE_DB_LOCK_KEY}')`);
167
-
168
20
  const versionToString = (config, version) => config.migrationId === "timestamp" ? `${version}` : `${version}`.padStart(config.migrationId.serial, "0");
169
21
  const columnTypeToSql = (item) => {
170
22
  return item.data.isOfCustomType ? item instanceof pqb.DomainColumn ? quoteNameFromString(item.dataType) : quoteCustomType(item.toSQL()) : item.toSQL();
@@ -3068,6 +2920,9 @@ const createMigrationsTable = async (db, config) => {
3068
2920
  };
3069
2921
 
3070
2922
  const RAKE_DB_LOCK_KEY = "8582141715823621641";
2923
+ const transactionIfSingle = (params, fn) => {
2924
+ return params.config.transaction === "single" ? transaction(params.adapter, fn) : fn(params.adapter);
2925
+ };
3071
2926
  function makeMigrateFn(up, fn) {
3072
2927
  return async (params) => {
3073
2928
  const ctx = params.ctx || {};
@@ -3076,7 +2931,7 @@ function makeMigrateFn(up, fn) {
3076
2931
  const force = params.force ?? false;
3077
2932
  let migrations;
3078
2933
  try {
3079
- await transaction(params.adapter, async (trx) => {
2934
+ await transactionIfSingle(params, async (trx) => {
3080
2935
  const versions = await getMigratedVersionsMap(
3081
2936
  ctx,
3082
2937
  trx,
@@ -3087,7 +2942,7 @@ function makeMigrateFn(up, fn) {
3087
2942
  });
3088
2943
  } catch (err) {
3089
2944
  if (err instanceof NoMigrationsTableError) {
3090
- await transaction(params.adapter, async (trx) => {
2945
+ await transactionIfSingle(params, async (trx) => {
3091
2946
  await createMigrationsTable(trx, params.config);
3092
2947
  const versions = await getMigratedVersionsMap(
3093
2948
  ctx,
@@ -3206,6 +3061,7 @@ const migrateOrRollback = async (trx, config, set, versions, count, up, redo2, f
3206
3061
  }
3207
3062
  let loggedAboutStarting = false;
3208
3063
  let migrations;
3064
+ const migrationRunner = config.transaction === "single" ? runMigration : runMigrationInOwnTransaction;
3209
3065
  for (const file of set.migrations) {
3210
3066
  if (up && versionsMap[file.version] || !up && !versionsMap[file.version]) {
3211
3067
  continue;
@@ -3219,7 +3075,7 @@ const migrateOrRollback = async (trx, config, set, versions, count, up, redo2, f
3219
3075
  );
3220
3076
  }
3221
3077
  const changes = await getChanges(file, config);
3222
- const adapter = await runMigration(trx, up, changes, config);
3078
+ const adapter = await migrationRunner(trx, up, changes, config);
3223
3079
  await changeMigratedVersion(adapter, up, file, config);
3224
3080
  (migrations ?? (migrations = [])).push(file);
3225
3081
  if (up) {
@@ -3298,6 +3154,9 @@ const getChanges = async (file, config) => {
3298
3154
  }
3299
3155
  return changes;
3300
3156
  };
3157
+ const runMigrationInOwnTransaction = (adapter, ...rest) => {
3158
+ return transaction(adapter, (trx) => runMigration(trx, ...rest));
3159
+ };
3301
3160
  const runMigration = async (trx, up, changes, config) => {
3302
3161
  const db = createMigrationInterface(trx, up, config);
3303
3162
  if (changes.length) {
@@ -3319,6 +3178,176 @@ const changeMigratedVersion = async (adapter, up, file, config) => {
3319
3178
  );
3320
3179
  };
3321
3180
 
3181
+ const getFirstWordAndRest = (input) => {
3182
+ const i = input.search(/(?=[A-Z])|[-_ ]/);
3183
+ if (i !== -1) {
3184
+ const restStart = input[i] === "-" || input[i] === "_" || input[i] === " " ? i + 1 : i;
3185
+ const rest = input.slice(restStart);
3186
+ return [input.slice(0, i), rest[0].toLowerCase() + rest.slice(1)];
3187
+ } else {
3188
+ return [input];
3189
+ }
3190
+ };
3191
+ const getTextAfterRegExp = (input, regex, length) => {
3192
+ let i = input.search(regex);
3193
+ if (i === -1) return;
3194
+ if (input[i] === "-" || input[i] === "_" || input[i] === " ") i++;
3195
+ i += length;
3196
+ const start = input[i] == "-" || input[i] === "_" || input[i] === " " ? i + 1 : i;
3197
+ const text = input.slice(start);
3198
+ return text[0].toLowerCase() + text.slice(1);
3199
+ };
3200
+ const getTextAfterTo = (input) => {
3201
+ return getTextAfterRegExp(input, /(To|-to|_to| to)[A-Z-_ ]/, 2);
3202
+ };
3203
+ const getTextAfterFrom = (input) => {
3204
+ return getTextAfterRegExp(input, /(From|-from|_from| from)[A-Z-_ ]/, 4);
3205
+ };
3206
+ const joinColumns = (columns) => {
3207
+ return columns.map((column) => `"${column}"`).join(", ");
3208
+ };
3209
+ const quoteWithSchema = ({
3210
+ schema,
3211
+ name
3212
+ }) => quoteTable(schema, name);
3213
+ const quoteTable = (schema, table) => schema ? `"${schema}"."${table}"` : `"${table}"`;
3214
+ const getSchemaAndTableFromName = (name) => {
3215
+ const i = name.indexOf(".");
3216
+ return i !== -1 ? [name.slice(0, i), name.slice(i + 1)] : [void 0, name];
3217
+ };
3218
+ const quoteNameFromString = (string) => {
3219
+ return quoteTable(...getSchemaAndTableFromName(string));
3220
+ };
3221
+ const quoteCustomType = (s) => {
3222
+ const [schema, type] = getSchemaAndTableFromName(s);
3223
+ return schema ? '"' + schema + '".' + type : type;
3224
+ };
3225
+ const quoteSchemaTable = (arg) => {
3226
+ return pqb.singleQuote(concatSchemaAndName(arg));
3227
+ };
3228
+ const concatSchemaAndName = ({
3229
+ schema,
3230
+ name
3231
+ }) => {
3232
+ return schema ? `${schema}.${name}` : name;
3233
+ };
3234
+ const makePopulateEnumQuery = (item) => {
3235
+ const [schema, name] = getSchemaAndTableFromName(item.enumName);
3236
+ return {
3237
+ text: `SELECT unnest(enum_range(NULL::${quoteTable(schema, name)}))::text`,
3238
+ then(result) {
3239
+ item.options.push(...result.rows.map(([value]) => value));
3240
+ }
3241
+ };
3242
+ };
3243
+ const transaction = (adapter, fn) => {
3244
+ return adapter.transaction(void 0, fn);
3245
+ };
3246
+ const queryLock = (trx) => trx.query(`SELECT pg_advisory_xact_lock('${RAKE_DB_LOCK_KEY}')`);
3247
+ const getCliParam = (args, name) => {
3248
+ if (args) {
3249
+ const key = "--" + name;
3250
+ for (let i = 0; i < args.length; i += 1) {
3251
+ const arg = args[i];
3252
+ if (arg === key) return args[i + 1];
3253
+ else if (arg.startsWith(key)) return arg.slice(key.length + 1);
3254
+ }
3255
+ }
3256
+ return;
3257
+ };
3258
+
3259
+ const migrationConfigDefaults = {
3260
+ schemaConfig: pqb.defaultSchemaConfig,
3261
+ migrationsPath: path.join("src", "db", "migrations"),
3262
+ migrationId: { serial: 4 },
3263
+ migrationsTable: "schemaMigrations",
3264
+ snakeCase: false,
3265
+ commands: {},
3266
+ log: true,
3267
+ logger: console,
3268
+ import() {
3269
+ throw new Error(
3270
+ "Add `import: (path) => import(path),` setting to `rakeDb` config"
3271
+ );
3272
+ }
3273
+ };
3274
+ const ensureMigrationsPath = (config) => {
3275
+ if (!config.migrationsPath) {
3276
+ config.migrationsPath = migrationConfigDefaults.migrationsPath;
3277
+ }
3278
+ if (!path.isAbsolute(config.migrationsPath)) {
3279
+ config.migrationsPath = path.resolve(
3280
+ config.basePath,
3281
+ config.migrationsPath
3282
+ );
3283
+ }
3284
+ return config;
3285
+ };
3286
+ const ensureBasePathAndDbScript = (config, intermediateCallers = 0) => {
3287
+ if (config.basePath && config.dbScript) return config;
3288
+ let filePath = pqb.getStackTrace()?.[3 + intermediateCallers].getFileName();
3289
+ if (!filePath) {
3290
+ throw new Error(
3291
+ "Failed to determine path to db script. Please set basePath option of rakeDb"
3292
+ );
3293
+ }
3294
+ if (filePath.startsWith("file://")) {
3295
+ filePath = node_url.fileURLToPath(filePath);
3296
+ }
3297
+ const ext = path.extname(filePath);
3298
+ if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
3299
+ throw new Error(
3300
+ `Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
3301
+ );
3302
+ }
3303
+ config.basePath = path.dirname(filePath);
3304
+ config.dbScript = path.basename(filePath);
3305
+ return config;
3306
+ };
3307
+ const processRakeDbConfig = (config, args) => {
3308
+ const result = { ...migrationConfigDefaults, ...config };
3309
+ if (!result.log) {
3310
+ delete result.logger;
3311
+ }
3312
+ ensureBasePathAndDbScript(result, 1);
3313
+ ensureMigrationsPath(result);
3314
+ if (!result.recurrentPath) {
3315
+ result.recurrentPath = path.join(
3316
+ result.migrationsPath,
3317
+ "recurrent"
3318
+ );
3319
+ }
3320
+ if ("recurrentPath" in result && !path.isAbsolute(result.recurrentPath)) {
3321
+ result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
3322
+ }
3323
+ if ("baseTable" in config && config.baseTable) {
3324
+ const { types, snakeCase, language } = config.baseTable.prototype;
3325
+ result.columnTypes = types || pqb.makeColumnTypes(pqb.defaultSchemaConfig);
3326
+ if (snakeCase) result.snakeCase = true;
3327
+ if (language) result.language = language;
3328
+ } else {
3329
+ const ct = "columnTypes" in config && config.columnTypes;
3330
+ result.columnTypes = (typeof ct === "function" ? ct(
3331
+ pqb.makeColumnTypes(pqb.defaultSchemaConfig)
3332
+ ) : ct) || pqb.makeColumnTypes(pqb.defaultSchemaConfig);
3333
+ }
3334
+ if (config.migrationId === "serial") {
3335
+ result.migrationId = { serial: 4 };
3336
+ }
3337
+ const transaction = getCliParam(args, "transaction");
3338
+ if (transaction) {
3339
+ if (transaction !== "single" && transaction !== "per-migration") {
3340
+ throw new Error(
3341
+ `Unsupported transaction param ${transaction}, expected single or per-migration`
3342
+ );
3343
+ }
3344
+ result.transaction = transaction;
3345
+ } else if (!result.transaction) {
3346
+ result.transaction = "single";
3347
+ }
3348
+ return result;
3349
+ };
3350
+
3322
3351
  const ESC = "\x1B";
3323
3352
  const CSI = `${ESC}[`;
3324
3353
  const cursorShow = `${CSI}?25h`;
@@ -5786,7 +5815,7 @@ const rakeDbCommands = {
5786
5815
  };
5787
5816
 
5788
5817
  const rakeDbWithAdapters = (adapters, partialConfig, args = process.argv.slice(2)) => {
5789
- const config = processRakeDbConfig(partialConfig);
5818
+ const config = processRakeDbConfig(partialConfig, args);
5790
5819
  const promise = runCommand(
5791
5820
  adapters,
5792
5821
  config,
@@ -5840,7 +5869,8 @@ const makeMigrateAdapter = (config) => {
5840
5869
  columnTypes: conf.columnTypes || pqb.makeColumnTypes(pqb.defaultSchemaConfig),
5841
5870
  migrationId: conf.migrationId || migrationConfigDefaults.migrationId,
5842
5871
  migrationsTable: conf.migrationsTable || migrationConfigDefaults.migrationsTable,
5843
- import: conf.import || migrationConfigDefaults.import
5872
+ import: conf.import || migrationConfigDefaults.import,
5873
+ transaction: conf.transaction || "single"
5844
5874
  }
5845
5875
  });
5846
5876
  };