@intentius/sql-yodeler 0.0.0-stage → 0.2.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 (324) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +112 -2
  3. package/dist/bin.d.ts +2 -0
  4. package/dist/bin.js +29 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/chant/apply.d.ts +59 -0
  7. package/dist/chant/apply.js +116 -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 +112 -0
  13. package/dist/chant/drift.js +238 -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/chant/runnable.d.ts +19 -0
  22. package/dist/chant/runnable.js +47 -0
  23. package/dist/chant/runnable.js.map +1 -0
  24. package/dist/cli.d.ts +8 -0
  25. package/dist/cli.js +99 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/command.d.ts +23 -0
  28. package/dist/command.js +13 -0
  29. package/dist/command.js.map +1 -0
  30. package/dist/commands/apply.d.ts +3 -0
  31. package/dist/commands/apply.js +426 -0
  32. package/dist/commands/apply.js.map +1 -0
  33. package/dist/commands/approve.d.ts +5 -0
  34. package/dist/commands/approve.js +111 -0
  35. package/dist/commands/approve.js.map +1 -0
  36. package/dist/commands/drift.d.ts +14 -0
  37. package/dist/commands/drift.js +267 -0
  38. package/dist/commands/drift.js.map +1 -0
  39. package/dist/commands/index.d.ts +3 -0
  40. package/dist/commands/index.js +28 -0
  41. package/dist/commands/index.js.map +1 -0
  42. package/dist/commands/init.d.ts +6 -0
  43. package/dist/commands/init.js +139 -0
  44. package/dist/commands/init.js.map +1 -0
  45. package/dist/commands/lint.d.ts +3 -0
  46. package/dist/commands/lint.js +202 -0
  47. package/dist/commands/lint.js.map +1 -0
  48. package/dist/commands/mcp.d.ts +3 -0
  49. package/dist/commands/mcp.js +50 -0
  50. package/dist/commands/mcp.js.map +1 -0
  51. package/dist/commands/new.d.ts +5 -0
  52. package/dist/commands/new.js +292 -0
  53. package/dist/commands/new.js.map +1 -0
  54. package/dist/commands/override.d.ts +3 -0
  55. package/dist/commands/override.js +118 -0
  56. package/dist/commands/override.js.map +1 -0
  57. package/dist/commands/plan.d.ts +3 -0
  58. package/dist/commands/plan.js +183 -0
  59. package/dist/commands/plan.js.map +1 -0
  60. package/dist/commands/rebase.d.ts +3 -0
  61. package/dist/commands/rebase.js +167 -0
  62. package/dist/commands/rebase.js.map +1 -0
  63. package/dist/commands/repair.d.ts +14 -0
  64. package/dist/commands/repair.js +125 -0
  65. package/dist/commands/repair.js.map +1 -0
  66. package/dist/commands/status.d.ts +7 -0
  67. package/dist/commands/status.js +54 -0
  68. package/dist/commands/status.js.map +1 -0
  69. package/dist/config/define.d.ts +148 -0
  70. package/dist/config/define.js +20 -0
  71. package/dist/config/define.js.map +1 -0
  72. package/dist/config/index.d.ts +11 -0
  73. package/dist/config/index.js +12 -0
  74. package/dist/config/index.js.map +1 -0
  75. package/dist/config/load.d.ts +17 -0
  76. package/dist/config/load.js +162 -0
  77. package/dist/config/load.js.map +1 -0
  78. package/dist/config/settings.d.ts +53 -0
  79. package/dist/config/settings.js +116 -0
  80. package/dist/config/settings.js.map +1 -0
  81. package/dist/env-args.d.ts +24 -0
  82. package/dist/env-args.js +92 -0
  83. package/dist/env-args.js.map +1 -0
  84. package/dist/exit.d.ts +20 -0
  85. package/dist/exit.js +28 -0
  86. package/dist/exit.js.map +1 -0
  87. package/dist/history/client.d.ts +25 -0
  88. package/dist/history/client.js +42 -0
  89. package/dist/history/client.js.map +1 -0
  90. package/dist/history/ddl.d.ts +58 -0
  91. package/dist/history/ddl.js +100 -0
  92. package/dist/history/ddl.js.map +1 -0
  93. package/dist/history/index.d.ts +25 -0
  94. package/dist/history/index.js +26 -0
  95. package/dist/history/index.js.map +1 -0
  96. package/dist/history/lock.d.ts +104 -0
  97. package/dist/history/lock.js +230 -0
  98. package/dist/history/lock.js.map +1 -0
  99. package/dist/history/postgres/ddl.d.ts +22 -0
  100. package/dist/history/postgres/ddl.js +47 -0
  101. package/dist/history/postgres/ddl.js.map +1 -0
  102. package/dist/history/postgres/index.d.ts +12 -0
  103. package/dist/history/postgres/index.js +13 -0
  104. package/dist/history/postgres/index.js.map +1 -0
  105. package/dist/history/postgres/lock.d.ts +48 -0
  106. package/dist/history/postgres/lock.js +95 -0
  107. package/dist/history/postgres/lock.js.map +1 -0
  108. package/dist/history/postgres/store.d.ts +39 -0
  109. package/dist/history/postgres/store.js +68 -0
  110. package/dist/history/postgres/store.js.map +1 -0
  111. package/dist/history/rows.d.ts +96 -0
  112. package/dist/history/rows.js +73 -0
  113. package/dist/history/rows.js.map +1 -0
  114. package/dist/history/store.d.ts +72 -0
  115. package/dist/history/store.js +134 -0
  116. package/dist/history/store.js.map +1 -0
  117. package/dist/history/topology.d.ts +41 -0
  118. package/dist/history/topology.js +54 -0
  119. package/dist/history/topology.js.map +1 -0
  120. package/dist/index.d.ts +10 -0
  121. package/dist/index.js +10 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/init/adopt.d.ts +70 -0
  124. package/dist/init/adopt.js +143 -0
  125. package/dist/init/adopt.js.map +1 -0
  126. package/dist/init/baseline.d.ts +61 -0
  127. package/dist/init/baseline.js +88 -0
  128. package/dist/init/baseline.js.map +1 -0
  129. package/dist/init/files.d.ts +23 -0
  130. package/dist/init/files.js +77 -0
  131. package/dist/init/files.js.map +1 -0
  132. package/dist/init/index.d.ts +16 -0
  133. package/dist/init/index.js +17 -0
  134. package/dist/init/index.js.map +1 -0
  135. package/dist/init/live.d.ts +39 -0
  136. package/dist/init/live.js +68 -0
  137. package/dist/init/live.js.map +1 -0
  138. package/dist/lint/check.d.ts +88 -0
  139. package/dist/lint/check.js +227 -0
  140. package/dist/lint/check.js.map +1 -0
  141. package/dist/lint/config.d.ts +21 -0
  142. package/dist/lint/config.js +43 -0
  143. package/dist/lint/config.js.map +1 -0
  144. package/dist/lint/index.d.ts +31 -0
  145. package/dist/lint/index.js +43 -0
  146. package/dist/lint/index.js.map +1 -0
  147. package/dist/lint/project-rules.d.ts +19 -0
  148. package/dist/lint/project-rules.js +32 -0
  149. package/dist/lint/project-rules.js.map +1 -0
  150. package/dist/lint/report.d.ts +7 -0
  151. package/dist/lint/report.js +48 -0
  152. package/dist/lint/report.js.map +1 -0
  153. package/dist/lint/rules.d.ts +53 -0
  154. package/dist/lint/rules.js +42 -0
  155. package/dist/lint/rules.js.map +1 -0
  156. package/dist/lint/silences.d.ts +49 -0
  157. package/dist/lint/silences.js +91 -0
  158. package/dist/lint/silences.js.map +1 -0
  159. package/dist/lint/statements.d.ts +38 -0
  160. package/dist/lint/statements.js +120 -0
  161. package/dist/lint/statements.js.map +1 -0
  162. package/dist/mcp/server.d.ts +40 -0
  163. package/dist/mcp/server.js +106 -0
  164. package/dist/mcp/server.js.map +1 -0
  165. package/dist/mcp/tools.d.ts +72 -0
  166. package/dist/mcp/tools.js +178 -0
  167. package/dist/mcp/tools.js.map +1 -0
  168. package/dist/migrations/checks.d.ts +28 -0
  169. package/dist/migrations/checks.js +97 -0
  170. package/dist/migrations/checks.js.map +1 -0
  171. package/dist/migrations/checksum.d.ts +56 -0
  172. package/dist/migrations/checksum.js +72 -0
  173. package/dist/migrations/checksum.js.map +1 -0
  174. package/dist/migrations/create.d.ts +75 -0
  175. package/dist/migrations/create.js +120 -0
  176. package/dist/migrations/create.js.map +1 -0
  177. package/dist/migrations/directory.d.ts +119 -0
  178. package/dist/migrations/directory.js +229 -0
  179. package/dist/migrations/directory.js.map +1 -0
  180. package/dist/migrations/document.d.ts +106 -0
  181. package/dist/migrations/document.js +83 -0
  182. package/dist/migrations/document.js.map +1 -0
  183. package/dist/migrations/index.d.ts +21 -0
  184. package/dist/migrations/index.js +22 -0
  185. package/dist/migrations/index.js.map +1 -0
  186. package/dist/pr/comment.d.ts +32 -0
  187. package/dist/pr/comment.js +99 -0
  188. package/dist/pr/comment.js.map +1 -0
  189. package/dist/pr/forge.d.ts +54 -0
  190. package/dist/pr/forge.js +119 -0
  191. package/dist/pr/forge.js.map +1 -0
  192. package/dist/pr/issue.d.ts +68 -0
  193. package/dist/pr/issue.js +107 -0
  194. package/dist/pr/issue.js.map +1 -0
  195. package/dist/pr/model.d.ts +99 -0
  196. package/dist/pr/model.js +137 -0
  197. package/dist/pr/model.js.map +1 -0
  198. package/dist/pr/render.d.ts +29 -0
  199. package/dist/pr/render.js +279 -0
  200. package/dist/pr/render.js.map +1 -0
  201. package/dist/project.d.ts +62 -0
  202. package/dist/project.js +92 -0
  203. package/dist/project.js.map +1 -0
  204. package/dist/rebase/index.d.ts +121 -0
  205. package/dist/rebase/index.js +390 -0
  206. package/dist/rebase/index.js.map +1 -0
  207. package/dist/rebase/repair.d.ts +41 -0
  208. package/dist/rebase/repair.js +68 -0
  209. package/dist/rebase/repair.js.map +1 -0
  210. package/dist/replay/clickhouse.d.ts +33 -0
  211. package/dist/replay/clickhouse.js +106 -0
  212. package/dist/replay/clickhouse.js.map +1 -0
  213. package/dist/replay/index.d.ts +39 -0
  214. package/dist/replay/index.js +57 -0
  215. package/dist/replay/index.js.map +1 -0
  216. package/dist/replay/postgres.d.ts +31 -0
  217. package/dist/replay/postgres.js +140 -0
  218. package/dist/replay/postgres.js.map +1 -0
  219. package/dist/replay/replay.d.ts +114 -0
  220. package/dist/replay/replay.js +98 -0
  221. package/dist/replay/replay.js.map +1 -0
  222. package/dist/replay/report.d.ts +18 -0
  223. package/dist/replay/report.js +72 -0
  224. package/dist/replay/report.js.map +1 -0
  225. package/dist/replay/shared.d.ts +28 -0
  226. package/dist/replay/shared.js +77 -0
  227. package/dist/replay/shared.js.map +1 -0
  228. package/dist/schemas.d.ts +34 -0
  229. package/dist/schemas.js +38 -0
  230. package/dist/schemas.js.map +1 -0
  231. package/dist/server.d.ts +40 -0
  232. package/dist/server.js +87 -0
  233. package/dist/server.js.map +1 -0
  234. package/dist/steps/backfill.d.ts +132 -0
  235. package/dist/steps/backfill.js +307 -0
  236. package/dist/steps/backfill.js.map +1 -0
  237. package/dist/steps/index.d.ts +52 -0
  238. package/dist/steps/index.js +52 -0
  239. package/dist/steps/index.js.map +1 -0
  240. package/dist/steps/kinds.d.ts +101 -0
  241. package/dist/steps/kinds.js +143 -0
  242. package/dist/steps/kinds.js.map +1 -0
  243. package/dist/steps/postgres-migration.d.ts +95 -0
  244. package/dist/steps/postgres-migration.js +149 -0
  245. package/dist/steps/postgres-migration.js.map +1 -0
  246. package/dist/steps/rebuild.d.ts +97 -0
  247. package/dist/steps/rebuild.js +155 -0
  248. package/dist/steps/rebuild.js.map +1 -0
  249. package/dist/steps/run.d.ts +45 -0
  250. package/dist/steps/run.js +72 -0
  251. package/dist/steps/run.js.map +1 -0
  252. package/dist/topology/render.d.ts +17 -0
  253. package/dist/topology/render.js +17 -0
  254. package/dist/topology/render.js.map +1 -0
  255. package/dist/version.d.ts +2 -0
  256. package/dist/version.js +11 -0
  257. package/dist/version.js.map +1 -0
  258. package/dist/versioned/approval.d.ts +35 -0
  259. package/dist/versioned/approval.js +53 -0
  260. package/dist/versioned/approval.js.map +1 -0
  261. package/dist/versioned/checks.d.ts +29 -0
  262. package/dist/versioned/checks.js +54 -0
  263. package/dist/versioned/checks.js.map +1 -0
  264. package/dist/versioned/clickhouse.d.ts +24 -0
  265. package/dist/versioned/clickhouse.js +42 -0
  266. package/dist/versioned/clickhouse.js.map +1 -0
  267. package/dist/versioned/digest.d.ts +77 -0
  268. package/dist/versioned/digest.js +69 -0
  269. package/dist/versioned/digest.js.map +1 -0
  270. package/dist/versioned/driver.d.ts +51 -0
  271. package/dist/versioned/driver.js +13 -0
  272. package/dist/versioned/driver.js.map +1 -0
  273. package/dist/versioned/engine.d.ts +206 -0
  274. package/dist/versioned/engine.js +370 -0
  275. package/dist/versioned/engine.js.map +1 -0
  276. package/dist/versioned/explain.d.ts +123 -0
  277. package/dist/versioned/explain.js +294 -0
  278. package/dist/versioned/explain.js.map +1 -0
  279. package/dist/versioned/index.d.ts +46 -0
  280. package/dist/versioned/index.js +77 -0
  281. package/dist/versioned/index.js.map +1 -0
  282. package/dist/versioned/op.d.ts +72 -0
  283. package/dist/versioned/op.js +185 -0
  284. package/dist/versioned/op.js.map +1 -0
  285. package/dist/versioned/policy.d.ts +67 -0
  286. package/dist/versioned/policy.js +161 -0
  287. package/dist/versioned/policy.js.map +1 -0
  288. package/dist/versioned/postgres/catalog.d.ts +33 -0
  289. package/dist/versioned/postgres/catalog.js +34 -0
  290. package/dist/versioned/postgres/catalog.js.map +1 -0
  291. package/dist/versioned/postgres/driver.d.ts +71 -0
  292. package/dist/versioned/postgres/driver.js +140 -0
  293. package/dist/versioned/postgres/driver.js.map +1 -0
  294. package/dist/versioned/postgres/executor.d.ts +104 -0
  295. package/dist/versioned/postgres/executor.js +172 -0
  296. package/dist/versioned/postgres/executor.js.map +1 -0
  297. package/dist/versioned/postgres/index.d.ts +11 -0
  298. package/dist/versioned/postgres/index.js +12 -0
  299. package/dist/versioned/postgres/index.js.map +1 -0
  300. package/dist/versioned/postgres/waits.d.ts +46 -0
  301. package/dist/versioned/postgres/waits.js +78 -0
  302. package/dist/versioned/postgres/waits.js.map +1 -0
  303. package/dist/versioned/report.d.ts +25 -0
  304. package/dist/versioned/report.js +84 -0
  305. package/dist/versioned/report.js.map +1 -0
  306. package/dist/versioned/stand-down.d.ts +30 -0
  307. package/dist/versioned/stand-down.js +56 -0
  308. package/dist/versioned/stand-down.js.map +1 -0
  309. package/dist/versioned/state.d.ts +108 -0
  310. package/dist/versioned/state.js +153 -0
  311. package/dist/versioned/state.js.map +1 -0
  312. package/package.json +61 -4
  313. package/schemas/apply.schema.json +269 -0
  314. package/schemas/common.schema.json +213 -0
  315. package/schemas/drift.schema.json +36 -0
  316. package/schemas/init.schema.json +31 -0
  317. package/schemas/lint-rules.schema.json +54 -0
  318. package/schemas/lint.schema.json +290 -0
  319. package/schemas/mcp.schema.json +70 -0
  320. package/schemas/new.schema.json +71 -0
  321. package/schemas/plan.schema.json +371 -0
  322. package/schemas/rebase.schema.json +54 -0
  323. package/schemas/repair.schema.json +20 -0
  324. package/schemas/status.schema.json +310 -0
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The replay check's result for people (text) and for tools (JSON), and its
3
+ * exit code.
4
+ */
5
+ import { type ReplayChange, type ReplayResult } from "./replay.js";
6
+ /** 0 when every migration replays to its recorded schema; 1 for a difference or a statement the server refused; 2 for a step the replay cannot run. */
7
+ export declare function replayExitCode(result: ReplayResult): number;
8
+ /** One difference: the object, the field, and the replay's value against the record's. */
9
+ export declare function describeChange(c: ReplayChange): string;
10
+ /** The failure in one paragraph, naming the first migration that fails; `undefined` when the replay matched. For `yodel lint`. */
11
+ export declare function replayFailure(result: ReplayResult): {
12
+ migration: string;
13
+ message: string;
14
+ } | undefined;
15
+ /** The result as text. */
16
+ export declare function renderReplay(result: ReplayResult): string;
17
+ /** The result as JSON. */
18
+ export declare function replayJson(result: ReplayResult): Record<string, unknown>;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The replay check's result for people (text) and for tools (JSON), and its
3
+ * exit code.
4
+ */
5
+ import { MIGRATIONS_DIR, MIGRATION_JSON, MIGRATION_SQL } from "../migrations/index.js";
6
+ import { UNREPLAYABLE } from "./replay.js";
7
+ /** 0 when every migration replays to its recorded schema; 1 for a difference or a statement the server refused; 2 for a step the replay cannot run. */
8
+ export function replayExitCode(result) {
9
+ if (result.outcome === "matches")
10
+ return 0;
11
+ if (result.outcome === "unreplayable")
12
+ return UNREPLAYABLE;
13
+ return 1;
14
+ }
15
+ const shown = (v) => (v === undefined ? "(absent)" : v);
16
+ /** One difference: the object, the field, and the replay's value against the record's. */
17
+ export function describeChange(c) {
18
+ return `${c.object}: ${c.field}: replay has ${shown(c.before)}, ${MIGRATION_JSON} records ${shown(c.after)} (${c.rule})`;
19
+ }
20
+ /** The failure in one paragraph, naming the first migration that fails; `undefined` when the replay matched. For `yodel lint`. */
21
+ export function replayFailure(result) {
22
+ const before = result.matched.length > 0 ? ` The ${String(result.matched.length)} migration${result.matched.length === 1 ? "" : "s"} before it replayed to ${result.matched.length === 1 ? "its" : "their"} recorded schema${result.matched.length === 1 ? "" : "s"}.` : "";
23
+ switch (result.outcome) {
24
+ case "matches":
25
+ return undefined;
26
+ case "differs": {
27
+ const m = result.migration;
28
+ const n = result.changes.length;
29
+ const skipped = m.skipped.length > 0 ? `\nSteps not replayed: ${m.skipped.join("; ")}.` : "";
30
+ return {
31
+ migration: m.id,
32
+ message: `${m.id}: replaying the history through it does not give the schema it records (${MIGRATIONS_DIR}/${m.id}/${MIGRATION_JSON}); ${String(n)} difference${n === 1 ? "" : "s"}:\n` +
33
+ result.changes.map((c) => ` ${describeChange(c)}`).join("\n") +
34
+ `\n${before.trim() ? `${before.trim()}\n` : ""}` +
35
+ `Its statements (the steps in ${MIGRATION_JSON}, which ${MIGRATION_SQL} shows) and its recorded schema disagree: make the statements produce the schema, or record the schema they produce, then yodel repair the migration where it is already applied.${skipped}`,
36
+ };
37
+ }
38
+ case "failed":
39
+ return {
40
+ migration: result.migration,
41
+ message: `${result.migration}: statement ${String(result.step)} failed in the replay: ${result.error}.${before} The history does not apply to an empty database as written.`,
42
+ };
43
+ case "unreplayable":
44
+ return {
45
+ migration: result.migration,
46
+ message: `${result.migration}: step ${String(result.step)} cannot be replayed: ${result.reason}.${before} The migrations from it on are not checked.`,
47
+ };
48
+ }
49
+ }
50
+ /** The result as text. */
51
+ export function renderReplay(result) {
52
+ const lines = [`Replay of ${String(result.total)} migration${result.total === 1 ? "" : "s"} (${result.dialect}) into ${result.where}`];
53
+ if (result.scope.length > 0)
54
+ lines.push(` ${result.dialect === "postgres" ? "schemas" : "databases"}: ${result.scope.join(", ")}${result.reset ? " (emptied first)" : ""}${result.kept ? " (left in place)" : ""}`);
55
+ for (const m of result.matched) {
56
+ const extra = [...m.ran.map((r) => `ran ${r}`), ...m.skipped.map((s) => `skipped ${s}`)];
57
+ lines.push(` ok ${m.id} (${String(m.statements)} statement${m.statements === 1 ? "" : "s"}${extra.length > 0 ? `; ${extra.join("; ")}` : ""})`);
58
+ }
59
+ const failure = replayFailure(result);
60
+ if (!failure) {
61
+ lines.push(result.total === 0 ? "No migrations to replay." : "Every migration replays to its recorded schema.");
62
+ return `${lines.join("\n")}\n`;
63
+ }
64
+ lines.push(` ${result.outcome.padEnd(7)} ${failure.migration}`, "", failure.message);
65
+ return `${lines.join("\n")}\n`;
66
+ }
67
+ /** The result as JSON. */
68
+ export function replayJson(result) {
69
+ const failure = replayFailure(result);
70
+ return { ...result, ok: result.outcome === "matches", ...(failure ? { message: failure.message } : {}) };
71
+ }
72
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/replay/report.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,YAAY,EAAwC,MAAM,aAAa,CAAC;AAEjF,uJAAuJ;AACvJ,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,OAAO,KAAK,cAAc;QAAE,OAAO,YAAY,CAAC;IAC3D,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,CAAqB,EAAU,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpF,0FAA0F;AAC1F,MAAM,UAAU,cAAc,CAAC,CAAe;IAC5C,OAAO,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,gBAAgB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,cAAc,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC;AAC3H,CAAC;AAED,kIAAkI;AAClI,MAAM,UAAU,aAAa,CAAC,MAAoB;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,0BAA0B,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,mBAAmB,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5Q,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC;YAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YAChC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7F,OAAO;gBACL,SAAS,EAAE,CAAC,CAAC,EAAE;gBACf,OAAO,EACL,GAAG,CAAC,CAAC,EAAE,2EAA2E,cAAc,IAAI,CAAC,CAAC,EAAE,IAAI,cAAc,MAAM,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK;oBAC9K,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;oBAC9D,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;oBAChD,gCAAgC,cAAc,WAAW,aAAa,oLAAoL,OAAO,EAAE;aACtQ,CAAC;QACJ,CAAC;QACD,KAAK,QAAQ;YACX,OAAO;gBACL,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,OAAO,EAAE,GAAG,MAAM,CAAC,SAAS,eAAe,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,MAAM,CAAC,KAAK,IAAI,MAAM,8DAA8D;aAC7K,CAAC;QACJ,KAAK,cAAc;YACjB,OAAO;gBACL,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,OAAO,EAAE,GAAG,MAAM,CAAC,SAAS,UAAU,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,MAAM,CAAC,MAAM,IAAI,MAAM,6CAA6C;aACtJ,CAAC;IACN,CAAC;AACH,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,MAAM,KAAK,GAAG,CAAC,aAAa,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACvI,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrN,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QACzF,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACxJ,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,iDAAiD,CAAC,CAAC;QAChH,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACtF,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC3G,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The replay empties every database (ClickHouse) or schema (Postgres) the
3
+ * history names on the server its profile binds. When another profile binds
4
+ * the same server and names one of those too (locally, `dev` and `replay`
5
+ * both on the emulator at 127.0.0.1), the replay would drop that profile's
6
+ * database: the one just applied to. So it refuses, naming the profile,
7
+ * even with `--reset`, unless that profile is named with
8
+ * `--reset-shared <profile>` (#12).
9
+ *
10
+ * Only profiles that resolve are compared: one whose credentials are not set
11
+ * in this shell (a CI job that holds only the replay server's) binds no
12
+ * server here, and the replay cannot reach its data through it.
13
+ */
14
+ import { type Environment, type Project } from "../project.js";
15
+ /** Another profile the replay would empty part of. */
16
+ export interface SharedProfile {
17
+ profile: string;
18
+ /** `host:port` (ClickHouse) or `host:port/database` (Postgres). */
19
+ server: string;
20
+ /** The databases or schemas both name. */
21
+ names: string[];
22
+ }
23
+ /** A server URL as a comparable key: loopback names folded together, the default port filled in, no credentials. */
24
+ export declare function serverKey(dialect: Project["dialect"], url: string): string;
25
+ /** The other profiles on `env`'s server that name one of `scope`, the databases or schemas the replay empties. */
26
+ export declare function sharedProfiles(project: Project, env: Environment, scope: readonly string[], processEnv?: NodeJS.ProcessEnv): Promise<SharedProfile[]>;
27
+ /** Refuses a replay that would empty another profile's databases, unless each such profile is named in `allowed`. */
28
+ export declare function refuseShared(env: Environment, shared: readonly SharedProfile[], allowed: readonly string[], dialect: Project["dialect"]): void;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The replay empties every database (ClickHouse) or schema (Postgres) the
3
+ * history names on the server its profile binds. When another profile binds
4
+ * the same server and names one of those too (locally, `dev` and `replay`
5
+ * both on the emulator at 127.0.0.1), the replay would drop that profile's
6
+ * database: the one just applied to. So it refuses, naming the profile,
7
+ * even with `--reset`, unless that profile is named with
8
+ * `--reset-shared <profile>` (#12).
9
+ *
10
+ * Only profiles that resolve are compared: one whose credentials are not set
11
+ * in this shell (a CI job that holds only the replay server's) binds no
12
+ * server here, and the replay cannot reach its data through it.
13
+ */
14
+ import { YodelError } from "../project.js";
15
+ import { environmentSettings } from "../config/settings.js";
16
+ import { NOT_FRESH } from "./replay.js";
17
+ const LOOPBACK = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
18
+ /** A server URL as a comparable key: loopback names folded together, the default port filled in, no credentials. */
19
+ export function serverKey(dialect, url) {
20
+ let u;
21
+ try {
22
+ u = new URL(url);
23
+ }
24
+ catch {
25
+ return url;
26
+ }
27
+ const host = LOOPBACK.has(u.hostname) ? "127.0.0.1" : u.hostname.toLowerCase();
28
+ if (dialect === "postgres")
29
+ return `${host}:${u.port || "5432"}/${decodeURIComponent(u.pathname.replace(/^\/+/, "")) || "postgres"}`;
30
+ return `${host}:${u.port || (u.protocol === "https:" ? "8443" : "8123")}`;
31
+ }
32
+ async function bind(project, name, processEnv) {
33
+ if (project.dialect === "postgres") {
34
+ const { resolvePostgresTarget, isUnresolvedTarget } = await import("@intentius/chant-lexicon-sql/postgres/live/bind");
35
+ const t = resolvePostgresTarget({ environment: name, config: project.config, env: processEnv });
36
+ if (isUnresolvedTarget(t) || !t.source.startsWith("sql.profiles."))
37
+ return undefined;
38
+ return { key: serverKey("postgres", t.endpoint.url), names: t.schemas };
39
+ }
40
+ const { resolveClickHouseTarget, isUnresolvedTarget } = await import("@intentius/chant-lexicon-sql/clickhouse/live/bind");
41
+ const t = resolveClickHouseTarget({ environment: name, config: project.config, env: processEnv });
42
+ if (isUnresolvedTarget(t) || !t.source.startsWith("sql.profiles."))
43
+ return undefined;
44
+ return { key: serverKey("clickhouse", t.endpoint.url), names: t.databases };
45
+ }
46
+ /** The other profiles on `env`'s server that name one of `scope`, the databases or schemas the replay empties. */
47
+ export async function sharedProfiles(project, env, scope, processEnv = process.env) {
48
+ const profiles = Object.keys(project.config.sql?.profiles ?? {});
49
+ const own = await bind(project, env.name, processEnv);
50
+ if (!own)
51
+ return [];
52
+ const shared = [];
53
+ for (const other of profiles) {
54
+ if (other === env.name)
55
+ continue;
56
+ const b = await bind(project, other, processEnv).catch(() => undefined);
57
+ if (!b || b.key !== own.key)
58
+ continue;
59
+ const history = environmentSettings(project, other, processEnv).historyDatabase;
60
+ const theirs = b.names === undefined ? undefined : new Set([...b.names, history]);
61
+ const names = scope.filter((s) => theirs === undefined || theirs.has(s));
62
+ if (names.length > 0)
63
+ shared.push({ profile: other, server: own.key, names });
64
+ }
65
+ return shared;
66
+ }
67
+ /** Refuses a replay that would empty another profile's databases, unless each such profile is named in `allowed`. */
68
+ export function refuseShared(env, shared, allowed, dialect) {
69
+ const blocking = shared.filter((s) => !allowed.includes(s.profile));
70
+ if (blocking.length === 0)
71
+ return;
72
+ const what = dialect === "postgres" ? "schema" : "database";
73
+ const lines = blocking.map((s) => `${env.name} and ${s.profile} are the same server (${s.server}) and both name ${s.names.join(", ")}; the replay would drop ${s.profile}'s ${what}${s.names.length === 1 ? "" : "s"}, with or without --reset`);
74
+ throw new YodelError(`refused: ${lines.join("; ")}. Point ${env.name} at a throwaway server of its own (a second emulator on another port), ` +
75
+ `or, to empty ${blocking.map((s) => s.profile).join(" and ")} too, add ${blocking.map((s) => `--reset-shared ${s.profile}`).join(" ")}. Nothing was run.`, NOT_FRESH);
76
+ }
77
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/replay/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The JSON Schemas of `yodel <command> --json` and of `yodel mcp`'s tool
3
+ * results. They are written beside the code, in `schemas/` at the package
4
+ * root, and ship in the package; the docs site serves them at their `$id`.
5
+ * test/schemas.test.ts validates each command's output against its schema.
6
+ *
7
+ * Within a version a schema only gains fields, and a reader ignores fields it
8
+ * does not know. Removing a field or changing what one means is a new version:
9
+ * a new `v<N>/` in every `$id`, and {@link SCHEMA_VERSION} moves with it.
10
+ */
11
+ export declare const SCHEMA_VERSION = 1;
12
+ /** Where the schemas are published; each `$id` is this plus `<name>.schema.json`. */
13
+ export declare const SCHEMA_BASE: string;
14
+ /** `schemas/` in the package: src/ and dist/ are both one level below it. */
15
+ export declare const schemasDir: string;
16
+ /** The schema of each command's `--json` output, by the command line that prints it. */
17
+ export declare const COMMAND_SCHEMAS: {
18
+ readonly init: "init";
19
+ readonly plan: "plan";
20
+ readonly apply: "apply";
21
+ readonly new: "new";
22
+ readonly lint: "lint";
23
+ readonly "lint --rules": "lint-rules";
24
+ readonly status: "status";
25
+ readonly drift: "drift";
26
+ readonly rebase: "rebase";
27
+ readonly repair: "repair";
28
+ };
29
+ /** Every schema file: the commands', the definitions they share, and the MCP tool results. */
30
+ export declare const SCHEMA_NAMES: readonly ["common", ...("lint" | "plan" | "status" | "apply" | "drift" | "init" | "new" | "lint-rules" | "rebase" | "repair")[], "mcp"];
31
+ export type SchemaName = (typeof SCHEMA_NAMES)[number];
32
+ export declare const schemaId: (name: SchemaName) => string;
33
+ /** A schema as the package ships it. */
34
+ export declare function readSchema(name: SchemaName): Record<string, unknown>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The JSON Schemas of `yodel <command> --json` and of `yodel mcp`'s tool
3
+ * results. They are written beside the code, in `schemas/` at the package
4
+ * root, and ship in the package; the docs site serves them at their `$id`.
5
+ * test/schemas.test.ts validates each command's output against its schema.
6
+ *
7
+ * Within a version a schema only gains fields, and a reader ignores fields it
8
+ * does not know. Removing a field or changing what one means is a new version:
9
+ * a new `v<N>/` in every `$id`, and {@link SCHEMA_VERSION} moves with it.
10
+ */
11
+ import { readFileSync } from "node:fs";
12
+ import { fileURLToPath } from "node:url";
13
+ export const SCHEMA_VERSION = 1;
14
+ /** Where the schemas are published; each `$id` is this plus `<name>.schema.json`. */
15
+ export const SCHEMA_BASE = `https://intentius.io/sql-yodeler/schemas/v${String(SCHEMA_VERSION)}/`;
16
+ /** `schemas/` in the package: src/ and dist/ are both one level below it. */
17
+ export const schemasDir = fileURLToPath(new URL("../schemas/", import.meta.url));
18
+ /** The schema of each command's `--json` output, by the command line that prints it. */
19
+ export const COMMAND_SCHEMAS = {
20
+ init: "init",
21
+ plan: "plan",
22
+ apply: "apply",
23
+ new: "new",
24
+ lint: "lint",
25
+ "lint --rules": "lint-rules",
26
+ status: "status",
27
+ drift: "drift",
28
+ rebase: "rebase",
29
+ repair: "repair",
30
+ };
31
+ /** Every schema file: the commands', the definitions they share, and the MCP tool results. */
32
+ export const SCHEMA_NAMES = ["common", ...Object.values(COMMAND_SCHEMAS), "mcp"];
33
+ export const schemaId = (name) => `${SCHEMA_BASE}${name}.schema.json`;
34
+ /** A schema as the package ships it. */
35
+ export function readSchema(name) {
36
+ return JSON.parse(readFileSync(`${schemasDir}${name}.schema.json`, "utf8"));
37
+ }
38
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,qFAAqF;AACrF,MAAM,CAAC,MAAM,WAAW,GAAG,6CAA6C,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC;AAElG,6EAA6E;AAC7E,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEjF,wFAAwF;AACxF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;IACZ,cAAc,EAAE,YAAY;IAC5B,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;CACR,CAAC;AAEX,8FAA8F;AAC9F,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,KAAK,CAAU,CAAC;AAI1F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAgB,EAAU,EAAE,CAAC,GAAG,WAAW,GAAG,IAAI,cAAc,CAAC;AAE1F,wCAAwC;AACxC,MAAM,UAAU,UAAU,CAAC,IAAgB;IACzC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,UAAU,GAAG,IAAI,cAAc,EAAE,MAAM,CAAC,CAA4B,CAAC;AACzG,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Which server a command reached, for the first line of its output (#11):
3
+ * `postgres 16.14 at 127.0.0.1:5432/postgres`. A wrong target (a native
4
+ * Postgres on localhost:5432 instead of the emulator) then shows in the
5
+ * header, by its address and its version.
6
+ *
7
+ * The address comes from the profile's URL, without credentials; the
8
+ * version is asked of the server. A server that does not answer the version
9
+ * query still gets its address.
10
+ */
11
+ import type { Environment, Project, SqlDialect } from "./project.js";
12
+ export interface ServerInfo {
13
+ dialect: SqlDialect;
14
+ /** `host:port/database` on Postgres, `host:port` on ClickHouse. */
15
+ address: string;
16
+ /** The server's own version string, first word: `16.14`, `25.3.2.39`. */
17
+ version?: string | undefined;
18
+ }
19
+ /** `postgres 16.14 at 127.0.0.1:5432/postgres`. */
20
+ export declare function describeServer(s: ServerInfo): string;
21
+ /** `host:port/database` (Postgres) or `host:port` (ClickHouse) from a server URL, with no credentials. */
22
+ export declare function serverAddress(dialect: SqlDialect, url: string): string;
23
+ /** The first word of a version string: `16.14 (Homebrew)` is `16.14`. */
24
+ export declare const versionWord: (v: unknown) => string | undefined;
25
+ /** Asks a Postgres connection its version. */
26
+ export declare function postgresVersion(client: {
27
+ query<T>(sql: string): Promise<T[]>;
28
+ }): Promise<string | undefined>;
29
+ /** Asks a ClickHouse server its version. */
30
+ export declare function clickhouseVersion(port: {
31
+ query<T>(sql: string): Promise<T[]>;
32
+ }): Promise<string | undefined>;
33
+ /** Runs `probe`, giving up quietly: the header is worth a line, not a failure. */
34
+ export declare function softly<T>(probe: () => Promise<T>): Promise<T | undefined>;
35
+ /**
36
+ * The server `sql.profiles.<env>` binds, with its version when it answers,
37
+ * for a command that does not hold its own connection (the declarative plan
38
+ * and apply, drift). Undefined when the profile binds no server.
39
+ */
40
+ export declare function probeServer(project: Project, env: Environment, processEnv?: NodeJS.ProcessEnv): Promise<ServerInfo | undefined>;
package/dist/server.js ADDED
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Which server a command reached, for the first line of its output (#11):
3
+ * `postgres 16.14 at 127.0.0.1:5432/postgres`. A wrong target (a native
4
+ * Postgres on localhost:5432 instead of the emulator) then shows in the
5
+ * header, by its address and its version.
6
+ *
7
+ * The address comes from the profile's URL, without credentials; the
8
+ * version is asked of the server. A server that does not answer the version
9
+ * query still gets its address.
10
+ */
11
+ /** `postgres 16.14 at 127.0.0.1:5432/postgres`. */
12
+ export function describeServer(s) {
13
+ return `${s.dialect}${s.version ? ` ${s.version}` : ""} at ${s.address}`;
14
+ }
15
+ /** `host:port/database` (Postgres) or `host:port` (ClickHouse) from a server URL, with no credentials. */
16
+ export function serverAddress(dialect, url) {
17
+ let u;
18
+ try {
19
+ u = new URL(url);
20
+ }
21
+ catch {
22
+ return url.replace(/\/\/[^@/]*@/, "//");
23
+ }
24
+ if (dialect === "postgres") {
25
+ const port = u.port || "5432";
26
+ const db = decodeURIComponent(u.pathname.replace(/^\/+/, "")) || "postgres";
27
+ return `${u.hostname}:${port}/${db}`;
28
+ }
29
+ const port = u.port || (u.protocol === "https:" ? "8443" : "8123");
30
+ return `${u.hostname}:${port}`;
31
+ }
32
+ /** The first word of a version string: `16.14 (Homebrew)` is `16.14`. */
33
+ export const versionWord = (v) => (typeof v === "string" && v.trim() ? v.trim().split(/\s+/)[0] : undefined);
34
+ /** Asks a Postgres connection its version. */
35
+ export async function postgresVersion(client) {
36
+ const rows = await client.query("SHOW server_version");
37
+ return versionWord(rows[0]?.server_version);
38
+ }
39
+ /** Asks a ClickHouse server its version. */
40
+ export async function clickhouseVersion(port) {
41
+ const rows = await port.query("SELECT version() AS version");
42
+ return versionWord(rows[0]?.version);
43
+ }
44
+ /** Runs `probe`, giving up quietly: the header is worth a line, not a failure. */
45
+ export async function softly(probe) {
46
+ try {
47
+ return await probe();
48
+ }
49
+ catch {
50
+ return undefined;
51
+ }
52
+ }
53
+ /**
54
+ * The server `sql.profiles.<env>` binds, with its version when it answers,
55
+ * for a command that does not hold its own connection (the declarative plan
56
+ * and apply, drift). Undefined when the profile binds no server.
57
+ */
58
+ export async function probeServer(project, env, processEnv = process.env) {
59
+ return softly(async () => {
60
+ if (project.dialect === "postgres") {
61
+ const { resolvePostgresTarget, isUnresolvedTarget } = await import("@intentius/chant-lexicon-sql/postgres/live/bind");
62
+ const target = resolvePostgresTarget({ environment: env.name, config: project.config, env: processEnv });
63
+ if (isUnresolvedTarget(target))
64
+ return undefined;
65
+ const info = { dialect: "postgres", address: serverAddress("postgres", target.endpoint.url) };
66
+ const { connectPostgres } = await import("@intentius/chant-lexicon-sql/postgres/live/client");
67
+ const client = await softly(() => connectPostgres(target.endpoint, { applicationName: "yodel" }));
68
+ if (client) {
69
+ try {
70
+ info.version = await softly(() => postgresVersion(client));
71
+ }
72
+ finally {
73
+ await client.end();
74
+ }
75
+ }
76
+ return info;
77
+ }
78
+ const { resolveClickHouseTarget, isUnresolvedTarget } = await import("@intentius/chant-lexicon-sql/clickhouse/live/bind");
79
+ const target = resolveClickHouseTarget({ environment: env.name, config: project.config, env: processEnv });
80
+ if (isUnresolvedTarget(target))
81
+ return undefined;
82
+ const { httpPort } = await import("./history/client.js");
83
+ const port = await httpPort(target.endpoint);
84
+ return { dialect: "clickhouse", address: serverAddress("clickhouse", target.endpoint.url), version: await softly(() => clickhouseVersion(port)) };
85
+ });
86
+ }
87
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * A backfill step: a data migration the author writes, run inside the
3
+ * migration between the statements around it, resumable from receipts.
4
+ *
5
+ * The step names a module in the migration's directory (`backfill.ts` by
6
+ * default) that exports a chant Op as `op` (or as its default export). Each
7
+ * step of its phases is an `effect()` step: one batch of the backfill, with
8
+ * its own receipt. The nested steps run SQL on the environment's server with
9
+ * the `yodelSql` activity yodel provides, or any activity chant has:
10
+ *
11
+ * import { EffectReceipt } from "@intentius/chant";
12
+ * import { Op, activity, effect, phase } from "@intentius/chant/op";
13
+ *
14
+ * const months = ["202601", "202602", "202603"];
15
+ * const batch = (m: string) =>
16
+ * effect(EffectReceipt(`country-${m}`, { effect: `country/${m}`, flavor: "existence" }), [
17
+ * activity("yodelSql", { sql: `ALTER TABLE shop.orders UPDATE country = ... WHERE toYYYYMM(ts) = ${m}` }, "atMostOnce"),
18
+ * ]);
19
+ *
20
+ * export const op = Op({ name: "backfill-country", overview: "...", phases: [phase("Backfill", months.map(batch))] });
21
+ *
22
+ * How a run goes is chant's `effect()` cycle, run by chant's local executor:
23
+ * for each batch, read its receipt; skip the batch when the receipt is there
24
+ * (an earlier run finished it); otherwise run its steps and write the
25
+ * receipt last, only when they all succeeded. A run that fails or is killed
26
+ * part way leaves the finished batches' receipts, so the next `yodel apply`
27
+ * resumes at the first batch without one and never redoes a finished one.
28
+ * A batch that was running when it stopped runs again: make each batch safe
29
+ * to repeat (an idempotent `UPDATE`, or a delete of its rows before the
30
+ * insert), as the rebuild's backfill does per partition.
31
+ *
32
+ * The receipts are rows on the environment's server, kept by the sql
33
+ * lexicon's receipt store (`sqlReceiptStore`), addressed
34
+ * `yodel/<env>/<migration id>/<effect>`, so the same effect name in two
35
+ * migrations is two receipts:
36
+ *
37
+ * - ClickHouse: `chant_receipts.receipts` (the table `ClickHouseRebuildOp`
38
+ * keeps its partition receipts in).
39
+ * - Postgres: `<history schema>.__chant_receipts`, in the schema yodel's
40
+ * history is in, over the apply's connection. Each batch runs in one
41
+ * transaction on that connection, and its receipt is written last
42
+ * inside it: the batch's statements and its receipt commit together or
43
+ * not at all, so a run killed anywhere leaves no batch half done, and a
44
+ * resumed backfill runs no batch twice. A batch's statements must be ones
45
+ * Postgres runs in a transaction block (no `CREATE INDEX CONCURRENTLY`,
46
+ * no `VACUUM`). The environment's `lockTimeoutMs` and `scanTimeoutMs` are
47
+ * the batch's `lock_timeout` and `statement_timeout`, and `yodelSql`'s
48
+ * `settings` are set for the batch's transaction (`set_config(..., true)`).
49
+ *
50
+ * The module is one of the migration's own files: it counts in the
51
+ * migration's checksum, so the plan digest an approval binds covers it, and
52
+ * an edit after it ran is a checksum mismatch. It is imported from the
53
+ * migration's directory, so it imports packages only (no relative imports).
54
+ * Its Op has no gates (the migration's gate approves it).
55
+ */
56
+ import type { OpConfig } from "@intentius/chant/op/types";
57
+ import type { SqlDialect } from "@intentius/chant-lexicon-sql/dialects";
58
+ import type { ClickHouseEndpoint } from "@intentius/chant-lexicon-sql/clickhouse/http";
59
+ import type { ReceiptStore } from "@intentius/chant/op/receipt-store";
60
+ import type { StepRecord } from "@intentius/chant/op/local-executor";
61
+ import type { ClickHousePort } from "../history/index.js";
62
+ import type { PgClient } from "../history/postgres/index.js";
63
+ import type { PgTimeouts } from "../versioned/postgres/executor.js";
64
+ import { type RunOpOptions } from "./run.js";
65
+ import { type BackfillStep } from "./kinds.js";
66
+ /** The activity a backfill's steps run SQL with: `activity("yodelSql", { sql, settings? })`. */
67
+ export declare const SQL_ACTIVITY = "yodelSql";
68
+ /** The step `yodel new --backfill` adds to a migration. */
69
+ export declare function backfillStep(migrationName: string, file?: string): BackfillStep;
70
+ /** Text only the template holds: a backfill still carrying it has not been written. */
71
+ export declare const TEMPLATE_MARK = "write the backfill of";
72
+ /** What `yodel new --backfill <file>` writes at `<file>` when there is none yet. */
73
+ export declare function backfillTemplate(name: string, dialect?: SqlDialect): string;
74
+ /** The Op config a module exports as `op` or as its default export. */
75
+ export declare function exportedOp(mod: Record<string, unknown>): OpConfig | undefined;
76
+ /** What is wrong with a backfill's Op, if anything: every phase step is an effect() step, and there are no gates. */
77
+ export declare function backfillProblems(config: OpConfig): string[];
78
+ /** Imports a backfill module and returns its Op, or throws naming what is wrong. `text` busts the import cache when the file changed. */
79
+ export declare function loadBackfill(path: string, text?: string): Promise<OpConfig>;
80
+ export interface BackfillSummary {
81
+ op: "backfill";
82
+ file: string;
83
+ /** The Op's name. */
84
+ name: string;
85
+ /** Batches (effect steps) the Op has. */
86
+ effects: number;
87
+ /** Batches skipped: their receipt was there (an earlier run finished them). */
88
+ skipped: number;
89
+ /** Batches run, and their receipt written, in this run. */
90
+ ran: number;
91
+ }
92
+ /** A receipt store whose every effect is under `prefix`, so receipts of different migrations never meet. */
93
+ export declare function prefixedStore(store: ReceiptStore, prefix: string): ReceiptStore;
94
+ /** Where a backfill's receipts are kept: the environment's ClickHouse server, or the apply's Postgres connection and the schema to keep them in. */
95
+ export type ReceiptServer = {
96
+ clickhouse: ClickHouseEndpoint;
97
+ } | {
98
+ postgres: PgClient;
99
+ schema: string;
100
+ };
101
+ /**
102
+ * The sql lexicon's receipt store on the environment's server, under the
103
+ * stack `yodel`. On Postgres it writes over the apply's connection (so a
104
+ * receipt written inside a batch's transaction commits with it, and the
105
+ * store never closes it), and the table is made here, before any batch's
106
+ * transaction opens.
107
+ */
108
+ export declare function serverReceipts(server: ReceiptServer, environment: string): Promise<ReceiptStore>;
109
+ /** A backfill on Postgres: the connection its batches run on, and the environment's timeouts. */
110
+ export interface PgBackfillServer {
111
+ client: PgClient;
112
+ timeouts: Pick<PgTimeouts, "lockTimeoutMs" | "scanTimeoutMs">;
113
+ }
114
+ export interface RunBackfillOptions extends Omit<RunOpOptions, "activities" | "cwd"> {
115
+ projectDir: string;
116
+ migrationId: string;
117
+ /** The migration's directory. */
118
+ dir: string;
119
+ /** The module's text as the migration read it (and checksummed). */
120
+ text?: string | undefined;
121
+ /** The ClickHouse server the SQL runs on; or `postgres`. */
122
+ port?: ClickHousePort | undefined;
123
+ /** The Postgres server the SQL runs on, a transaction per batch; or `port`. */
124
+ postgres?: PgBackfillServer | undefined;
125
+ receipts: ReceiptStore;
126
+ log?: (line: string) => void;
127
+ }
128
+ /** Runs a backfill step to the end, counting batches as they skip or finish. */
129
+ export declare function runBackfill(file: string, run: RunBackfillOptions): Promise<{
130
+ summary: BackfillSummary;
131
+ records: StepRecord[];
132
+ }>;