okmodel 0.2.1 → 0.4.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/README.md +882 -48
- package/dist/contracts/catalog/document.d.ts +6 -2
- package/dist/contracts/catalog/enum.d.ts +31 -4
- package/dist/contracts/catalog/extension.d.ts +61 -0
- package/dist/contracts/catalog/privilege.d.ts +64 -0
- package/dist/contracts/catalog/routine.d.ts +56 -0
- package/dist/contracts/catalog/types.d.ts +164 -10
- package/dist/contracts/catalog/view.d.ts +73 -0
- package/dist/dialects/pg/column.d.ts +3 -1
- package/dist/dialects/pg/ddl.d.ts +65 -1
- package/dist/dialects/pg/enum.d.ts +10 -8
- package/dist/dialects/pg/ext/citext.d.ts +14 -0
- package/dist/dialects/pg/ext/citext.js +11 -0
- package/dist/dialects/pg/ext/index.d.ts +52 -0
- package/dist/dialects/pg/ext/index.js +6 -0
- package/dist/dialects/pg/ext/pg-trgm.d.ts +53 -0
- package/dist/dialects/pg/ext/pg-trgm.js +42 -0
- package/dist/dialects/pg/fn/index.d.ts +107 -0
- package/dist/dialects/pg/fn/index.js +175 -0
- package/dist/dialects/pg/fn/touch.d.ts +14 -0
- package/dist/dialects/pg/index.js +104 -19
- package/dist/dialects/pg/introspect.d.ts +10 -1
- package/dist/dialects/pg/operators.d.ts +8 -1
- package/dist/dialects/pg/role/check.d.ts +45 -0
- package/dist/dialects/pg/role/index.d.ts +50 -0
- package/dist/dialects/pg/role/sql.d.ts +51 -0
- package/dist/dialects/pg/table.d.ts +24 -1
- package/dist/dialects/pg/tenancy.d.ts +9 -0
- package/dist/dialects/pg/view/client.d.ts +30 -0
- package/dist/dialects/pg/view/depend.d.ts +35 -0
- package/dist/dialects/pg/view/index.d.ts +114 -0
- package/dist/dialects/pg/view/index.js +289 -0
- package/dist/dialects/pg/view/scratch.d.ts +22 -0
- package/dist/dialects/pg/where.d.ts +2 -2
- package/dist/runtime/catalog-cache.d.ts +17 -0
- package/dist/runtime/compat-words.d.ts +23 -0
- package/dist/runtime/drift-detail.d.ts +20 -4
- package/dist/runtime/drift.d.ts +4 -2
- package/dist/runtime/pg/bun.js +3 -3
- package/dist/runtime/pg/pg.js +3 -3
- package/dist/runtime/pg/pglite.js +3 -3
- package/dist/runtime/pg/postgresjs.js +3 -3
- package/dist/runtime/tenancy/index.js +6 -3
- package/dist/runtime/traits/index.d.ts +7 -2
- package/dist/runtime/traits/index.js +151 -13
- package/dist/runtime/types.d.ts +2 -0
- package/dist/runtime/validate/index.js +4 -4
- package/dist/shared/{xkz8g6by.js → 1g0drakv.js} +2 -2
- package/dist/shared/2321avmn.js +418 -0
- package/dist/shared/{7mht49yd.js → 3p4b1fg0.js} +57 -18
- package/dist/shared/41kv2xdm.js +318 -0
- package/dist/shared/{97g2jnrw.js → 4ef7mmqf.js} +3 -3
- package/dist/shared/{sacqha1y.js → 4m9fn52z.js} +2 -2
- package/dist/shared/5mtf6cj3.js +94 -0
- package/dist/shared/{1dp5knt7.js → 5vdm4sgp.js} +2 -2
- package/dist/shared/{a1gdp7j9.js → 6693j9rs.js} +1 -1
- package/dist/shared/{38crxbgn.js → 6p5k20sm.js} +3 -3
- package/dist/shared/7nk68fj8.js +751 -0
- package/dist/shared/84ptn35q.js +71 -0
- package/dist/shared/{d2whjz4k.js → 8jb4ymh2.js} +581 -28
- package/dist/shared/8ktwd3rh.js +97 -0
- package/dist/shared/94ez8kzh.js +19 -0
- package/dist/shared/{3a5ne750.js → 9m80mkac.js} +2 -2
- package/dist/shared/9x25fxhc.js +150 -0
- package/dist/shared/9yn6a2vd.js +11 -0
- package/dist/shared/ady1ms74.js +72 -0
- package/dist/shared/{4jzzghr6.js → awrsqrn7.js} +6 -6
- package/dist/shared/{4b9da9d7.js → axhk06q1.js} +19 -1
- package/dist/shared/{d04j53v8.js → c5g81ngb.js} +82 -14
- package/dist/shared/{n47rd821.js → c8aghh05.js} +1 -1
- package/dist/shared/{dd4f8mnx.js → c9z5g0fm.js} +4 -2
- package/dist/shared/{ps43134h.js → dyj86cmj.js} +4 -4
- package/dist/shared/{0qkxbm1f.js → fa9vt245.js} +1 -1
- package/dist/shared/{qa5dsc7z.js → fb00y8fp.js} +3 -3
- package/dist/shared/{qxa0yb9j.js → g7ez901n.js} +30 -1
- package/dist/shared/{py3nh7jy.js → gdh9mrtp.js} +2 -2
- package/dist/shared/{yw5c610b.js → gjthds9j.js} +2 -2
- package/dist/shared/hcmdtwgh.js +102 -0
- package/dist/shared/hqjsxnz7.js +13 -0
- package/dist/shared/htnaj77v.js +17 -0
- package/dist/shared/{v18jva5b.js → jgxzjzcz.js} +1 -1
- package/dist/shared/{x9v1qgeb.js → jsd07prz.js} +3 -3
- package/dist/shared/{g9f0zqce.js → kafaa5zv.js} +1 -1
- package/dist/shared/kj680nxv.js +19 -0
- package/dist/shared/{mxmcdsh5.js → kkzwp3d2.js} +9 -9
- package/dist/shared/{g1b5zzj9.js → n0dgs0pb.js} +1 -1
- package/dist/shared/n5y9zyj1.js +2431 -0
- package/dist/shared/{zt8y0wzb.js → n7mcc1gk.js} +1 -1
- package/dist/shared/{ge03bfca.js → nxb42q7h.js} +2 -2
- package/dist/shared/q6zsyh31.js +2192 -0
- package/dist/shared/{sfh4pk75.js → q795afwa.js} +26 -21
- package/dist/shared/{10tjenmd.js → qn0srwwq.js} +1 -1
- package/dist/shared/s4mb6a4b.js +545 -0
- package/dist/shared/{ytg3xf9p.js → sf8m6tfy.js} +3 -3
- package/dist/shared/{zd93g3rq.js → sr5ms7b3.js} +1 -1
- package/dist/shared/{xatfg0gn.js → tmbdywx0.js} +4 -19
- package/dist/shared/tny2t3sm.js +100 -0
- package/dist/shared/{e7a268fy.js → v7tpnhnz.js} +1 -1
- package/dist/shared/{ecdzej21.js → wqem4jed.js} +7 -7
- package/dist/shared/xghkt7a9.js +1144 -0
- package/dist/shared/y005b761.js +112 -0
- package/dist/shared/ycatkxmq.js +84 -0
- package/dist/shared/ygem90rn.js +900 -0
- package/dist/shared/{eaxwrgby.js → yjw02enp.js} +6 -3
- package/dist/shared/{mrq77sgw.js → zg24x0hm.js} +1 -1
- package/dist/shared/{cstgkzdx.js → zvbjc949.js} +1 -1
- package/dist/tooling/cli.js +66 -13
- package/dist/tooling/migrate/apply.d.ts +75 -5
- package/dist/tooling/migrate/backfill.d.ts +136 -0
- package/dist/tooling/migrate/check.d.ts +65 -0
- package/dist/tooling/migrate/classify.d.ts +108 -0
- package/dist/tooling/migrate/commands.d.ts +2 -1
- package/dist/tooling/migrate/config.d.ts +30 -0
- package/dist/tooling/migrate/doctor.d.ts +28 -0
- package/dist/tooling/migrate/drift.d.ts +35 -0
- package/dist/tooling/migrate/estimate.d.ts +50 -0
- package/dist/tooling/migrate/ext.d.ts +17 -0
- package/dist/tooling/migrate/extensions.d.ts +53 -0
- package/dist/tooling/migrate/files.d.ts +12 -0
- package/dist/tooling/migrate/index.d.ts +3 -2
- package/dist/tooling/migrate/index.js +67 -1
- package/dist/tooling/migrate/lint-rules.d.ts +51 -0
- package/dist/tooling/migrate/lint.d.ts +71 -0
- package/dist/tooling/migrate/managed.d.ts +17 -0
- package/dist/tooling/migrate/plan.d.ts +78 -10
- package/dist/tooling/migrate/project.d.ts +64 -5
- package/dist/tooling/migrate/provision.d.ts +18 -0
- package/dist/tooling/migrate/reference.d.ts +40 -0
- package/dist/tooling/migrate/runner.d.ts +108 -0
- package/dist/tooling/migrate/safe.d.ts +77 -0
- package/dist/tooling/migrate/seed.d.ts +20 -0
- package/dist/tooling/migrate/snapshot.d.ts +78 -0
- package/dist/tooling/migrate/status.d.ts +25 -6
- package/dist/tooling/migrate/type-name.d.ts +19 -0
- package/dist/tooling/testing/factories.d.ts +117 -0
- package/dist/tooling/testing/facts.d.ts +72 -0
- package/dist/tooling/testing/index.d.ts +89 -0
- package/dist/tooling/testing/index.js +8 -0
- package/dist/tooling/testing/isolation.d.ts +30 -0
- package/dist/tooling/testing/random.d.ts +40 -0
- package/dist/tooling/testing/record.d.ts +38 -0
- package/package.json +26 -2
- package/dist/shared/5z4q2zda.js +0 -2073
- package/dist/shared/eqmtn1bj.js +0 -399
- package/dist/shared/rtnaqre0.js +0 -37
- package/dist/shared/zwmqxb0g.js +0 -79
- package/dist/shared/{m9tv7xn7.js → radd3z4g.js} +3 -3
- /package/dist/shared/{9k6vetvf.js → rrstp3kb.js} +0 -0
package/dist/shared/eqmtn1bj.js
DELETED
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
open2
|
|
3
|
-
} from "./ecdzej21.js";
|
|
4
|
-
import {
|
|
5
|
-
catalogHash2
|
|
6
|
-
} from "./d2whjz4k.js";
|
|
7
|
-
import"./n442h54c.js";
|
|
8
|
-
import {
|
|
9
|
-
loadMigrations
|
|
10
|
-
} from "./rtnaqre0.js";
|
|
11
|
-
import {
|
|
12
|
-
quoteIdent,
|
|
13
|
-
planMigration,
|
|
14
|
-
assertTargetPolicy,
|
|
15
|
-
assertDirectConnection,
|
|
16
|
-
selectTarget,
|
|
17
|
-
projectHead,
|
|
18
|
-
loadConfig
|
|
19
|
-
} from "./5z4q2zda.js";
|
|
20
|
-
import {
|
|
21
|
-
OkmError2
|
|
22
|
-
} from "./52szzakm.js";
|
|
23
|
-
|
|
24
|
-
// src/tooling/migrate/apply.ts
|
|
25
|
-
import { join } from "node:path";
|
|
26
|
-
|
|
27
|
-
// src/tooling/migrate/engine.ts
|
|
28
|
-
var IDENT = String.raw`"(?:[^"]|"")+"|[A-Za-z_][\w$]*`;
|
|
29
|
-
var DEFAULT_UUIDV7 = /\bdefault\s+uuidv7\s*\(\s*\)/i;
|
|
30
|
-
var TABLE = new RegExp(String.raw`^\s*(?:create\s+table(?:\s+if\s+not\s+exists)?|alter\s+table(?:\s+if\s+exists)?(?:\s+only)?)\s+(?:(?:${IDENT})\.)?(${IDENT})`, "i");
|
|
31
|
-
var COLUMN = new RegExp(String.raw`(${IDENT})\s+(?:uuid\b|set\s+default\b)`, "i");
|
|
32
|
-
function findUuidV7Default(migrations) {
|
|
33
|
-
for (const migration of migrations) {
|
|
34
|
-
for (let stepIndex = 0;stepIndex < migration.steps.length; stepIndex += 1) {
|
|
35
|
-
const sql = migration.steps[stepIndex]?.sql ?? "";
|
|
36
|
-
if (!DEFAULT_UUIDV7.test(sql))
|
|
37
|
-
continue;
|
|
38
|
-
return { migrationId: migration.id, stepIndex, column: columnOf(sql) };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
async function assertUuidV7Available(connection, migrations) {
|
|
44
|
-
const found = findUuidV7Default(migrations);
|
|
45
|
-
if (found === undefined)
|
|
46
|
-
return;
|
|
47
|
-
const result = await connection.execute("select current_setting('server_version_num'), to_regprocedure('uuidv7()')::text");
|
|
48
|
-
const row = result.rows[0];
|
|
49
|
-
const major = Math.floor(Number(row?.[0] ?? "0") / 1e4);
|
|
50
|
-
const defined = row?.[1] !== null && row?.[1] !== undefined;
|
|
51
|
-
if (major >= 18 || defined)
|
|
52
|
-
return;
|
|
53
|
-
const where = found.column === undefined ? "A column" : `Column ${found.column}`;
|
|
54
|
-
throw new OkmError2("OKM1812", `${where} has a uuidv7() default (migration ${found.migrationId}, step ${String(found.stepIndex)}), and the server is PostgreSQL ${String(major)}. uuidv7() arrives in PostgreSQL 18. Nothing was changed.`, {
|
|
55
|
-
fix: {
|
|
56
|
-
summary: 'Either run PostgreSQL 18 and declare schema({ requires: { postgres: ">=18" } }), or use t.id({ default: "uuidv4" }) (or schema({ defaults: { id: "uuidv4" } })), which uses gen_random_uuid() and works on PostgreSQL 13 and newer. Then delete the migration that was not applied and generate it again.'
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
function columnOf(sql) {
|
|
61
|
-
const table = TABLE.exec(sql)?.[1];
|
|
62
|
-
if (table === undefined)
|
|
63
|
-
return;
|
|
64
|
-
const line = sql.split(`
|
|
65
|
-
`).find((text) => DEFAULT_UUIDV7.test(text));
|
|
66
|
-
const column = line === undefined ? undefined : COLUMN.exec(line)?.[1];
|
|
67
|
-
if (column === undefined)
|
|
68
|
-
return;
|
|
69
|
-
return `${unquote(table)}.${unquote(column)}`;
|
|
70
|
-
}
|
|
71
|
-
function unquote(name) {
|
|
72
|
-
return name.startsWith('"') ? name.slice(1, -1).replaceAll('""', '"') : name;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// src/tooling/migrate/apply.ts
|
|
76
|
-
var DEFAULT_LOCK_MS = 5000;
|
|
77
|
-
var DEFAULT_STATEMENT_MS = 30000;
|
|
78
|
-
var DEFAULT_RETRIES = 3;
|
|
79
|
-
var BACKOFF_MS = 50;
|
|
80
|
-
var META = `create table if not exists okm_meta (
|
|
81
|
-
id text primary key,
|
|
82
|
-
catalog_hash text not null,
|
|
83
|
-
migration_id text not null
|
|
84
|
-
)`;
|
|
85
|
-
var HISTORY = `create table if not exists okm_history (
|
|
86
|
-
migration_id text not null,
|
|
87
|
-
step_index integer not null,
|
|
88
|
-
class text not null,
|
|
89
|
-
catalog_hash text not null,
|
|
90
|
-
applied_at timestamptz not null default now(),
|
|
91
|
-
primary key (migration_id, step_index)
|
|
92
|
-
)`;
|
|
93
|
-
function applyUnits(migration, done) {
|
|
94
|
-
const pending = [];
|
|
95
|
-
for (let index = 0;index < migration.steps.length; index += 1) {
|
|
96
|
-
if (done.has(`${migration.id}:${String(index)}`))
|
|
97
|
-
continue;
|
|
98
|
-
const step = migration.steps[index];
|
|
99
|
-
if (step !== undefined)
|
|
100
|
-
pending.push({ index, step });
|
|
101
|
-
}
|
|
102
|
-
const units = [];
|
|
103
|
-
let batch = [];
|
|
104
|
-
const flush = () => {
|
|
105
|
-
if (batch.length === 0)
|
|
106
|
-
return;
|
|
107
|
-
const last = batch.at(-1);
|
|
108
|
-
units.push({
|
|
109
|
-
migrationId: migration.id,
|
|
110
|
-
catalogHash: migration.catalogHash,
|
|
111
|
-
finishes: last !== undefined && last.index === migration.steps.length - 1,
|
|
112
|
-
transactional: true,
|
|
113
|
-
steps: batch
|
|
114
|
-
});
|
|
115
|
-
batch = [];
|
|
116
|
-
};
|
|
117
|
-
for (const item of pending) {
|
|
118
|
-
if (item.step.transactional && !outsideTransaction(item.step.sql)) {
|
|
119
|
-
batch.push(item);
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
flush();
|
|
123
|
-
units.push({
|
|
124
|
-
migrationId: migration.id,
|
|
125
|
-
catalogHash: migration.catalogHash,
|
|
126
|
-
finishes: item.index === migration.steps.length - 1,
|
|
127
|
-
transactional: false,
|
|
128
|
-
steps: [item]
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
flush();
|
|
132
|
-
return units;
|
|
133
|
-
}
|
|
134
|
-
async function applyTarget(request) {
|
|
135
|
-
assertDirectConnection(request.url, request.allowPooler === true);
|
|
136
|
-
const pool = open2({
|
|
137
|
-
url: request.url,
|
|
138
|
-
max: 1,
|
|
139
|
-
...request.searchPath !== undefined ? { searchPath: request.searchPath } : {}
|
|
140
|
-
});
|
|
141
|
-
if (pool.reserve === undefined) {
|
|
142
|
-
await pool.close();
|
|
143
|
-
throw new OkmError2("invalid", "The driver cannot reserve a connection.", {
|
|
144
|
-
fix: { summary: "Apply needs a driver with interactive transactions." }
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
const connection = await pool.reserve();
|
|
148
|
-
let locked = false;
|
|
149
|
-
try {
|
|
150
|
-
await setTimeouts(connection, request);
|
|
151
|
-
await lockTarget(connection, request.target);
|
|
152
|
-
locked = true;
|
|
153
|
-
request.onLocked?.();
|
|
154
|
-
await assertUuidV7Available(connection, request.migrations);
|
|
155
|
-
await connection.execute(META);
|
|
156
|
-
await connection.execute(HISTORY);
|
|
157
|
-
const done = await readDone(connection);
|
|
158
|
-
const applied = [];
|
|
159
|
-
for (const migration of request.migrations) {
|
|
160
|
-
const units = applyUnits(migration, done);
|
|
161
|
-
if (units.length === 0)
|
|
162
|
-
continue;
|
|
163
|
-
for (const unit of units) {
|
|
164
|
-
assertUnitPolicy(request, unit);
|
|
165
|
-
await runUnit(connection, unit, request);
|
|
166
|
-
for (const item of unit.steps)
|
|
167
|
-
done.add(`${unit.migrationId}:${String(item.index)}`);
|
|
168
|
-
}
|
|
169
|
-
applied.push(migration.id);
|
|
170
|
-
}
|
|
171
|
-
return { target: request.target, applied };
|
|
172
|
-
} finally {
|
|
173
|
-
if (locked)
|
|
174
|
-
await connection.execute("select pg_advisory_unlock(hashtext($1))", [
|
|
175
|
-
lockKey(request.target)
|
|
176
|
-
]);
|
|
177
|
-
await connection.release();
|
|
178
|
-
await pool.close();
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
async function applyProject(cwd, flags) {
|
|
182
|
-
const config = await loadConfig(cwd);
|
|
183
|
-
const target = selectTarget(config, flags.target);
|
|
184
|
-
const migrations = loadMigrations(joinMigrations(cwd, config.migrations));
|
|
185
|
-
if (migrations.length === 0)
|
|
186
|
-
return `target ${target.name}
|
|
187
|
-
nothing to apply
|
|
188
|
-
`;
|
|
189
|
-
const report = await applyTarget({
|
|
190
|
-
url: target.url,
|
|
191
|
-
target: target.name,
|
|
192
|
-
protected: target.protected,
|
|
193
|
-
allowProtected: flags.allowProtected,
|
|
194
|
-
allowPooler: flags.allowPooler || config.allowPooler === true,
|
|
195
|
-
...flags.lockTimeoutMs !== undefined ? { lockTimeoutMs: flags.lockTimeoutMs } : config.timeouts?.lock !== undefined ? { lockTimeoutMs: config.timeouts.lock } : {},
|
|
196
|
-
...flags.statementTimeoutMs !== undefined ? { statementTimeoutMs: flags.statementTimeoutMs } : config.timeouts?.statement !== undefined ? { statementTimeoutMs: config.timeouts.statement } : {},
|
|
197
|
-
migrations
|
|
198
|
-
});
|
|
199
|
-
return formatReport(report);
|
|
200
|
-
}
|
|
201
|
-
async function pushProject(cwd, flags) {
|
|
202
|
-
const config = await loadConfig(cwd);
|
|
203
|
-
const target = selectTarget(config, flags.target);
|
|
204
|
-
assertTargetPolicy(target, "push", flags.allowProtected);
|
|
205
|
-
const head = await projectHead(cwd);
|
|
206
|
-
const plan = planMigration({
|
|
207
|
-
before: head.previous,
|
|
208
|
-
after: head.catalog,
|
|
209
|
-
renames: head.renames,
|
|
210
|
-
name: "push"
|
|
211
|
-
});
|
|
212
|
-
if (plan.steps.length === 0)
|
|
213
|
-
return `target ${target.name}
|
|
214
|
-
no changes
|
|
215
|
-
`;
|
|
216
|
-
const report = await applyTarget({
|
|
217
|
-
url: target.url,
|
|
218
|
-
target: target.name,
|
|
219
|
-
protected: target.protected,
|
|
220
|
-
allowProtected: flags.allowProtected,
|
|
221
|
-
allowPooler: flags.allowPooler || config.allowPooler === true,
|
|
222
|
-
migrations: [
|
|
223
|
-
{
|
|
224
|
-
id: "push",
|
|
225
|
-
catalogHash: catalogHash2(head.catalog),
|
|
226
|
-
steps: plan.steps
|
|
227
|
-
}
|
|
228
|
-
]
|
|
229
|
-
});
|
|
230
|
-
return formatReport(report);
|
|
231
|
-
}
|
|
232
|
-
function formatReport(report) {
|
|
233
|
-
if (report.applied.length === 0)
|
|
234
|
-
return `target ${report.target}
|
|
235
|
-
nothing to apply
|
|
236
|
-
`;
|
|
237
|
-
return `target ${report.target}
|
|
238
|
-
${report.applied.map((id) => `applied ${id}`).join(`
|
|
239
|
-
`)}
|
|
240
|
-
`;
|
|
241
|
-
}
|
|
242
|
-
function joinMigrations(cwd, migrations) {
|
|
243
|
-
return join(cwd, migrations ?? "migrations");
|
|
244
|
-
}
|
|
245
|
-
function assertUnitPolicy(request, unit) {
|
|
246
|
-
let operation = "expand";
|
|
247
|
-
for (const item of unit.steps) {
|
|
248
|
-
if (item.step.action === "backfill") {
|
|
249
|
-
operation = "backfill";
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
if (item.step.class === "contract" || item.step.class === "unclassified")
|
|
253
|
-
operation = item.step.class;
|
|
254
|
-
}
|
|
255
|
-
assertTargetPolicy({ name: request.target, protected: request.protected }, operation, request.allowProtected === true);
|
|
256
|
-
}
|
|
257
|
-
async function setTimeouts(connection, request) {
|
|
258
|
-
const lock = request.lockTimeoutMs ?? DEFAULT_LOCK_MS;
|
|
259
|
-
const statement = request.statementTimeoutMs ?? DEFAULT_STATEMENT_MS;
|
|
260
|
-
await connection.execute("select set_config('lock_timeout', $1, false)", [String(lock)]);
|
|
261
|
-
await connection.execute("select set_config('statement_timeout', $1, false)", [
|
|
262
|
-
String(statement)
|
|
263
|
-
]);
|
|
264
|
-
}
|
|
265
|
-
async function lockTarget(connection, target) {
|
|
266
|
-
const result = await connection.execute("select pg_try_advisory_lock(hashtext($1))", [
|
|
267
|
-
lockKey(target)
|
|
268
|
-
]);
|
|
269
|
-
if (!wireTrue(result.rows[0]?.[0])) {
|
|
270
|
-
throw new OkmError2("OKM1522", `Another apply holds the lock for ${target}.`, {
|
|
271
|
-
kind: "conflict",
|
|
272
|
-
fix: {
|
|
273
|
-
summary: "Wait for that apply to finish. Do not start a second apply against the same target."
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
function lockKey(target) {
|
|
279
|
-
return `okm:${target}`;
|
|
280
|
-
}
|
|
281
|
-
async function readDone(connection) {
|
|
282
|
-
const result = await connection.execute("select migration_id, step_index::text from okm_history");
|
|
283
|
-
const done = new Set;
|
|
284
|
-
for (const row of result.rows) {
|
|
285
|
-
const id = row[0];
|
|
286
|
-
const step = row[1];
|
|
287
|
-
if (id !== null && step !== null)
|
|
288
|
-
done.add(`${id}:${step}`);
|
|
289
|
-
}
|
|
290
|
-
return done;
|
|
291
|
-
}
|
|
292
|
-
async function runUnit(connection, unit, request) {
|
|
293
|
-
const retries = request.retries ?? DEFAULT_RETRIES;
|
|
294
|
-
for (let attempt = 0;attempt <= retries; attempt += 1) {
|
|
295
|
-
let began = false;
|
|
296
|
-
let current = unit.steps[0]?.index ?? 0;
|
|
297
|
-
try {
|
|
298
|
-
if (unit.transactional) {
|
|
299
|
-
await connection.execute("begin");
|
|
300
|
-
began = true;
|
|
301
|
-
}
|
|
302
|
-
for (const item of unit.steps) {
|
|
303
|
-
current = item.index;
|
|
304
|
-
await rebuildInvalidIndex(connection, item.step.sql);
|
|
305
|
-
await connection.execute(item.step.sql);
|
|
306
|
-
if (!unit.transactional) {
|
|
307
|
-
await connection.execute("begin");
|
|
308
|
-
began = true;
|
|
309
|
-
await writeStep(connection, unit, item);
|
|
310
|
-
if (unit.finishes)
|
|
311
|
-
await writeMeta(connection, unit);
|
|
312
|
-
await connection.execute("commit");
|
|
313
|
-
began = false;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
if (unit.transactional) {
|
|
317
|
-
for (const item of unit.steps)
|
|
318
|
-
await writeStep(connection, unit, item);
|
|
319
|
-
if (unit.finishes)
|
|
320
|
-
await writeMeta(connection, unit);
|
|
321
|
-
await connection.execute("commit");
|
|
322
|
-
began = false;
|
|
323
|
-
}
|
|
324
|
-
return;
|
|
325
|
-
} catch (error) {
|
|
326
|
-
if (began)
|
|
327
|
-
await connection.execute("rollback").catch(() => {
|
|
328
|
-
return;
|
|
329
|
-
});
|
|
330
|
-
if (!isLockTimeout(error) || attempt === retries)
|
|
331
|
-
throw failStep(unit, current, error);
|
|
332
|
-
await delay(BACKOFF_MS * 2 ** attempt);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
async function writeStep(connection, unit, item) {
|
|
337
|
-
await connection.execute("insert into okm_history (migration_id, step_index, class, catalog_hash) values ($1, $2, $3, $4)", [unit.migrationId, String(item.index), item.step.class, unit.catalogHash]);
|
|
338
|
-
}
|
|
339
|
-
async function writeMeta(connection, unit) {
|
|
340
|
-
await connection.execute(`insert into okm_meta (id, catalog_hash, migration_id) values ('head', $1, $2)
|
|
341
|
-
on conflict (id) do update set catalog_hash = excluded.catalog_hash, migration_id = excluded.migration_id`, [unit.catalogHash, unit.migrationId]);
|
|
342
|
-
}
|
|
343
|
-
async function rebuildInvalidIndex(connection, sql) {
|
|
344
|
-
const name = concurrentIndexName(sql);
|
|
345
|
-
if (name === undefined)
|
|
346
|
-
return;
|
|
347
|
-
const found = await connection.execute(`select i.indisvalid
|
|
348
|
-
from pg_class c
|
|
349
|
-
join pg_namespace n on n.oid = c.relnamespace
|
|
350
|
-
join pg_index i on i.indexrelid = c.oid
|
|
351
|
-
where c.relname = $1 and n.nspname = current_schema()`, [name]);
|
|
352
|
-
const valid = found.rows[0]?.[0];
|
|
353
|
-
if (valid === undefined || wireTrue(valid))
|
|
354
|
-
return;
|
|
355
|
-
await connection.execute(`drop index concurrently if exists ${quoteIdent(name)}`);
|
|
356
|
-
}
|
|
357
|
-
function concurrentIndexName(sql) {
|
|
358
|
-
const match = /^create\s+(?:unique\s+)?index\s+concurrently\s+(?:if\s+not\s+exists\s+)?(?:"([^"]+)"|([A-Za-z_][\w$]*))/i.exec(sql.trim());
|
|
359
|
-
return match?.[1] ?? match?.[2];
|
|
360
|
-
}
|
|
361
|
-
function outsideTransaction(sql) {
|
|
362
|
-
const text = sql.trim().toLowerCase();
|
|
363
|
-
if (text.startsWith("vacuum"))
|
|
364
|
-
return true;
|
|
365
|
-
if (/^alter\s+type\b/.test(text) && /\badd\s+value\b/.test(text))
|
|
366
|
-
return true;
|
|
367
|
-
if (/^create\s+(?:unique\s+)?index\s+concurrently\b/.test(text))
|
|
368
|
-
return true;
|
|
369
|
-
return false;
|
|
370
|
-
}
|
|
371
|
-
function failStep(unit, index, error) {
|
|
372
|
-
if (error instanceof OkmError2)
|
|
373
|
-
return error;
|
|
374
|
-
const message = error instanceof Error ? error.message : "The step failed.";
|
|
375
|
-
return new OkmError2("invalid", `Migration ${unit.migrationId} failed at step ${String(index)}: ${message}`, {
|
|
376
|
-
cause: error,
|
|
377
|
-
fix: { summary: "Fix the step and run apply again. Finished steps are not repeated." }
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
function isLockTimeout(error) {
|
|
381
|
-
if (typeof error !== "object" || error === null)
|
|
382
|
-
return false;
|
|
383
|
-
if ("sqlstate" in error && error.sqlstate === "55P03")
|
|
384
|
-
return true;
|
|
385
|
-
const message = error instanceof Error ? error.message : "";
|
|
386
|
-
return message.includes("lock timeout");
|
|
387
|
-
}
|
|
388
|
-
function wireTrue(value) {
|
|
389
|
-
return value === "t" || value === "true";
|
|
390
|
-
}
|
|
391
|
-
function delay(ms) {
|
|
392
|
-
return new Promise((resolve) => {
|
|
393
|
-
setTimeout(resolve, ms);
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
export {
|
|
397
|
-
applyProject,
|
|
398
|
-
pushProject
|
|
399
|
-
};
|
package/dist/shared/rtnaqre0.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
catalogHash2,
|
|
3
|
-
parseCatalog2
|
|
4
|
-
} from "./d2whjz4k.js";
|
|
5
|
-
import {
|
|
6
|
-
parsePlan
|
|
7
|
-
} from "./5z4q2zda.js";
|
|
8
|
-
import {
|
|
9
|
-
OkmError2
|
|
10
|
-
} from "./52szzakm.js";
|
|
11
|
-
|
|
12
|
-
// src/tooling/migrate/files.ts
|
|
13
|
-
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
14
|
-
import { join } from "node:path";
|
|
15
|
-
function loadMigrations(directory) {
|
|
16
|
-
if (!existsSync(directory))
|
|
17
|
-
return [];
|
|
18
|
-
const names = readdirSync(directory).filter((file) => file.endsWith(".sql")).sort();
|
|
19
|
-
const migrations = [];
|
|
20
|
-
for (const file of names) {
|
|
21
|
-
const id = file.slice(0, -".sql".length);
|
|
22
|
-
const catalogPath = join(directory, `${id}.catalog.json`);
|
|
23
|
-
if (!existsSync(catalogPath)) {
|
|
24
|
-
throw new OkmError2("invalid", `Migration ${id} is missing its catalog snapshot.`, {
|
|
25
|
-
fix: {
|
|
26
|
-
summary: "Generate the migration again so the SQL and the catalog are written together."
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
const plan = parsePlan(readFileSync(join(directory, file), "utf8"));
|
|
31
|
-
const hash = catalogHash2(parseCatalog2(readFileSync(catalogPath, "utf8")));
|
|
32
|
-
migrations.push({ id, catalogHash: hash, steps: plan.steps });
|
|
33
|
-
}
|
|
34
|
-
return migrations;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export { loadMigrations };
|
package/dist/shared/zwmqxb0g.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
OkmError2
|
|
3
|
-
} from "./52szzakm.js";
|
|
4
|
-
|
|
5
|
-
// src/runtime/drift-detail.ts
|
|
6
|
-
function driftVerdict(codeHash, recordedHash, migrations) {
|
|
7
|
-
const codeAt = indexOfHash(migrations, codeHash);
|
|
8
|
-
const recordedAt = indexOfHash(migrations, recordedHash);
|
|
9
|
-
if (codeAt < 0 || recordedAt < 0 || recordedAt < codeAt)
|
|
10
|
-
return "behind";
|
|
11
|
-
if (recordedAt === codeAt)
|
|
12
|
-
return "ok";
|
|
13
|
-
for (let index = codeAt + 1;index <= recordedAt; index += 1) {
|
|
14
|
-
if (migrations[index]?.expand !== true)
|
|
15
|
-
return "contract";
|
|
16
|
-
}
|
|
17
|
-
return "ok";
|
|
18
|
-
}
|
|
19
|
-
async function assertDrift(pool, codeHash, recordedHash, options) {
|
|
20
|
-
let rows;
|
|
21
|
-
try {
|
|
22
|
-
const result = await pool.execute("select migration_id, class, catalog_hash from okm_history order by migration_id, step_index", undefined, options);
|
|
23
|
-
rows = result.rows;
|
|
24
|
-
} catch (error) {
|
|
25
|
-
throw behind(error);
|
|
26
|
-
}
|
|
27
|
-
const verdict = driftVerdict(codeHash, recordedHash, groupMigrations(rows));
|
|
28
|
-
if (verdict === "ok")
|
|
29
|
-
return;
|
|
30
|
-
if (verdict === "contract") {
|
|
31
|
-
throw new OkmError2("OKM1520", "The database is ahead of the code by a contract migration.", {
|
|
32
|
-
fix: {
|
|
33
|
-
summary: "Roll the application forward, or repair the database. A contract step is not compatible with this code."
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
throw behind(undefined);
|
|
38
|
-
}
|
|
39
|
-
function indexOfHash(migrations, hash) {
|
|
40
|
-
let found = -1;
|
|
41
|
-
for (let index = 0;index < migrations.length; index += 1) {
|
|
42
|
-
if (migrations[index]?.catalogHash === hash)
|
|
43
|
-
found = index;
|
|
44
|
-
}
|
|
45
|
-
return found;
|
|
46
|
-
}
|
|
47
|
-
function groupMigrations(rows) {
|
|
48
|
-
const grouped = [];
|
|
49
|
-
for (const row of rows) {
|
|
50
|
-
const id = row[0];
|
|
51
|
-
const stepClass = row[1];
|
|
52
|
-
const hash = row[2];
|
|
53
|
-
if (id == null || stepClass == null || hash == null)
|
|
54
|
-
continue;
|
|
55
|
-
const expand = stepClass === "expand";
|
|
56
|
-
const last = grouped.at(-1);
|
|
57
|
-
if (last !== undefined && last.id === id) {
|
|
58
|
-
grouped[grouped.length - 1] = {
|
|
59
|
-
id,
|
|
60
|
-
catalogHash: hash,
|
|
61
|
-
expand: last.expand && expand
|
|
62
|
-
};
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
grouped.push({ id, catalogHash: hash, expand });
|
|
66
|
-
}
|
|
67
|
-
return grouped;
|
|
68
|
-
}
|
|
69
|
-
function behind(cause) {
|
|
70
|
-
return new OkmError2("OKM1520", "The database is behind the code.", {
|
|
71
|
-
...cause === undefined ? {} : { cause },
|
|
72
|
-
fix: {
|
|
73
|
-
summary: "Inspect the diff and repair the database, or generate a migration that matches the drift."
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
export {
|
|
78
|
-
assertDrift
|
|
79
|
-
};
|
|
File without changes
|