@syncular/typegen 0.0.6-245 → 0.0.6-246
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/dist/checksums.d.ts +6 -0
- package/dist/checksums.d.ts.map +1 -0
- package/dist/checksums.js +173 -0
- package/dist/checksums.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/checksums.ts +257 -0
- package/src/index.ts +1 -0
- package/src/types.ts +20 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DefinedMigrations, MigrationChecksums } from '@syncular/migrations';
|
|
2
|
+
import type { GenerateMigrationChecksumsOptions, GenerateMigrationChecksumsResult, TypegenDialect } from './types';
|
|
3
|
+
export declare function createMigrationChecksums<DB>(migrations: DefinedMigrations<DB>, dialect?: TypegenDialect): Promise<MigrationChecksums>;
|
|
4
|
+
export declare function renderMigrationChecksums(checksums: MigrationChecksums): string;
|
|
5
|
+
export declare function generateMigrationChecksums<DB>(options: GenerateMigrationChecksumsOptions<DB>): Promise<GenerateMigrationChecksumsResult>;
|
|
6
|
+
//# sourceMappingURL=checksums.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksums.d.ts","sourceRoot":"","sources":["../src/checksums.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EACV,iCAAiC,EACjC,gCAAgC,EAChC,cAAc,EACf,MAAM,SAAS,CAAC;AAqLjB,wBAAsB,wBAAwB,CAAC,EAAE,EAC/C,UAAU,EAAE,iBAAiB,CAAC,EAAE,CAAC,EACjC,OAAO,GAAE,cAAyB,GACjC,OAAO,CAAC,kBAAkB,CAAC,CAgB7B;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,kBAAkB,GAC5B,MAAM,CAoBR;AAED,wBAAsB,0BAA0B,CAAC,EAAE,EACjD,OAAO,EAAE,iCAAiC,CAAC,EAAE,CAAC,GAC7C,OAAO,CAAC,gCAAgC,CAAC,CAc3C"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { PGlite } from '@electric-sql/pglite';
|
|
4
|
+
import { Kysely, SqliteDialect } from 'kysely';
|
|
5
|
+
import { PGliteDialect } from 'kysely-pglite-dialect';
|
|
6
|
+
const runtimeGlobals = globalThis;
|
|
7
|
+
const isBun = typeof runtimeGlobals.Bun !== 'undefined';
|
|
8
|
+
function hashString(value) {
|
|
9
|
+
let hash = 0;
|
|
10
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
11
|
+
hash = (hash * 31 + value.charCodeAt(index)) >>> 0;
|
|
12
|
+
}
|
|
13
|
+
return hash.toString(16).padStart(8, '0');
|
|
14
|
+
}
|
|
15
|
+
function normalizeParameterValue(value) {
|
|
16
|
+
if (typeof value === 'bigint') {
|
|
17
|
+
return { type: 'bigint', value: value.toString() };
|
|
18
|
+
}
|
|
19
|
+
if (value instanceof Date) {
|
|
20
|
+
return { type: 'date', value: value.toISOString() };
|
|
21
|
+
}
|
|
22
|
+
if (value instanceof Uint8Array) {
|
|
23
|
+
return { type: 'bytes', value: Array.from(value) };
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
return value.map((entry) => normalizeParameterValue(entry));
|
|
27
|
+
}
|
|
28
|
+
if (value && typeof value === 'object') {
|
|
29
|
+
return Object.fromEntries(Object.entries(value)
|
|
30
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
31
|
+
.map(([key, entry]) => [key, normalizeParameterValue(entry)]));
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function serializeQuery(query) {
|
|
36
|
+
return JSON.stringify({
|
|
37
|
+
sql: query.sql,
|
|
38
|
+
parameters: query.parameters.map((value) => normalizeParameterValue(value)),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function hashTrace(entries) {
|
|
42
|
+
return hashString(entries.join('\n'));
|
|
43
|
+
}
|
|
44
|
+
function quoteTsString(value) {
|
|
45
|
+
return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'")}'`;
|
|
46
|
+
}
|
|
47
|
+
async function createSqliteTraceDb(traceEntries) {
|
|
48
|
+
if (isBun) {
|
|
49
|
+
const bunSqliteSpecifier = 'bun:sqlite';
|
|
50
|
+
const sqliteModule = await import(bunSqliteSpecifier);
|
|
51
|
+
const dialectModule = await import('kysely-bun-sqlite');
|
|
52
|
+
const sqliteDb = new sqliteModule.Database(':memory:');
|
|
53
|
+
const db = new Kysely({
|
|
54
|
+
dialect: new dialectModule.BunSqliteDialect({
|
|
55
|
+
database: sqliteDb,
|
|
56
|
+
}),
|
|
57
|
+
log(event) {
|
|
58
|
+
if (event.level === 'query') {
|
|
59
|
+
traceEntries.push(serializeQuery(event.query));
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
return { db, sqliteDb };
|
|
64
|
+
}
|
|
65
|
+
const { default: Database } = await import('better-sqlite3');
|
|
66
|
+
const sqliteDb = new Database(':memory:');
|
|
67
|
+
const db = new Kysely({
|
|
68
|
+
dialect: new SqliteDialect({
|
|
69
|
+
database: sqliteDb,
|
|
70
|
+
}),
|
|
71
|
+
log(event) {
|
|
72
|
+
if (event.level === 'query') {
|
|
73
|
+
traceEntries.push(serializeQuery(event.query));
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
return { db, sqliteDb };
|
|
78
|
+
}
|
|
79
|
+
async function createPostgresTraceDb(traceEntries) {
|
|
80
|
+
const pglite = await PGlite.create();
|
|
81
|
+
const db = new Kysely({
|
|
82
|
+
dialect: new PGliteDialect(pglite),
|
|
83
|
+
log(event) {
|
|
84
|
+
if (event.level === 'query') {
|
|
85
|
+
traceEntries.push(serializeQuery(event.query));
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
db,
|
|
91
|
+
dispose: async () => {
|
|
92
|
+
if (!pglite.closed) {
|
|
93
|
+
await pglite.close();
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function createTraceDb(dialect, traceEntries) {
|
|
99
|
+
if (dialect === 'postgres') {
|
|
100
|
+
return createPostgresTraceDb(traceEntries);
|
|
101
|
+
}
|
|
102
|
+
const { db, sqliteDb } = await createSqliteTraceDb(traceEntries);
|
|
103
|
+
return {
|
|
104
|
+
db,
|
|
105
|
+
dispose: async () => {
|
|
106
|
+
sqliteDb.close();
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
async function computeMigrationChecksum(migrations, targetMigration, dialect) {
|
|
111
|
+
const traceEntries = [];
|
|
112
|
+
const { db, dispose } = await createTraceDb(dialect, traceEntries);
|
|
113
|
+
try {
|
|
114
|
+
for (const migration of migrations.migrations) {
|
|
115
|
+
if (migration.version > targetMigration.version) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
if (migration.version === targetMigration.version) {
|
|
119
|
+
traceEntries.length = 0;
|
|
120
|
+
}
|
|
121
|
+
await migration.up(db);
|
|
122
|
+
if (migration.version === targetMigration.version) {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return hashTrace(traceEntries);
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
await db.destroy();
|
|
130
|
+
await dispose();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export async function createMigrationChecksums(migrations, dialect = 'sqlite') {
|
|
134
|
+
const checksums = {};
|
|
135
|
+
for (const migration of migrations.migrations) {
|
|
136
|
+
if (migration.checksum === 'disabled') {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
checksums[String(migration.version)] = await computeMigrationChecksum(migrations, migration, dialect);
|
|
140
|
+
}
|
|
141
|
+
return checksums;
|
|
142
|
+
}
|
|
143
|
+
export function renderMigrationChecksums(checksums) {
|
|
144
|
+
const entries = Object.entries(checksums)
|
|
145
|
+
.sort(([left], [right]) => Number(left) - Number(right))
|
|
146
|
+
.map(([version, checksum]) => ` ${quoteTsString(version)}: ${quoteTsString(checksum)},`)
|
|
147
|
+
.join('\n');
|
|
148
|
+
return [
|
|
149
|
+
'/**',
|
|
150
|
+
' * Generated by @syncular/typegen.',
|
|
151
|
+
' * Do not edit by hand.',
|
|
152
|
+
' */',
|
|
153
|
+
'',
|
|
154
|
+
'export const migrationChecksums = {',
|
|
155
|
+
entries,
|
|
156
|
+
'} as const;',
|
|
157
|
+
'',
|
|
158
|
+
].join('\n');
|
|
159
|
+
}
|
|
160
|
+
export async function generateMigrationChecksums(options) {
|
|
161
|
+
const { migrations, output, dialect = 'sqlite' } = options;
|
|
162
|
+
const checksums = await createMigrationChecksums(migrations, dialect);
|
|
163
|
+
const code = renderMigrationChecksums(checksums);
|
|
164
|
+
await mkdir(dirname(output), { recursive: true });
|
|
165
|
+
await writeFile(output, code, 'utf-8');
|
|
166
|
+
return {
|
|
167
|
+
outputPath: output,
|
|
168
|
+
currentVersion: migrations.currentVersion,
|
|
169
|
+
checksumCount: Object.keys(checksums).length,
|
|
170
|
+
code,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=checksums.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksums.js","sourceRoot":"","sources":["../src/checksums.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -114,4 +114,22 @@ export interface GenerateTypesResult {
|
|
|
114
114
|
/** Generated TypeScript code */
|
|
115
115
|
code: string;
|
|
116
116
|
}
|
|
117
|
+
export interface GenerateMigrationChecksumsOptions<DB = unknown> {
|
|
118
|
+
/** Defined migrations from defineMigrations() */
|
|
119
|
+
migrations: DefinedMigrations<DB>;
|
|
120
|
+
/** Output file path for generated checksums */
|
|
121
|
+
output: string;
|
|
122
|
+
/** Database dialect to use for replay (default: 'sqlite') */
|
|
123
|
+
dialect?: TypegenDialect;
|
|
124
|
+
}
|
|
125
|
+
export interface GenerateMigrationChecksumsResult {
|
|
126
|
+
/** Path to the generated file */
|
|
127
|
+
outputPath: string;
|
|
128
|
+
/** Current schema version */
|
|
129
|
+
currentVersion: number;
|
|
130
|
+
/** Number of checksums generated */
|
|
131
|
+
checksumCount: number;
|
|
132
|
+
/** Generated TypeScript code */
|
|
133
|
+
code: string;
|
|
134
|
+
}
|
|
117
135
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/typegen",
|
|
3
|
-
"version": "0.0.6-
|
|
3
|
+
"version": "0.0.6-246",
|
|
4
4
|
"description": "TypeScript type generator for Syncular schemas",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@electric-sql/pglite": "^0.3.15",
|
|
47
|
-
"@syncular/migrations": "0.0.6-
|
|
47
|
+
"@syncular/migrations": "0.0.6-246",
|
|
48
48
|
"better-sqlite3": "^12.8.0",
|
|
49
49
|
"kysely-bun-sqlite": "^0.4.0",
|
|
50
50
|
"kysely-pglite-dialect": "^1.2.0"
|
package/src/checksums.ts
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { PGlite } from '@electric-sql/pglite';
|
|
4
|
+
import type {
|
|
5
|
+
DefinedMigrations,
|
|
6
|
+
MigrationChecksums,
|
|
7
|
+
ParsedMigration,
|
|
8
|
+
} from '@syncular/migrations';
|
|
9
|
+
import { Kysely, SqliteDialect } from 'kysely';
|
|
10
|
+
import { PGliteDialect } from 'kysely-pglite-dialect';
|
|
11
|
+
import type {
|
|
12
|
+
GenerateMigrationChecksumsOptions,
|
|
13
|
+
GenerateMigrationChecksumsResult,
|
|
14
|
+
TypegenDialect,
|
|
15
|
+
} from './types';
|
|
16
|
+
|
|
17
|
+
interface TraceableQuery {
|
|
18
|
+
sql: string;
|
|
19
|
+
parameters: readonly unknown[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface SqliteDb {
|
|
23
|
+
close(): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type BunAwareGlobals = typeof globalThis & {
|
|
27
|
+
Bun?: object;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const runtimeGlobals = globalThis as BunAwareGlobals;
|
|
31
|
+
const isBun = typeof runtimeGlobals.Bun !== 'undefined';
|
|
32
|
+
|
|
33
|
+
function hashString(value: string): string {
|
|
34
|
+
let hash = 0;
|
|
35
|
+
|
|
36
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
37
|
+
hash = (hash * 31 + value.charCodeAt(index)) >>> 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return hash.toString(16).padStart(8, '0');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function normalizeParameterValue(value: unknown): unknown {
|
|
44
|
+
if (typeof value === 'bigint') {
|
|
45
|
+
return { type: 'bigint', value: value.toString() };
|
|
46
|
+
}
|
|
47
|
+
if (value instanceof Date) {
|
|
48
|
+
return { type: 'date', value: value.toISOString() };
|
|
49
|
+
}
|
|
50
|
+
if (value instanceof Uint8Array) {
|
|
51
|
+
return { type: 'bytes', value: Array.from(value) };
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(value)) {
|
|
54
|
+
return value.map((entry) => normalizeParameterValue(entry));
|
|
55
|
+
}
|
|
56
|
+
if (value && typeof value === 'object') {
|
|
57
|
+
return Object.fromEntries(
|
|
58
|
+
Object.entries(value)
|
|
59
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
60
|
+
.map(([key, entry]) => [key, normalizeParameterValue(entry)])
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function serializeQuery(query: TraceableQuery): string {
|
|
67
|
+
return JSON.stringify({
|
|
68
|
+
sql: query.sql,
|
|
69
|
+
parameters: query.parameters.map((value) => normalizeParameterValue(value)),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function hashTrace(entries: string[]): string {
|
|
74
|
+
return hashString(entries.join('\n'));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function quoteTsString(value: string): string {
|
|
78
|
+
return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'")}'`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function createSqliteTraceDb<DB>(traceEntries: string[]): Promise<{
|
|
82
|
+
db: Kysely<DB>;
|
|
83
|
+
sqliteDb: SqliteDb;
|
|
84
|
+
}> {
|
|
85
|
+
if (isBun) {
|
|
86
|
+
const bunSqliteSpecifier = 'bun:sqlite';
|
|
87
|
+
const sqliteModule = await import(bunSqliteSpecifier);
|
|
88
|
+
const dialectModule = await import('kysely-bun-sqlite');
|
|
89
|
+
const sqliteDb = new sqliteModule.Database(':memory:');
|
|
90
|
+
const db = new Kysely<DB>({
|
|
91
|
+
dialect: new dialectModule.BunSqliteDialect({
|
|
92
|
+
database: sqliteDb as never,
|
|
93
|
+
}),
|
|
94
|
+
log(event) {
|
|
95
|
+
if (event.level === 'query') {
|
|
96
|
+
traceEntries.push(serializeQuery(event.query));
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return { db, sqliteDb };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const { default: Database } = await import('better-sqlite3');
|
|
105
|
+
const sqliteDb = new Database(':memory:');
|
|
106
|
+
const db = new Kysely<DB>({
|
|
107
|
+
dialect: new SqliteDialect({
|
|
108
|
+
database: sqliteDb as never,
|
|
109
|
+
}),
|
|
110
|
+
log(event) {
|
|
111
|
+
if (event.level === 'query') {
|
|
112
|
+
traceEntries.push(serializeQuery(event.query));
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return { db, sqliteDb };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function createPostgresTraceDb<DB>(traceEntries: string[]): Promise<{
|
|
121
|
+
db: Kysely<DB>;
|
|
122
|
+
dispose: () => Promise<void>;
|
|
123
|
+
}> {
|
|
124
|
+
const pglite = await PGlite.create();
|
|
125
|
+
const db = new Kysely<DB>({
|
|
126
|
+
dialect: new PGliteDialect(pglite),
|
|
127
|
+
log(event) {
|
|
128
|
+
if (event.level === 'query') {
|
|
129
|
+
traceEntries.push(serializeQuery(event.query));
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
db,
|
|
136
|
+
dispose: async () => {
|
|
137
|
+
if (!pglite.closed) {
|
|
138
|
+
await pglite.close();
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function createTraceDb<DB>(
|
|
145
|
+
dialect: TypegenDialect,
|
|
146
|
+
traceEntries: string[]
|
|
147
|
+
): Promise<{
|
|
148
|
+
db: Kysely<DB>;
|
|
149
|
+
dispose: () => Promise<void>;
|
|
150
|
+
}> {
|
|
151
|
+
if (dialect === 'postgres') {
|
|
152
|
+
return createPostgresTraceDb<DB>(traceEntries);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const { db, sqliteDb } = await createSqliteTraceDb<DB>(traceEntries);
|
|
156
|
+
return {
|
|
157
|
+
db,
|
|
158
|
+
dispose: async () => {
|
|
159
|
+
sqliteDb.close();
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function computeMigrationChecksum<DB>(
|
|
165
|
+
migrations: DefinedMigrations<DB>,
|
|
166
|
+
targetMigration: ParsedMigration<DB>,
|
|
167
|
+
dialect: TypegenDialect
|
|
168
|
+
): Promise<string> {
|
|
169
|
+
const traceEntries: string[] = [];
|
|
170
|
+
const { db, dispose } = await createTraceDb<DB>(dialect, traceEntries);
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
for (const migration of migrations.migrations) {
|
|
174
|
+
if (migration.version > targetMigration.version) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (migration.version === targetMigration.version) {
|
|
179
|
+
traceEntries.length = 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
await migration.up(db);
|
|
183
|
+
|
|
184
|
+
if (migration.version === targetMigration.version) {
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return hashTrace(traceEntries);
|
|
190
|
+
} finally {
|
|
191
|
+
await db.destroy();
|
|
192
|
+
await dispose();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function createMigrationChecksums<DB>(
|
|
197
|
+
migrations: DefinedMigrations<DB>,
|
|
198
|
+
dialect: TypegenDialect = 'sqlite'
|
|
199
|
+
): Promise<MigrationChecksums> {
|
|
200
|
+
const checksums: Record<string, string> = {};
|
|
201
|
+
|
|
202
|
+
for (const migration of migrations.migrations) {
|
|
203
|
+
if (migration.checksum === 'disabled') {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
checksums[String(migration.version)] = await computeMigrationChecksum(
|
|
208
|
+
migrations,
|
|
209
|
+
migration,
|
|
210
|
+
dialect
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return checksums;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function renderMigrationChecksums(
|
|
218
|
+
checksums: MigrationChecksums
|
|
219
|
+
): string {
|
|
220
|
+
const entries = Object.entries(checksums)
|
|
221
|
+
.sort(([left], [right]) => Number(left) - Number(right))
|
|
222
|
+
.map(
|
|
223
|
+
([version, checksum]) =>
|
|
224
|
+
` ${quoteTsString(version)}: ${quoteTsString(checksum)},`
|
|
225
|
+
)
|
|
226
|
+
.join('\n');
|
|
227
|
+
|
|
228
|
+
return [
|
|
229
|
+
'/**',
|
|
230
|
+
' * Generated by @syncular/typegen.',
|
|
231
|
+
' * Do not edit by hand.',
|
|
232
|
+
' */',
|
|
233
|
+
'',
|
|
234
|
+
'export const migrationChecksums = {',
|
|
235
|
+
entries,
|
|
236
|
+
'} as const;',
|
|
237
|
+
'',
|
|
238
|
+
].join('\n');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export async function generateMigrationChecksums<DB>(
|
|
242
|
+
options: GenerateMigrationChecksumsOptions<DB>
|
|
243
|
+
): Promise<GenerateMigrationChecksumsResult> {
|
|
244
|
+
const { migrations, output, dialect = 'sqlite' } = options;
|
|
245
|
+
const checksums = await createMigrationChecksums(migrations, dialect);
|
|
246
|
+
const code = renderMigrationChecksums(checksums);
|
|
247
|
+
|
|
248
|
+
await mkdir(dirname(output), { recursive: true });
|
|
249
|
+
await writeFile(output, code, 'utf-8');
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
outputPath: output,
|
|
253
|
+
currentVersion: migrations.currentVersion,
|
|
254
|
+
checksumCount: Object.keys(checksums).length,
|
|
255
|
+
code,
|
|
256
|
+
};
|
|
257
|
+
}
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -132,3 +132,23 @@ export interface GenerateTypesResult {
|
|
|
132
132
|
/** Generated TypeScript code */
|
|
133
133
|
code: string;
|
|
134
134
|
}
|
|
135
|
+
|
|
136
|
+
export interface GenerateMigrationChecksumsOptions<DB = unknown> {
|
|
137
|
+
/** Defined migrations from defineMigrations() */
|
|
138
|
+
migrations: DefinedMigrations<DB>;
|
|
139
|
+
/** Output file path for generated checksums */
|
|
140
|
+
output: string;
|
|
141
|
+
/** Database dialect to use for replay (default: 'sqlite') */
|
|
142
|
+
dialect?: TypegenDialect;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface GenerateMigrationChecksumsResult {
|
|
146
|
+
/** Path to the generated file */
|
|
147
|
+
outputPath: string;
|
|
148
|
+
/** Current schema version */
|
|
149
|
+
currentVersion: number;
|
|
150
|
+
/** Number of checksums generated */
|
|
151
|
+
checksumCount: number;
|
|
152
|
+
/** Generated TypeScript code */
|
|
153
|
+
code: string;
|
|
154
|
+
}
|