@plumbus/core 0.2.9 → 0.3.0
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/.tsbuildinfo +1 -1
- package/dist/ai/__tests__/ai-service.test.js +704 -1
- package/dist/ai/__tests__/ai-service.test.js.map +1 -1
- package/dist/ai/__tests__/chunking.test.js +34 -0
- package/dist/ai/__tests__/chunking.test.js.map +1 -1
- package/dist/ai/__tests__/provider.test.d.ts.map +1 -1
- package/dist/ai/__tests__/provider.test.js +425 -0
- package/dist/ai/__tests__/provider.test.js.map +1 -1
- package/dist/ai/__tests__/validation.test.js +200 -1
- package/dist/ai/__tests__/validation.test.js.map +1 -1
- package/dist/ai/__tests__/zod-to-provider-schema.test.d.ts +2 -0
- package/dist/ai/__tests__/zod-to-provider-schema.test.d.ts.map +1 -0
- package/dist/ai/__tests__/zod-to-provider-schema.test.js +60 -0
- package/dist/ai/__tests__/zod-to-provider-schema.test.js.map +1 -0
- package/dist/ai/ai-service.d.ts +19 -2
- package/dist/ai/ai-service.d.ts.map +1 -1
- package/dist/ai/ai-service.js +544 -110
- package/dist/ai/ai-service.js.map +1 -1
- package/dist/ai/cost-tracker.d.ts +26 -1
- package/dist/ai/cost-tracker.d.ts.map +1 -1
- package/dist/ai/cost-tracker.js +1 -0
- package/dist/ai/cost-tracker.js.map +1 -1
- package/dist/ai/index.d.ts +5 -3
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +5 -1
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/provider.d.ts +45 -1
- package/dist/ai/provider.d.ts.map +1 -1
- package/dist/ai/provider.js +226 -32
- package/dist/ai/provider.js.map +1 -1
- package/dist/ai/rag/chunking.js +53 -3
- package/dist/ai/rag/chunking.js.map +1 -1
- package/dist/ai/refusal.d.ts +28 -0
- package/dist/ai/refusal.d.ts.map +1 -0
- package/dist/ai/refusal.js +36 -0
- package/dist/ai/refusal.js.map +1 -0
- package/dist/ai/validation.d.ts +40 -8
- package/dist/ai/validation.d.ts.map +1 -1
- package/dist/ai/validation.js +97 -6
- package/dist/ai/validation.js.map +1 -1
- package/dist/ai/zod-to-provider-schema.d.ts +15 -0
- package/dist/ai/zod-to-provider-schema.d.ts.map +1 -0
- package/dist/ai/zod-to-provider-schema.js +200 -0
- package/dist/ai/zod-to-provider-schema.js.map +1 -0
- package/dist/cli/__tests__/doctor.test.js +104 -2
- package/dist/cli/__tests__/doctor.test.js.map +1 -1
- package/dist/cli/__tests__/init.test.js +127 -7
- package/dist/cli/__tests__/init.test.js.map +1 -1
- package/dist/cli/__tests__/migrate.test.js +159 -2
- package/dist/cli/__tests__/migrate.test.js.map +1 -1
- package/dist/cli/commands/__tests__/commands.test.js +5 -0
- package/dist/cli/commands/__tests__/commands.test.js.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +21 -1
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +2 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +78 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +7 -2
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/init.d.ts +16 -2
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +226 -25
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +258 -8
- package/dist/cli/commands/migrate.js.map +1 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +21 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/data/__tests__/drift-inspector.test.d.ts +2 -0
- package/dist/data/__tests__/drift-inspector.test.d.ts.map +1 -0
- package/dist/data/__tests__/drift-inspector.test.js +170 -0
- package/dist/data/__tests__/drift-inspector.test.js.map +1 -0
- package/dist/data/__tests__/framework-migration-rewriter.test.d.ts +2 -0
- package/dist/data/__tests__/framework-migration-rewriter.test.d.ts.map +1 -0
- package/dist/data/__tests__/framework-migration-rewriter.test.js +329 -0
- package/dist/data/__tests__/framework-migration-rewriter.test.js.map +1 -0
- package/dist/data/__tests__/migration.test.js +93 -2
- package/dist/data/__tests__/migration.test.js.map +1 -1
- package/dist/data/__tests__/repository.test.js +126 -0
- package/dist/data/__tests__/repository.test.js.map +1 -1
- package/dist/data/drift-inspector.d.ts +41 -0
- package/dist/data/drift-inspector.d.ts.map +1 -0
- package/dist/data/drift-inspector.js +197 -0
- package/dist/data/drift-inspector.js.map +1 -0
- package/dist/data/framework-migration-rewriter.d.ts +61 -0
- package/dist/data/framework-migration-rewriter.d.ts.map +1 -0
- package/dist/data/framework-migration-rewriter.js +357 -0
- package/dist/data/framework-migration-rewriter.js.map +1 -0
- package/dist/data/index.d.ts +2 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +2 -1
- package/dist/data/index.js.map +1 -1
- package/dist/data/migration.d.ts +31 -1
- package/dist/data/migration.d.ts.map +1 -1
- package/dist/data/migration.js +113 -3
- package/dist/data/migration.js.map +1 -1
- package/dist/data/repository.d.ts.map +1 -1
- package/dist/data/repository.js +21 -0
- package/dist/data/repository.js.map +1 -1
- package/dist/define/__tests__/definePrompt.test.js +37 -0
- package/dist/define/__tests__/definePrompt.test.js.map +1 -1
- package/dist/define/definePrompt.d.ts +13 -0
- package/dist/define/definePrompt.d.ts.map +1 -1
- package/dist/define/definePrompt.js +3 -0
- package/dist/define/definePrompt.js.map +1 -1
- package/dist/errors/http.d.ts.map +1 -1
- package/dist/errors/http.js +2 -0
- package/dist/errors/http.js.map +1 -1
- package/dist/errors/index.d.ts +12 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +21 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/events/__tests__/event-emitter.test.js +72 -0
- package/dist/events/__tests__/event-emitter.test.js.map +1 -1
- package/dist/events/emitter.d.ts.map +1 -1
- package/dist/events/emitter.js +51 -0
- package/dist/events/emitter.js.map +1 -1
- package/dist/execution/__tests__/context-factory.test.js +1 -0
- package/dist/execution/__tests__/context-factory.test.js.map +1 -1
- package/dist/execution/context-factory.d.ts.map +1 -1
- package/dist/execution/context-factory.js +2 -0
- package/dist/execution/context-factory.js.map +1 -1
- package/dist/flows/__tests__/flow-engine.test.js +451 -4
- package/dist/flows/__tests__/flow-engine.test.js.map +1 -1
- package/dist/flows/__tests__/flow-service.test.js +8 -0
- package/dist/flows/__tests__/flow-service.test.js.map +1 -1
- package/dist/flows/__tests__/step-executor.test.js +8 -2
- package/dist/flows/__tests__/step-executor.test.js.map +1 -1
- package/dist/flows/engine.d.ts +50 -1
- package/dist/flows/engine.d.ts.map +1 -1
- package/dist/flows/engine.js +427 -23
- package/dist/flows/engine.js.map +1 -1
- package/dist/flows/flow-service.d.ts.map +1 -1
- package/dist/flows/flow-service.js +4 -0
- package/dist/flows/flow-service.js.map +1 -1
- package/dist/flows/index.d.ts +1 -1
- package/dist/flows/index.d.ts.map +1 -1
- package/dist/flows/index.js +1 -1
- package/dist/flows/index.js.map +1 -1
- package/dist/flows/schema.d.ts +34 -0
- package/dist/flows/schema.d.ts.map +1 -1
- package/dist/flows/schema.js +3 -0
- package/dist/flows/schema.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/server/bootstrap.d.ts +14 -0
- package/dist/server/bootstrap.d.ts.map +1 -1
- package/dist/server/bootstrap.js +23 -4
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/testing/context.d.ts.map +1 -1
- package/dist/testing/context.js +37 -1
- package/dist/testing/context.js.map +1 -1
- package/dist/types/context.d.ts +110 -0
- package/dist/types/context.d.ts.map +1 -1
- package/dist/types/enums.d.ts +2 -0
- package/dist/types/enums.d.ts.map +1 -1
- package/dist/types/enums.js +2 -0
- package/dist/types/enums.js.map +1 -1
- package/dist/types/prompt.d.ts +64 -0
- package/dist/types/prompt.d.ts.map +1 -1
- package/dist/worker/__tests__/bootstrap.test.js +36 -2
- package/dist/worker/__tests__/bootstrap.test.js.map +1 -1
- package/dist/worker/bootstrap.d.ts +7 -0
- package/dist/worker/bootstrap.d.ts.map +1 -1
- package/dist/worker/bootstrap.js +153 -12
- package/dist/worker/bootstrap.js.map +1 -1
- package/instructions/framework.md +7 -0
- package/instructions/guardrails.md +39 -0
- package/instructions/patterns.md +10 -0
- package/package.json +3 -2
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
// ── Framework Migration Rewriter ──
|
|
2
|
+
// Transforms drizzle-kit's raw migration SQL so that it can be safely applied
|
|
3
|
+
// against a database whose framework-managed tables (flow_executions, etc.)
|
|
4
|
+
// already exist but are missing newly-added framework columns.
|
|
5
|
+
//
|
|
6
|
+
// Why this exists:
|
|
7
|
+
// When a project upgrades `@plumbus/core`, the framework's own table schemas
|
|
8
|
+
// may have grown new columns (e.g. flow leasing added `lease_owner` and
|
|
9
|
+
// `lease_expires_at` to `flow_executions`). Drizzle-kit, which generates
|
|
10
|
+
// migrations purely from snapshot diffs, has no awareness of which tables
|
|
11
|
+
// are framework-managed and emits `CREATE TABLE` for the entire framework
|
|
12
|
+
// table — even when the table already exists in the live DB. That migration
|
|
13
|
+
// is then rejected by the `migrate apply` preflight ("framework table
|
|
14
|
+
// already exists"), leaving users with no clean upgrade path.
|
|
15
|
+
//
|
|
16
|
+
// What this does:
|
|
17
|
+
// Given the raw SQL drizzle-kit produced and a `DriftReport` from
|
|
18
|
+
// `inspectFrameworkDrift`, we rewrite the SQL so that:
|
|
19
|
+
// • CREATE TABLE statements for framework tables that already exist are
|
|
20
|
+
// replaced with one ALTER TABLE … ADD COLUMN per `missing_in_db`
|
|
21
|
+
// column reported by the drift inspector. Column type/null/default
|
|
22
|
+
// text is parsed verbatim out of the original CREATE TABLE body so we
|
|
23
|
+
// inherit drizzle-kit's exact serialization.
|
|
24
|
+
// • CREATE TABLE statements for framework tables whose columns already
|
|
25
|
+
// fully match the schema are dropped entirely.
|
|
26
|
+
// • CREATE INDEX / CREATE UNIQUE INDEX statements are wrapped with
|
|
27
|
+
// IF NOT EXISTS so re-running on a partially migrated DB doesn't trip
|
|
28
|
+
// on indexes that already exist (Postgres ≥ 9.5).
|
|
29
|
+
// • Everything else (entity tables, ALTERs to entity tables, constraints,
|
|
30
|
+
// etc.) passes through unchanged.
|
|
31
|
+
//
|
|
32
|
+
// Limitations (future work):
|
|
33
|
+
// • IF NOT EXISTS only suppresses the duplicate-name error on relations
|
|
34
|
+
// and indexes; it does NOT verify that the existing definition actually
|
|
35
|
+
// matches what the migration intends. Safe full reconciliation requires
|
|
36
|
+
// comparing columns, defaults, constraints, and indexes — see
|
|
37
|
+
// `inspectFrameworkDrift` for a starting point. We currently only act
|
|
38
|
+
// on `missing_in_db` columns; `type_mismatch`, `nullability_mismatch`,
|
|
39
|
+
// and `extra_in_db` are surfaced in the summary but not auto-rewritten,
|
|
40
|
+
// because resolving them safely usually needs human judgment.
|
|
41
|
+
// • CONSTRAINT clauses inside a rewrite-target CREATE TABLE (e.g. table-
|
|
42
|
+
// level UNIQUE / CHECK) are dropped with a warning — Postgres has no
|
|
43
|
+
// ADD CONSTRAINT IF NOT EXISTS, so we can't safely re-add idempotently.
|
|
44
|
+
import { FRAMEWORK_TABLE_NAMES, } from './drift-inspector.js';
|
|
45
|
+
const STATEMENT_BREAKPOINT = '--> statement-breakpoint';
|
|
46
|
+
const FRAMEWORK_TABLE_SET = new Set(FRAMEWORK_TABLE_NAMES);
|
|
47
|
+
/**
|
|
48
|
+
* Rewrite drizzle-kit migration statements to be safe against framework-table
|
|
49
|
+
* drift.
|
|
50
|
+
*
|
|
51
|
+
* Operates on the raw `string[]` that `drizzle-kit/api.generateMigration`
|
|
52
|
+
* returns — one element per SQL statement. Returns a new array of statements
|
|
53
|
+
* (some may be removed, some may expand into multiple ALTER TABLE …
|
|
54
|
+
* statements) along with a structured summary for logging.
|
|
55
|
+
*
|
|
56
|
+
* Pure function — no IO, no DB access.
|
|
57
|
+
*
|
|
58
|
+
* If the report contains no `existingFrameworkTables`, the input is returned
|
|
59
|
+
* unchanged apart from index IF NOT EXISTS wrapping, which is always safe.
|
|
60
|
+
*/
|
|
61
|
+
export function rewriteFrameworkDriftMigration(inputStatements, driftReport, _schemas) {
|
|
62
|
+
const summary = {
|
|
63
|
+
alteredTables: [],
|
|
64
|
+
droppedCreateTables: [],
|
|
65
|
+
wrappedIndexes: [],
|
|
66
|
+
idempotentAddColumns: [],
|
|
67
|
+
warnings: [],
|
|
68
|
+
};
|
|
69
|
+
const driftByTable = new Map();
|
|
70
|
+
for (const table of driftReport.tables) {
|
|
71
|
+
driftByTable.set(table.tableName, table);
|
|
72
|
+
}
|
|
73
|
+
const existingFrameworkSet = new Set(driftReport.existingFrameworkTables);
|
|
74
|
+
const out = [];
|
|
75
|
+
for (const stmt of inputStatements) {
|
|
76
|
+
const trimmed = stmt.trim();
|
|
77
|
+
if (!trimmed)
|
|
78
|
+
continue;
|
|
79
|
+
const createTableName = matchCreateTableName(trimmed);
|
|
80
|
+
if (createTableName && existingFrameworkSet.has(createTableName)) {
|
|
81
|
+
const tableDrift = driftByTable.get(createTableName);
|
|
82
|
+
const missing = tableDrift?.columnDrifts.filter((d) => d.kind === 'missing_in_db') ?? [];
|
|
83
|
+
if (missing.length === 0) {
|
|
84
|
+
// Table already fully matches — drop the CREATE TABLE.
|
|
85
|
+
summary.droppedCreateTables.push(createTableName);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const parsed = parseCreateTableBody(trimmed);
|
|
89
|
+
if (!parsed) {
|
|
90
|
+
// Couldn't parse safely — leave as-is and warn. Apply preflight will
|
|
91
|
+
// still catch the conflict; better to fail loudly than to lose data.
|
|
92
|
+
summary.warnings.push(`Could not parse CREATE TABLE for "${createTableName}"; passing through unchanged.`);
|
|
93
|
+
out.push(stmt);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const columnLineByName = new Map(parsed.columnLines.map((c) => [c.name, c.line]));
|
|
97
|
+
const altered = [];
|
|
98
|
+
const alterStatements = [];
|
|
99
|
+
for (const col of missing) {
|
|
100
|
+
const line = columnLineByName.get(col.column);
|
|
101
|
+
if (!line) {
|
|
102
|
+
// Drift inspector reported a missing column but drizzle-kit didn't
|
|
103
|
+
// include a definition for it — schema desync. Warn and skip.
|
|
104
|
+
summary.warnings.push(`Drift reported missing column "${createTableName}.${col.column}" but the generated CREATE TABLE has no matching definition.`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
alterStatements.push(`ALTER TABLE "${createTableName}" ADD COLUMN ${line};`);
|
|
108
|
+
altered.push(col.column);
|
|
109
|
+
}
|
|
110
|
+
if (parsed.constraintLines.length > 0) {
|
|
111
|
+
summary.warnings.push(`Dropped ${parsed.constraintLines.length} table-level constraint clause(s) from CREATE TABLE for "${createTableName}" because Postgres does not support ADD CONSTRAINT IF NOT EXISTS. If a new framework constraint is required, add it manually.`);
|
|
112
|
+
}
|
|
113
|
+
if (alterStatements.length === 0) {
|
|
114
|
+
summary.droppedCreateTables.push(createTableName);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
summary.alteredTables.push({
|
|
118
|
+
table: createTableName,
|
|
119
|
+
addedColumns: altered,
|
|
120
|
+
});
|
|
121
|
+
// Push each ALTER as its own array element so the caller can join with
|
|
122
|
+
// any separator (including a literal newline, which is what drizzle-kit
|
|
123
|
+
// already does for migration files).
|
|
124
|
+
for (const a of alterStatements)
|
|
125
|
+
out.push(a);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const indexWrapped = wrapCreateIndexIfNotExists(trimmed);
|
|
129
|
+
if (indexWrapped !== trimmed) {
|
|
130
|
+
summary.wrappedIndexes.push(extractIndexName(trimmed) ?? '<anonymous>');
|
|
131
|
+
out.push(indexWrapped);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const addColWrapped = wrapAlterAddColumnIfNotExists(trimmed);
|
|
135
|
+
if (addColWrapped !== trimmed) {
|
|
136
|
+
summary.idempotentAddColumns.push(extractAddColumnTarget(trimmed) ?? '<unknown>');
|
|
137
|
+
out.push(addColWrapped);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
out.push(stmt);
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
statements: out,
|
|
144
|
+
summary,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
// ── Internals ──
|
|
148
|
+
/**
|
|
149
|
+
* Re-exported for callers that want to render rewritten statements with the
|
|
150
|
+
* same separator drizzle-kit uses internally for breakpoint-aware tooling.
|
|
151
|
+
*/
|
|
152
|
+
export const STATEMENT_BREAKPOINT_MARKER = STATEMENT_BREAKPOINT;
|
|
153
|
+
const CREATE_TABLE_HEAD_RE = /^\s*CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"|([a-zA-Z_]\w*))/i;
|
|
154
|
+
function matchCreateTableName(stmt) {
|
|
155
|
+
const m = stmt.match(CREATE_TABLE_HEAD_RE);
|
|
156
|
+
if (!m)
|
|
157
|
+
return null;
|
|
158
|
+
return m[1] ?? m[2] ?? null;
|
|
159
|
+
}
|
|
160
|
+
const TABLE_LEVEL_CONSTRAINT_KEYWORDS = [
|
|
161
|
+
'CONSTRAINT',
|
|
162
|
+
'PRIMARY KEY',
|
|
163
|
+
'UNIQUE',
|
|
164
|
+
'CHECK',
|
|
165
|
+
'FOREIGN KEY',
|
|
166
|
+
'EXCLUDE',
|
|
167
|
+
];
|
|
168
|
+
/**
|
|
169
|
+
* Parse the parenthesized body of a CREATE TABLE statement into individual
|
|
170
|
+
* column definition lines. Drizzle-kit emits one column per line, separated
|
|
171
|
+
* by commas, with the column name as a quoted identifier at the start.
|
|
172
|
+
*
|
|
173
|
+
* Returns null if the body cannot be located (e.g. no opening paren).
|
|
174
|
+
*/
|
|
175
|
+
function parseCreateTableBody(stmt) {
|
|
176
|
+
const openIdx = stmt.indexOf('(');
|
|
177
|
+
if (openIdx < 0)
|
|
178
|
+
return null;
|
|
179
|
+
// Find the matching closing paren. Drizzle-kit-generated bodies don't
|
|
180
|
+
// contain nested parens for our purposes (no inline CHECK constraints etc.
|
|
181
|
+
// — those would surface as constraintLines). We still scan with depth so we
|
|
182
|
+
// don't get fooled by anything embedded.
|
|
183
|
+
let depth = 0;
|
|
184
|
+
let closeIdx = -1;
|
|
185
|
+
let inSingleQuote = false;
|
|
186
|
+
for (let i = openIdx; i < stmt.length; i++) {
|
|
187
|
+
const ch = stmt[i];
|
|
188
|
+
if (ch === "'" && stmt[i - 1] !== '\\')
|
|
189
|
+
inSingleQuote = !inSingleQuote;
|
|
190
|
+
if (inSingleQuote)
|
|
191
|
+
continue;
|
|
192
|
+
if (ch === '(')
|
|
193
|
+
depth++;
|
|
194
|
+
else if (ch === ')') {
|
|
195
|
+
depth--;
|
|
196
|
+
if (depth === 0) {
|
|
197
|
+
closeIdx = i;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (closeIdx < 0)
|
|
203
|
+
return null;
|
|
204
|
+
const body = stmt.slice(openIdx + 1, closeIdx);
|
|
205
|
+
// Split by top-level commas (no nesting expected in column defs, but be
|
|
206
|
+
// defensive about quoted strings and parens just in case).
|
|
207
|
+
const segments = splitTopLevelCommas(body);
|
|
208
|
+
const columnLines = [];
|
|
209
|
+
const constraintLines = [];
|
|
210
|
+
for (const raw of segments) {
|
|
211
|
+
const line = raw.trim();
|
|
212
|
+
if (!line)
|
|
213
|
+
continue;
|
|
214
|
+
if (isConstraintLine(line)) {
|
|
215
|
+
constraintLines.push(line);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const nameMatch = line.match(/^"([^"]+)"\s+(.+)$/) ?? line.match(/^([a-zA-Z_]\w*)\s+(.+)$/);
|
|
219
|
+
if (!nameMatch) {
|
|
220
|
+
// Unrecognized — treat as constraint to be safe (will trigger warning).
|
|
221
|
+
constraintLines.push(line);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
const colName = nameMatch[1];
|
|
225
|
+
columnLines.push({ name: colName, line });
|
|
226
|
+
}
|
|
227
|
+
return { columnLines, constraintLines };
|
|
228
|
+
}
|
|
229
|
+
function splitTopLevelCommas(body) {
|
|
230
|
+
const parts = [];
|
|
231
|
+
let depth = 0;
|
|
232
|
+
let inSingleQuote = false;
|
|
233
|
+
let start = 0;
|
|
234
|
+
for (let i = 0; i < body.length; i++) {
|
|
235
|
+
const ch = body[i];
|
|
236
|
+
if (ch === "'" && body[i - 1] !== '\\')
|
|
237
|
+
inSingleQuote = !inSingleQuote;
|
|
238
|
+
if (inSingleQuote)
|
|
239
|
+
continue;
|
|
240
|
+
if (ch === '(')
|
|
241
|
+
depth++;
|
|
242
|
+
else if (ch === ')')
|
|
243
|
+
depth--;
|
|
244
|
+
else if (ch === ',' && depth === 0) {
|
|
245
|
+
parts.push(body.slice(start, i));
|
|
246
|
+
start = i + 1;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
parts.push(body.slice(start));
|
|
250
|
+
return parts;
|
|
251
|
+
}
|
|
252
|
+
function isConstraintLine(line) {
|
|
253
|
+
const upper = line.toUpperCase();
|
|
254
|
+
return TABLE_LEVEL_CONSTRAINT_KEYWORDS.some((kw) => upper.startsWith(kw));
|
|
255
|
+
}
|
|
256
|
+
const CREATE_INDEX_RE = /^(\s*)CREATE\s+(UNIQUE\s+)?INDEX(?!\s+IF\s+NOT\s+EXISTS\b)\s+/i;
|
|
257
|
+
function wrapCreateIndexIfNotExists(stmt) {
|
|
258
|
+
return stmt.replace(CREATE_INDEX_RE, (_match, leading, unique) => {
|
|
259
|
+
const u = unique ? unique : '';
|
|
260
|
+
return `${leading}CREATE ${u}INDEX IF NOT EXISTS `;
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
const INDEX_NAME_RE = /CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?"?([^"\s]+)"?/i;
|
|
264
|
+
function extractIndexName(stmt) {
|
|
265
|
+
const m = stmt.match(INDEX_NAME_RE);
|
|
266
|
+
return m?.[1] ?? null;
|
|
267
|
+
}
|
|
268
|
+
// Match `ALTER TABLE [IF EXISTS] <tbl> ADD COLUMN [IF NOT EXISTS]`. We only
|
|
269
|
+
// want to rewrite when IF NOT EXISTS is *not* already present. Multiple
|
|
270
|
+
// ADD COLUMN clauses can appear in one ALTER TABLE statement separated by
|
|
271
|
+
// commas; we wrap every one of them.
|
|
272
|
+
const ALTER_ADD_COLUMN_RE = /\bADD\s+COLUMN(?!\s+IF\s+NOT\s+EXISTS\b)\s+/gi;
|
|
273
|
+
function isAlterTableStatement(stmt) {
|
|
274
|
+
return /^\s*ALTER\s+TABLE\b/i.test(stmt);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Rewrite `ALTER TABLE … ADD COLUMN <name> …` to `ADD COLUMN IF NOT EXISTS
|
|
278
|
+
* <name> …`. We do not touch `ADD CONSTRAINT`, `ALTER COLUMN`, etc.
|
|
279
|
+
*
|
|
280
|
+
* Why universal idempotency:
|
|
281
|
+
* Drizzle-kit's diff-based generation depends on the snapshot in
|
|
282
|
+
* drizzle/meta accurately reflecting the live schema. Real projects
|
|
283
|
+
* accumulate snapshot drift (manually edited migrations, partial applies,
|
|
284
|
+
* prod hotfixes). Making framework-emitted ADD COLUMN idempotent removes a
|
|
285
|
+
* whole class of "column already exists" apply failures without changing
|
|
286
|
+
* semantics: a real type/default mismatch will still surface elsewhere
|
|
287
|
+
* (e.g. queries failing at runtime), and the apply path remains a no-op
|
|
288
|
+
* when the column is already there.
|
|
289
|
+
*
|
|
290
|
+
* Limitation (future work, mirrors the index case):
|
|
291
|
+
* Postgres' `IF NOT EXISTS` only suppresses the duplicate-name error; it
|
|
292
|
+
* does NOT verify that the existing column matches the requested type,
|
|
293
|
+
* nullability, or default. Comprehensive reconciliation requires
|
|
294
|
+
* `inspectFrameworkDrift`-style comparison across every column for every
|
|
295
|
+
* user-managed entity, not just the framework-managed tables.
|
|
296
|
+
*/
|
|
297
|
+
function wrapAlterAddColumnIfNotExists(stmt) {
|
|
298
|
+
if (!isAlterTableStatement(stmt))
|
|
299
|
+
return stmt;
|
|
300
|
+
return stmt.replace(ALTER_ADD_COLUMN_RE, 'ADD COLUMN IF NOT EXISTS ');
|
|
301
|
+
}
|
|
302
|
+
const ALTER_TABLE_TARGET_RE = /^\s*ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?(?:"([^"]+)"|([a-zA-Z_]\w*))/i;
|
|
303
|
+
const ADD_COLUMN_NAME_RE = /\bADD\s+COLUMN(?:\s+IF\s+NOT\s+EXISTS)?\s+(?:"([^"]+)"|([a-zA-Z_]\w*))/gi;
|
|
304
|
+
function extractAddColumnTarget(stmt) {
|
|
305
|
+
const tableMatch = stmt.match(ALTER_TABLE_TARGET_RE);
|
|
306
|
+
const table = tableMatch?.[1] ?? tableMatch?.[2] ?? null;
|
|
307
|
+
if (!table)
|
|
308
|
+
return null;
|
|
309
|
+
const columns = [];
|
|
310
|
+
for (const m of stmt.matchAll(ADD_COLUMN_NAME_RE)) {
|
|
311
|
+
columns.push(m[1] ?? m[2]);
|
|
312
|
+
}
|
|
313
|
+
if (columns.length === 0)
|
|
314
|
+
return `"${table}"`;
|
|
315
|
+
return `"${table}".${columns.map((c) => `"${c}"`).join(',')}`;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Convenience: format the rewriter summary for human-readable CLI output.
|
|
319
|
+
* Returns an array of lines (no trailing newlines), or an empty array if no
|
|
320
|
+
* meaningful rewriting happened.
|
|
321
|
+
*/
|
|
322
|
+
export function formatRewriteSummary(summary) {
|
|
323
|
+
const lines = [];
|
|
324
|
+
if (summary.alteredTables.length > 0) {
|
|
325
|
+
lines.push('Framework drift rewrite: emitted ALTER TABLE ADD COLUMN for:');
|
|
326
|
+
for (const t of summary.alteredTables) {
|
|
327
|
+
lines.push(` ${t.table}: ${t.addedColumns.join(', ')}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (summary.droppedCreateTables.length > 0) {
|
|
331
|
+
lines.push(`Framework drift rewrite: dropped redundant CREATE TABLE for: ${summary.droppedCreateTables.join(', ')}`);
|
|
332
|
+
}
|
|
333
|
+
if (summary.wrappedIndexes.length > 0) {
|
|
334
|
+
lines.push(`Framework drift rewrite: wrapped ${summary.wrappedIndexes.length} CREATE INDEX statement(s) with IF NOT EXISTS.`);
|
|
335
|
+
}
|
|
336
|
+
if (summary.idempotentAddColumns.length > 0) {
|
|
337
|
+
lines.push(`Framework drift rewrite: made ${summary.idempotentAddColumns.length} ALTER TABLE ADD COLUMN statement(s) idempotent.`);
|
|
338
|
+
}
|
|
339
|
+
for (const w of summary.warnings) {
|
|
340
|
+
lines.push(` warning: ${w}`);
|
|
341
|
+
}
|
|
342
|
+
return lines;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* True if the rewriter actually changed anything beyond cosmetic whitespace.
|
|
346
|
+
* Useful for skipping noisy logs when the migration was clean already.
|
|
347
|
+
*/
|
|
348
|
+
export function rewriteHadEffect(summary) {
|
|
349
|
+
return (summary.alteredTables.length > 0 ||
|
|
350
|
+
summary.droppedCreateTables.length > 0 ||
|
|
351
|
+
summary.wrappedIndexes.length > 0 ||
|
|
352
|
+
summary.idempotentAddColumns.length > 0 ||
|
|
353
|
+
summary.warnings.length > 0);
|
|
354
|
+
}
|
|
355
|
+
// Re-export so callers can keep a single import surface.
|
|
356
|
+
export { FRAMEWORK_TABLE_SET };
|
|
357
|
+
//# sourceMappingURL=framework-migration-rewriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework-migration-rewriter.js","sourceRoot":"","sources":["../../src/data/framework-migration-rewriter.ts"],"names":[],"mappings":"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"}
|
package/dist/data/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { gte, ilike, like, lte, sql } from 'drizzle-orm';
|
|
2
|
-
export { applyMigrations, collectSchemas, rollbackLastMigration, type MigrationConfig, type MigrationRecord, } from './migration.js';
|
|
2
|
+
export { applyMigrations, collectSchemas, readPendingMigrations, rollbackLastMigration, type MigrationApplyResult, type MigrationConfig, type MigrationRecord, type PendingMigration, } from './migration.js';
|
|
3
|
+
export { extractCreateTableNames, formatDriftReport, FRAMEWORK_TABLE_NAMES, getExistingFrameworkTables, inspectFrameworkDrift, type ColumnDrift, type DriftReport, type FrameworkTableName, type TableDrift, } from './drift-inspector.js';
|
|
3
4
|
export { EntityRegistry } from './registry.js';
|
|
4
5
|
export { createRepository, type RepositoryOptions } from './repository.js';
|
|
5
6
|
export { generateDrizzleSchema, generateSchemas } from './schema-generator.js';
|
package/dist/data/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,UAAU,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/data/index.js
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// Key exports: createRepository, EntityRegistry, generateDrizzleSchema, applyMigrations
|
|
6
6
|
// Re-export Drizzle operators for use in query conditions
|
|
7
7
|
export { gte, ilike, like, lte, sql } from 'drizzle-orm';
|
|
8
|
-
export { applyMigrations, collectSchemas, rollbackLastMigration, } from './migration.js';
|
|
8
|
+
export { applyMigrations, collectSchemas, readPendingMigrations, rollbackLastMigration, } from './migration.js';
|
|
9
|
+
export { extractCreateTableNames, formatDriftReport, FRAMEWORK_TABLE_NAMES, getExistingFrameworkTables, inspectFrameworkDrift, } from './drift-inspector.js';
|
|
9
10
|
export { EntityRegistry } from './registry.js';
|
|
10
11
|
export { createRepository } from './repository.js';
|
|
11
12
|
export { generateDrizzleSchema, generateSchemas } from './schema-generator.js';
|
package/dist/data/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,+EAA+E;AAC/E,oEAAoE;AACpE,EAAE;AACF,wFAAwF;AAExF,0DAA0D;AAC1D,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,eAAe,EACf,cAAc,EACd,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,+EAA+E;AAC/E,oEAAoE;AACpE,EAAE;AACF,wFAAwF;AAExF,0DAA0D;AAC1D,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,qBAAqB,GAKtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,GAKtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAA0B,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/data/migration.d.ts
CHANGED
|
@@ -5,10 +5,40 @@ export interface MigrationConfig {
|
|
|
5
5
|
db: PostgresJsDatabase;
|
|
6
6
|
migrationsFolder: string;
|
|
7
7
|
}
|
|
8
|
+
export interface PendingMigration {
|
|
9
|
+
tag: string;
|
|
10
|
+
hash: string;
|
|
11
|
+
statements: string[];
|
|
12
|
+
rawSql: string;
|
|
13
|
+
folderMillis: number;
|
|
14
|
+
}
|
|
15
|
+
export interface MigrationApplyResult {
|
|
16
|
+
applied: number;
|
|
17
|
+
tags: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface MigrationReconcileResult {
|
|
20
|
+
adopted: number;
|
|
21
|
+
alreadyApplied: number;
|
|
22
|
+
adoptedTags: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Read the migration journal and determine which migrations are pending
|
|
26
|
+
* (not yet applied to the database).
|
|
27
|
+
*/
|
|
28
|
+
export declare function readPendingMigrations(config: MigrationConfig): Promise<PendingMigration[]>;
|
|
8
29
|
/**
|
|
9
30
|
* Apply pending migrations from the migrations folder.
|
|
31
|
+
*
|
|
32
|
+
* Each migration runs inside a transaction. On failure, the error includes
|
|
33
|
+
* the migration tag, statement index, and a SQL preview for diagnostics.
|
|
34
|
+
*/
|
|
35
|
+
export declare function applyMigrations(config: MigrationConfig): Promise<MigrationApplyResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Reconcile migration history by marking journal migrations as applied
|
|
38
|
+
* without executing schema changes. Intended for adoption/recovery when
|
|
39
|
+
* the live database already matches the current Plumbus schema.
|
|
10
40
|
*/
|
|
11
|
-
export declare function
|
|
41
|
+
export declare function reconcileMigrationHistory(config: MigrationConfig): Promise<MigrationReconcileResult>;
|
|
12
42
|
/**
|
|
13
43
|
* Collect all Drizzle table schemas from entity definitions,
|
|
14
44
|
* plus framework-internal tables (e.g. audit_records).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/data/migration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/data/migration.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAKlE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,kBAAkB,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAYD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AA4DD;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAShG;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+B5F;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,wBAAwB,CAAC,CA+BnC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAmBzC;AAID,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;IAC5E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,aAAa,GAAG,eAAe,CAAC;CACzC,CAAC,CA2BD"}
|
package/dist/data/migration.js
CHANGED
|
@@ -1,16 +1,126 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { sql } from 'drizzle-orm';
|
|
2
5
|
import { documentChunksTable, documentsTable } from '../ai/rag/schema.js';
|
|
3
6
|
import { auditRecords } from '../audit/schema.js';
|
|
4
7
|
import { deadLetterTable, idempotencyTable, outboxTable } from '../events/outbox.js';
|
|
5
8
|
import { flowDeadLetterTable, flowExecutionsTable, flowSchedulesTable } from '../flows/schema.js';
|
|
6
9
|
import { generateDrizzleSchema } from './schema-generator.js';
|
|
10
|
+
function readMigrationJournalEntries(migrationsFolder) {
|
|
11
|
+
const journalPath = path.join(migrationsFolder, 'meta', '_journal.json');
|
|
12
|
+
if (!fs.existsSync(journalPath)) {
|
|
13
|
+
throw new Error(`Can't find meta/_journal.json in ${migrationsFolder}`);
|
|
14
|
+
}
|
|
15
|
+
const journal = JSON.parse(fs.readFileSync(journalPath, 'utf-8'));
|
|
16
|
+
return journal.entries;
|
|
17
|
+
}
|
|
18
|
+
function readJournalMigrations(migrationsFolder) {
|
|
19
|
+
const journalEntries = readMigrationJournalEntries(migrationsFolder);
|
|
20
|
+
return journalEntries.map((entry) => {
|
|
21
|
+
const sqlPath = path.join(migrationsFolder, `${entry.tag}.sql`);
|
|
22
|
+
if (!fs.existsSync(sqlPath)) {
|
|
23
|
+
throw new Error(`Missing migration file: ${sqlPath}`);
|
|
24
|
+
}
|
|
25
|
+
const rawSql = fs.readFileSync(sqlPath, 'utf-8');
|
|
26
|
+
const hash = crypto.createHash('sha256').update(rawSql).digest('hex');
|
|
27
|
+
const statements = entry.breakpoints
|
|
28
|
+
? rawSql
|
|
29
|
+
.split('--> statement-breakpoint')
|
|
30
|
+
.map((statement) => statement.trim())
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
: [rawSql];
|
|
33
|
+
return {
|
|
34
|
+
tag: entry.tag,
|
|
35
|
+
hash,
|
|
36
|
+
statements,
|
|
37
|
+
rawSql,
|
|
38
|
+
folderMillis: entry.when,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async function ensureMigrationsTable(db) {
|
|
43
|
+
await db.execute(sql `CREATE TABLE IF NOT EXISTS "__drizzle_migrations" (
|
|
44
|
+
id SERIAL PRIMARY KEY,
|
|
45
|
+
hash TEXT NOT NULL,
|
|
46
|
+
created_at BIGINT
|
|
47
|
+
)`);
|
|
48
|
+
}
|
|
49
|
+
async function getAppliedMigrationHashes(db) {
|
|
50
|
+
const appliedRows = (await db.execute(sql `SELECT hash FROM "__drizzle_migrations"`));
|
|
51
|
+
return new Set(appliedRows.map((row) => row.hash));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Read the migration journal and determine which migrations are pending
|
|
55
|
+
* (not yet applied to the database).
|
|
56
|
+
*/
|
|
57
|
+
export async function readPendingMigrations(config) {
|
|
58
|
+
const { db, migrationsFolder } = config;
|
|
59
|
+
await ensureMigrationsTable(db);
|
|
60
|
+
const appliedHashes = await getAppliedMigrationHashes(db);
|
|
61
|
+
const journalMigrations = readJournalMigrations(migrationsFolder);
|
|
62
|
+
return journalMigrations.filter((migration) => !appliedHashes.has(migration.hash));
|
|
63
|
+
}
|
|
7
64
|
/**
|
|
8
65
|
* Apply pending migrations from the migrations folder.
|
|
66
|
+
*
|
|
67
|
+
* Each migration runs inside a transaction. On failure, the error includes
|
|
68
|
+
* the migration tag, statement index, and a SQL preview for diagnostics.
|
|
9
69
|
*/
|
|
10
70
|
export async function applyMigrations(config) {
|
|
11
|
-
await
|
|
12
|
-
|
|
71
|
+
const pending = await readPendingMigrations(config);
|
|
72
|
+
if (pending.length === 0) {
|
|
73
|
+
return { applied: 0, tags: [] };
|
|
74
|
+
}
|
|
75
|
+
const appliedTags = [];
|
|
76
|
+
for (const migration of pending) {
|
|
77
|
+
await config.db.transaction(async (tx) => {
|
|
78
|
+
for (let i = 0; i < migration.statements.length; i++) {
|
|
79
|
+
const stmt = migration.statements[i] ?? '';
|
|
80
|
+
try {
|
|
81
|
+
await tx.execute(sql.raw(stmt));
|
|
82
|
+
}
|
|
83
|
+
catch (stmtErr) {
|
|
84
|
+
const preview = stmt.length > 200 ? `${stmt.slice(0, 200)}...` : stmt;
|
|
85
|
+
throw new Error(`Migration "${migration.tag}" failed at statement ${i + 1}/${migration.statements.length}:\n` +
|
|
86
|
+
` SQL: ${preview}\n` +
|
|
87
|
+
` Error: ${stmtErr instanceof Error ? stmtErr.message : String(stmtErr)}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
await tx.execute(sql `INSERT INTO "__drizzle_migrations" (hash, created_at) VALUES (${migration.hash}, ${migration.folderMillis})`);
|
|
91
|
+
});
|
|
92
|
+
appliedTags.push(migration.tag);
|
|
93
|
+
}
|
|
94
|
+
return { applied: appliedTags.length, tags: appliedTags };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Reconcile migration history by marking journal migrations as applied
|
|
98
|
+
* without executing schema changes. Intended for adoption/recovery when
|
|
99
|
+
* the live database already matches the current Plumbus schema.
|
|
100
|
+
*/
|
|
101
|
+
export async function reconcileMigrationHistory(config) {
|
|
102
|
+
const journalMigrations = readJournalMigrations(config.migrationsFolder);
|
|
103
|
+
await ensureMigrationsTable(config.db);
|
|
104
|
+
const appliedHashes = await getAppliedMigrationHashes(config.db);
|
|
105
|
+
const missingMigrations = journalMigrations.filter((migration) => !appliedHashes.has(migration.hash));
|
|
106
|
+
if (missingMigrations.length === 0) {
|
|
107
|
+
return {
|
|
108
|
+
adopted: 0,
|
|
109
|
+
alreadyApplied: journalMigrations.length,
|
|
110
|
+
adoptedTags: [],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
await config.db.transaction(async (tx) => {
|
|
114
|
+
for (const migration of missingMigrations) {
|
|
115
|
+
await tx.execute(sql `INSERT INTO "__drizzle_migrations" (hash, created_at)
|
|
116
|
+
VALUES (${migration.hash}, ${migration.folderMillis})`);
|
|
117
|
+
}
|
|
13
118
|
});
|
|
119
|
+
return {
|
|
120
|
+
adopted: missingMigrations.length,
|
|
121
|
+
alreadyApplied: journalMigrations.length - missingMigrations.length,
|
|
122
|
+
adoptedTags: missingMigrations.map((migration) => migration.tag),
|
|
123
|
+
};
|
|
14
124
|
}
|
|
15
125
|
/**
|
|
16
126
|
* Collect all Drizzle table schemas from entity definitions,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration.js","sourceRoot":"","sources":["../../src/data/migration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration.js","sourceRoot":"","sources":["../../src/data/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGlC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAElG,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAoC9D,SAAS,2BAA2B,CAAC,gBAAwB;IAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IACzE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,oCAAoC,gBAAgB,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAE/D,CAAC;IAEF,OAAO,OAAO,CAAC,OAAO,CAAC;AACzB,CAAC;AAED,SAAS,qBAAqB,CAAC,gBAAwB;IACrD,MAAM,cAAc,GAAG,2BAA2B,CAAC,gBAAgB,CAAC,CAAC;IAErE,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC;QAChE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW;YAClC,CAAC,CAAC,MAAM;iBACH,KAAK,CAAC,0BAA0B,CAAC;iBACjC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;iBACpC,MAAM,CAAC,OAAO,CAAC;YACpB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAEb,OAAO;YACL,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI;YACJ,UAAU;YACV,MAAM;YACN,YAAY,EAAE,KAAK,CAAC,IAAI;SACzB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,EAAsB;IACzD,MAAM,EAAE,CAAC,OAAO,CACd,GAAG,CAAA;;;;MAID,CACH,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,yBAAyB,CAAC,EAAsB;IAC7D,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,CACnC,GAAG,CAAA,yCAAyC,CAC7C,CAAuC,CAAC;IAEzC,OAAO,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAuB;IACjE,MAAM,EAAE,EAAE,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAAC;IAExC,MAAM,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAEhC,MAAM,aAAa,GAAG,MAAM,yBAAyB,CAAC,EAAE,CAAC,CAAC;IAC1D,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;IAElE,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAuB;IAC3D,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAEpD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,CAAC;QAChC,MAAM,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrD,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC3C,IAAI,CAAC;oBACH,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;gBAClC,CAAC;gBAAC,OAAO,OAAO,EAAE,CAAC;oBACjB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;oBACtE,MAAM,IAAI,KAAK,CACb,cAAc,SAAS,CAAC,GAAG,yBAAyB,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,KAAK;wBAC3F,UAAU,OAAO,IAAI;wBACrB,YAAY,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAC7E,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,MAAM,EAAE,CAAC,OAAO,CACd,GAAG,CAAA,iEAAiE,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,YAAY,GAAG,CACjH,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAuB;IAEvB,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAEzE,MAAM,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,MAAM,yBAAyB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjE,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,MAAM,CAChD,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAClD,CAAC;IAEF,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO;YACL,OAAO,EAAE,CAAC;YACV,cAAc,EAAE,iBAAiB,CAAC,MAAM;YACxC,WAAW,EAAE,EAAE;SAChB,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACvC,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;YAC1C,MAAM,EAAE,CAAC,OAAO,CACd,GAAG,CAAA;sBACW,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,YAAY,GAAG,CAC3D,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,iBAAiB,CAAC,MAAM;QACjC,cAAc,EAAE,iBAAiB,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM;QACnE,WAAW,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC;KACjE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,QAA4B;IAE5B,MAAM,OAAO,GAA4C,EAAE,CAAC;IAC5D,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACvD,CAAC;IACD,4BAA4B;IAC5B,OAAO,CAAC,eAAe,GAAG,YAAkD,CAAC;IAC7E,sBAAsB;IACtB,OAAO,CAAC,cAAc,GAAG,WAAiD,CAAC;IAC3E,OAAO,CAAC,mBAAmB,GAAG,gBAAsD,CAAC;IACrF,OAAO,CAAC,mBAAmB,GAAG,eAAqD,CAAC;IACpF,cAAc;IACd,OAAO,CAAC,iBAAiB,GAAG,mBAAyD,CAAC;IACtF,OAAO,CAAC,kBAAkB,GAAG,mBAAyD,CAAC;IACvF,OAAO,CAAC,gBAAgB,GAAG,kBAAwD,CAAC;IACpF,aAAa;IACb,OAAO,CAAC,WAAW,GAAG,cAAoD,CAAC;IAC3E,OAAO,CAAC,iBAAiB,GAAG,mBAAyD,CAAC;IACtF,OAAO,OAAO,CAAC;AACjB,CAAC;AAWD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAuB;IAIjE,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;IAErB,sEAAsE;IACtE,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC;QAC7B,GAAG,EAAE,oFAAoF;QACzF,MAAM,EAAE,EAAE;KACJ,CAAC,CAA2D,CAAC;IAErE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QACxD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,aAAa,GAAG,aAAa,CAAC,IAAI,CAAC;IAEzC,sDAAsD;IACtD,MAAM,EAAE,CAAC,OAAO,CAAC;QACf,GAAG,EAAE,kDAAkD;QACvD,MAAM,EAAE,CAAC,aAAa,CAAC;KACjB,CAAC,CAAC;IAEV,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AAC9D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/data/repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC/B,EAAE,EAAE,kBAAkB,CAAC;IACvB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7D,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7D,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/data/repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC/B,EAAE,EAAE,kBAAkB,CAAC;IACvB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7D,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7D,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAyP7D"}
|
package/dist/data/repository.js
CHANGED
|
@@ -76,6 +76,27 @@ export function createRepository(options) {
|
|
|
76
76
|
await auditMutation('create', record);
|
|
77
77
|
return created;
|
|
78
78
|
},
|
|
79
|
+
async createMany(records) {
|
|
80
|
+
if (records.length === 0)
|
|
81
|
+
return [];
|
|
82
|
+
const prepared = records.map((data) => {
|
|
83
|
+
const record = { ...data };
|
|
84
|
+
if (isTenantScoped && !bypassTenantScope) {
|
|
85
|
+
if (!auth.tenantId) {
|
|
86
|
+
throw new Error(`Tenant-scoped entity "${entity.name}" requires auth.tenantId`);
|
|
87
|
+
}
|
|
88
|
+
record.tenantId = auth.tenantId;
|
|
89
|
+
}
|
|
90
|
+
return record;
|
|
91
|
+
});
|
|
92
|
+
const rows = await db.insert(table).values(prepared).returning();
|
|
93
|
+
// One summary audit row per batch instead of N per-row audits.
|
|
94
|
+
await auditMutation('createMany', {
|
|
95
|
+
count: prepared.length,
|
|
96
|
+
sample: maskData(prepared[0] ?? {}),
|
|
97
|
+
});
|
|
98
|
+
return rows;
|
|
99
|
+
},
|
|
79
100
|
async update(id, updates) {
|
|
80
101
|
const conditions = [];
|
|
81
102
|
const idCol = table.id;
|