@blackglory/pg-migrations 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -1,13 +1,11 @@
1
1
  # pg-migrations
2
2
  A utility for database migrations with [pg].
3
3
 
4
- The module using [customized options] `migrations.schema_version` to record the schema version.
4
+ The module create a simple migrations table to record the schema version.
5
5
 
6
6
  [pg]: https://www.npmjs.com/package/pg
7
- [customized options]: https://www.postgresql.org/docs/current/runtime-config-custom.html
8
7
 
9
8
  ## Install
10
-
11
9
  ```sh
12
10
  npm install --save @blackglory/pg-migrations
13
11
  # or
@@ -15,7 +13,6 @@ yarn add @blackglory/pg-migrations
15
13
  ```
16
14
 
17
15
  ## API
18
-
19
16
  ```ts
20
17
  interface IMigration {
21
18
  version: number
@@ -25,9 +22,21 @@ interface IMigration {
25
22
  ```
26
23
 
27
24
  ### migrate
28
-
29
25
  ```ts
30
- function migrate(client: Client, migrations: IMigration[], targetVersion?: number): Promise<void>
26
+ function migrate(
27
+ client: Client
28
+ , migrations: IMigration[]
29
+ , targetVersion = getMaximumVersion(migrations)
30
+ , migrationsTable: string = 'migrations'
31
+ , advisoryLockKey: bigint = BigInt('-9223372036854775808') // The smallest bigint for postgres
32
+ ): Promise<void>
31
33
  ```
32
34
 
33
- If targetVersion is `undefined`, then use the maximum version of migrations.
35
+ ## FAQ
36
+ ### Can multiple instances migrate in parallel?
37
+ Yes, it uses advisory lock to ensure that only one instance is migrating at a time.
38
+ When the maximum migration version is less than the database schema version (which means it is an obsolete instance), it will skip the migration.
39
+
40
+ ### What if my migration requires more than one connection?
41
+ You can get all connection configurations through properties to create a new `pg.Client`.
42
+ It is important to note that the custom client you create is not part of the migration transaction.
@@ -4,4 +4,4 @@ export interface IMigration {
4
4
  up: string | ((client: Client) => PromiseLike<void>);
5
5
  down: string | ((client: Client) => PromiseLike<void>);
6
6
  }
7
- export declare function migrate(client: Client, migrations: IMigration[], targetVersion?: number): Promise<void>;
7
+ export declare function migrate(client: Client, migrations: IMigration[], targetVersion?: number, migrationsTable?: string, advisoryLockKey?: bigint): Promise<void>;
@@ -12,57 +12,78 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.migrate = void 0;
13
13
  const types_1 = require("@blackglory/types");
14
14
  const errors_1 = require("@blackglory/errors");
15
- function migrate(client, migrations, targetVersion = getMaximumVersion(migrations)) {
15
+ function migrate(client, migrations, targetVersion = getMaximumVersion(migrations), migrationsTable = 'migrations', advisoryLockKey = BigInt('-9223372036854775808')) {
16
16
  return __awaiter(this, void 0, void 0, function* () {
17
- let currentVersion;
18
- while ((currentVersion = yield getDatabaseVersion(client)) !== targetVersion) {
19
- if (currentVersion < targetVersion) {
20
- yield upgrade();
21
- }
22
- else {
23
- yield downgrade();
17
+ const maxVersion = getMaximumVersion(migrations);
18
+ yield lock(client, advisoryLockKey);
19
+ try {
20
+ while (true) {
21
+ const currentVersion = yield getDatabaseVersion(client, migrationsTable);
22
+ if (maxVersion < currentVersion) {
23
+ break;
24
+ }
25
+ else {
26
+ if (currentVersion === targetVersion) {
27
+ break;
28
+ }
29
+ else if (currentVersion < targetVersion) {
30
+ yield upgrade();
31
+ }
32
+ else {
33
+ yield downgrade();
34
+ }
35
+ }
24
36
  }
25
37
  }
38
+ finally {
39
+ yield unlock(client, advisoryLockKey);
40
+ }
26
41
  function upgrade() {
27
42
  return __awaiter(this, void 0, void 0, function* () {
28
- const currentVersion = yield getDatabaseVersion(client);
43
+ yield client.query('BEGIN');
44
+ const currentVersion = yield getDatabaseVersion(client, migrationsTable);
29
45
  const targetVersion = currentVersion + 1;
30
- const migration = migrations.find(x => x.version === targetVersion);
31
- errors_1.assert(migration, `Cannot find migration for version ${targetVersion}`);
32
46
  try {
33
- if (types_1.isFunction(migration.up)) {
47
+ const migration = migrations.find(x => x.version === targetVersion);
48
+ (0, errors_1.assert)(migration, `Cannot find migration for version ${targetVersion}`);
49
+ if ((0, types_1.isFunction)(migration.up)) {
34
50
  yield migration.up(client);
35
51
  }
36
52
  else {
37
53
  yield client.query(migration.up);
38
54
  }
55
+ yield setDatabaseVersion(client, migrationsTable, targetVersion);
56
+ yield client.query('COMMIT');
39
57
  }
40
58
  catch (e) {
41
59
  console.error(`Upgrade from version ${currentVersion} to version ${targetVersion} failed.`);
60
+ yield client.query('ROLLBACK');
42
61
  throw e;
43
62
  }
44
- yield setDatabaseVersion(client, targetVersion);
45
63
  });
46
64
  }
47
65
  function downgrade() {
48
66
  return __awaiter(this, void 0, void 0, function* () {
49
- const currentVersion = yield getDatabaseVersion(client);
67
+ yield client.query('BEGIN');
68
+ const currentVersion = yield getDatabaseVersion(client, migrationsTable);
50
69
  const targetVersion = currentVersion - 1;
51
- const migration = migrations.find(x => x.version === currentVersion);
52
- errors_1.assert(migration, `Cannot find migration for version ${targetVersion}`);
53
70
  try {
54
- if (types_1.isFunction(migration.down)) {
71
+ const migration = migrations.find(x => x.version === currentVersion);
72
+ (0, errors_1.assert)(migration, `Cannot find migration for version ${targetVersion}`);
73
+ if ((0, types_1.isFunction)(migration.down)) {
55
74
  yield migration.down(client);
56
75
  }
57
76
  else {
58
77
  yield client.query(migration.down);
59
78
  }
79
+ yield setDatabaseVersion(client, migrationsTable, targetVersion);
80
+ yield client.query('COMMIT');
60
81
  }
61
82
  catch (e) {
62
83
  console.error(`Downgrade from version ${currentVersion} to version ${targetVersion} failed.`);
84
+ yield client.query('ROLLBACK');
63
85
  throw e;
64
86
  }
65
- yield setDatabaseVersion(client, targetVersion);
66
87
  });
67
88
  }
68
89
  });
@@ -71,32 +92,54 @@ exports.migrate = migrate;
71
92
  function getMaximumVersion(migrations) {
72
93
  return migrations.reduce((max, cur) => Math.max(cur.version, max), 0);
73
94
  }
74
- function getDatabaseVersion(client) {
95
+ function getDatabaseVersion(client, migrationTable) {
75
96
  return __awaiter(this, void 0, void 0, function* () {
97
+ yield ensureMigrationsTable(client, migrationTable);
76
98
  const result = yield client.query(`
77
- SELECT COALESCE(current_setting('migrations.schema_version', true), '0')::integer AS version;
99
+ SELECT schema_version
100
+ FROM "${migrationTable}";
78
101
  `);
79
- return result.rows[0].version;
102
+ if (result.rows.length) {
103
+ return result.rows[0].schema_version;
104
+ }
105
+ else {
106
+ yield client.query(`
107
+ INSERT INTO "${migrationTable}" (schema_version)
108
+ VALUES (0);
109
+ `);
110
+ return 0;
111
+ }
80
112
  });
81
113
  }
82
- function setDatabaseVersion(client, version) {
114
+ function ensureMigrationsTable(client, migrationTable) {
83
115
  return __awaiter(this, void 0, void 0, function* () {
84
- const database = yield getCurrentDatabase(client);
85
116
  yield client.query(`
86
- SET migrations.schema_version to ${version};
87
-
88
- ALTER DATABASE "${database}"
89
- SET migrations.schema_version
90
- FROM current;
117
+ CREATE TABLE IF NOT EXISTS "${migrationTable}" (
118
+ schema_version INTEGER NOT NULL
119
+ );
91
120
  `);
92
121
  });
93
122
  }
94
- function getCurrentDatabase(client) {
123
+ function setDatabaseVersion(client, migrationTable, version) {
95
124
  return __awaiter(this, void 0, void 0, function* () {
96
- const result = yield client.query(`
97
- SELECT current_database() AS database;
125
+ yield client.query(`
126
+ UPDATE ${migrationTable}
127
+ SET schema_version = ${version};
128
+ `);
129
+ });
130
+ }
131
+ function lock(client, key) {
132
+ return __awaiter(this, void 0, void 0, function* () {
133
+ yield client.query(`
134
+ SELECT pg_advisory_lock(${key});
135
+ `);
136
+ });
137
+ }
138
+ function unlock(client, key) {
139
+ return __awaiter(this, void 0, void 0, function* () {
140
+ yield client.query(`
141
+ SELECT pg_advisory_unlock(${key});
98
142
  `);
99
- return result.rows[0].database;
100
143
  });
101
144
  }
102
145
  //# sourceMappingURL=migrate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/migrate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/migrate.ts"],"names":[],"mappings":"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"}
@@ -4,4 +4,4 @@ export interface IMigration {
4
4
  up: string | ((client: Client) => PromiseLike<void>);
5
5
  down: string | ((client: Client) => PromiseLike<void>);
6
6
  }
7
- export declare function migrate(client: Client, migrations: IMigration[], targetVersion?: number): Promise<void>;
7
+ export declare function migrate(client: Client, migrations: IMigration[], targetVersion?: number, migrationsTable?: string, advisoryLockKey?: bigint): Promise<void>;
@@ -3,79 +3,118 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.migrate = void 0;
4
4
  const types_1 = require("@blackglory/types");
5
5
  const errors_1 = require("@blackglory/errors");
6
- async function migrate(client, migrations, targetVersion = getMaximumVersion(migrations)) {
7
- let currentVersion;
8
- while ((currentVersion = await getDatabaseVersion(client)) !== targetVersion) {
9
- if (currentVersion < targetVersion) {
10
- await upgrade();
11
- }
12
- else {
13
- await downgrade();
6
+ async function migrate(client, migrations, targetVersion = getMaximumVersion(migrations), migrationsTable = 'migrations', advisoryLockKey = BigInt('-9223372036854775808')) {
7
+ const maxVersion = getMaximumVersion(migrations);
8
+ await lock(client, advisoryLockKey);
9
+ try {
10
+ while (true) {
11
+ const currentVersion = await getDatabaseVersion(client, migrationsTable);
12
+ if (maxVersion < currentVersion) {
13
+ break;
14
+ }
15
+ else {
16
+ if (currentVersion === targetVersion) {
17
+ break;
18
+ }
19
+ else if (currentVersion < targetVersion) {
20
+ await upgrade();
21
+ }
22
+ else {
23
+ await downgrade();
24
+ }
25
+ }
14
26
  }
15
27
  }
28
+ finally {
29
+ await unlock(client, advisoryLockKey);
30
+ }
16
31
  async function upgrade() {
17
- const currentVersion = await getDatabaseVersion(client);
32
+ await client.query('BEGIN');
33
+ const currentVersion = await getDatabaseVersion(client, migrationsTable);
18
34
  const targetVersion = currentVersion + 1;
19
- const migration = migrations.find(x => x.version === targetVersion);
20
- errors_1.assert(migration, `Cannot find migration for version ${targetVersion}`);
21
35
  try {
22
- if (types_1.isFunction(migration.up)) {
36
+ const migration = migrations.find(x => x.version === targetVersion);
37
+ (0, errors_1.assert)(migration, `Cannot find migration for version ${targetVersion}`);
38
+ if ((0, types_1.isFunction)(migration.up)) {
23
39
  await migration.up(client);
24
40
  }
25
41
  else {
26
42
  await client.query(migration.up);
27
43
  }
44
+ await setDatabaseVersion(client, migrationsTable, targetVersion);
45
+ await client.query('COMMIT');
28
46
  }
29
47
  catch (e) {
30
48
  console.error(`Upgrade from version ${currentVersion} to version ${targetVersion} failed.`);
49
+ await client.query('ROLLBACK');
31
50
  throw e;
32
51
  }
33
- await setDatabaseVersion(client, targetVersion);
34
52
  }
35
53
  async function downgrade() {
36
- const currentVersion = await getDatabaseVersion(client);
54
+ await client.query('BEGIN');
55
+ const currentVersion = await getDatabaseVersion(client, migrationsTable);
37
56
  const targetVersion = currentVersion - 1;
38
- const migration = migrations.find(x => x.version === currentVersion);
39
- errors_1.assert(migration, `Cannot find migration for version ${targetVersion}`);
40
57
  try {
41
- if (types_1.isFunction(migration.down)) {
58
+ const migration = migrations.find(x => x.version === currentVersion);
59
+ (0, errors_1.assert)(migration, `Cannot find migration for version ${targetVersion}`);
60
+ if ((0, types_1.isFunction)(migration.down)) {
42
61
  await migration.down(client);
43
62
  }
44
63
  else {
45
64
  await client.query(migration.down);
46
65
  }
66
+ await setDatabaseVersion(client, migrationsTable, targetVersion);
67
+ await client.query('COMMIT');
47
68
  }
48
69
  catch (e) {
49
70
  console.error(`Downgrade from version ${currentVersion} to version ${targetVersion} failed.`);
71
+ await client.query('ROLLBACK');
50
72
  throw e;
51
73
  }
52
- await setDatabaseVersion(client, targetVersion);
53
74
  }
54
75
  }
55
76
  exports.migrate = migrate;
56
77
  function getMaximumVersion(migrations) {
57
78
  return migrations.reduce((max, cur) => Math.max(cur.version, max), 0);
58
79
  }
59
- async function getDatabaseVersion(client) {
80
+ async function getDatabaseVersion(client, migrationTable) {
81
+ await ensureMigrationsTable(client, migrationTable);
60
82
  const result = await client.query(`
61
- SELECT COALESCE(current_setting('migrations.schema_version', true), '0')::integer AS version;
83
+ SELECT schema_version
84
+ FROM "${migrationTable}";
62
85
  `);
63
- return result.rows[0].version;
86
+ if (result.rows.length) {
87
+ return result.rows[0].schema_version;
88
+ }
89
+ else {
90
+ await client.query(`
91
+ INSERT INTO "${migrationTable}" (schema_version)
92
+ VALUES (0);
93
+ `);
94
+ return 0;
95
+ }
64
96
  }
65
- async function setDatabaseVersion(client, version) {
66
- const database = await getCurrentDatabase(client);
97
+ async function ensureMigrationsTable(client, migrationTable) {
67
98
  await client.query(`
68
- SET migrations.schema_version to ${version};
69
-
70
- ALTER DATABASE "${database}"
71
- SET migrations.schema_version
72
- FROM current;
99
+ CREATE TABLE IF NOT EXISTS "${migrationTable}" (
100
+ schema_version INTEGER NOT NULL
101
+ );
73
102
  `);
74
103
  }
75
- async function getCurrentDatabase(client) {
76
- const result = await client.query(`
77
- SELECT current_database() AS database;
104
+ async function setDatabaseVersion(client, migrationTable, version) {
105
+ await client.query(`
106
+ UPDATE ${migrationTable}
107
+ SET schema_version = ${version};
108
+ `);
109
+ }
110
+ async function lock(client, key) {
111
+ await client.query(`
112
+ SELECT pg_advisory_lock(${key});
113
+ `);
114
+ }
115
+ async function unlock(client, key) {
116
+ await client.query(`
117
+ SELECT pg_advisory_unlock(${key});
78
118
  `);
79
- return result.rows[0].database;
80
119
  }
81
120
  //# sourceMappingURL=migrate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/migrate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/migrate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blackglory/pg-migrations",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A utility for database migrations with pg",
5
5
  "keywords": [
6
6
  "migration",
@@ -20,7 +20,7 @@
20
20
  "license": "MIT",
21
21
  "scripts": {
22
22
  "lint": "eslint --ext .js,.jsx,.ts,.tsx --quiet src __tests__",
23
- "test": "jest --config jest.config.js",
23
+ "test": "jest --runInBand --config jest.config.js",
24
24
  "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
25
25
  "test:coverage": "jest --coverage --config jest.config.js",
26
26
  "prepublishOnly": "run-s clean build",
@@ -45,29 +45,28 @@
45
45
  }
46
46
  },
47
47
  "devDependencies": {
48
- "@commitlint/cli": "^11.0.0",
49
- "@commitlint/config-conventional": "^11.0.0",
50
- "@types/jest": "^26.0.14",
51
- "@types/node": "^14.14.24",
52
- "@types/pg": "^7.14.10",
53
- "@typescript-eslint/eslint-plugin": "^4.4.1",
54
- "@typescript-eslint/parser": "^4.4.1",
55
- "eslint": "^7.11.0",
48
+ "@commitlint/cli": "^16.2.1",
49
+ "@commitlint/config-conventional": "^16.2.1",
50
+ "@types/jest": "^27.4.0",
51
+ "@types/pg": "^8.6.4",
52
+ "@typescript-eslint/eslint-plugin": "^5.12.0",
53
+ "@typescript-eslint/parser": "^5.12.0",
54
+ "eslint": "^8.9.0",
56
55
  "husky": "^4.3.0",
57
- "jest": "^26.5.3",
56
+ "jest": "^27.5.1",
58
57
  "npm-run-all": "^4.1.5",
59
- "pg": "^8.5.1",
58
+ "pg": "^8.7.3",
60
59
  "rimraf": "^3.0.2",
61
- "standard-version": "^9.0.0",
62
- "ts-jest": "^26.4.1",
60
+ "standard-version": "^9.3.0",
61
+ "ts-jest": "^27.1.3",
63
62
  "tscpaths": "^0.0.9",
64
- "typescript": "^4.0.3"
63
+ "typescript": "^4.5.5"
65
64
  },
66
65
  "dependencies": {
67
- "@blackglory/errors": "^1.1.2",
68
- "@blackglory/types": "^0.2.13"
66
+ "@blackglory/errors": "^2.2.0",
67
+ "@blackglory/types": "^0.6.5"
69
68
  },
70
69
  "peerDependencies": {
71
- "pg": "8.x"
70
+ "pg": "8"
72
71
  }
73
72
  }
package/CHANGELOG.md DELETED
@@ -1,10 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
-
5
- ## 0.1.0 (2021-02-20)
6
-
7
-
8
- ### Features
9
-
10
- * init ([f5fcf82](https://github.com/BlackGlory/pg-migrations/commit/f5fcf8206e11fa669b6f7b95c7f4ef718550898a))