@intentius/sql-yodeler 0.0.0-stage → 0.1.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.
Files changed (264) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +110 -2
  3. package/dist/bin.d.ts +2 -0
  4. package/dist/bin.js +14 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/chant/apply.d.ts +51 -0
  7. package/dist/chant/apply.js +104 -0
  8. package/dist/chant/apply.js.map +1 -0
  9. package/dist/chant/build.d.ts +34 -0
  10. package/dist/chant/build.js +48 -0
  11. package/dist/chant/build.js.map +1 -0
  12. package/dist/chant/drift.d.ts +44 -0
  13. package/dist/chant/drift.js +91 -0
  14. package/dist/chant/drift.js.map +1 -0
  15. package/dist/chant/plan.d.ts +45 -0
  16. package/dist/chant/plan.js +61 -0
  17. package/dist/chant/plan.js.map +1 -0
  18. package/dist/chant/process.d.ts +41 -0
  19. package/dist/chant/process.js +87 -0
  20. package/dist/chant/process.js.map +1 -0
  21. package/dist/cli.d.ts +4 -0
  22. package/dist/cli.js +59 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/command.d.ts +17 -0
  25. package/dist/command.js +13 -0
  26. package/dist/command.js.map +1 -0
  27. package/dist/commands/apply.d.ts +3 -0
  28. package/dist/commands/apply.js +306 -0
  29. package/dist/commands/apply.js.map +1 -0
  30. package/dist/commands/drift.d.ts +3 -0
  31. package/dist/commands/drift.js +38 -0
  32. package/dist/commands/drift.js.map +1 -0
  33. package/dist/commands/index.d.ts +3 -0
  34. package/dist/commands/index.js +22 -0
  35. package/dist/commands/index.js.map +1 -0
  36. package/dist/commands/init.d.ts +3 -0
  37. package/dist/commands/init.js +135 -0
  38. package/dist/commands/init.js.map +1 -0
  39. package/dist/commands/lint.d.ts +3 -0
  40. package/dist/commands/lint.js +193 -0
  41. package/dist/commands/lint.js.map +1 -0
  42. package/dist/commands/new.d.ts +3 -0
  43. package/dist/commands/new.js +168 -0
  44. package/dist/commands/new.js.map +1 -0
  45. package/dist/commands/plan.d.ts +3 -0
  46. package/dist/commands/plan.js +171 -0
  47. package/dist/commands/plan.js.map +1 -0
  48. package/dist/commands/rebase.d.ts +3 -0
  49. package/dist/commands/rebase.js +167 -0
  50. package/dist/commands/rebase.js.map +1 -0
  51. package/dist/commands/repair.d.ts +3 -0
  52. package/dist/commands/repair.js +117 -0
  53. package/dist/commands/repair.js.map +1 -0
  54. package/dist/commands/status.d.ts +7 -0
  55. package/dist/commands/status.js +54 -0
  56. package/dist/commands/status.js.map +1 -0
  57. package/dist/config/define.d.ts +50 -0
  58. package/dist/config/define.js +20 -0
  59. package/dist/config/define.js.map +1 -0
  60. package/dist/config/index.d.ts +11 -0
  61. package/dist/config/index.js +12 -0
  62. package/dist/config/index.js.map +1 -0
  63. package/dist/config/load.d.ts +17 -0
  64. package/dist/config/load.js +102 -0
  65. package/dist/config/load.js.map +1 -0
  66. package/dist/config/settings.d.ts +40 -0
  67. package/dist/config/settings.js +88 -0
  68. package/dist/config/settings.js.map +1 -0
  69. package/dist/env-args.d.ts +18 -0
  70. package/dist/env-args.js +62 -0
  71. package/dist/env-args.js.map +1 -0
  72. package/dist/history/client.d.ts +17 -0
  73. package/dist/history/client.js +19 -0
  74. package/dist/history/client.js.map +1 -0
  75. package/dist/history/ddl.d.ts +58 -0
  76. package/dist/history/ddl.js +100 -0
  77. package/dist/history/ddl.js.map +1 -0
  78. package/dist/history/index.d.ts +25 -0
  79. package/dist/history/index.js +26 -0
  80. package/dist/history/index.js.map +1 -0
  81. package/dist/history/lock.d.ts +100 -0
  82. package/dist/history/lock.js +224 -0
  83. package/dist/history/lock.js.map +1 -0
  84. package/dist/history/postgres/ddl.d.ts +22 -0
  85. package/dist/history/postgres/ddl.js +47 -0
  86. package/dist/history/postgres/ddl.js.map +1 -0
  87. package/dist/history/postgres/index.d.ts +12 -0
  88. package/dist/history/postgres/index.js +13 -0
  89. package/dist/history/postgres/index.js.map +1 -0
  90. package/dist/history/postgres/lock.d.ts +48 -0
  91. package/dist/history/postgres/lock.js +95 -0
  92. package/dist/history/postgres/lock.js.map +1 -0
  93. package/dist/history/postgres/store.d.ts +39 -0
  94. package/dist/history/postgres/store.js +68 -0
  95. package/dist/history/postgres/store.js.map +1 -0
  96. package/dist/history/rows.d.ts +96 -0
  97. package/dist/history/rows.js +73 -0
  98. package/dist/history/rows.js.map +1 -0
  99. package/dist/history/store.d.ts +72 -0
  100. package/dist/history/store.js +134 -0
  101. package/dist/history/store.js.map +1 -0
  102. package/dist/history/topology.d.ts +41 -0
  103. package/dist/history/topology.js +54 -0
  104. package/dist/history/topology.js.map +1 -0
  105. package/dist/index.d.ts +10 -0
  106. package/dist/index.js +10 -0
  107. package/dist/index.js.map +1 -0
  108. package/dist/init/adopt.d.ts +70 -0
  109. package/dist/init/adopt.js +138 -0
  110. package/dist/init/adopt.js.map +1 -0
  111. package/dist/init/baseline.d.ts +61 -0
  112. package/dist/init/baseline.js +88 -0
  113. package/dist/init/baseline.js.map +1 -0
  114. package/dist/init/files.d.ts +23 -0
  115. package/dist/init/files.js +77 -0
  116. package/dist/init/files.js.map +1 -0
  117. package/dist/init/index.d.ts +16 -0
  118. package/dist/init/index.js +17 -0
  119. package/dist/init/index.js.map +1 -0
  120. package/dist/init/live.d.ts +28 -0
  121. package/dist/init/live.js +45 -0
  122. package/dist/init/live.js.map +1 -0
  123. package/dist/lint/check.d.ts +81 -0
  124. package/dist/lint/check.js +208 -0
  125. package/dist/lint/check.js.map +1 -0
  126. package/dist/lint/config.d.ts +21 -0
  127. package/dist/lint/config.js +43 -0
  128. package/dist/lint/config.js.map +1 -0
  129. package/dist/lint/index.d.ts +31 -0
  130. package/dist/lint/index.js +43 -0
  131. package/dist/lint/index.js.map +1 -0
  132. package/dist/lint/project-rules.d.ts +19 -0
  133. package/dist/lint/project-rules.js +32 -0
  134. package/dist/lint/project-rules.js.map +1 -0
  135. package/dist/lint/report.d.ts +7 -0
  136. package/dist/lint/report.js +48 -0
  137. package/dist/lint/report.js.map +1 -0
  138. package/dist/lint/rules.d.ts +53 -0
  139. package/dist/lint/rules.js +42 -0
  140. package/dist/lint/rules.js.map +1 -0
  141. package/dist/lint/silences.d.ts +49 -0
  142. package/dist/lint/silences.js +91 -0
  143. package/dist/lint/silences.js.map +1 -0
  144. package/dist/lint/statements.d.ts +38 -0
  145. package/dist/lint/statements.js +120 -0
  146. package/dist/lint/statements.js.map +1 -0
  147. package/dist/migrations/checksum.d.ts +56 -0
  148. package/dist/migrations/checksum.js +72 -0
  149. package/dist/migrations/checksum.js.map +1 -0
  150. package/dist/migrations/create.d.ts +73 -0
  151. package/dist/migrations/create.js +119 -0
  152. package/dist/migrations/create.js.map +1 -0
  153. package/dist/migrations/directory.d.ts +119 -0
  154. package/dist/migrations/directory.js +225 -0
  155. package/dist/migrations/directory.js.map +1 -0
  156. package/dist/migrations/document.d.ts +83 -0
  157. package/dist/migrations/document.js +82 -0
  158. package/dist/migrations/document.js.map +1 -0
  159. package/dist/migrations/index.d.ts +20 -0
  160. package/dist/migrations/index.js +21 -0
  161. package/dist/migrations/index.js.map +1 -0
  162. package/dist/pr/comment.d.ts +32 -0
  163. package/dist/pr/comment.js +99 -0
  164. package/dist/pr/comment.js.map +1 -0
  165. package/dist/pr/forge.d.ts +50 -0
  166. package/dist/pr/forge.js +105 -0
  167. package/dist/pr/forge.js.map +1 -0
  168. package/dist/pr/model.d.ts +91 -0
  169. package/dist/pr/model.js +113 -0
  170. package/dist/pr/model.js.map +1 -0
  171. package/dist/pr/render.d.ts +27 -0
  172. package/dist/pr/render.js +246 -0
  173. package/dist/pr/render.js.map +1 -0
  174. package/dist/project.d.ts +62 -0
  175. package/dist/project.js +92 -0
  176. package/dist/project.js.map +1 -0
  177. package/dist/rebase/index.d.ts +121 -0
  178. package/dist/rebase/index.js +390 -0
  179. package/dist/rebase/index.js.map +1 -0
  180. package/dist/rebase/repair.d.ts +41 -0
  181. package/dist/rebase/repair.js +68 -0
  182. package/dist/rebase/repair.js.map +1 -0
  183. package/dist/replay/clickhouse.d.ts +33 -0
  184. package/dist/replay/clickhouse.js +106 -0
  185. package/dist/replay/clickhouse.js.map +1 -0
  186. package/dist/replay/index.d.ts +36 -0
  187. package/dist/replay/index.js +54 -0
  188. package/dist/replay/index.js.map +1 -0
  189. package/dist/replay/postgres.d.ts +31 -0
  190. package/dist/replay/postgres.js +140 -0
  191. package/dist/replay/postgres.js.map +1 -0
  192. package/dist/replay/replay.d.ts +114 -0
  193. package/dist/replay/replay.js +98 -0
  194. package/dist/replay/replay.js.map +1 -0
  195. package/dist/replay/report.d.ts +18 -0
  196. package/dist/replay/report.js +72 -0
  197. package/dist/replay/report.js.map +1 -0
  198. package/dist/steps/backfill.d.ts +128 -0
  199. package/dist/steps/backfill.js +307 -0
  200. package/dist/steps/backfill.js.map +1 -0
  201. package/dist/steps/index.d.ts +52 -0
  202. package/dist/steps/index.js +52 -0
  203. package/dist/steps/index.js.map +1 -0
  204. package/dist/steps/kinds.d.ts +101 -0
  205. package/dist/steps/kinds.js +143 -0
  206. package/dist/steps/kinds.js.map +1 -0
  207. package/dist/steps/postgres-migration.d.ts +95 -0
  208. package/dist/steps/postgres-migration.js +149 -0
  209. package/dist/steps/postgres-migration.js.map +1 -0
  210. package/dist/steps/rebuild.d.ts +97 -0
  211. package/dist/steps/rebuild.js +162 -0
  212. package/dist/steps/rebuild.js.map +1 -0
  213. package/dist/steps/run.d.ts +45 -0
  214. package/dist/steps/run.js +72 -0
  215. package/dist/steps/run.js.map +1 -0
  216. package/dist/topology/render.d.ts +17 -0
  217. package/dist/topology/render.js +17 -0
  218. package/dist/topology/render.js.map +1 -0
  219. package/dist/version.d.ts +2 -0
  220. package/dist/version.js +11 -0
  221. package/dist/version.js.map +1 -0
  222. package/dist/versioned/approval.d.ts +35 -0
  223. package/dist/versioned/approval.js +53 -0
  224. package/dist/versioned/approval.js.map +1 -0
  225. package/dist/versioned/clickhouse.d.ts +24 -0
  226. package/dist/versioned/clickhouse.js +34 -0
  227. package/dist/versioned/clickhouse.js.map +1 -0
  228. package/dist/versioned/digest.d.ts +77 -0
  229. package/dist/versioned/digest.js +69 -0
  230. package/dist/versioned/digest.js.map +1 -0
  231. package/dist/versioned/driver.d.ts +41 -0
  232. package/dist/versioned/driver.js +13 -0
  233. package/dist/versioned/driver.js.map +1 -0
  234. package/dist/versioned/engine.d.ts +152 -0
  235. package/dist/versioned/engine.js +277 -0
  236. package/dist/versioned/engine.js.map +1 -0
  237. package/dist/versioned/explain.d.ts +123 -0
  238. package/dist/versioned/explain.js +289 -0
  239. package/dist/versioned/explain.js.map +1 -0
  240. package/dist/versioned/index.d.ts +37 -0
  241. package/dist/versioned/index.js +54 -0
  242. package/dist/versioned/index.js.map +1 -0
  243. package/dist/versioned/op.d.ts +62 -0
  244. package/dist/versioned/op.js +153 -0
  245. package/dist/versioned/op.js.map +1 -0
  246. package/dist/versioned/postgres/catalog.d.ts +33 -0
  247. package/dist/versioned/postgres/catalog.js +34 -0
  248. package/dist/versioned/postgres/catalog.js.map +1 -0
  249. package/dist/versioned/postgres/driver.d.ts +69 -0
  250. package/dist/versioned/postgres/driver.js +113 -0
  251. package/dist/versioned/postgres/driver.js.map +1 -0
  252. package/dist/versioned/postgres/executor.d.ts +104 -0
  253. package/dist/versioned/postgres/executor.js +172 -0
  254. package/dist/versioned/postgres/executor.js.map +1 -0
  255. package/dist/versioned/postgres/index.d.ts +11 -0
  256. package/dist/versioned/postgres/index.js +12 -0
  257. package/dist/versioned/postgres/index.js.map +1 -0
  258. package/dist/versioned/report.d.ts +22 -0
  259. package/dist/versioned/report.js +81 -0
  260. package/dist/versioned/report.js.map +1 -0
  261. package/dist/versioned/state.d.ts +108 -0
  262. package/dist/versioned/state.js +153 -0
  263. package/dist/versioned/state.js.map +1 -0
  264. package/package.json +51 -4
@@ -0,0 +1,167 @@
1
+ import { parseArgs } from "node:util";
2
+ import { guarded } from "../env-args.js";
3
+ import { loadProject, resolveEnvironment, YodelError } from "../project.js";
4
+ import { MigrationDirectoryError, refusedSteps, scanMigrations } from "../migrations/index.js";
5
+ import { closeVersioned, migrationsDir, openVersioned } from "../versioned/index.js";
6
+ import { planRebase, REBASE_REFUSED, writeRebase } from "../rebase/index.js";
7
+ const usage = "usage: yodel rebase [<id>] [--onto <parent-id>] [--env <env>]... [--force] [--json] [--dir <project>]";
8
+ const help = `${usage}
9
+
10
+ Moves a migration onto another parent and rewrites it, so two branches that
11
+ each added a migration can both merge. With no <id>, the directory's one
12
+ fork (two migrations that follow the same parent) is resolved: the newer of
13
+ the two (by the timestamp in its id) moves onto the end of the other's
14
+ branch. Name <id> to move another one, and --onto to choose its new parent.
15
+ Migrations that follow the moved one move with it.
16
+
17
+ Each moved migration's change (its recorded schema against its old
18
+ parent's) is applied to its new parent's recorded schema, giving its new
19
+ recorded schema; its statements are diffed again from the new parent's, and
20
+ its migration.sql, migration.json and checksum are written again. When both
21
+ branches change the same object, differently, nothing is written and the
22
+ object is named: resolve it by hand (delete the migration, then yodel new).
23
+ Each -- yodel:allow line is carried over to the same statement in the new
24
+ migration.sql; when that statement is gone or changed, nothing is written
25
+ and the line is named.
26
+ Offline: no database is read, except the histories --env names.
27
+
28
+ Ids do not change. The order is the chain of parent ids, not the ids'
29
+ timestamps, so a rebased migration runs after its new parent whatever its
30
+ timestamp says, and anything that names it still does.
31
+
32
+ Options:
33
+ --onto <id> the new parent (default: the end of the other branch)
34
+ --env <env> refuse if this environment's history records a migration
35
+ the rebase would rewrite; repeat for more environments.
36
+ Without it, no history is checked: never rebase a
37
+ migration that ran somewhere
38
+ --force rewrite migrations whose files were edited by hand (the
39
+ edits are dropped; well-formed -- yodel:allow lines are
40
+ still carried over)
41
+ --json print what was rewritten as JSON
42
+ -C, --dir <dir> the project directory (default: the working directory)
43
+
44
+ Exit codes:
45
+ 0 rebased, or no fork to rebase
46
+ 4 refused, nothing written: both branches change the same object, a
47
+ migration to rewrite was edited by hand (without --force), a
48
+ yodel:allow line's statement is gone or changed, a history records one
49
+ of them, or the moved migration adds nothing on its new parent
50
+ 1 the rebase could not be worked out: no such migration, a fork the
51
+ defaults cannot settle, a bad config, a server that does not answer
52
+ `;
53
+ function parseRebaseArgs(args) {
54
+ let parsed;
55
+ try {
56
+ parsed = parseArgs({
57
+ args,
58
+ allowPositionals: true,
59
+ strict: true,
60
+ options: {
61
+ onto: { type: "string" },
62
+ env: { type: "string", multiple: true },
63
+ force: { type: "boolean" },
64
+ json: { type: "boolean" },
65
+ dir: { type: "string", short: "C" },
66
+ },
67
+ });
68
+ }
69
+ catch (e) {
70
+ throw new YodelError(`${e instanceof Error ? e.message : String(e)}\n${usage}`);
71
+ }
72
+ const { values, positionals } = parsed;
73
+ if (positionals.length > 1)
74
+ throw new YodelError(usage);
75
+ const envs = Array.isArray(values.env) ? values.env.filter((e) => typeof e === "string") : [];
76
+ return {
77
+ id: positionals[0],
78
+ onto: typeof values.onto === "string" ? values.onto : undefined,
79
+ envs,
80
+ force: values.force === true,
81
+ json: values.json === true,
82
+ dir: typeof values.dir === "string" ? values.dir : process.cwd(),
83
+ };
84
+ }
85
+ /** Refuses when an environment's history names a migration the rebase would rewrite. */
86
+ async function checkHistories(project, envs, plan) {
87
+ for (const name of envs) {
88
+ const env = resolveEnvironment(project, name);
89
+ const venv = await openVersioned(project, env);
90
+ const state = await venv.store.state().finally(() => closeVersioned(venv));
91
+ const ran = plan.rewritten.flatMap((m) => {
92
+ const rec = state.byId.get(m.id);
93
+ return rec ? [`${m.id} (${rec.status === "succeeded" ? "applied" : `ran part way, ${rec.status}`})`] : [];
94
+ });
95
+ if (ran.length > 0) {
96
+ throw new YodelError(`refused: ${name}'s history records ${ran.join(", ")}. Nothing was written. A migration that ran is never rebased: ` +
97
+ `its statements already ran in that order. Rebase the other branch onto it instead (yodel rebase <the other> --onto <the end of this one>).`, REBASE_REFUSED);
98
+ }
99
+ }
100
+ }
101
+ function report(io, json, plan, envs) {
102
+ if (json) {
103
+ io.out(`${JSON.stringify({
104
+ rebased: true,
105
+ moved: plan.moved,
106
+ from: plan.from,
107
+ onto: plan.onto,
108
+ historiesChecked: envs,
109
+ rewritten: plan.rewritten.map((m) => ({
110
+ id: m.id,
111
+ path: m.dir,
112
+ oldParent: m.oldParent,
113
+ parent: m.parent,
114
+ oldChecksum: m.oldChecksum,
115
+ checksum: m.checksum,
116
+ statements: m.statements.steps.length - refusedSteps(m.statements.steps).length,
117
+ refused: m.statements.refused,
118
+ silences: m.silences.map((x) => ({ step: x.step, rule: x.rule, reason: x.reason, line: x.line })),
119
+ handEdited: m.handEdited,
120
+ })),
121
+ }, null, 2)}\n`);
122
+ return;
123
+ }
124
+ const lines = [`Rebased ${plan.moved} onto ${plan.onto} (it followed ${plan.from ?? "nothing"}).`];
125
+ for (const m of plan.rewritten) {
126
+ const n = m.statements.steps.length - refusedSteps(m.statements.steps).length;
127
+ lines.push(` ${m.id}: follows ${m.parent}; ${String(n)} statement${n === 1 ? "" : "s"}${m.statements.refused ? " and an Op or manual step" : ""}${m.silences.length > 0 ? `; ${String(m.silences.length)} yodel:allow line${m.silences.length === 1 ? "" : "s"} carried over` : ""}; checksum ${m.oldChecksum} -> ${m.checksum}`);
128
+ for (const h of m.statements.hints)
129
+ lines.push(` hint: ${h}`);
130
+ }
131
+ lines.push(envs.length > 0
132
+ ? `Checked against the history of ${envs.join(", ")}: none of them had run.`
133
+ : "No history was checked (--env): make sure none of these ran anywhere before merging.");
134
+ io.out(`${lines.join("\n")}\n`);
135
+ }
136
+ /** `yodel rebase`; the exit codes are in `help`. */
137
+ export const rebase = {
138
+ name: "rebase",
139
+ summary: "move a migration onto a new parent and recompute its schema",
140
+ implemented: true,
141
+ run: (args, io) => guarded("rebase", io, args, help, async () => {
142
+ const options = parseRebaseArgs(args);
143
+ const project = await loadProject(options.dir);
144
+ const scan = scanMigrations(migrationsDir(project));
145
+ const structural = scan.problems.filter((p) => p.kind === "unreadable" || p.kind === "id-mismatch" || p.kind === "missing-parent");
146
+ if (structural.length > 0)
147
+ throw new MigrationDirectoryError(scan.dir, structural);
148
+ const plan = planRebase(scan.migrations, { id: options.id, onto: options.onto });
149
+ if (plan.moved === undefined) {
150
+ if (options.json)
151
+ io.out(`${JSON.stringify({ rebased: false }, null, 2)}\n`);
152
+ else
153
+ io.out("No fork: every migration follows a different parent. Nothing to rebase.\n");
154
+ return 0;
155
+ }
156
+ const edited = plan.rewritten.filter((m) => m.handEdited);
157
+ if (edited.length > 0 && !options.force) {
158
+ throw new YodelError(`refused: ${edited.map((m) => m.id).join(", ")} ${edited.length === 1 ? "has" : "have"} files that differ from what yodel wrote (an edit by hand, or a checksum that no longer matches). ` +
159
+ `Rebasing writes them again from their recorded schema and drops that edit. Nothing was written; pass --force to rebase anyway, then make the edit again.`, REBASE_REFUSED);
160
+ }
161
+ await checkHistories(project, options.envs, plan);
162
+ writeRebase(plan);
163
+ report(io, options.json, plan, options.envs);
164
+ return 0;
165
+ }),
166
+ };
167
+ //# sourceMappingURL=rebase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebase.js","sourceRoot":"","sources":["../../src/commands/rebase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "../command.js";
2
+ /** `yodel repair <id> --reason ... <env>`; the exit codes are in `help`. */
3
+ export declare const repair: Command;
@@ -0,0 +1,117 @@
1
+ import { renameSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parseArgs } from "node:util";
4
+ import { guarded } from "../env-args.js";
5
+ import { loadProject, resolveEnvironment, YodelError } from "../project.js";
6
+ import { MIGRATION_JSON, scanMigrations, serializeDocument, verifyChecksum } from "../migrations/index.js";
7
+ import { appliedBy, newRunContext, withLock } from "../history/index.js";
8
+ import { closeVersioned, migrationsDir, openVersioned } from "../versioned/index.js";
9
+ import { checkRepair, repairRow } from "../rebase/repair.js";
10
+ const usage = 'usage: yodel repair <id> --reason "<text>" <env> [--json] [--dir <project>]';
11
+ const help = `${usage}
12
+
13
+ Records an intended edit to a migration that is already applied in <env>:
14
+ appends a row to the environment's history table (yodel.config.ts
15
+ history.database, else YODEL_HISTORY_DATABASE, default yodeler; on
16
+ Postgres the schema of that name) with the
17
+ checksum the migration's files have now and the reason, under the apply lock. After it, yodel status and yodel apply compare
18
+ the files with the new checksum. Nothing is run on the server: the edit is
19
+ recorded, not applied. Repair each environment the migration ran in.
20
+
21
+ When migration.json's own checksum field is stale too (it is not part of
22
+ what the checksum covers), it is written again to match.
23
+
24
+ Options:
25
+ --reason <text> why the files changed; required, and kept in the history
26
+ --json print the repair as JSON
27
+ -C, --dir <dir> the project directory (default: the working directory)
28
+
29
+ Exit codes:
30
+ 0 the new checksum is recorded
31
+ 4 refused, nothing written: the migration is not applied in <env> (not
32
+ run, or part way), its files already match the history, or it is gone
33
+ from the directory
34
+ 5 another apply holds the lock
35
+ 1 anything else: no --reason, a bad config, a server that does not answer
36
+ `;
37
+ function parseRepairArgs(args) {
38
+ let parsed;
39
+ try {
40
+ parsed = parseArgs({
41
+ args,
42
+ allowPositionals: true,
43
+ strict: true,
44
+ options: { reason: { type: "string" }, json: { type: "boolean" }, dir: { type: "string", short: "C" } },
45
+ });
46
+ }
47
+ catch (e) {
48
+ throw new YodelError(`${e instanceof Error ? e.message : String(e)}\n${usage}`);
49
+ }
50
+ const { values, positionals } = parsed;
51
+ const [id, env, ...rest] = positionals;
52
+ if (id === undefined || env === undefined || rest.length > 0)
53
+ throw new YodelError(usage);
54
+ const reason = typeof values.reason === "string" ? values.reason.trim() : "";
55
+ if (reason === "")
56
+ throw new YodelError(`a repair needs a reason: --reason "<why the files changed>"\n${usage}`);
57
+ return { id, env, reason, json: values.json === true, dir: typeof values.dir === "string" ? values.dir : process.cwd() };
58
+ }
59
+ /** Writes migration.json again with its checksum field matching its files, when it does not. Returns whether it wrote. */
60
+ function syncRecordedChecksum(m) {
61
+ const check = verifyChecksum(m);
62
+ if (check.ok)
63
+ return false;
64
+ const path = join(m.dir, MIGRATION_JSON);
65
+ const tmp = join(m.dir, `.${MIGRATION_JSON}.repairing`);
66
+ writeFileSync(tmp, serializeDocument({ ...JSON.parse(m.files.json), checksum: check.actual }));
67
+ renameSync(tmp, path);
68
+ return true;
69
+ }
70
+ /** `yodel repair <id> --reason ... <env>`; the exit codes are in `help`. */
71
+ export const repair = {
72
+ name: "repair",
73
+ summary: "record a new checksum for an applied migration, with a reason",
74
+ implemented: true,
75
+ run: (args, io) => guarded("repair", io, args, help, async () => {
76
+ const { id, env: name, reason, json, dir } = parseRepairArgs(args);
77
+ const project = await loadProject(dir);
78
+ const env = resolveEnvironment(project, name);
79
+ const m = scanMigrations(migrationsDir(project)).migrations.find((x) => x.id === id);
80
+ const venv = await openVersioned(project, env);
81
+ try {
82
+ return await repairWith(venv, m, { id, envName: env.name, reason, json, io });
83
+ }
84
+ finally {
85
+ await closeVersioned(venv);
86
+ }
87
+ }),
88
+ };
89
+ async function repairWith(venv, m, { id, envName, reason, json, io }) {
90
+ checkRepair(m, id, await venv.store.state(), envName); // refuse before taking the lock
91
+ const lock = await venv.driver.acquireLock(appliedBy());
92
+ if (lock.notice && !json)
93
+ io.err(`lock: ${lock.notice}\n`);
94
+ const row = await withLock(lock, venv.lockTtlMs, async () => {
95
+ const state = await venv.store.state();
96
+ const check = checkRepair(m, id, state, envName);
97
+ const r = repairRow({ migration: m, check, reason, run: newRunContext(check.record.planDigest), seq: state.maxSeq + 1 });
98
+ await venv.store.append([r]);
99
+ return { r, check };
100
+ });
101
+ const synced = syncRecordedChecksum(m);
102
+ if (json) {
103
+ io.out(`${JSON.stringify({ repaired: true, id, environment: envName, oldChecksum: row.check.oldChecksum, newChecksum: row.check.newChecksum, reason, seq: row.r.seq, runId: row.r.run_id, migrationJsonUpdated: synced }, null, 2)}\n`);
104
+ }
105
+ else {
106
+ io.out([
107
+ `Repaired ${id} in ${envName}'s history (${venv.location.database}).`,
108
+ ` old checksum: ${row.check.oldChecksum}`,
109
+ ` new checksum: ${row.check.newChecksum}`,
110
+ ` reason: ${reason}`,
111
+ ...(synced ? [` ${MIGRATION_JSON}'s checksum field updated to match`] : []),
112
+ "",
113
+ ].join("\n"));
114
+ }
115
+ return 0;
116
+ }
117
+ //# sourceMappingURL=repair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repair.js","sourceRoot":"","sources":["../../src/commands/repair.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Command } from "../command.js";
2
+ /** Exit code: migrations are pending, and nothing is wrong. */
3
+ export declare const STATUS_PENDING = 3;
4
+ /** Exit code: a checksum mismatch, an applied migration gone from the directory, or an out-of-order migration. */
5
+ export declare const STATUS_REFUSED = 4;
6
+ /** `yodel status <env>`; the exit codes are in `help`. */
7
+ export declare const status: Command;
@@ -0,0 +1,54 @@
1
+ import { guarded, parseEnvArgs, usage } from "../env-args.js";
2
+ import { loadProject, resolveEnvironment } from "../project.js";
3
+ import { readMigrations } from "../migrations/index.js";
4
+ import { closeVersioned, migrationsDir, openVersioned, renderStatus, statusJson, statusReport } from "../versioned/index.js";
5
+ /** Exit code: migrations are pending, and nothing is wrong. */
6
+ export const STATUS_PENDING = 3;
7
+ /** Exit code: a checksum mismatch, an applied migration gone from the directory, or an out-of-order migration. */
8
+ export const STATUS_REFUSED = 4;
9
+ const help = `${usage("status")}
10
+
11
+ Lists the environment's migrations against its history table
12
+ (yodel.config.ts history.database, else YODEL_HISTORY_DATABASE, default
13
+ yodeler) and its topology: applied, pending, out of order (pending, but before an applied migration in the chain), failed part way
14
+ (with the statement it resumes at), and checksum mismatches (an applied
15
+ migration whose files changed, or that is gone from the directory). When
16
+ yodel apply would run, prints the plan digest it would ask approval for.
17
+ Reads only; takes no lock.
18
+
19
+ Options:
20
+ --json print the status as JSON
21
+ -C, --dir <dir> the project directory (default: the working directory)
22
+
23
+ Exit codes:
24
+ 0 every migration is applied
25
+ 3 migrations are pending (failed part way included), and nothing is wrong
26
+ 4 a checksum mismatch, an applied migration gone from the directory, or an
27
+ out-of-order migration (apply refuses it without --allow-out-of-order)
28
+ 2 a pending migration has a manual step or an Op step yodel apply does not run
29
+ 1 the status could not be read: a bad config, a malformed migrations
30
+ directory, a server that does not answer
31
+ `;
32
+ /** `yodel status <env>`; the exit codes are in `help`. */
33
+ export const status = {
34
+ name: "status",
35
+ summary: "list applied, pending and out-of-order migrations",
36
+ implemented: true,
37
+ run: (args, io) => guarded("status", io, args, help, async () => {
38
+ const { env: name, json, dir } = parseEnvArgs("status", args);
39
+ const project = await loadProject(dir);
40
+ const env = resolveEnvironment(project, name);
41
+ const ordered = readMigrations(migrationsDir(project));
42
+ const venv = await openVersioned(project, env);
43
+ const report = await statusReport(venv, ordered, { sync: false }).finally(() => closeVersioned(venv));
44
+ if (json)
45
+ io.out(`${JSON.stringify(statusJson(report), null, 2)}\n`);
46
+ // The sections already say what is wrong; the refusal's wording is apply's.
47
+ else
48
+ io.out(renderStatus({ ...report, refusal: undefined }));
49
+ if (report.refusal)
50
+ return report.refusal.exitCode;
51
+ return report.status.pending.length > 0 ? STATUS_PENDING : 0;
52
+ }),
53
+ };
54
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE7H,+DAA+D;AAC/D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAChC,kHAAkH;AAClH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,MAAM,IAAI,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;CAsB9B,CAAC;AAEF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,mDAAmD;IAC5D,WAAW,EAAE,IAAI;IACjB,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAChB,OAAO,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QACtG,IAAI,IAAI;YAAE,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACrE,4EAA4E;;YACvE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAC7D,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;QACnD,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC;CACL,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * `yodel.config.ts`: what yodel needs per environment that chant's
3
+ * `chant.config.ts` does not say. Optional; a project without one runs on
4
+ * the defaults below.
5
+ *
6
+ * ```ts
7
+ * // yodel.config.ts
8
+ * import { defineConfig } from "@intentius/sql-yodeler";
9
+ *
10
+ * export default defineConfig({
11
+ * environments: {
12
+ * dev: { topology: "single" },
13
+ * prod: { topology: "cluster:main", history: { database: "yodeler" }, lockTtl: 1800 },
14
+ * },
15
+ * });
16
+ * ```
17
+ */
18
+ import type { Topology } from "@intentius/chant-lexicon-sql/clickhouse/topology";
19
+ export type { Topology };
20
+ /**
21
+ * A ClickHouse topology in its string form (`single`, `cluster:<name>`,
22
+ * `replicated`, `replicated:<cluster>`, `cloud`) or chant's object form,
23
+ * which also sets a cluster's Keeper path and replica name for the tables
24
+ * the migrations create.
25
+ */
26
+ export type TopologySetting = string | Topology;
27
+ export interface EnvironmentConfig {
28
+ /**
29
+ * The ClickHouse topology this environment runs. Every statement of every
30
+ * migration is rendered for it when it is sent (`ON CLUSTER`, the
31
+ * replicated engine), and the history table's engine follows it.
32
+ * Default: `sql.profiles.<env>.topology` in chant.config.ts, then
33
+ * `YODEL_TOPOLOGY`, then `single`.
34
+ */
35
+ topology?: TopologySetting;
36
+ history?: {
37
+ /** The database the history and lock tables live in. Default: `YODEL_HISTORY_DATABASE`, then `yodeler`. */
38
+ database?: string;
39
+ };
40
+ /** The apply lock's TTL, in seconds. Default: `YODEL_LOCK_TTL`, then 900. */
41
+ lockTtl?: number;
42
+ }
43
+ export interface YodelConfig {
44
+ /** Keyed by the environment's name in `sql.profiles`. */
45
+ environments?: Record<string, EnvironmentConfig>;
46
+ /** Reserved for `yodel lint`'s rule levels. */
47
+ lint?: Record<string, unknown>;
48
+ }
49
+ /** Returns `config` as is; it types the default export of `yodel.config.ts`. */
50
+ export declare const defineConfig: (config: YodelConfig) => YodelConfig;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `yodel.config.ts`: what yodel needs per environment that chant's
3
+ * `chant.config.ts` does not say. Optional; a project without one runs on
4
+ * the defaults below.
5
+ *
6
+ * ```ts
7
+ * // yodel.config.ts
8
+ * import { defineConfig } from "@intentius/sql-yodeler";
9
+ *
10
+ * export default defineConfig({
11
+ * environments: {
12
+ * dev: { topology: "single" },
13
+ * prod: { topology: "cluster:main", history: { database: "yodeler" }, lockTtl: 1800 },
14
+ * },
15
+ * });
16
+ * ```
17
+ */
18
+ /** Returns `config` as is; it types the default export of `yodel.config.ts`. */
19
+ export const defineConfig = (config) => config;
20
+ //# sourceMappingURL=define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/config/define.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAsCH,gFAAgF;AAChF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAmB,EAAe,EAAE,CAAC,MAAM,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `yodel.config.ts` (#9): per-environment settings chant.config.ts does not
3
+ * hold, the ClickHouse topology first.
4
+ *
5
+ * defineConfig({ environments: { <env>: { topology, history, lockTtl } } })
6
+ * loadYodelConfig(dir, profiles) the file, checked; undefined when there is none
7
+ * environmentSettings(project, env) topology, history database, lock TTL, with their fallbacks
8
+ */
9
+ export * from "./define.js";
10
+ export * from "./load.js";
11
+ export * from "./settings.js";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `yodel.config.ts` (#9): per-environment settings chant.config.ts does not
3
+ * hold, the ClickHouse topology first.
4
+ *
5
+ * defineConfig({ environments: { <env>: { topology, history, lockTtl } } })
6
+ * loadYodelConfig(dir, profiles) the file, checked; undefined when there is none
7
+ * environmentSettings(project, env) topology, history database, lock TTL, with their fallbacks
8
+ */
9
+ export * from "./define.js";
10
+ export * from "./load.js";
11
+ export * from "./settings.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Finding, loading and checking `yodel.config.ts`. The file is optional; a
3
+ * project without one gets `undefined` and every setting's default.
4
+ */
5
+ import type { YodelConfig } from "./define.js";
6
+ export declare const CONFIG_FILE = "yodel.config.ts";
7
+ /**
8
+ * Checks a loaded config's shape. `environments` names each environment by
9
+ * its `sql.profiles` name; one that chant.config.ts does not declare is an
10
+ * error, so a typo does not silently leave an environment on the defaults.
11
+ */
12
+ export declare function checkYodelConfig(value: unknown, path: string, profiles?: readonly string[]): YodelConfig;
13
+ /** Loads `<dir>/yodel.config.ts`, or `undefined` when there is none. */
14
+ export declare function loadYodelConfig(dir: string, profiles?: readonly string[]): Promise<{
15
+ path: string;
16
+ config: YodelConfig;
17
+ } | undefined>;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Finding, loading and checking `yodel.config.ts`. The file is optional; a
3
+ * project without one gets `undefined` and every setting's default.
4
+ */
5
+ import { existsSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { pathToFileURL } from "node:url";
8
+ import { parseTopology } from "@intentius/chant-lexicon-sql/clickhouse/topology";
9
+ import { YodelError } from "../project.js";
10
+ export const CONFIG_FILE = "yodel.config.ts";
11
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
12
+ const TOPOLOGY_KINDS = ["single", "cluster", "replicated", "cloud"];
13
+ function checkTopology(value, where) {
14
+ if (typeof value === "string") {
15
+ try {
16
+ parseTopology(value);
17
+ }
18
+ catch (e) {
19
+ throw new YodelError(`${where}: ${e instanceof Error ? e.message : String(e)}`);
20
+ }
21
+ return;
22
+ }
23
+ if (!isRecord(value) || typeof value.kind !== "string" || !TOPOLOGY_KINDS.includes(value.kind)) {
24
+ throw new YodelError(`${where}: expected single, cluster:<name>, replicated, replicated:<cluster>, cloud, or { kind: ... }`);
25
+ }
26
+ const allowed = { single: [], cloud: [], replicated: ["cluster"], cluster: ["cluster", "replicaPath", "replicaName"] };
27
+ for (const [k, v] of Object.entries(value)) {
28
+ if (k === "kind")
29
+ continue;
30
+ if (!(allowed[value.kind] ?? []).includes(k))
31
+ throw new YodelError(`${where}.${k}: a ${value.kind} topology takes no ${k}`);
32
+ if (typeof v !== "string" || v === "")
33
+ throw new YodelError(`${where}.${k}: expected a non-empty string`);
34
+ }
35
+ if (value.kind === "cluster" && typeof value.cluster !== "string")
36
+ throw new YodelError(`${where}.cluster: a cluster topology needs the cluster's name`);
37
+ }
38
+ function checkEnvironment(value, where) {
39
+ if (!isRecord(value))
40
+ throw new YodelError(`${where}: expected an object`);
41
+ for (const k of Object.keys(value)) {
42
+ if (!["topology", "history", "lockTtl"].includes(k))
43
+ throw new YodelError(`${where}.${k}: unknown setting (expected topology, history, lockTtl)`);
44
+ }
45
+ if (value.topology !== undefined)
46
+ checkTopology(value.topology, `${where}.topology`);
47
+ if (value.history !== undefined) {
48
+ if (!isRecord(value.history))
49
+ throw new YodelError(`${where}.history: expected an object`);
50
+ for (const k of Object.keys(value.history))
51
+ if (k !== "database")
52
+ throw new YodelError(`${where}.history.${k}: unknown setting (expected database)`);
53
+ const db = value.history.database;
54
+ if (db !== undefined && (typeof db !== "string" || db === ""))
55
+ throw new YodelError(`${where}.history.database: expected a database name`);
56
+ }
57
+ if (value.lockTtl !== undefined && !(typeof value.lockTtl === "number" && Number.isFinite(value.lockTtl) && value.lockTtl > 0)) {
58
+ throw new YodelError(`${where}.lockTtl: expected a number of seconds greater than 0`);
59
+ }
60
+ return value;
61
+ }
62
+ /**
63
+ * Checks a loaded config's shape. `environments` names each environment by
64
+ * its `sql.profiles` name; one that chant.config.ts does not declare is an
65
+ * error, so a typo does not silently leave an environment on the defaults.
66
+ */
67
+ export function checkYodelConfig(value, path, profiles) {
68
+ if (!isRecord(value))
69
+ throw new YodelError(`${path}: the default export must be a config object (export default defineConfig({ ... }))`);
70
+ for (const k of Object.keys(value)) {
71
+ if (k !== "environments" && k !== "lint")
72
+ throw new YodelError(`${path}: unknown setting ${k} (expected environments, lint)`);
73
+ }
74
+ if (value.lint !== undefined && !isRecord(value.lint))
75
+ throw new YodelError(`${path}: lint: expected an object`);
76
+ if (value.environments !== undefined) {
77
+ if (!isRecord(value.environments))
78
+ throw new YodelError(`${path}: environments: expected an object keyed by environment`);
79
+ for (const [name, env] of Object.entries(value.environments)) {
80
+ checkEnvironment(env, `${path}: environments.${name}`);
81
+ if (profiles && !profiles.includes(name)) {
82
+ throw new YodelError(`${path}: environments.${name} is not an environment chant.config.ts declares` + (profiles.length > 0 ? ` (sql.profiles: ${profiles.join(", ")})` : " (it declares no sql.profiles)"));
83
+ }
84
+ }
85
+ }
86
+ return value;
87
+ }
88
+ /** Loads `<dir>/yodel.config.ts`, or `undefined` when there is none. */
89
+ export async function loadYodelConfig(dir, profiles) {
90
+ const path = join(dir, CONFIG_FILE);
91
+ if (!existsSync(path))
92
+ return undefined;
93
+ let mod;
94
+ try {
95
+ mod = (await import(pathToFileURL(path).href));
96
+ }
97
+ catch (e) {
98
+ throw new YodelError(`${path}: ${e instanceof Error ? e.message : String(e)}`);
99
+ }
100
+ return { path, config: checkYodelConfig(mod.default, path, profiles) };
101
+ }
102
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"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"}