@blackglory/sqlite3-migrations 0.1.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/LICENSE +21 -0
- package/README.md +42 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/migrate.d.ts +7 -0
- package/lib/migrate.js +89 -0
- package/lib/migrate.js.map +1 -0
- package/package.json +71 -0
- package/src/index.ts +1 -0
- package/src/migrate.ts +111 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 BlackGlory <woshenmedoubuzhidao@blackglory.me>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# sqlite3-migrations
|
|
2
|
+
A utility for database migrations with [sqlite3].
|
|
3
|
+
|
|
4
|
+
The module using [user_version] to record the schema version.
|
|
5
|
+
|
|
6
|
+
[sqlite3]: https://www.npmjs.com/package/sqlite3
|
|
7
|
+
[user_version]: https://www.sqlite.org/pragma.html#pragma_user_version
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
```sh
|
|
11
|
+
npm install --save @blackglory/sqlite3-migrations
|
|
12
|
+
# or
|
|
13
|
+
yarn add @blackglory/sqlite3-migrations
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## API
|
|
17
|
+
```ts
|
|
18
|
+
interface IMigration {
|
|
19
|
+
version: number
|
|
20
|
+
up: string | ((db: Database) => PromiseLike<void>)
|
|
21
|
+
down: string | ((db: Database) => PromiseLike<void>)
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
You may need [migration-files].
|
|
26
|
+
|
|
27
|
+
[migration-files]: https://github.com/BlackGlory/migration-files
|
|
28
|
+
|
|
29
|
+
### migrate
|
|
30
|
+
```ts
|
|
31
|
+
function migrate(db: Database, migrations: IMigration[], targetVersion?: number): void
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If targetVersion is `undefined`, then use the maximum version of migrations.
|
|
35
|
+
|
|
36
|
+
## FAQ
|
|
37
|
+
### Can multiple instances migrate in parallel?
|
|
38
|
+
Yes, the `user_version` update is visible to every database connection.
|
|
39
|
+
When the maximum migration version is less than the `user_version` (which means it is an obsolete instance), it will skip the migration.
|
|
40
|
+
|
|
41
|
+
You may need a proper retry strategy,
|
|
42
|
+
because each migration uses `BEGIN IMMEDIATE` to ensure that parallel write transactions fail early.
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './migrate.js';
|
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA"}
|
package/lib/migrate.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Database } from 'sqlite3';
|
|
2
|
+
export interface IMigration {
|
|
3
|
+
version: number;
|
|
4
|
+
up: string | ((db: Database) => PromiseLike<void>);
|
|
5
|
+
down: string | ((db: Database) => PromiseLike<void>);
|
|
6
|
+
}
|
|
7
|
+
export declare function migrate(db: Database, migrations: IMigration[], targetVersion?: number): Promise<void>;
|
package/lib/migrate.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { assert, isFunction } from '@blackglory/prelude';
|
|
2
|
+
import { promisify } from 'extra-promise';
|
|
3
|
+
export async function migrate(db, migrations, targetVersion = getMaximumVersion(migrations)) {
|
|
4
|
+
const run = promisify(db.run.bind(db));
|
|
5
|
+
const exec = promisify(db.exec.bind(db));
|
|
6
|
+
const get = promisify(db.get.bind(db));
|
|
7
|
+
const maxVersion = getMaximumVersion(migrations);
|
|
8
|
+
await run('BEGIN IMMEDIATE');
|
|
9
|
+
try {
|
|
10
|
+
while (true) {
|
|
11
|
+
const done = await migrate(targetVersion, maxVersion);
|
|
12
|
+
if (done)
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
await run('COMMIT');
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
await run('ROLLBACK');
|
|
19
|
+
throw e;
|
|
20
|
+
}
|
|
21
|
+
async function migrate(targetVersion, maxVersion) {
|
|
22
|
+
const currentVersion = await getDatabaseVersion();
|
|
23
|
+
if (maxVersion < currentVersion) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
if (currentVersion === targetVersion) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
else if (currentVersion < targetVersion) {
|
|
31
|
+
await upgrade();
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
await downgrade();
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function upgrade() {
|
|
41
|
+
const currentVersion = await getDatabaseVersion();
|
|
42
|
+
const targetVersion = currentVersion + 1;
|
|
43
|
+
const migration = migrations.find(x => x.version === targetVersion);
|
|
44
|
+
assert(migration, `Cannot find migration for version ${targetVersion}`);
|
|
45
|
+
try {
|
|
46
|
+
if (isFunction(migration.up)) {
|
|
47
|
+
await migration.up(db);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
await exec(migration.up);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
console.error(`Upgrade from version ${currentVersion} to version ${targetVersion} failed.`);
|
|
55
|
+
throw e;
|
|
56
|
+
}
|
|
57
|
+
await setDatabaseVersion(targetVersion);
|
|
58
|
+
}
|
|
59
|
+
async function downgrade() {
|
|
60
|
+
const currentVersion = await getDatabaseVersion();
|
|
61
|
+
const targetVersion = currentVersion - 1;
|
|
62
|
+
const migration = migrations.find(x => x.version === currentVersion);
|
|
63
|
+
assert(migration, `Cannot find migration for version ${targetVersion}`);
|
|
64
|
+
try {
|
|
65
|
+
if (isFunction(migration.down)) {
|
|
66
|
+
await migration.down(db);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
await exec(migration.down);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
console.error(`Downgrade from version ${currentVersion} to version ${targetVersion} failed.`);
|
|
74
|
+
throw e;
|
|
75
|
+
}
|
|
76
|
+
await setDatabaseVersion(targetVersion);
|
|
77
|
+
}
|
|
78
|
+
async function getDatabaseVersion() {
|
|
79
|
+
const row = await get('PRAGMA user_version;');
|
|
80
|
+
return row.user_version;
|
|
81
|
+
}
|
|
82
|
+
async function setDatabaseVersion(version) {
|
|
83
|
+
await run(`PRAGMA user_version = ${version}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function getMaximumVersion(migrations) {
|
|
87
|
+
return migrations.reduce((max, cur) => Math.max(cur.version, max), 0);
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blackglory/sqlite3-migrations",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A utility for database migrations with sqlite3",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"migration",
|
|
7
|
+
"migrations",
|
|
8
|
+
"sqlite3",
|
|
9
|
+
"up",
|
|
10
|
+
"down",
|
|
11
|
+
"sql"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
"lib",
|
|
15
|
+
"src"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "lib/index.js",
|
|
19
|
+
"types": "lib/index.d.ts",
|
|
20
|
+
"repository": "git@github.com:BlackGlory/sqlite3-migrations.git",
|
|
21
|
+
"author": "BlackGlory <woshenmedoubuzhidao@blackglory.me>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18.17.0"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"prepare": "ts-patch install -s",
|
|
29
|
+
"lint": "eslint --ext .js,.jsx,.ts,.tsx --quiet src __tests__",
|
|
30
|
+
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --runInBand --config jest.config.cjs",
|
|
31
|
+
"prepublishOnly": "run-s prepare clean build",
|
|
32
|
+
"clean": "rimraf lib",
|
|
33
|
+
"build": "tsc --project tsconfig.build.json",
|
|
34
|
+
"release": "standard-version"
|
|
35
|
+
},
|
|
36
|
+
"husky": {
|
|
37
|
+
"hooks": {
|
|
38
|
+
"pre-commit": "run-s prepare clean lint build test",
|
|
39
|
+
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@blackglory/jest-resolver": "^0.3.1",
|
|
44
|
+
"@commitlint/cli": "^18.4.3",
|
|
45
|
+
"@commitlint/config-conventional": "^18.4.3",
|
|
46
|
+
"@types/jest": "^29.5.11",
|
|
47
|
+
"@types/node": "18",
|
|
48
|
+
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
|
49
|
+
"@typescript-eslint/parser": "^6.14.0",
|
|
50
|
+
"cross-env": "^7.0.3",
|
|
51
|
+
"eslint": "^8.55.0",
|
|
52
|
+
"husky": "4",
|
|
53
|
+
"jest": "^29.7.0",
|
|
54
|
+
"jest-resolve": "^29.7.0",
|
|
55
|
+
"npm-run-all": "^4.1.5",
|
|
56
|
+
"rimraf": "^5.0.5",
|
|
57
|
+
"sqlite3": "^5.1.6",
|
|
58
|
+
"standard-version": "^9.5.0",
|
|
59
|
+
"ts-jest": "^29.1.1",
|
|
60
|
+
"ts-patch": "^3.1.1",
|
|
61
|
+
"typescript": "^5.3.3",
|
|
62
|
+
"typescript-transform-paths": "^3.4.6"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@blackglory/prelude": "^0.3.4",
|
|
66
|
+
"extra-promise": "^6.0.8"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"sqlite3": "^5.1.6"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './migrate.js'
|
package/src/migrate.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { Database } from 'sqlite3'
|
|
2
|
+
import { assert, isFunction } from '@blackglory/prelude'
|
|
3
|
+
import { promisify } from 'extra-promise'
|
|
4
|
+
|
|
5
|
+
export interface IMigration {
|
|
6
|
+
version: number
|
|
7
|
+
up: string | ((db: Database) => PromiseLike<void>)
|
|
8
|
+
down: string | ((db: Database) => PromiseLike<void>)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function migrate(
|
|
12
|
+
db: Database
|
|
13
|
+
, migrations: IMigration[]
|
|
14
|
+
, targetVersion: number = getMaximumVersion(migrations)
|
|
15
|
+
): Promise<void> {
|
|
16
|
+
const run = promisify(db.run.bind(db))
|
|
17
|
+
const exec = promisify(db.exec.bind(db))
|
|
18
|
+
const get = promisify(db.get.bind(db))
|
|
19
|
+
|
|
20
|
+
const maxVersion = getMaximumVersion(migrations)
|
|
21
|
+
|
|
22
|
+
await run('BEGIN IMMEDIATE')
|
|
23
|
+
try {
|
|
24
|
+
while (true) {
|
|
25
|
+
const done = await migrate(targetVersion, maxVersion)
|
|
26
|
+
if (done) break
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await run('COMMIT')
|
|
30
|
+
} catch (e) {
|
|
31
|
+
await run('ROLLBACK')
|
|
32
|
+
throw e
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function migrate(
|
|
36
|
+
targetVersion: number
|
|
37
|
+
, maxVersion: number
|
|
38
|
+
): Promise<boolean> {
|
|
39
|
+
const currentVersion = await getDatabaseVersion()
|
|
40
|
+
if (maxVersion < currentVersion) {
|
|
41
|
+
return true
|
|
42
|
+
} else {
|
|
43
|
+
if (currentVersion === targetVersion) {
|
|
44
|
+
return true
|
|
45
|
+
} else if (currentVersion < targetVersion) {
|
|
46
|
+
await upgrade()
|
|
47
|
+
return false
|
|
48
|
+
} else {
|
|
49
|
+
await downgrade()
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function upgrade(): Promise<void> {
|
|
56
|
+
const currentVersion = await getDatabaseVersion()
|
|
57
|
+
const targetVersion = currentVersion + 1
|
|
58
|
+
|
|
59
|
+
const migration = migrations.find(x => x.version === targetVersion)
|
|
60
|
+
assert(migration, `Cannot find migration for version ${targetVersion}`)
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
if (isFunction(migration.up)) {
|
|
64
|
+
await migration.up(db)
|
|
65
|
+
} else {
|
|
66
|
+
await exec(migration.up)
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
console.error(`Upgrade from version ${currentVersion} to version ${targetVersion} failed.`)
|
|
70
|
+
throw e
|
|
71
|
+
}
|
|
72
|
+
await setDatabaseVersion(targetVersion)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function downgrade(): Promise<void> {
|
|
76
|
+
const currentVersion = await getDatabaseVersion()
|
|
77
|
+
const targetVersion = currentVersion - 1
|
|
78
|
+
|
|
79
|
+
const migration = migrations.find(x => x.version === currentVersion)
|
|
80
|
+
assert(migration, `Cannot find migration for version ${targetVersion}`)
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
if (isFunction(migration.down)) {
|
|
84
|
+
await migration.down(db)
|
|
85
|
+
} else {
|
|
86
|
+
await exec(migration.down)
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.error(`Downgrade from version ${currentVersion} to version ${targetVersion} failed.`)
|
|
90
|
+
throw e
|
|
91
|
+
}
|
|
92
|
+
await setDatabaseVersion(targetVersion)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function getDatabaseVersion(): Promise<number> {
|
|
96
|
+
const row = await get('PRAGMA user_version;') as {
|
|
97
|
+
user_version: number
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return row.user_version
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function setDatabaseVersion(version: number): Promise<void> {
|
|
104
|
+
// PRAGMA不支持变量
|
|
105
|
+
await run(`PRAGMA user_version = ${ version }`)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getMaximumVersion(migrations: IMigration[]): number {
|
|
110
|
+
return migrations.reduce((max, cur) => Math.max(cur.version, max), 0)
|
|
111
|
+
}
|