bunsql-native-migrate 0.3.1 → 0.3.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.
- package/package.json +1 -1
- package/src/api/down.ts +10 -7
- package/src/api/mark.ts +18 -14
- package/src/api/pending.ts +37 -0
- package/src/api/up.ts +9 -16
- package/src/cli/main.ts +8 -7
- package/src/core/console.ts +18 -18
- package/src/drivers/mariadb.ts +11 -18
- package/src/drivers/postgres.ts +30 -20
- package/src/drivers/shared.ts +25 -1
- package/src/drivers/sqlite.ts +6 -18
package/package.json
CHANGED
package/src/api/down.ts
CHANGED
|
@@ -8,15 +8,20 @@ import { runMigrationStep } from "./run-step.js";
|
|
|
8
8
|
import { isSqlMigration, loadMigration } from "./load-migration.js";
|
|
9
9
|
import { ensureTrackingTable, listExecutedForPlan } from "./tracking-table.js";
|
|
10
10
|
|
|
11
|
-
function
|
|
11
|
+
export function parseSteps(steps: number | "all" | undefined): number | "all" {
|
|
12
12
|
if (steps === undefined) return 1;
|
|
13
|
-
if (steps === "all") return
|
|
13
|
+
if (steps === "all") return "all";
|
|
14
14
|
if (!Number.isInteger(steps) || steps < 1) {
|
|
15
15
|
throw new Error(`Invalid steps: ${String(steps)} — expected a positive integer or "all"`);
|
|
16
16
|
}
|
|
17
17
|
return steps;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function resolveStepCount(steps: number | "all" | undefined, appliedCount: number): number {
|
|
21
|
+
const parsed = parseSteps(steps);
|
|
22
|
+
return parsed === "all" ? appliedCount : parsed;
|
|
23
|
+
}
|
|
24
|
+
|
|
20
25
|
async function revertOne(driver: MigrationDriver, listDir: string, file: string): Promise<void> {
|
|
21
26
|
const { down } = await loadMigration(listDir, file);
|
|
22
27
|
|
|
@@ -49,10 +54,8 @@ export async function migrateDown(options: MigrateDownOptions = {}): Promise<Mig
|
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
const count = resolveStepCount(options.steps, executed.length);
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
.reverse()
|
|
55
|
-
.map((entry) => entry.name);
|
|
57
|
+
const revertList = executed.slice(-count).reverse();
|
|
58
|
+
const plan = revertList.map((entry) => entry.name);
|
|
56
59
|
|
|
57
60
|
if (dryRun) {
|
|
58
61
|
log({ text: "Dry run — no changes will be made.", type: "info" });
|
|
@@ -64,7 +67,7 @@ export async function migrateDown(options: MigrateDownOptions = {}): Promise<Mig
|
|
|
64
67
|
|
|
65
68
|
const reverted: string[] = [];
|
|
66
69
|
|
|
67
|
-
for (const entry of
|
|
70
|
+
for (const entry of revertList) {
|
|
68
71
|
try {
|
|
69
72
|
await revertOne(driver, listDir, entry.name);
|
|
70
73
|
} catch (error) {
|
package/src/api/mark.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { checksumFile, listFiles, MIGRATION_EXTENSIONS, resolveListDir } from "../core/fs.js";
|
|
3
3
|
import { log } from "../core/console.js";
|
|
4
|
-
import { type MarkOptions, type MarkResult
|
|
4
|
+
import { type MarkOptions, type MarkResult } from "./options.js";
|
|
5
|
+
import { resolvePendingToTarget } from "./pending.js";
|
|
5
6
|
import { runWithDriver } from "./run-with-driver.js";
|
|
6
7
|
import { ensureTrackingTable } from "./tracking-table.js";
|
|
7
8
|
|
|
@@ -13,24 +14,27 @@ export async function markMigrationsApplied(options: MarkOptions = {}): Promise<
|
|
|
13
14
|
await ensureTrackingTable(driver);
|
|
14
15
|
|
|
15
16
|
const allFiles = await listFiles(listDir, MIGRATION_EXTENSIONS);
|
|
16
|
-
if (target !== undefined && !allFiles.includes(target)) {
|
|
17
|
-
throw new MigrationNotFoundError(target);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
17
|
const executed = await driver.listExecuted();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
|
|
19
|
+
const { pending, targetApplied } = resolvePendingToTarget({
|
|
20
|
+
allFiles,
|
|
21
|
+
executedNames: executed.map((entry) => entry.name),
|
|
22
|
+
target,
|
|
23
|
+
});
|
|
24
|
+
if (targetApplied) {
|
|
25
|
+
return { marked: [] };
|
|
29
26
|
}
|
|
30
27
|
|
|
28
|
+
const checksums = new Map(
|
|
29
|
+
await Promise.all(
|
|
30
|
+
pending.map(async (file) => [file, await checksumFile(path.join(listDir, file))] as const),
|
|
31
|
+
),
|
|
32
|
+
);
|
|
33
|
+
|
|
31
34
|
const marked: string[] = [];
|
|
32
35
|
for (const file of pending) {
|
|
33
|
-
const checksum =
|
|
36
|
+
const checksum = checksums.get(file);
|
|
37
|
+
if (!checksum) continue;
|
|
34
38
|
await driver.record(file, checksum);
|
|
35
39
|
marked.push(file);
|
|
36
40
|
log({ text: `${file} marked as applied`, type: "success" });
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { log } from "../core/console.js";
|
|
2
|
+
import { MigrationNotFoundError } from "./options.js";
|
|
3
|
+
|
|
4
|
+
export interface PendingToTargetResult {
|
|
5
|
+
pending: string[];
|
|
6
|
+
targetApplied: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ResolvePendingOptions {
|
|
10
|
+
allFiles: string[];
|
|
11
|
+
executedNames: string[];
|
|
12
|
+
target: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resolvePendingToTarget({
|
|
16
|
+
allFiles,
|
|
17
|
+
executedNames,
|
|
18
|
+
target,
|
|
19
|
+
}: ResolvePendingOptions): PendingToTargetResult {
|
|
20
|
+
const executed = new Set(executedNames);
|
|
21
|
+
|
|
22
|
+
if (target !== undefined && !allFiles.includes(target)) {
|
|
23
|
+
throw new MigrationNotFoundError(target);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let pending = allFiles.filter((file) => !executed.has(file));
|
|
27
|
+
let targetApplied = false;
|
|
28
|
+
if (target !== undefined) {
|
|
29
|
+
if (executed.has(target)) {
|
|
30
|
+
log({ text: `${target} is already applied.`, type: "info" });
|
|
31
|
+
targetApplied = true;
|
|
32
|
+
} else {
|
|
33
|
+
pending = pending.slice(0, pending.indexOf(target) + 1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { pending, targetApplied };
|
|
37
|
+
}
|
package/src/api/up.ts
CHANGED
|
@@ -2,15 +2,11 @@ import path from "node:path";
|
|
|
2
2
|
import { checksumFile, listFiles, MIGRATION_EXTENSIONS, resolveListDir } from "../core/fs.js";
|
|
3
3
|
import { log } from "../core/console.js";
|
|
4
4
|
import { formatDuration } from "../core/duration.js";
|
|
5
|
-
import {
|
|
6
|
-
type MigrateUpOptions,
|
|
7
|
-
type MigrateUpResult,
|
|
8
|
-
ChecksumDriftError,
|
|
9
|
-
MigrationNotFoundError,
|
|
10
|
-
} from "./options.js";
|
|
5
|
+
import { type MigrateUpOptions, type MigrateUpResult, ChecksumDriftError } from "./options.js";
|
|
11
6
|
import { runWithDriver } from "./run-with-driver.js";
|
|
12
7
|
import { runMigrationStep } from "./run-step.js";
|
|
13
8
|
import { loadMigration } from "./load-migration.js";
|
|
9
|
+
import { resolvePendingToTarget } from "./pending.js";
|
|
14
10
|
import { resolveLockTimeout, withMigrationLock } from "./lock.js";
|
|
15
11
|
import { ensureTrackingTable, listExecutedForPlan } from "./tracking-table.js";
|
|
16
12
|
|
|
@@ -27,9 +23,6 @@ export async function migrateUp(options: MigrateUpOptions = {}): Promise<Migrate
|
|
|
27
23
|
|
|
28
24
|
const run = async (): Promise<MigrateUpResult> => {
|
|
29
25
|
const allFiles = await listFiles(listDir, MIGRATION_EXTENSIONS);
|
|
30
|
-
if (target !== undefined && !allFiles.includes(target)) {
|
|
31
|
-
throw new MigrationNotFoundError(target);
|
|
32
|
-
}
|
|
33
26
|
|
|
34
27
|
const checksums = new Map(
|
|
35
28
|
await Promise.all(
|
|
@@ -59,13 +52,13 @@ export async function migrateUp(options: MigrateUpOptions = {}): Promise<Migrate
|
|
|
59
52
|
}
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
const { pending, targetApplied } = resolvePendingToTarget({
|
|
56
|
+
allFiles,
|
|
57
|
+
executedNames: executed.map((entry) => entry.name),
|
|
58
|
+
target,
|
|
59
|
+
});
|
|
60
|
+
if (targetApplied) {
|
|
61
|
+
return dryRun ? { applied: [], planned: [] } : { applied: [] };
|
|
69
62
|
}
|
|
70
63
|
|
|
71
64
|
if (dryRun) {
|
package/src/cli/main.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { migrateUp } from "../api/up.js";
|
|
3
|
-
import { migrateDown } from "../api/down.js";
|
|
3
|
+
import { migrateDown, parseSteps } from "../api/down.js";
|
|
4
4
|
import { migrateStatus } from "../api/status.js";
|
|
5
5
|
import { installMigrations } from "../api/install.js";
|
|
6
6
|
import { createMigrationCommand, type MigrationLang } from "../api/create.js";
|
|
7
7
|
import { initMigrations } from "../api/init.js";
|
|
8
8
|
import { markMigrationsApplied } from "../api/mark.js";
|
|
9
|
+
import { resolveLockTimeout } from "../api/lock.js";
|
|
9
10
|
import { ChecksumDriftError, MigrationLockError, MigrationNotFoundError } from "../api/options.js";
|
|
10
11
|
import { InvalidIdentifierError } from "../core/identifiers.js";
|
|
11
12
|
import { log } from "../core/console.js";
|
|
@@ -63,15 +64,15 @@ function parseArgs(argv: string[]): CliArgs {
|
|
|
63
64
|
}
|
|
64
65
|
} else if (arg === "--lock-timeout") {
|
|
65
66
|
const value = argv[++i];
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
try {
|
|
68
|
+
lockTimeout = resolveLockTimeout(Number(value));
|
|
69
|
+
} catch {
|
|
68
70
|
log({
|
|
69
71
|
text: `Invalid --lock-timeout: ${value ?? "(missing)"} (expected a non-negative integer of seconds)`,
|
|
70
72
|
type: "error",
|
|
71
73
|
});
|
|
72
74
|
usage(1);
|
|
73
75
|
}
|
|
74
|
-
lockTimeout = parsed;
|
|
75
76
|
} else if (arg === "--table") {
|
|
76
77
|
table = argv[++i];
|
|
77
78
|
if (table === undefined) {
|
|
@@ -160,15 +161,15 @@ try {
|
|
|
160
161
|
if (args.all) {
|
|
161
162
|
steps = "all";
|
|
162
163
|
} else if (stepsArg !== undefined) {
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
try {
|
|
165
|
+
steps = parseSteps(Number(stepsArg));
|
|
166
|
+
} catch {
|
|
165
167
|
log({
|
|
166
168
|
text: `Invalid step count: ${stepsArg} (expected a positive integer)`,
|
|
167
169
|
type: "error",
|
|
168
170
|
});
|
|
169
171
|
usage(1);
|
|
170
172
|
}
|
|
171
|
-
steps = parsed;
|
|
172
173
|
}
|
|
173
174
|
const { reverted, planned } = await migrateDown({
|
|
174
175
|
...listDirOptions,
|
package/src/core/console.ts
CHANGED
|
@@ -13,32 +13,32 @@ interface LogOptions {
|
|
|
13
13
|
error?: unknown;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
function formatError(error: any): void {
|
|
16
|
+
function formatError(error: unknown): void {
|
|
18
17
|
if (error instanceof Error) {
|
|
19
18
|
console.log(error.message);
|
|
20
19
|
if (error.stack) console.log(error.stack);
|
|
21
20
|
return;
|
|
22
21
|
}
|
|
23
|
-
if (typeof error
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if ("
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
if (typeof error !== "object" || error === null) {
|
|
23
|
+
console.log(String(error));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if ("code" in error && "detail" in error) {
|
|
27
|
+
console.table(error);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if ("code" in error && "errno" in error) {
|
|
31
|
+
console.log(error.code);
|
|
32
|
+
console.log(error.errno);
|
|
33
|
+
if ("byteOffset" in error) console.log(error.byteOffset);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if ("message" in error) {
|
|
37
|
+
console.log(error.message);
|
|
38
|
+
return;
|
|
38
39
|
}
|
|
39
40
|
console.log(String(error));
|
|
40
41
|
}
|
|
41
|
-
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
42
42
|
|
|
43
43
|
export function log({ text, type, error = null }: LogOptions): void {
|
|
44
44
|
console.log(colors[type], text);
|
package/src/drivers/mariadb.ts
CHANGED
|
@@ -1,26 +1,16 @@
|
|
|
1
1
|
import { type SQL } from "bun";
|
|
2
2
|
import type { DriverTableOptions, MigrationDriver } from "../core/driver.js";
|
|
3
|
-
import { backtickQuoted
|
|
4
|
-
import {
|
|
3
|
+
import { backtickQuoted } from "../core/identifiers.js";
|
|
4
|
+
import {
|
|
5
|
+
createReservedLock,
|
|
6
|
+
createSqlDriver,
|
|
7
|
+
resolveTableRef,
|
|
8
|
+
UNIQUE_INDEX_SUFFIX,
|
|
9
|
+
} from "./shared.js";
|
|
5
10
|
|
|
6
11
|
const LOCK_NAME_PREFIX = "bunsql-native-migrate:";
|
|
7
12
|
|
|
8
13
|
const TABLE_NAME_MAX_LENGTH = 47;
|
|
9
|
-
const UNIQUE_INDEX_SUFFIX = "_migration_unique";
|
|
10
|
-
|
|
11
|
-
function resolveTableRef(options: DriverTableOptions): {
|
|
12
|
-
table: string;
|
|
13
|
-
index: string;
|
|
14
|
-
name: string;
|
|
15
|
-
} {
|
|
16
|
-
const tableName = options.tableName ?? "migrations";
|
|
17
|
-
validateIdentifier("table", tableName, TABLE_NAME_MAX_LENGTH);
|
|
18
|
-
return {
|
|
19
|
-
table: backtickQuoted(tableName),
|
|
20
|
-
index: backtickQuoted(`${tableName}${UNIQUE_INDEX_SUFFIX}`),
|
|
21
|
-
name: tableName,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
14
|
|
|
25
15
|
async function checksumColumnExists(db: SQL, tableName: string): Promise<boolean> {
|
|
26
16
|
const rows = await db`SELECT column_name FROM information_schema.columns
|
|
@@ -39,7 +29,10 @@ async function uniqueIndexExists(db: SQL, tableName: string): Promise<boolean> {
|
|
|
39
29
|
}
|
|
40
30
|
|
|
41
31
|
export function create(databaseUrl: string, options: DriverTableOptions = {}): MigrationDriver {
|
|
42
|
-
const { table, index, name } = resolveTableRef(options
|
|
32
|
+
const { table, index, name } = resolveTableRef(options, {
|
|
33
|
+
quote: backtickQuoted,
|
|
34
|
+
maxLength: TABLE_NAME_MAX_LENGTH,
|
|
35
|
+
});
|
|
43
36
|
return createSqlDriver(
|
|
44
37
|
databaseUrl,
|
|
45
38
|
{
|
package/src/drivers/postgres.ts
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import { type SQL } from "bun";
|
|
2
2
|
import type { DriverTableOptions, MigrationDriver } from "../core/driver.js";
|
|
3
3
|
import { doubleQuoted, validateIdentifier } from "../core/identifiers.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createReservedLock,
|
|
6
|
+
createSqlDriver,
|
|
7
|
+
resolveTableRef,
|
|
8
|
+
UNIQUE_INDEX_SUFFIX,
|
|
9
|
+
type TableRef,
|
|
10
|
+
} from "./shared.js";
|
|
5
11
|
|
|
6
12
|
const LOCK_SCOPE = "bunsql-native-migrate:up";
|
|
7
13
|
|
|
8
14
|
const IDENTIFIER_MAX_LENGTH = 63;
|
|
9
|
-
const UNIQUE_INDEX_SUFFIX = "_migration_unique";
|
|
10
15
|
|
|
11
|
-
interface TableRef {
|
|
12
|
-
table: string;
|
|
13
|
-
index: string;
|
|
14
|
-
name: string;
|
|
16
|
+
interface PostgresTableRef extends TableRef {
|
|
15
17
|
schemaName?: string;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
function
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
function resolvePostgresTableRef(options: DriverTableOptions): PostgresTableRef {
|
|
21
|
+
const base = resolveTableRef(options, {
|
|
22
|
+
quote: doubleQuoted,
|
|
23
|
+
maxLength: IDENTIFIER_MAX_LENGTH,
|
|
24
|
+
});
|
|
22
25
|
if (options.schema === undefined) {
|
|
23
|
-
return
|
|
26
|
+
return base;
|
|
24
27
|
}
|
|
25
28
|
validateIdentifier("schema", options.schema, IDENTIFIER_MAX_LENGTH);
|
|
26
29
|
return {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
name: tableName,
|
|
30
|
+
...base,
|
|
31
|
+
table: `${doubleQuoted(options.schema)}.${base.table}`,
|
|
30
32
|
schemaName: options.schema,
|
|
31
33
|
};
|
|
32
34
|
}
|
|
@@ -38,7 +40,7 @@ async function advisoryKeyComponents(lock: SQL): Promise<[number, number]> {
|
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export function create(databaseUrl: string, options: DriverTableOptions = {}): MigrationDriver {
|
|
41
|
-
const { table, index, name, schemaName } =
|
|
43
|
+
const { table, index, name, schemaName } = resolvePostgresTableRef(options);
|
|
42
44
|
return createSqlDriver(
|
|
43
45
|
databaseUrl,
|
|
44
46
|
{
|
|
@@ -76,11 +78,18 @@ export function create(databaseUrl: string, options: DriverTableOptions = {}): M
|
|
|
76
78
|
VALUES (${migration}, ${checksum})
|
|
77
79
|
ON CONFLICT (migration) DO NOTHING`;
|
|
78
80
|
},
|
|
79
|
-
createLock: (db) =>
|
|
80
|
-
|
|
81
|
+
createLock: (db) => {
|
|
82
|
+
let cachedKey: [number, number] | null = null;
|
|
83
|
+
const resolveAdvisoryKey = async (lock: SQL): Promise<[number, number]> => {
|
|
84
|
+
if (cachedKey === null) {
|
|
85
|
+
cachedKey = await advisoryKeyComponents(lock);
|
|
86
|
+
}
|
|
87
|
+
return cachedKey;
|
|
88
|
+
};
|
|
89
|
+
return createReservedLock(
|
|
81
90
|
db,
|
|
82
91
|
async (lock) => {
|
|
83
|
-
const [first, second] = await
|
|
92
|
+
const [first, second] = await resolveAdvisoryKey(lock);
|
|
84
93
|
const rows =
|
|
85
94
|
(await lock`SELECT pg_try_advisory_lock(${first}, ${second}) AS locked`) as Array<{
|
|
86
95
|
locked: boolean;
|
|
@@ -88,10 +97,11 @@ export function create(databaseUrl: string, options: DriverTableOptions = {}): M
|
|
|
88
97
|
return rows[0]?.locked === true;
|
|
89
98
|
},
|
|
90
99
|
async (lock) => {
|
|
91
|
-
const [first, second] = await
|
|
100
|
+
const [first, second] = await resolveAdvisoryKey(lock);
|
|
92
101
|
await lock`SELECT pg_advisory_unlock(${first}, ${second})`;
|
|
93
102
|
},
|
|
94
|
-
)
|
|
103
|
+
);
|
|
104
|
+
},
|
|
95
105
|
},
|
|
96
106
|
table,
|
|
97
107
|
);
|
package/src/drivers/shared.ts
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import { SQL, type ReservedSQL } from "bun";
|
|
2
|
-
import type { ExecutedMigration, MigrationDriver } from "../core/driver.js";
|
|
2
|
+
import type { DriverTableOptions, ExecutedMigration, MigrationDriver } from "../core/driver.js";
|
|
3
|
+
import { validateIdentifier } from "../core/identifiers.js";
|
|
4
|
+
|
|
5
|
+
export const UNIQUE_INDEX_SUFFIX = "_migration_unique";
|
|
6
|
+
|
|
7
|
+
export interface TableRef {
|
|
8
|
+
table: string;
|
|
9
|
+
index: string;
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface TableRefSpec {
|
|
14
|
+
quote: (identifier: string) => string;
|
|
15
|
+
maxLength: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function resolveTableRef(options: DriverTableOptions, spec: TableRefSpec): TableRef {
|
|
19
|
+
const tableName = options.tableName ?? "migrations";
|
|
20
|
+
validateIdentifier("table", tableName, spec.maxLength);
|
|
21
|
+
return {
|
|
22
|
+
table: spec.quote(tableName),
|
|
23
|
+
index: spec.quote(`${tableName}${UNIQUE_INDEX_SUFFIX}`),
|
|
24
|
+
name: tableName,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
3
27
|
|
|
4
28
|
export interface SqlLock {
|
|
5
29
|
tryLock(timeoutSeconds: number): Promise<boolean>;
|
package/src/drivers/sqlite.ts
CHANGED
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
import type { DriverTableOptions, MigrationDriver } from "../core/driver.js";
|
|
2
|
-
import { doubleQuoted
|
|
3
|
-
import { createSqlDriver } from "./shared.js";
|
|
2
|
+
import { doubleQuoted } from "../core/identifiers.js";
|
|
3
|
+
import { createSqlDriver, resolveTableRef, UNIQUE_INDEX_SUFFIX } from "./shared.js";
|
|
4
4
|
|
|
5
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
6
|
|
|
22
7
|
export function create(databaseUrl: string, options: DriverTableOptions = {}): MigrationDriver {
|
|
23
|
-
const { table, index, name } = resolveTableRef(options
|
|
8
|
+
const { table, index, name } = resolveTableRef(options, {
|
|
9
|
+
quote: doubleQuoted,
|
|
10
|
+
maxLength: TABLE_NAME_MAX_LENGTH,
|
|
11
|
+
});
|
|
24
12
|
return createSqlDriver(
|
|
25
13
|
databaseUrl,
|
|
26
14
|
{
|