@pikku/cli 0.12.25 → 0.12.26
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/console-app/assets/{index-D4DgafuS.js → index-Ba9K10XZ.js} +4 -4
- package/console-app/index.html +1 -1
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +6 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +9 -0
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +116 -101
- package/dist/.pikku/function/pikku-functions.gen.js +3 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +10 -9
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +7 -5
- package/dist/.pikku/schemas/schemas/DbAuditInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuTestsCoverageInput.schema.json +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/cli.wiring.js +8 -0
- package/dist/src/fabric/functions/validate.function.js +1 -1
- package/dist/src/functions/commands/db-audit.d.ts +1 -0
- package/dist/src/functions/commands/db-audit.js +67 -0
- package/dist/src/functions/commands/db-migrate.js +5 -8
- package/dist/src/functions/commands/db-reset.js +9 -8
- package/dist/src/functions/commands/db-seed.js +9 -8
- package/dist/src/functions/commands/db-shared.d.ts +2 -4
- package/dist/src/functions/commands/db-shared.js +15 -5
- package/dist/src/functions/commands/dev.js +14 -8
- package/dist/src/functions/commands/new-addon.js +2 -2
- package/dist/src/functions/commands/tests-coverage.d.ts +3 -0
- package/dist/src/functions/commands/tests-coverage.js +34 -0
- package/dist/src/functions/db/annotation-parser.d.ts +31 -0
- package/dist/src/functions/db/annotation-parser.js +93 -0
- package/dist/src/functions/db/db-codegen.d.ts +24 -0
- package/dist/src/functions/db/db-codegen.js +276 -0
- package/dist/src/functions/db/db-introspector.d.ts +15 -0
- package/dist/src/functions/db/db-introspector.js +1 -0
- package/dist/src/functions/db/db-migrator.d.ts +32 -0
- package/dist/src/functions/db/db-migrator.js +65 -0
- package/dist/src/functions/db/local-db.d.ts +27 -33
- package/dist/src/functions/db/local-db.js +100 -53
- package/dist/src/functions/db/postgres/postgres-introspector.d.ts +10 -0
- package/dist/src/functions/db/postgres/postgres-introspector.js +54 -0
- package/dist/src/functions/db/postgres/postgres-migrator.d.ts +9 -0
- package/dist/src/functions/db/postgres/postgres-migrator.js +32 -0
- package/dist/src/functions/db/sqlite/sqlite-introspector.d.ts +9 -0
- package/dist/src/functions/db/sqlite/sqlite-introspector.js +35 -0
- package/dist/src/functions/db/sqlite/sqlite-migrator.d.ts +10 -0
- package/dist/src/functions/db/sqlite/sqlite-migrator.js +36 -0
- package/dist/src/functions/validate/workspace-validate.js +3 -2
- package/dist/src/functions/wirings/ai-agent/serialize-public-agent.js +2 -1
- package/dist/src/functions/wirings/console/serialize-console-functions.js +4 -4
- package/dist/src/functions/wirings/functions/serialize-addon-types.js +1 -1
- package/dist/src/scaffold/rpc-remote.gen.js +1 -1
- package/dist/src/services.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -3
- package/skills/pikku-testing/SKILL.md +208 -0
- package/dist/src/functions/db/sql-migrator.d.ts +0 -26
- package/dist/src/functions/db/sql-migrator.js +0 -104
- package/dist/src/functions/db/sqlite-codegen.d.ts +0 -45
- package/dist/src/functions/db/sqlite-codegen.js +0 -294
- /package/dist/src/functions/db/{seed.d.ts → sqlite/seed.d.ts} +0 -0
- /package/dist/src/functions/db/{seed.js → sqlite/seed.js} +0 -0
- /package/dist/src/functions/db/{sqlite-kysely.d.ts → sqlite/sqlite-kysely.d.ts} +0 -0
- /package/dist/src/functions/db/{sqlite-kysely.js → sqlite/sqlite-kysely.js} +0 -0
- /package/dist/src/functions/db/{sqlite-runtime-bun.d.ts → sqlite/sqlite-runtime-bun.d.ts} +0 -0
- /package/dist/src/functions/db/{sqlite-runtime-bun.js → sqlite/sqlite-runtime-bun.js} +0 -0
- /package/dist/src/functions/db/{sqlite-runtime-node.d.ts → sqlite/sqlite-runtime-node.d.ts} +0 -0
- /package/dist/src/functions/db/{sqlite-runtime-node.js → sqlite/sqlite-runtime-node.js} +0 -0
- /package/dist/src/functions/db/{sqlite-runtime.d.ts → sqlite/sqlite-runtime.d.ts} +0 -0
- /package/dist/src/functions/db/{sqlite-runtime.js → sqlite/sqlite-runtime.js} +0 -0
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
const SKIP_TABLES = new Set(['sqlite_sequence', 'sql_migrations']);
|
|
4
|
-
function snakeToPascal(name) {
|
|
5
|
-
return name
|
|
6
|
-
.split('_')
|
|
7
|
-
.map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
|
|
8
|
-
.join('');
|
|
9
|
-
}
|
|
10
|
-
function snakeToCamel(name) {
|
|
11
|
-
return name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
12
|
-
}
|
|
13
|
-
function mapType(sqlType) {
|
|
14
|
-
const upper = sqlType.toUpperCase();
|
|
15
|
-
if (upper.includes('INT'))
|
|
16
|
-
return 'number';
|
|
17
|
-
if (upper.includes('CHAR') ||
|
|
18
|
-
upper.includes('CLOB') ||
|
|
19
|
-
upper.includes('TEXT')) {
|
|
20
|
-
return 'string';
|
|
21
|
-
}
|
|
22
|
-
if (upper.includes('BLOB'))
|
|
23
|
-
return 'Buffer';
|
|
24
|
-
if (upper.includes('REAL') ||
|
|
25
|
-
upper.includes('FLOA') ||
|
|
26
|
-
upper.includes('DOUB')) {
|
|
27
|
-
return 'number';
|
|
28
|
-
}
|
|
29
|
-
if (upper.includes('NUMERIC') || upper.includes('DECIMAL'))
|
|
30
|
-
return 'number';
|
|
31
|
-
if (upper.includes('BOOL'))
|
|
32
|
-
return 'number';
|
|
33
|
-
return 'string';
|
|
34
|
-
}
|
|
35
|
-
function listTables(db) {
|
|
36
|
-
const tableRows = db
|
|
37
|
-
.prepare(`SELECT name FROM sqlite_master
|
|
38
|
-
WHERE type = 'table'
|
|
39
|
-
AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\'
|
|
40
|
-
ORDER BY name`)
|
|
41
|
-
.all();
|
|
42
|
-
return tableRows
|
|
43
|
-
.filter((t) => !SKIP_TABLES.has(t.name))
|
|
44
|
-
.map((t) => {
|
|
45
|
-
const allColumns = db
|
|
46
|
-
.prepare(`PRAGMA table_xinfo(${escapeIdentifier(t.name)})`)
|
|
47
|
-
.all();
|
|
48
|
-
// hidden: 0=regular, 2=virtual generated, 3=stored generated — include all; skip 1 (vtab hidden)
|
|
49
|
-
const columns = allColumns.filter((c) => c.hidden !== 1);
|
|
50
|
-
return { name: t.name, columns };
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
function escapeIdentifier(name) {
|
|
54
|
-
return `"${name.replace(/"/g, '""')}"`;
|
|
55
|
-
}
|
|
56
|
-
// ─── Annotation parsing ──────────────────────────────────────────────────────
|
|
57
|
-
/**
|
|
58
|
-
* Determine column kind from naming conventions:
|
|
59
|
-
* *_at / *_on → date
|
|
60
|
-
* is_* / has_* / can_* → bool
|
|
61
|
-
*/
|
|
62
|
-
function annotationFromName(colName) {
|
|
63
|
-
if (/_at$|_on$/.test(colName))
|
|
64
|
-
return { kind: 'date' };
|
|
65
|
-
if (/^is_|^has_|^can_/.test(colName))
|
|
66
|
-
return { kind: 'bool' };
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Parse `-- @bool | @date | @json [TypescriptType]` inline annotations from
|
|
71
|
-
* migration SQL files. The TypeScript type is optional and only meaningful for
|
|
72
|
-
* `@json` — it controls the generated TypeScript type (e.g. `string[]`,
|
|
73
|
-
* `Record<string, number>`).
|
|
74
|
-
*
|
|
75
|
-
* Returns an AnnotationMap: { table_name: { col_name: ColAnnotation } }.
|
|
76
|
-
*/
|
|
77
|
-
export function parseAnnotations(migrationsDir) {
|
|
78
|
-
let files;
|
|
79
|
-
try {
|
|
80
|
-
files = readdirSync(migrationsDir)
|
|
81
|
-
.filter((f) => f.endsWith('.sql'))
|
|
82
|
-
.sort();
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return {};
|
|
86
|
-
}
|
|
87
|
-
const result = {};
|
|
88
|
-
for (const file of files) {
|
|
89
|
-
const content = readFileSync(join(migrationsDir, file), 'utf8');
|
|
90
|
-
const createTablePattern = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?"?(\w+)"?\s*\(([^;]+)\)/gis;
|
|
91
|
-
let tableMatch;
|
|
92
|
-
while ((tableMatch = createTablePattern.exec(content)) !== null) {
|
|
93
|
-
const tableName = tableMatch[1].toLowerCase();
|
|
94
|
-
const body = tableMatch[2];
|
|
95
|
-
for (const line of body.split('\n')) {
|
|
96
|
-
const trimmed = line.trim();
|
|
97
|
-
if (/^(PRIMARY|UNIQUE|CHECK|FOREIGN|CONSTRAINT)/i.test(trimmed))
|
|
98
|
-
continue;
|
|
99
|
-
// Match: col_name TYPE ... -- @kind [optional ts type]
|
|
100
|
-
const annotationMatch = trimmed.match(/^(\w+)\s+\w.*?--\s*@(bool|date|json)(?:\s+(.+?))?$/i);
|
|
101
|
-
if (annotationMatch) {
|
|
102
|
-
const colName = annotationMatch[1].toLowerCase();
|
|
103
|
-
const kind = annotationMatch[2].toLowerCase();
|
|
104
|
-
const tsType = annotationMatch[3]?.trim() || undefined;
|
|
105
|
-
if (!result[tableName])
|
|
106
|
-
result[tableName] = {};
|
|
107
|
-
result[tableName][colName] = {
|
|
108
|
-
kind,
|
|
109
|
-
tsType: kind === 'json' ? tsType : undefined,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return result;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Merge explicit SQL annotations with naming-convention-based ones.
|
|
119
|
-
* Explicit annotations take precedence.
|
|
120
|
-
*/
|
|
121
|
-
function buildAnnotationMap(tables, explicit) {
|
|
122
|
-
const merged = {};
|
|
123
|
-
for (const table of tables) {
|
|
124
|
-
const explicitCols = explicit[table.name] ?? {};
|
|
125
|
-
for (const col of table.columns) {
|
|
126
|
-
const annotation = explicitCols[col.name] ?? annotationFromName(col.name);
|
|
127
|
-
if (annotation) {
|
|
128
|
-
if (!merged[table.name])
|
|
129
|
-
merged[table.name] = {};
|
|
130
|
-
merged[table.name][col.name] = annotation;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return merged;
|
|
135
|
-
}
|
|
136
|
-
// ─── Type expression ─────────────────────────────────────────────────────────
|
|
137
|
-
function columnTypeExpression(col, annotation) {
|
|
138
|
-
const nullable = !col.notnull && col.pk === 0;
|
|
139
|
-
const hasDefault = col.dflt_value !== null && col.dflt_value !== undefined;
|
|
140
|
-
const isAutoInt = col.pk === 1 && mapType(col.type) === 'number';
|
|
141
|
-
const isGenerated = col.hidden === 2 || col.hidden === 3;
|
|
142
|
-
const wrap = (inner) => hasDefault || isAutoInt || isGenerated ? `Generated<${inner}>` : inner;
|
|
143
|
-
if (annotation?.kind === 'bool') {
|
|
144
|
-
const base = nullable ? 'boolean | null' : 'boolean';
|
|
145
|
-
const rw = nullable ? 'boolean | number | null' : 'boolean | number';
|
|
146
|
-
return wrap(`ColumnType<${base}, ${rw}, ${rw}>`);
|
|
147
|
-
}
|
|
148
|
-
if (annotation?.kind === 'date') {
|
|
149
|
-
const base = nullable ? 'Date | null' : 'Date';
|
|
150
|
-
const rw = nullable ? 'Date | string | null' : 'Date | string';
|
|
151
|
-
return wrap(`ColumnType<${base}, ${rw}, ${rw}>`);
|
|
152
|
-
}
|
|
153
|
-
if (annotation?.kind === 'json') {
|
|
154
|
-
const base = annotation.tsType
|
|
155
|
-
? nullable
|
|
156
|
-
? `${annotation.tsType} | null`
|
|
157
|
-
: annotation.tsType
|
|
158
|
-
: nullable
|
|
159
|
-
? 'unknown | null'
|
|
160
|
-
: 'unknown';
|
|
161
|
-
return wrap(base);
|
|
162
|
-
}
|
|
163
|
-
// Default: plain SQL-mapped type
|
|
164
|
-
const base = mapType(col.type);
|
|
165
|
-
if (isAutoInt)
|
|
166
|
-
return `Generated<${base}>`;
|
|
167
|
-
if (hasDefault || isGenerated)
|
|
168
|
-
return `Generated<${base}${nullable ? ' | null' : ''}>`;
|
|
169
|
-
return nullable ? `${base} | null` : base;
|
|
170
|
-
}
|
|
171
|
-
// ─── Interface emitter ───────────────────────────────────────────────────────
|
|
172
|
-
function emitInterface(table, camelCase, annotations) {
|
|
173
|
-
const ifaceName = snakeToPascal(table.name);
|
|
174
|
-
const tableCols = annotations[table.name] ?? {};
|
|
175
|
-
const fields = table.columns
|
|
176
|
-
.map((col) => {
|
|
177
|
-
const fieldName = camelCase ? snakeToCamel(col.name) : col.name;
|
|
178
|
-
const annotation = tableCols[col.name] ?? null;
|
|
179
|
-
const type = columnTypeExpression(col, annotation);
|
|
180
|
-
const safeName = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(fieldName)
|
|
181
|
-
? fieldName
|
|
182
|
-
: JSON.stringify(fieldName);
|
|
183
|
-
return ` ${safeName}: ${type}`;
|
|
184
|
-
})
|
|
185
|
-
.join('\n');
|
|
186
|
-
return `export interface ${ifaceName} {\n${fields}\n}`;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Introspect the open SQLite database and emit a Kysely DB type to outFile
|
|
190
|
-
* plus a CoercionMap to coercionFile.
|
|
191
|
-
*
|
|
192
|
-
* Columns are annotated via:
|
|
193
|
-
* 1. Naming conventions (_at/_on → date; is_/has_/can_ → bool)
|
|
194
|
-
* 2. Inline SQL comments: `col_name TYPE ... -- @bool|@date|@json [TsType]`
|
|
195
|
-
* For @json, an optional TypeScript type string controls the generated type.
|
|
196
|
-
*
|
|
197
|
-
* Returns `written: false` if the on-disk file already matches.
|
|
198
|
-
*/
|
|
199
|
-
export function generateSchemaTypes(db, options) {
|
|
200
|
-
const camelCase = options.camelCase ?? true;
|
|
201
|
-
const tables = listTables(db);
|
|
202
|
-
const explicitAnnotations = options.migrationsDir
|
|
203
|
-
? parseAnnotations(options.migrationsDir)
|
|
204
|
-
: {};
|
|
205
|
-
const annotations = buildAnnotationMap(tables, explicitAnnotations);
|
|
206
|
-
// ── schema.d.ts ──
|
|
207
|
-
const interfaces = tables
|
|
208
|
-
.map((t) => emitInterface(t, camelCase, annotations))
|
|
209
|
-
.join('\n\n');
|
|
210
|
-
const dbEntries = tables
|
|
211
|
-
.map((t) => {
|
|
212
|
-
const tableKey = camelCase ? snakeToCamel(t.name) : t.name;
|
|
213
|
-
const safe = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableKey)
|
|
214
|
-
? tableKey
|
|
215
|
-
: JSON.stringify(tableKey);
|
|
216
|
-
return ` ${safe}: ${snakeToPascal(t.name)}`;
|
|
217
|
-
})
|
|
218
|
-
.join('\n');
|
|
219
|
-
const schemaBody = [
|
|
220
|
-
`// Generated by @pikku/cli — do not edit by hand.`,
|
|
221
|
-
`// Run \`pikku db migrate\` to refresh.`,
|
|
222
|
-
``,
|
|
223
|
-
`import type { ColumnType } from 'kysely'`,
|
|
224
|
-
``,
|
|
225
|
-
`export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>`,
|
|
226
|
-
` ? ColumnType<S, I | undefined, U>`,
|
|
227
|
-
` : ColumnType<T, T | undefined, T>`,
|
|
228
|
-
``,
|
|
229
|
-
interfaces,
|
|
230
|
-
``,
|
|
231
|
-
`export interface DB {`,
|
|
232
|
-
dbEntries,
|
|
233
|
-
`}`,
|
|
234
|
-
``,
|
|
235
|
-
].join('\n');
|
|
236
|
-
// ── coercion.gen.ts (runtime map — only kind, not tsType) ──
|
|
237
|
-
const runtimeMap = {};
|
|
238
|
-
for (const [table, cols] of Object.entries(annotations)) {
|
|
239
|
-
for (const [col, ann] of Object.entries(cols)) {
|
|
240
|
-
if (!runtimeMap[table])
|
|
241
|
-
runtimeMap[table] = {};
|
|
242
|
-
runtimeMap[table][col] = ann.kind;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
const coercionEntries = Object.entries(runtimeMap)
|
|
246
|
-
.map(([table, cols]) => {
|
|
247
|
-
const colEntries = Object.entries(cols)
|
|
248
|
-
.map(([col, kind]) => ` "${col}": "${kind}"`)
|
|
249
|
-
.join(',\n');
|
|
250
|
-
return ` "${table}": {\n${colEntries}\n }`;
|
|
251
|
-
})
|
|
252
|
-
.join(',\n');
|
|
253
|
-
const coercionBody = [
|
|
254
|
-
`// Generated by @pikku/cli — do not edit by hand.`,
|
|
255
|
-
`// Run \`pikku db migrate\` to refresh.`,
|
|
256
|
-
``,
|
|
257
|
-
`export const coercionMap = {`,
|
|
258
|
-
coercionEntries,
|
|
259
|
-
`} as const`,
|
|
260
|
-
``,
|
|
261
|
-
].join('\n');
|
|
262
|
-
// ── write files ──
|
|
263
|
-
let existingSchema = null;
|
|
264
|
-
let existingCoercion = null;
|
|
265
|
-
try {
|
|
266
|
-
existingSchema = readFileSync(options.outFile, 'utf8');
|
|
267
|
-
}
|
|
268
|
-
catch {
|
|
269
|
-
/* ok */
|
|
270
|
-
}
|
|
271
|
-
try {
|
|
272
|
-
existingCoercion = readFileSync(options.coercionFile, 'utf8');
|
|
273
|
-
}
|
|
274
|
-
catch {
|
|
275
|
-
/* ok */
|
|
276
|
-
}
|
|
277
|
-
const schemaChanged = existingSchema !== schemaBody;
|
|
278
|
-
const coercionChanged = existingCoercion !== coercionBody;
|
|
279
|
-
if (schemaChanged) {
|
|
280
|
-
mkdirSync(dirname(options.outFile), { recursive: true });
|
|
281
|
-
writeFileSync(options.outFile, schemaBody, 'utf8');
|
|
282
|
-
}
|
|
283
|
-
if (coercionChanged) {
|
|
284
|
-
mkdirSync(dirname(options.coercionFile), { recursive: true });
|
|
285
|
-
writeFileSync(options.coercionFile, coercionBody, 'utf8');
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
outFile: options.outFile,
|
|
289
|
-
coercionFile: options.coercionFile,
|
|
290
|
-
written: schemaChanged,
|
|
291
|
-
coercionWritten: coercionChanged,
|
|
292
|
-
tables: tables.map((t) => t.name),
|
|
293
|
-
};
|
|
294
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|