@vibeorm/migrate 1.3.1 → 2.0.0-alpha.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/README.md +33 -66
- package/dist/ddl/drop-order.d.ts +25 -0
- package/dist/ddl/drop-order.d.ts.map +1 -0
- package/dist/ddl/mysql.d.ts +46 -0
- package/dist/ddl/mysql.d.ts.map +1 -0
- package/dist/ddl/postgres.d.ts +24 -0
- package/dist/ddl/postgres.d.ts.map +1 -0
- package/dist/ddl/render.d.ts +25 -0
- package/dist/ddl/render.d.ts.map +1 -0
- package/dist/ddl/sqlite.d.ts +62 -0
- package/dist/ddl/sqlite.d.ts.map +1 -0
- package/dist/differ.d.ts +33 -0
- package/dist/differ.d.ts.map +1 -0
- package/dist/down.d.ts +55 -0
- package/dist/down.d.ts.map +1 -0
- package/dist/enum-values.d.ts +19 -0
- package/dist/enum-values.d.ts.map +1 -0
- package/dist/execute.d.ts +41 -0
- package/dist/execute.d.ts.map +1 -0
- package/dist/extensions.d.ts +74 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3858 -0
- package/dist/index.js.map +31 -0
- package/dist/introspect/mysql.d.ts +31 -0
- package/dist/introspect/mysql.d.ts.map +1 -0
- package/dist/introspect/postgres.d.ts +25 -0
- package/dist/introspect/postgres.d.ts.map +1 -0
- package/dist/introspect/shared.d.ts +76 -0
- package/dist/introspect/shared.d.ts.map +1 -0
- package/dist/introspect/sqlite.d.ts +53 -0
- package/dist/introspect/sqlite.d.ts.map +1 -0
- package/dist/mysql-types.d.ts +66 -0
- package/dist/mysql-types.d.ts.map +1 -0
- package/dist/normalize.d.ts +115 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/postgres-types.d.ts +95 -0
- package/dist/postgres-types.d.ts.map +1 -0
- package/dist/push.d.ts +45 -0
- package/dist/push.d.ts.map +1 -0
- package/dist/relations.d.ts +40 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/runner.d.ts +120 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/sqlite-types.d.ts +87 -0
- package/dist/sqlite-types.d.ts.map +1 -0
- package/dist/types.d.ts +217 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +33 -23
- package/src/cascade-actions.ts +0 -88
- package/src/ddl-builder.ts +0 -415
- package/src/index.ts +0 -41
- package/src/introspector.ts +0 -684
- package/src/migration-runner.ts +0 -127
- package/src/relation-utils.ts +0 -79
- package/src/schema-differ.ts +0 -865
- package/src/schema-printer.ts +0 -259
- package/src/snapshot.ts +0 -141
- package/src/sql-utils.ts +0 -45
- package/src/types.ts +0 -13
package/src/migration-runner.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Migration Runner — Apply SQL files with tracking
|
|
3
|
-
*
|
|
4
|
-
* Handles creating the migration tracking table, querying applied migrations,
|
|
5
|
-
* executing migration SQL files, and recording results.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { SqlExecutor } from "./types.ts";
|
|
9
|
-
import { splitSqlStatements } from "./sql-utils.ts";
|
|
10
|
-
|
|
11
|
-
// ─── Types ────────────────────────────────────────────────────────
|
|
12
|
-
|
|
13
|
-
export type AppliedMigration = {
|
|
14
|
-
id: number;
|
|
15
|
-
migrationName: string;
|
|
16
|
-
checksum: string;
|
|
17
|
-
appliedAt: Date;
|
|
18
|
-
executionTime: number | null;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// ─── Migration Table Management ───────────────────────────────────
|
|
22
|
-
|
|
23
|
-
const CREATE_TABLE_SQL = `
|
|
24
|
-
CREATE TABLE IF NOT EXISTS "_vibeorm_migrations" (
|
|
25
|
-
"id" SERIAL PRIMARY KEY,
|
|
26
|
-
"migration_name" TEXT NOT NULL UNIQUE,
|
|
27
|
-
"checksum" TEXT NOT NULL,
|
|
28
|
-
"applied_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
29
|
-
"execution_time" INTEGER
|
|
30
|
-
);
|
|
31
|
-
`;
|
|
32
|
-
|
|
33
|
-
export async function ensureMigrationTable(params: { executor: SqlExecutor }): Promise<void> {
|
|
34
|
-
await params.executor({ text: CREATE_TABLE_SQL });
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function getAppliedMigrations(params: { executor: SqlExecutor }): Promise<AppliedMigration[]> {
|
|
38
|
-
const rows = await params.executor({
|
|
39
|
-
text: `SELECT id, migration_name, checksum, applied_at, execution_time FROM "_vibeorm_migrations" ORDER BY id;`,
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
return rows.map((row) => ({
|
|
43
|
-
id: row.id as number,
|
|
44
|
-
migrationName: row.migration_name as string,
|
|
45
|
-
checksum: row.checksum as string,
|
|
46
|
-
appliedAt: new Date(row.applied_at as string),
|
|
47
|
-
executionTime: row.execution_time as number | null,
|
|
48
|
-
}));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ─── Apply Migration ──────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
export async function applyMigration(params: {
|
|
54
|
-
executor: SqlExecutor;
|
|
55
|
-
migrationName: string;
|
|
56
|
-
sql: string;
|
|
57
|
-
checksum: string;
|
|
58
|
-
}): Promise<{ executionTime: number }> {
|
|
59
|
-
const { executor, migrationName, sql, checksum } = params;
|
|
60
|
-
const start = Date.now();
|
|
61
|
-
|
|
62
|
-
// Split migration SQL into individual statements to handle
|
|
63
|
-
// DO $$ blocks and multi-statement migrations correctly
|
|
64
|
-
const statements = splitSqlStatements({ sql });
|
|
65
|
-
for (const stmt of statements) {
|
|
66
|
-
await executor({ text: stmt });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const executionTime = Date.now() - start;
|
|
70
|
-
|
|
71
|
-
// Record the applied migration
|
|
72
|
-
await executor({
|
|
73
|
-
text: `INSERT INTO "_vibeorm_migrations" ("migration_name", "checksum", "execution_time") VALUES ($1, $2, $3);`,
|
|
74
|
-
values: [migrationName, checksum, executionTime],
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
return { executionTime };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// ─── Repair Tools ─────────────────────────────────────────────────
|
|
81
|
-
|
|
82
|
-
export async function markMigrationApplied(params: {
|
|
83
|
-
executor: SqlExecutor;
|
|
84
|
-
migrationName: string;
|
|
85
|
-
checksum: string;
|
|
86
|
-
}): Promise<void> {
|
|
87
|
-
const { executor, migrationName, checksum } = params;
|
|
88
|
-
await executor({
|
|
89
|
-
text: `INSERT INTO "_vibeorm_migrations" ("migration_name", "checksum", "execution_time") VALUES ($1, $2, $3) ON CONFLICT ("migration_name") DO NOTHING;`,
|
|
90
|
-
values: [migrationName, checksum, 0],
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export async function removeMigrationRecord(params: {
|
|
95
|
-
executor: SqlExecutor;
|
|
96
|
-
migrationName: string;
|
|
97
|
-
}): Promise<void> {
|
|
98
|
-
const { executor, migrationName } = params;
|
|
99
|
-
await executor({
|
|
100
|
-
text: `DELETE FROM "_vibeorm_migrations" WHERE "migration_name" = $1;`,
|
|
101
|
-
values: [migrationName],
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ─── Rollback Migration ───────────────────────────────────────────
|
|
106
|
-
|
|
107
|
-
export async function rollbackMigration(params: {
|
|
108
|
-
executor: SqlExecutor;
|
|
109
|
-
migrationName: string;
|
|
110
|
-
sql: string;
|
|
111
|
-
}): Promise<{ executionTime: number }> {
|
|
112
|
-
const { executor, migrationName, sql } = params;
|
|
113
|
-
const start = Date.now();
|
|
114
|
-
|
|
115
|
-
// Split down migration SQL into individual statements
|
|
116
|
-
const statements = splitSqlStatements({ sql });
|
|
117
|
-
for (const stmt of statements) {
|
|
118
|
-
await executor({ text: stmt });
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const executionTime = Date.now() - start;
|
|
122
|
-
|
|
123
|
-
// Remove the migration tracking record
|
|
124
|
-
await removeMigrationRecord({ executor, migrationName });
|
|
125
|
-
|
|
126
|
-
return { executionTime };
|
|
127
|
-
}
|
package/src/relation-utils.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Relation utilities — shared implicit many-to-many detection.
|
|
3
|
-
*
|
|
4
|
-
* Single source of truth for "which model pairs are joined by an implicit
|
|
5
|
-
* many-to-many table". Both the DDL builder (initial create / `migrate
|
|
6
|
-
* generate`) and the schema differ (`db push` / migration diffs) consume this
|
|
7
|
-
* so they can never drift apart — the previous divergence between those two
|
|
8
|
-
* copies was the root cause of phantom join tables for 1:N self-relations and
|
|
9
|
-
* for two separate 1:N relations between the same pair of models.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { Schema, RelationField } from "@vibeorm/parser";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* A detected implicit many-to-many relation, identified by its two endpoint
|
|
16
|
-
* model names sorted alphabetically (matching Prisma's `_AToB` join-table
|
|
17
|
-
* naming convention). For a self-relation both names are equal.
|
|
18
|
-
*/
|
|
19
|
-
export type ImplicitM2MPair = {
|
|
20
|
-
readonly modelA: string;
|
|
21
|
-
readonly modelB: string;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Detect every implicit many-to-many relation in a schema.
|
|
26
|
-
*
|
|
27
|
-
* Pairing rule (kept in lock-step with the parser's `resolveRelationType`):
|
|
28
|
-
* two relation fields form an implicit M:N **iff** both are lists with no
|
|
29
|
-
* foreign key, they are **distinct fields** (self-relation safe), and their
|
|
30
|
-
* relation names match **symmetrically** — both unnamed, or both the same name.
|
|
31
|
-
*
|
|
32
|
-
* Detection is purely structural (it does not read `relation.type`), so it
|
|
33
|
-
* works for both parsed schemas (where each side carries `type: "manyToMany"`)
|
|
34
|
-
* and introspected schemas (where a real join table round-trips as two unnamed
|
|
35
|
-
* `oneToMany` list fields). That keeps the differ stable across round-trips.
|
|
36
|
-
*/
|
|
37
|
-
export function detectImplicitM2MPairs(params: { schema: Schema }): ImplicitM2MPair[] {
|
|
38
|
-
const { schema } = params;
|
|
39
|
-
const result: ImplicitM2MPair[] = [];
|
|
40
|
-
const seen = new Set<string>();
|
|
41
|
-
|
|
42
|
-
for (const model of schema.models) {
|
|
43
|
-
for (const field of model.fields) {
|
|
44
|
-
if (field.kind !== "relation") continue;
|
|
45
|
-
if (!field.isList) continue;
|
|
46
|
-
if (field.relation.isForeignKey) continue;
|
|
47
|
-
if (field.relation.fields.length > 0) continue;
|
|
48
|
-
|
|
49
|
-
const relatedModel = schema.models.find((m) => m.name === field.relatedModel);
|
|
50
|
-
if (!relatedModel) continue;
|
|
51
|
-
|
|
52
|
-
const backRef = relatedModel.fields.find(
|
|
53
|
-
(f): f is RelationField =>
|
|
54
|
-
f.kind === "relation" &&
|
|
55
|
-
// Self-exclusion: a list field must never pair with itself, otherwise
|
|
56
|
-
// every 1:N self-relation would be mistaken for an M:N self-relation.
|
|
57
|
-
f !== field &&
|
|
58
|
-
f.relatedModel === model.name &&
|
|
59
|
-
f.isList &&
|
|
60
|
-
!f.relation.isForeignKey &&
|
|
61
|
-
f.relation.fields.length === 0 &&
|
|
62
|
-
// Symmetric relation-name match — see doc comment above.
|
|
63
|
-
(f.relation.name ?? undefined) === (field.relation.name ?? undefined),
|
|
64
|
-
);
|
|
65
|
-
if (!backRef) continue;
|
|
66
|
-
|
|
67
|
-
const sorted = [model.name, relatedModel.name].sort();
|
|
68
|
-
const nameA = sorted[0]!;
|
|
69
|
-
const nameB = sorted[1]!;
|
|
70
|
-
const key = `${nameA}_${nameB}`;
|
|
71
|
-
if (seen.has(key)) continue;
|
|
72
|
-
seen.add(key);
|
|
73
|
-
|
|
74
|
-
result.push({ modelA: nameA, modelB: nameB });
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return result;
|
|
79
|
-
}
|