bunsql-native-migrate 0.2.0 → 0.3.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 +135 -34
- package/package.json +2 -1
- package/src/api/down.ts +23 -7
- package/src/api/init.ts +57 -0
- package/src/api/load-migration.ts +45 -0
- package/src/api/mark.ts +43 -0
- package/src/api/options.ts +14 -0
- package/src/api/run-step.ts +4 -2
- package/src/api/run-with-driver.ts +4 -1
- package/src/api/up.ts +42 -11
- package/src/cli/main.ts +77 -6
- package/src/core/driver.ts +18 -4
- package/src/core/duration.ts +7 -0
- package/src/core/fs.ts +1 -1
- package/src/core/identifiers.ts +32 -0
- package/src/drivers/mariadb.ts +70 -41
- package/src/drivers/postgres.ts +73 -33
- package/src/drivers/shared.ts +12 -4
- package/src/drivers/sqlite.ts +58 -31
- package/src/index.ts +15 -1
package/src/drivers/shared.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface SqlLock {
|
|
|
10
10
|
export interface SqlDialect {
|
|
11
11
|
install(db: SQL): Promise<void>;
|
|
12
12
|
record(db: SQL, migration: string, checksum: string): Promise<void>;
|
|
13
|
+
trackingTableExists?(db: SQL): Promise<boolean>;
|
|
13
14
|
createLock?(db: SQL): SqlLock;
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -54,14 +55,18 @@ export function createReservedLock(
|
|
|
54
55
|
};
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
export function createSqlDriver(
|
|
58
|
+
export function createSqlDriver(
|
|
59
|
+
databaseUrl: string,
|
|
60
|
+
dialect: SqlDialect,
|
|
61
|
+
table: string,
|
|
62
|
+
): MigrationDriver {
|
|
58
63
|
const db = new SQL(databaseUrl);
|
|
59
64
|
const lock = dialect.createLock?.(db);
|
|
60
65
|
|
|
61
66
|
return {
|
|
62
67
|
install: () => dialect.install(db),
|
|
63
68
|
async listExecuted() {
|
|
64
|
-
const rows = await db`SELECT migration, checksum FROM
|
|
69
|
+
const rows = await db`SELECT migration, checksum FROM ${db.unsafe(table)} ORDER BY id ASC`;
|
|
65
70
|
return rows.map(
|
|
66
71
|
(r: { migration: string; checksum: string | null }): ExecutedMigration => ({
|
|
67
72
|
name: r.migration,
|
|
@@ -71,12 +76,15 @@ export function createSqlDriver(databaseUrl: string, dialect: SqlDialect): Migra
|
|
|
71
76
|
},
|
|
72
77
|
record: (migration, checksum) => dialect.record(db, migration, checksum),
|
|
73
78
|
async setChecksum(migration, checksum) {
|
|
74
|
-
await db`UPDATE
|
|
79
|
+
await db`UPDATE ${db.unsafe(table)} SET checksum = ${checksum} WHERE migration = ${migration}`;
|
|
75
80
|
},
|
|
76
81
|
async remove(migration) {
|
|
77
|
-
await db`DELETE FROM
|
|
82
|
+
await db`DELETE FROM ${db.unsafe(table)} WHERE migration = ${migration}`;
|
|
78
83
|
},
|
|
79
84
|
transaction: (run) => db.begin(run),
|
|
85
|
+
...(dialect.trackingTableExists
|
|
86
|
+
? { trackingTableExists: () => dialect.trackingTableExists!(db) }
|
|
87
|
+
: {}),
|
|
80
88
|
...(lock
|
|
81
89
|
? {
|
|
82
90
|
tryLock: (timeoutSeconds: number) => lock.tryLock(timeoutSeconds),
|
package/src/drivers/sqlite.ts
CHANGED
|
@@ -1,36 +1,63 @@
|
|
|
1
|
-
import type { MigrationDriver } from "../core/driver.js";
|
|
1
|
+
import type { DriverTableOptions, MigrationDriver } from "../core/driver.js";
|
|
2
|
+
import { doubleQuoted, validateIdentifier } from "../core/identifiers.js";
|
|
2
3
|
import { createSqlDriver } from "./shared.js";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
async
|
|
27
|
-
await db
|
|
28
|
-
|
|
5
|
+
const TABLE_NAME_MAX_LENGTH = 128;
|
|
6
|
+
const UNIQUE_INDEX_SUFFIX = "_migration_unique";
|
|
7
|
+
|
|
8
|
+
function resolveTableRef(options: DriverTableOptions): {
|
|
9
|
+
table: string;
|
|
10
|
+
index: string;
|
|
11
|
+
name: string;
|
|
12
|
+
} {
|
|
13
|
+
const tableName = options.tableName ?? "migrations";
|
|
14
|
+
validateIdentifier("table", tableName, TABLE_NAME_MAX_LENGTH);
|
|
15
|
+
return {
|
|
16
|
+
table: doubleQuoted(tableName),
|
|
17
|
+
index: doubleQuoted(`${tableName}${UNIQUE_INDEX_SUFFIX}`),
|
|
18
|
+
name: tableName,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function create(databaseUrl: string, options: DriverTableOptions = {}): MigrationDriver {
|
|
23
|
+
const { table, index, name } = resolveTableRef(options);
|
|
24
|
+
return createSqlDriver(
|
|
25
|
+
databaseUrl,
|
|
26
|
+
{
|
|
27
|
+
async install(db) {
|
|
28
|
+
await db`CREATE TABLE IF NOT EXISTS ${db.unsafe(table)} (
|
|
29
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
30
|
+
migration TEXT NOT NULL,
|
|
31
|
+
checksum TEXT
|
|
32
|
+
)`;
|
|
33
|
+
const columns = (await db.unsafe(`PRAGMA table_info(${table})`)) as Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
}>;
|
|
36
|
+
const hasChecksum = columns.some((column) => column.name === "checksum");
|
|
37
|
+
if (!hasChecksum) {
|
|
38
|
+
await db`ALTER TABLE ${db.unsafe(table)} ADD COLUMN checksum TEXT`;
|
|
39
|
+
}
|
|
40
|
+
await db`CREATE UNIQUE INDEX IF NOT EXISTS ${db.unsafe(index)} ON ${db.unsafe(table)} (migration)`;
|
|
41
|
+
},
|
|
42
|
+
async trackingTableExists(db) {
|
|
43
|
+
const rows = await db`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${name}`;
|
|
44
|
+
return rows.length > 0;
|
|
29
45
|
},
|
|
30
|
-
async
|
|
31
|
-
await db.unsafe(
|
|
46
|
+
async record(db, migration, checksum) {
|
|
47
|
+
await db`INSERT OR IGNORE INTO ${db.unsafe(table)} (migration, checksum)
|
|
48
|
+
VALUES (${migration}, ${checksum})`;
|
|
32
49
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
50
|
+
createLock: (db) => ({
|
|
51
|
+
async tryLock(timeoutSeconds: number) {
|
|
52
|
+
await db.unsafe(`PRAGMA busy_timeout = ${timeoutSeconds * 1000}`);
|
|
53
|
+
return true;
|
|
54
|
+
},
|
|
55
|
+
async releaseLock() {
|
|
56
|
+
await db.unsafe("PRAGMA busy_timeout = 0");
|
|
57
|
+
},
|
|
58
|
+
dispose() {},
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
table,
|
|
62
|
+
);
|
|
36
63
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createDriver,
|
|
3
|
+
type DriverTableOptions,
|
|
4
|
+
type ExecutedMigration,
|
|
5
|
+
type MigrationDriver,
|
|
6
|
+
} from "./core/driver.js";
|
|
7
|
+
import { InvalidIdentifierError } from "./core/identifiers.js";
|
|
2
8
|
import { migrateUp } from "./api/up.js";
|
|
3
9
|
import { migrateDown } from "./api/down.js";
|
|
4
10
|
import { migrateStatus } from "./api/status.js";
|
|
5
11
|
import { installMigrations } from "./api/install.js";
|
|
6
12
|
import { createMigration } from "./api/create.js";
|
|
13
|
+
import { markMigrationsApplied } from "./api/mark.js";
|
|
7
14
|
import {
|
|
8
15
|
type MigrateDownOptions,
|
|
9
16
|
type MigrateDownResult,
|
|
17
|
+
type MarkOptions,
|
|
18
|
+
type MarkResult,
|
|
10
19
|
type MigrateOptions,
|
|
11
20
|
type MigrateStatusResult,
|
|
12
21
|
type MigrateUpOptions,
|
|
@@ -24,12 +33,15 @@ export {
|
|
|
24
33
|
migrateStatus,
|
|
25
34
|
installMigrations,
|
|
26
35
|
createMigration,
|
|
36
|
+
markMigrationsApplied,
|
|
27
37
|
ChecksumDriftError,
|
|
28
38
|
GitStageError,
|
|
39
|
+
InvalidIdentifierError,
|
|
29
40
|
MigrationLockError,
|
|
30
41
|
MigrationNotFoundError,
|
|
31
42
|
};
|
|
32
43
|
export type {
|
|
44
|
+
DriverTableOptions,
|
|
33
45
|
ExecutedMigration,
|
|
34
46
|
MigrationDriver,
|
|
35
47
|
MigrateOptions,
|
|
@@ -37,5 +49,7 @@ export type {
|
|
|
37
49
|
MigrateUpResult,
|
|
38
50
|
MigrateDownOptions,
|
|
39
51
|
MigrateDownResult,
|
|
52
|
+
MarkOptions,
|
|
53
|
+
MarkResult,
|
|
40
54
|
MigrateStatusResult,
|
|
41
55
|
};
|