zenstack-kit 0.1.4 → 0.1.5
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 +10 -0
- package/dist/cli/app.d.ts.map +1 -1
- package/dist/cli/app.js +4 -1
- package/dist/cli/commands.d.ts +1 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +12 -3
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +11 -9
- package/dist/migrations/prisma/apply.d.ts +52 -0
- package/dist/migrations/prisma/apply.d.ts.map +1 -0
- package/dist/migrations/prisma/apply.js +382 -0
- package/dist/migrations/prisma/create.d.ts +63 -0
- package/dist/migrations/prisma/create.d.ts.map +1 -0
- package/dist/migrations/prisma/create.js +119 -0
- package/dist/migrations/prisma/diff.d.ts +104 -0
- package/dist/migrations/prisma/diff.d.ts.map +1 -0
- package/dist/migrations/prisma/diff.js +442 -0
- package/dist/migrations/prisma/log.d.ts +31 -0
- package/dist/migrations/prisma/log.d.ts.map +1 -0
- package/dist/migrations/prisma/log.js +101 -0
- package/dist/migrations/prisma/rename.d.ts +23 -0
- package/dist/migrations/prisma/rename.d.ts.map +1 -0
- package/dist/migrations/prisma/rename.js +57 -0
- package/dist/migrations/prisma/snapshot.d.ts +32 -0
- package/dist/migrations/prisma/snapshot.d.ts.map +1 -0
- package/dist/migrations/prisma/snapshot.js +65 -0
- package/dist/migrations/prisma.d.ts +5 -202
- package/dist/migrations/prisma.d.ts.map +1 -1
- package/dist/migrations/prisma.js +5 -1168
- package/package.json +1 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { KyselyDialect } from "../../sql/kysely-adapter.js";
|
|
2
|
+
export interface PrismaMigrationOptions {
|
|
3
|
+
/** Migration name */
|
|
4
|
+
name: string;
|
|
5
|
+
/** Path to ZenStack schema file */
|
|
6
|
+
schemaPath: string;
|
|
7
|
+
/** Output directory for migration files */
|
|
8
|
+
outputPath: string;
|
|
9
|
+
/** Database dialect for SQL generation */
|
|
10
|
+
dialect: KyselyDialect;
|
|
11
|
+
/** Table rename mappings */
|
|
12
|
+
renameTables?: Array<{
|
|
13
|
+
from: string;
|
|
14
|
+
to: string;
|
|
15
|
+
}>;
|
|
16
|
+
/** Column rename mappings */
|
|
17
|
+
renameColumns?: Array<{
|
|
18
|
+
table: string;
|
|
19
|
+
from: string;
|
|
20
|
+
to: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
export interface PrismaMigration {
|
|
24
|
+
/** Migration folder name (timestamp_name) */
|
|
25
|
+
folderName: string;
|
|
26
|
+
/** Full path to migration folder */
|
|
27
|
+
folderPath: string;
|
|
28
|
+
/** SQL content */
|
|
29
|
+
sql: string;
|
|
30
|
+
/** Timestamp */
|
|
31
|
+
timestamp: number;
|
|
32
|
+
}
|
|
33
|
+
export interface CreateInitialMigrationOptions {
|
|
34
|
+
/** Migration name (default: "init") */
|
|
35
|
+
name?: string;
|
|
36
|
+
/** Path to ZenStack schema file */
|
|
37
|
+
schemaPath: string;
|
|
38
|
+
/** Output directory for migration files */
|
|
39
|
+
outputPath: string;
|
|
40
|
+
/** Database dialect for SQL generation */
|
|
41
|
+
dialect: KyselyDialect;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generate timestamp string for migration folder name
|
|
45
|
+
*/
|
|
46
|
+
export declare function generateTimestamp(): string;
|
|
47
|
+
/**
|
|
48
|
+
* Create a Prisma-compatible migration
|
|
49
|
+
*/
|
|
50
|
+
export declare function createPrismaMigration(options: PrismaMigrationOptions): Promise<PrismaMigration | null>;
|
|
51
|
+
/**
|
|
52
|
+
* Create an initial migration that creates all tables from scratch.
|
|
53
|
+
* This is used when initializing a project where the database is empty.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createInitialMigration(options: CreateInitialMigrationOptions): Promise<PrismaMigration>;
|
|
56
|
+
/**
|
|
57
|
+
* Check if there are schema changes
|
|
58
|
+
*/
|
|
59
|
+
export declare function hasPrismaSchemaChanges(options: {
|
|
60
|
+
schemaPath: string;
|
|
61
|
+
outputPath: string;
|
|
62
|
+
}): Promise<boolean>;
|
|
63
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/migrations/prisma/create.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAMjE,MAAM,WAAW,sBAAsB;IACrC,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,OAAO,EAAE,aAAa,CAAC;IACvB,4BAA4B;IAC5B,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,6BAA6B;IAC7B,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAED,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,6BAA6B;IAC5C,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAU1C;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAiDjC;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,eAAe,CAAC,CAwC1B;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,OAAO,CAAC,CAqBnB"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import * as fs from "fs/promises";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { generateSchemaSnapshot } from "../../schema/snapshot.js";
|
|
4
|
+
import { applyRenameMappings, buildSqlStatements, diffSchemas } from "./diff.js";
|
|
5
|
+
import { appendToMigrationLog, calculateChecksum } from "./log.js";
|
|
6
|
+
import { getSnapshotPaths, readSnapshot, writeSnapshot } from "./snapshot.js";
|
|
7
|
+
/**
|
|
8
|
+
* Generate timestamp string for migration folder name
|
|
9
|
+
*/
|
|
10
|
+
export function generateTimestamp() {
|
|
11
|
+
const now = new Date();
|
|
12
|
+
return [
|
|
13
|
+
now.getFullYear(),
|
|
14
|
+
String(now.getMonth() + 1).padStart(2, "0"),
|
|
15
|
+
String(now.getDate()).padStart(2, "0"),
|
|
16
|
+
String(now.getHours()).padStart(2, "0"),
|
|
17
|
+
String(now.getMinutes()).padStart(2, "0"),
|
|
18
|
+
String(now.getSeconds()).padStart(2, "0"),
|
|
19
|
+
].join("");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a Prisma-compatible migration
|
|
23
|
+
*/
|
|
24
|
+
export async function createPrismaMigration(options) {
|
|
25
|
+
const currentSchema = await generateSchemaSnapshot(options.schemaPath);
|
|
26
|
+
const { snapshotPath } = getSnapshotPaths(options.outputPath);
|
|
27
|
+
const previousSnapshot = await readSnapshot(snapshotPath);
|
|
28
|
+
const diff = applyRenameMappings(diffSchemas(previousSnapshot?.schema ?? null, currentSchema), options.renameTables, options.renameColumns);
|
|
29
|
+
const { up } = buildSqlStatements(diff, options.dialect);
|
|
30
|
+
if (up.length === 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const timestamp = Date.now();
|
|
34
|
+
const timestampStr = generateTimestamp();
|
|
35
|
+
const safeName = options.name.replace(/[^a-z0-9]/gi, "_").toLowerCase();
|
|
36
|
+
const folderName = `${timestampStr}_${safeName}`;
|
|
37
|
+
const folderPath = path.join(options.outputPath, folderName);
|
|
38
|
+
// Build migration.sql content with comments
|
|
39
|
+
const sqlContent = [
|
|
40
|
+
`-- Migration: ${options.name}`,
|
|
41
|
+
`-- Generated at: ${new Date(timestamp).toISOString()}`,
|
|
42
|
+
"",
|
|
43
|
+
...up,
|
|
44
|
+
"",
|
|
45
|
+
].join("\n");
|
|
46
|
+
// Create migration folder and file
|
|
47
|
+
await fs.mkdir(folderPath, { recursive: true });
|
|
48
|
+
await fs.writeFile(path.join(folderPath, "migration.sql"), sqlContent, "utf-8");
|
|
49
|
+
// Update snapshot
|
|
50
|
+
await writeSnapshot(snapshotPath, currentSchema);
|
|
51
|
+
// Append to migration log
|
|
52
|
+
const checksum = calculateChecksum(sqlContent);
|
|
53
|
+
await appendToMigrationLog(options.outputPath, { name: folderName, checksum });
|
|
54
|
+
return {
|
|
55
|
+
folderName,
|
|
56
|
+
folderPath,
|
|
57
|
+
sql: sqlContent,
|
|
58
|
+
timestamp,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Create an initial migration that creates all tables from scratch.
|
|
63
|
+
* This is used when initializing a project where the database is empty.
|
|
64
|
+
*/
|
|
65
|
+
export async function createInitialMigration(options) {
|
|
66
|
+
const currentSchema = await generateSchemaSnapshot(options.schemaPath);
|
|
67
|
+
const { snapshotPath } = getSnapshotPaths(options.outputPath);
|
|
68
|
+
// Diff against empty schema to get full creation SQL
|
|
69
|
+
const diff = diffSchemas(null, currentSchema);
|
|
70
|
+
const { up } = buildSqlStatements(diff, options.dialect);
|
|
71
|
+
const timestamp = Date.now();
|
|
72
|
+
const timestampStr = generateTimestamp();
|
|
73
|
+
const safeName = (options.name ?? "init").replace(/[^a-z0-9]/gi, "_").toLowerCase();
|
|
74
|
+
const folderName = `${timestampStr}_${safeName}`;
|
|
75
|
+
const folderPath = path.join(options.outputPath, folderName);
|
|
76
|
+
// Build migration.sql content with comments
|
|
77
|
+
const sqlContent = [
|
|
78
|
+
`-- Migration: ${options.name ?? "init"}`,
|
|
79
|
+
`-- Generated at: ${new Date(timestamp).toISOString()}`,
|
|
80
|
+
"",
|
|
81
|
+
...up,
|
|
82
|
+
"",
|
|
83
|
+
].join("\n");
|
|
84
|
+
// Create migration folder and file
|
|
85
|
+
await fs.mkdir(folderPath, { recursive: true });
|
|
86
|
+
await fs.writeFile(path.join(folderPath, "migration.sql"), sqlContent, "utf-8");
|
|
87
|
+
// Update snapshot
|
|
88
|
+
await writeSnapshot(snapshotPath, currentSchema);
|
|
89
|
+
// Append to migration log
|
|
90
|
+
const checksum = calculateChecksum(sqlContent);
|
|
91
|
+
await appendToMigrationLog(options.outputPath, { name: folderName, checksum });
|
|
92
|
+
return {
|
|
93
|
+
folderName,
|
|
94
|
+
folderPath,
|
|
95
|
+
sql: sqlContent,
|
|
96
|
+
timestamp,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if there are schema changes
|
|
101
|
+
*/
|
|
102
|
+
export async function hasPrismaSchemaChanges(options) {
|
|
103
|
+
const currentSchema = await generateSchemaSnapshot(options.schemaPath);
|
|
104
|
+
const { snapshotPath } = getSnapshotPaths(options.outputPath);
|
|
105
|
+
const previousSnapshot = await readSnapshot(snapshotPath);
|
|
106
|
+
const diff = diffSchemas(previousSnapshot?.schema ?? null, currentSchema);
|
|
107
|
+
return (diff.addedModels.length > 0 ||
|
|
108
|
+
diff.removedModels.length > 0 ||
|
|
109
|
+
diff.addedFields.length > 0 ||
|
|
110
|
+
diff.removedFields.length > 0 ||
|
|
111
|
+
diff.alteredFields.length > 0 ||
|
|
112
|
+
diff.addedUniqueConstraints.length > 0 ||
|
|
113
|
+
diff.removedUniqueConstraints.length > 0 ||
|
|
114
|
+
diff.addedIndexes.length > 0 ||
|
|
115
|
+
diff.removedIndexes.length > 0 ||
|
|
116
|
+
diff.addedForeignKeys.length > 0 ||
|
|
117
|
+
diff.removedForeignKeys.length > 0 ||
|
|
118
|
+
diff.primaryKeyChanges.length > 0);
|
|
119
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { KyselyDialect } from "../../sql/kysely-adapter.js";
|
|
2
|
+
import type { SchemaSnapshot, SchemaTable, SchemaColumn } from "../../schema/snapshot.js";
|
|
3
|
+
export declare function diffSchemas(previous: SchemaSnapshot | null, current: SchemaSnapshot): {
|
|
4
|
+
addedModels: SchemaTable[];
|
|
5
|
+
removedModels: SchemaTable[];
|
|
6
|
+
addedFields: {
|
|
7
|
+
tableName: string;
|
|
8
|
+
column: SchemaColumn;
|
|
9
|
+
}[];
|
|
10
|
+
removedFields: {
|
|
11
|
+
tableName: string;
|
|
12
|
+
column: SchemaColumn;
|
|
13
|
+
}[];
|
|
14
|
+
alteredFields: {
|
|
15
|
+
tableName: string;
|
|
16
|
+
columnName: string;
|
|
17
|
+
previous: SchemaColumn;
|
|
18
|
+
current: SchemaColumn;
|
|
19
|
+
}[];
|
|
20
|
+
addedUniqueConstraints: {
|
|
21
|
+
tableName: string;
|
|
22
|
+
constraint: {
|
|
23
|
+
name: string;
|
|
24
|
+
columns: string[];
|
|
25
|
+
};
|
|
26
|
+
}[];
|
|
27
|
+
removedUniqueConstraints: {
|
|
28
|
+
tableName: string;
|
|
29
|
+
constraint: {
|
|
30
|
+
name: string;
|
|
31
|
+
columns: string[];
|
|
32
|
+
};
|
|
33
|
+
}[];
|
|
34
|
+
addedIndexes: {
|
|
35
|
+
tableName: string;
|
|
36
|
+
index: {
|
|
37
|
+
name: string;
|
|
38
|
+
columns: string[];
|
|
39
|
+
};
|
|
40
|
+
}[];
|
|
41
|
+
removedIndexes: {
|
|
42
|
+
tableName: string;
|
|
43
|
+
index: {
|
|
44
|
+
name: string;
|
|
45
|
+
columns: string[];
|
|
46
|
+
};
|
|
47
|
+
}[];
|
|
48
|
+
addedForeignKeys: {
|
|
49
|
+
tableName: string;
|
|
50
|
+
foreignKey: {
|
|
51
|
+
name: string;
|
|
52
|
+
columns: string[];
|
|
53
|
+
referencedTable: string;
|
|
54
|
+
referencedColumns: string[];
|
|
55
|
+
};
|
|
56
|
+
}[];
|
|
57
|
+
removedForeignKeys: {
|
|
58
|
+
tableName: string;
|
|
59
|
+
foreignKey: {
|
|
60
|
+
name: string;
|
|
61
|
+
columns: string[];
|
|
62
|
+
referencedTable: string;
|
|
63
|
+
referencedColumns: string[];
|
|
64
|
+
};
|
|
65
|
+
}[];
|
|
66
|
+
primaryKeyChanges: {
|
|
67
|
+
tableName: string;
|
|
68
|
+
previous?: {
|
|
69
|
+
name: string;
|
|
70
|
+
columns: string[];
|
|
71
|
+
};
|
|
72
|
+
current?: {
|
|
73
|
+
name: string;
|
|
74
|
+
columns: string[];
|
|
75
|
+
};
|
|
76
|
+
}[];
|
|
77
|
+
renamedTables: Array<{
|
|
78
|
+
from: string;
|
|
79
|
+
to: string;
|
|
80
|
+
}>;
|
|
81
|
+
renamedColumns: Array<{
|
|
82
|
+
tableName: string;
|
|
83
|
+
from: string;
|
|
84
|
+
to: string;
|
|
85
|
+
}>;
|
|
86
|
+
};
|
|
87
|
+
type PrismaDiff = ReturnType<typeof diffSchemas>;
|
|
88
|
+
export declare function applyRenameMappings(diff: PrismaDiff, renameTables?: Array<{
|
|
89
|
+
from: string;
|
|
90
|
+
to: string;
|
|
91
|
+
}>, renameColumns?: Array<{
|
|
92
|
+
table: string;
|
|
93
|
+
from: string;
|
|
94
|
+
to: string;
|
|
95
|
+
}>): PrismaDiff;
|
|
96
|
+
/**
|
|
97
|
+
* Build SQL statements from diff
|
|
98
|
+
*/
|
|
99
|
+
export declare function buildSqlStatements(diff: ReturnType<typeof diffSchemas>, dialect: KyselyDialect): {
|
|
100
|
+
up: string[];
|
|
101
|
+
down: string[];
|
|
102
|
+
};
|
|
103
|
+
export {};
|
|
104
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/migrations/prisma/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAyK1F,wBAAgB,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,EAAE,OAAO,EAAE,cAAc;;;;mBAsB5C,MAAM;gBAAU,YAAY;;;mBAC1B,MAAM;gBAAU,YAAY;;;mBAEvD,MAAM;oBACL,MAAM;kBACR,YAAY;iBACb,YAAY;;;mBAGV,MAAM;oBACL;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,EAAE,CAAA;SAAE;;;mBAGpC,MAAM;oBACL;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,EAAE,CAAA;SAAE;;;mBAGpC,MAAM;eACV;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,EAAE,CAAA;SAAE;;;mBAG/B,MAAM;eACV;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,EAAE,CAAA;SAAE;;;mBAG/B,MAAM;oBACL;YACV,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,EAAE,CAAC;YAClB,eAAe,EAAE,MAAM,CAAC;YACxB,iBAAiB,EAAE,MAAM,EAAE,CAAC;SAC7B;;;mBAGU,MAAM;oBACL;YACV,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,EAAE,CAAC;YAClB,eAAe,EAAE,MAAM,CAAC;YACxB,iBAAiB,EAAE,MAAM,EAAE,CAAC;SAC7B;;;mBAGU,MAAM;mBACN;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,EAAE,CAAA;SAAE;kBACpC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,EAAE,CAAA;SAAE;;mBAiCxB,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;oBAClC,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;EAE/E;AAED,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAkGjD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,YAAY,GAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAM,EACtD,aAAa,GAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAM,GACrE,UAAU,CA8FZ;AA2CD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,EACpC,OAAO,EAAE,aAAa,GACrB;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAkNlC"}
|