@sqb/migrator 4.10.0 → 4.10.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.
@@ -46,6 +46,7 @@ class PgMigrationAdapter extends migration_adapter_js_1.MigrationAdapter {
46
46
  try {
47
47
  const adapter = new PgMigrationAdapter();
48
48
  adapter._connection = connection;
49
+ adapter._packageName = options.migrationPackage.name;
49
50
  adapter._infoSchema = options.infoSchema || '__migration';
50
51
  adapter.defaultVariables.schema = options.connection.schema || '';
51
52
  if (!adapter.defaultVariables.schema) {
@@ -108,14 +109,16 @@ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
108
109
  const params = [];
109
110
  if (info.status && info.status !== this.status) {
110
111
  params.push(info.status);
111
- sql += ', status = $' + (params.length);
112
+ sql += ',\n status = $' + (params.length);
112
113
  }
113
114
  if (info.version && info.version !== this.version) {
114
115
  params.push(info.version);
115
- sql += ', current_version = $' + (params.length);
116
+ sql += ',\n current_version = $' + (params.length);
116
117
  }
117
118
  if (sql) {
118
- sql = `update ${this.summaryTableFull} set updated_at = current_timestamp` + sql;
119
+ params.push(this.packageName);
120
+ sql = `update ${this.summaryTableFull} set updated_at = current_timestamp` + sql +
121
+ `\n where package_name =$` + (params.length);
119
122
  await this._connection.query(sql, { params });
120
123
  if (info.status)
121
124
  this._status = info.status;
@@ -49,12 +49,19 @@ class DbMigrator extends strict_typed_events_1.AsyncEventEmitter {
49
49
  await migrationAdapter.backupDatabase();
50
50
  }
51
51
  // Execute migration tasks
52
+ let migrationIndex = -1;
52
53
  for (const migration of migrations) {
54
+ migrationIndex++;
53
55
  if (migration.version > targetVersion || migrationAdapter.version >= migration.version)
54
56
  continue;
57
+ await this.emitAsync('migration-start', {
58
+ migration,
59
+ total: migrations.length,
60
+ index: migrationIndex
61
+ });
55
62
  for (let index = 0; index < migration.tasks.length; index++) {
56
63
  task = migration.tasks[index];
57
- await this.emitAsync('task-start', { task: task.title, total, index });
64
+ await this.emitAsync('task-start', { migration, task, total, index });
58
65
  await migrationAdapter.update({ status: types_js_1.MigrationStatus.busy });
59
66
  await migrationAdapter.writeEvent({
60
67
  event: migration_adapter_js_1.MigrationAdapter.EventKind.started,
@@ -76,14 +83,23 @@ class DbMigrator extends strict_typed_events_1.AsyncEventEmitter {
76
83
  await migrationAdapter.writeEvent({
77
84
  event: migration_adapter_js_1.MigrationAdapter.EventKind.error,
78
85
  version: migration.version,
79
- message: String(e)
86
+ message: String(e),
87
+ details: e.message + '\n\n' +
88
+ Object.keys(e)
89
+ .filter(k => e[k] != null)
90
+ .map(k => k + ': ' + e[k]).join('\n')
80
91
  });
81
92
  // noinspection ExceptionCaughtLocallyJS
82
93
  throw e;
83
94
  }
84
- await this.emitAsync('task-finish', { task: task.title, total, index });
95
+ await this.emitAsync('task-finish', { migration, task, total, index });
85
96
  }
86
- await migrationAdapter.update({ version: migration.version });
97
+ await migrationAdapter.update({ version: migration.version, status: types_js_1.MigrationStatus.idle });
98
+ await this.emitAsync('migration-finish', {
99
+ migration,
100
+ total: migrations.length,
101
+ index: migrationIndex
102
+ });
87
103
  }
88
104
  }
89
105
  catch (e) {
@@ -57,7 +57,11 @@ var MigrationPackage;
57
57
  else if (typeof t === 'string') {
58
58
  let pattern = t.replace(/\\/g, '/');
59
59
  pattern = path_1.default.resolve(migration.dirname || baseDir, pattern);
60
- const files = await (0, fast_glob_1.default)(pattern, { absolute: true, onlyFiles: true });
60
+ const files = await (0, fast_glob_1.default)(pattern, {
61
+ absolute: true,
62
+ onlyFiles: true
63
+ });
64
+ files.sort();
61
65
  for (const filename of files) {
62
66
  const ext = path_1.default.extname(filename).toLowerCase();
63
67
  if (!path_1.default.basename(filename, ext).endsWith('.task'))
@@ -43,6 +43,7 @@ export class PgMigrationAdapter extends MigrationAdapter {
43
43
  try {
44
44
  const adapter = new PgMigrationAdapter();
45
45
  adapter._connection = connection;
46
+ adapter._packageName = options.migrationPackage.name;
46
47
  adapter._infoSchema = options.infoSchema || '__migration';
47
48
  adapter.defaultVariables.schema = options.connection.schema || '';
48
49
  if (!adapter.defaultVariables.schema) {
@@ -105,14 +106,16 @@ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
105
106
  const params = [];
106
107
  if (info.status && info.status !== this.status) {
107
108
  params.push(info.status);
108
- sql += ', status = $' + (params.length);
109
+ sql += ',\n status = $' + (params.length);
109
110
  }
110
111
  if (info.version && info.version !== this.version) {
111
112
  params.push(info.version);
112
- sql += ', current_version = $' + (params.length);
113
+ sql += ',\n current_version = $' + (params.length);
113
114
  }
114
115
  if (sql) {
115
- sql = `update ${this.summaryTableFull} set updated_at = current_timestamp` + sql;
116
+ params.push(this.packageName);
117
+ sql = `update ${this.summaryTableFull} set updated_at = current_timestamp` + sql +
118
+ `\n where package_name =$` + (params.length);
116
119
  await this._connection.query(sql, { params });
117
120
  if (info.status)
118
121
  this._status = info.status;
@@ -46,12 +46,19 @@ export class DbMigrator extends AsyncEventEmitter {
46
46
  await migrationAdapter.backupDatabase();
47
47
  }
48
48
  // Execute migration tasks
49
+ let migrationIndex = -1;
49
50
  for (const migration of migrations) {
51
+ migrationIndex++;
50
52
  if (migration.version > targetVersion || migrationAdapter.version >= migration.version)
51
53
  continue;
54
+ await this.emitAsync('migration-start', {
55
+ migration,
56
+ total: migrations.length,
57
+ index: migrationIndex
58
+ });
52
59
  for (let index = 0; index < migration.tasks.length; index++) {
53
60
  task = migration.tasks[index];
54
- await this.emitAsync('task-start', { task: task.title, total, index });
61
+ await this.emitAsync('task-start', { migration, task, total, index });
55
62
  await migrationAdapter.update({ status: MigrationStatus.busy });
56
63
  await migrationAdapter.writeEvent({
57
64
  event: MigrationAdapter.EventKind.started,
@@ -73,14 +80,23 @@ export class DbMigrator extends AsyncEventEmitter {
73
80
  await migrationAdapter.writeEvent({
74
81
  event: MigrationAdapter.EventKind.error,
75
82
  version: migration.version,
76
- message: String(e)
83
+ message: String(e),
84
+ details: e.message + '\n\n' +
85
+ Object.keys(e)
86
+ .filter(k => e[k] != null)
87
+ .map(k => k + ': ' + e[k]).join('\n')
77
88
  });
78
89
  // noinspection ExceptionCaughtLocallyJS
79
90
  throw e;
80
91
  }
81
- await this.emitAsync('task-finish', { task: task.title, total, index });
92
+ await this.emitAsync('task-finish', { migration, task, total, index });
82
93
  }
83
- await migrationAdapter.update({ version: migration.version });
94
+ await migrationAdapter.update({ version: migration.version, status: MigrationStatus.idle });
95
+ await this.emitAsync('migration-finish', {
96
+ migration,
97
+ total: migrations.length,
98
+ index: migrationIndex
99
+ });
84
100
  }
85
101
  }
86
102
  catch (e) {
@@ -50,7 +50,11 @@ export var MigrationPackage;
50
50
  else if (typeof t === 'string') {
51
51
  let pattern = t.replace(/\\/g, '/');
52
52
  pattern = path.resolve(migration.dirname || baseDir, pattern);
53
- const files = await glob(pattern, { absolute: true, onlyFiles: true });
53
+ const files = await glob(pattern, {
54
+ absolute: true,
55
+ onlyFiles: true
56
+ });
57
+ files.sort();
54
58
  for (const filename of files) {
55
59
  const ext = path.extname(filename).toLowerCase();
56
60
  if (!path.basename(filename, ext).endsWith('.task'))
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sqb/migrator",
3
3
  "description": "Database migrator for SQB",
4
- "version": "4.10.0",
4
+ "version": "4.10.2",
5
5
  "author": "Panates",
6
6
  "contributors": [
7
7
  "Eray Hanoglu <e.hanoglu@panates.com>",
@@ -36,9 +36,9 @@
36
36
  "ts-gems": "^2.5.0"
37
37
  },
38
38
  "peerDependencies": {
39
- "@sqb/builder": "^4.10.0",
40
- "@sqb/connect": "^4.10.0",
41
- "@sqb/postgres": "^4.10.0"
39
+ "@sqb/builder": "^4.10.2",
40
+ "@sqb/connect": "^4.10.2",
41
+ "@sqb/postgres": "^4.10.2"
42
42
  },
43
43
  "engines": {
44
44
  "node": ">=16.0",
@@ -48,6 +48,7 @@
48
48
  "bin/",
49
49
  "cjs/",
50
50
  "esm/",
51
+ "types/",
51
52
  "LICENSE",
52
53
  "README.md"
53
54
  ],
@@ -0,0 +1,39 @@
1
+ import { Connection } from 'postgresql-client';
2
+ import type { DbMigratorOptions } from '../db-migrator.js';
3
+ import { MigrationAdapter } from '../migration-adapter.js';
4
+ import { MigrationTask } from '../migration-package.js';
5
+ import { MigrationStatus } from '../types.js';
6
+ export declare class PgMigrationAdapter extends MigrationAdapter {
7
+ protected _connection: Connection;
8
+ protected _infoSchema: string;
9
+ protected _packageName: string;
10
+ protected _version: number;
11
+ protected _status: MigrationStatus;
12
+ protected defaultVariables: {
13
+ tablespace: string;
14
+ schema: string;
15
+ owner: string;
16
+ };
17
+ readonly summaryTable = "migration_summary";
18
+ readonly eventTable = "migration_events";
19
+ get packageName(): string;
20
+ get version(): number;
21
+ get status(): MigrationStatus;
22
+ get infoSchema(): string;
23
+ get summaryTableFull(): string;
24
+ get eventTableFull(): string;
25
+ static create(options: DbMigratorOptions): Promise<PgMigrationAdapter>;
26
+ close(): Promise<void>;
27
+ refresh(): Promise<void>;
28
+ update(info: {
29
+ status?: MigrationStatus;
30
+ version?: number;
31
+ }): Promise<void>;
32
+ writeEvent(event: MigrationAdapter.Event): Promise<void>;
33
+ executeTask(task: MigrationTask, variables: Record<string, any>): Promise<void>;
34
+ backupDatabase(): Promise<void>;
35
+ lockSchema(): Promise<void>;
36
+ restoreDatabase(): Promise<void>;
37
+ unlockSchema(): Promise<void>;
38
+ protected rowToSql(tableName: string, row: Object): string;
39
+ }
@@ -0,0 +1,15 @@
1
+ import { AsyncEventEmitter } from 'strict-typed-events';
2
+ import { ClientConfiguration } from '@sqb/connect';
3
+ import { MigrationAdapter } from './migration-adapter.js';
4
+ import { MigrationPackage, MigrationPackageAsync } from './migration-package.js';
5
+ export interface DbMigratorOptions {
6
+ connection: ClientConfiguration;
7
+ migrationPackage: MigrationPackage | MigrationPackageAsync;
8
+ infoSchema?: string;
9
+ scriptVariables?: Record<string, string>;
10
+ targetVersion?: number;
11
+ }
12
+ export declare class DbMigrator extends AsyncEventEmitter {
13
+ protected adapter: MigrationAdapter;
14
+ execute(options: DbMigratorOptions): Promise<boolean>;
15
+ }
@@ -0,0 +1,4 @@
1
+ export * from './db-migrator.js';
2
+ export * from './migration-package.js';
3
+ export * from './migration-adapter.js';
4
+ export * from './types.js';
@@ -0,0 +1,32 @@
1
+ import type { MigrationTask } from './migration-package.js';
2
+ import { MigrationStatus } from './types.js';
3
+ export declare abstract class MigrationAdapter {
4
+ abstract readonly packageName: string;
5
+ abstract readonly status: MigrationStatus;
6
+ abstract readonly version: number;
7
+ abstract close(): Promise<void>;
8
+ abstract refresh(): Promise<void>;
9
+ abstract update(info: {
10
+ status?: MigrationStatus;
11
+ version?: number;
12
+ }): Promise<void>;
13
+ abstract writeEvent(event: MigrationAdapter.Event): Promise<void>;
14
+ abstract executeTask(task: MigrationTask, variables: Record<string, any>): Promise<void>;
15
+ abstract lockSchema(): Promise<void>;
16
+ abstract unlockSchema(): Promise<void>;
17
+ abstract backupDatabase(): Promise<void>;
18
+ abstract restoreDatabase(): Promise<void>;
19
+ }
20
+ export declare namespace MigrationAdapter {
21
+ enum EventKind {
22
+ started = "started",
23
+ success = "success",
24
+ error = "error"
25
+ }
26
+ interface Event {
27
+ event: EventKind;
28
+ version: number;
29
+ message: string;
30
+ details?: string;
31
+ }
32
+ }
@@ -0,0 +1,44 @@
1
+ import { StrictOmit } from 'ts-gems';
2
+ import type { MigrationAdapter } from './migration-adapter.js';
3
+ export interface MigrationPackage {
4
+ name: string;
5
+ description?: string;
6
+ migrations: Migration[];
7
+ informationTableName?: string;
8
+ }
9
+ export interface Migration {
10
+ version: number;
11
+ tasks: MigrationTask[];
12
+ dirname?: string;
13
+ backup?: boolean;
14
+ }
15
+ export type MigrationTask = SqlScriptMigrationTask | CustomMigrationTask | InsertDataMigrationTask;
16
+ export interface BaseMigrationTask {
17
+ title: string;
18
+ filename?: string;
19
+ }
20
+ export interface SqlScriptMigrationTask extends BaseMigrationTask {
21
+ title: string;
22
+ script: string;
23
+ }
24
+ export interface InsertDataMigrationTask extends BaseMigrationTask {
25
+ title: string;
26
+ tableName: string;
27
+ rows: Record<string, any>[];
28
+ }
29
+ export interface CustomMigrationTask extends BaseMigrationTask {
30
+ title: string;
31
+ fn: (connection: any, adapter: MigrationAdapter) => void | Promise<void>;
32
+ }
33
+ export declare function isSqlScriptMigrationTask(x: any): x is SqlScriptMigrationTask;
34
+ export declare function isInsertDataMigrationTask(x: any): x is InsertDataMigrationTask;
35
+ export declare function isCustomMigrationTask(x: any): x is CustomMigrationTask;
36
+ export interface MigrationPackageAsync extends StrictOmit<MigrationPackage, 'migrations'> {
37
+ migrations: (string | MigrationAsync | (() => MigrationAsync) | (() => Promise<MigrationAsync>))[];
38
+ }
39
+ export interface MigrationAsync extends StrictOmit<Migration, 'tasks'> {
40
+ tasks: (string | MigrationTask | (() => MigrationTask) | (() => Promise<MigrationTask>))[];
41
+ }
42
+ export declare namespace MigrationPackage {
43
+ function load(asyncConfig: MigrationPackageAsync): Promise<MigrationPackage>;
44
+ }
@@ -0,0 +1,9 @@
1
+ export interface MigrationInfo {
2
+ packageName: string;
3
+ status: MigrationStatus;
4
+ version: number;
5
+ }
6
+ export declare enum MigrationStatus {
7
+ idle = "idle",
8
+ busy = "busy"
9
+ }
@@ -0,0 +1 @@
1
+ export declare function getCallingFilename(position?: number): string;