@intentius/chant-lexicon-sql 0.124.46 → 0.124.48

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 (360) hide show
  1. package/dist/change-set.d.ts +1 -1
  2. package/dist/change-set.d.ts.map +1 -1
  3. package/dist/change-set.js +2 -1
  4. package/dist/clickhouse/apply/statements.d.ts +9 -0
  5. package/dist/clickhouse/apply/statements.d.ts.map +1 -1
  6. package/dist/clickhouse/apply/statements.js +24 -0
  7. package/dist/clickhouse/import/live-export.d.ts +7 -3
  8. package/dist/clickhouse/import/live-export.d.ts.map +1 -1
  9. package/dist/clickhouse/import/live-export.js +21 -5
  10. package/dist/clickhouse/live/named-collections.d.ts +27 -0
  11. package/dist/clickhouse/live/named-collections.d.ts.map +1 -0
  12. package/dist/clickhouse/live/named-collections.js +53 -0
  13. package/dist/clickhouse/live/undeclarable.d.ts +15 -3
  14. package/dist/clickhouse/live/undeclarable.d.ts.map +1 -1
  15. package/dist/clickhouse/live/undeclarable.js +18 -4
  16. package/dist/clickhouse/named-collections.d.ts +83 -0
  17. package/dist/clickhouse/named-collections.d.ts.map +1 -0
  18. package/dist/clickhouse/named-collections.js +203 -0
  19. package/dist/clickhouse/parser.d.ts.map +1 -1
  20. package/dist/clickhouse/parser.js +1 -1
  21. package/dist/clickhouse/plan/commands.d.ts +2 -1
  22. package/dist/clickhouse/plan/commands.d.ts.map +1 -1
  23. package/dist/clickhouse/plan/commands.js +17 -2
  24. package/dist/clickhouse/plan/diff.d.ts +15 -0
  25. package/dist/clickhouse/plan/diff.d.ts.map +1 -1
  26. package/dist/clickhouse/plan/diff.js +43 -1
  27. package/dist/clickhouse/plan/disruption.d.ts.map +1 -1
  28. package/dist/clickhouse/plan/disruption.js +5 -0
  29. package/dist/clickhouse/plan/rebuild-handoff.d.ts.map +1 -1
  30. package/dist/clickhouse/plan/rebuild-handoff.js +4 -0
  31. package/dist/clickhouse/plan/report.d.ts.map +1 -1
  32. package/dist/clickhouse/plan/report.js +6 -1
  33. package/dist/clickhouse/plan/rules.d.ts +5 -1
  34. package/dist/clickhouse/plan/rules.d.ts.map +1 -1
  35. package/dist/clickhouse/plan/rules.js +7 -3
  36. package/dist/clickhouse/plan/stream.d.ts +40 -0
  37. package/dist/clickhouse/plan/stream.d.ts.map +1 -0
  38. package/dist/clickhouse/plan/stream.js +107 -0
  39. package/dist/clickhouse/rebuild/observe.d.ts +3 -1
  40. package/dist/clickhouse/rebuild/observe.d.ts.map +1 -1
  41. package/dist/clickhouse/rebuild/observe.js +14 -1
  42. package/dist/clickhouse/review-catalog.d.ts +213 -0
  43. package/dist/clickhouse/review-catalog.d.ts.map +1 -0
  44. package/dist/clickhouse/review-catalog.js +330 -0
  45. package/dist/codegen/classifier-page.d.ts.map +1 -1
  46. package/dist/codegen/classifier-page.js +21 -4
  47. package/dist/codegen/clickhouse-module.d.ts.map +1 -1
  48. package/dist/codegen/clickhouse-module.js +3 -0
  49. package/dist/codegen/coverage-page.d.ts.map +1 -1
  50. package/dist/codegen/coverage-page.js +5 -3
  51. package/dist/codegen/docs.js +1 -1
  52. package/dist/codegen/postgres-classifier-page.js +1 -1
  53. package/dist/codegen/registry.d.ts.map +1 -1
  54. package/dist/codegen/registry.js +5 -0
  55. package/dist/composites/catalog.d.ts.map +1 -1
  56. package/dist/composites/catalog.js +100 -0
  57. package/dist/composites/clickhouse.d.ts +2 -0
  58. package/dist/composites/clickhouse.d.ts.map +1 -1
  59. package/dist/composites/clickhouse.js +2 -0
  60. package/dist/composites/otel-tables.d.ts +100 -0
  61. package/dist/composites/otel-tables.d.ts.map +1 -0
  62. package/dist/composites/otel-tables.js +282 -0
  63. package/dist/composites/stream-ingest.d.ts +63 -0
  64. package/dist/composites/stream-ingest.d.ts.map +1 -0
  65. package/dist/composites/stream-ingest.js +39 -0
  66. package/dist/coverage/clickhouse.json +1 -1
  67. package/dist/coverage/postgres.json +7 -7
  68. package/dist/coverage.d.ts +16 -6
  69. package/dist/coverage.d.ts.map +1 -1
  70. package/dist/coverage.js +10 -5
  71. package/dist/drizzle-command.d.ts +17 -0
  72. package/dist/drizzle-command.d.ts.map +1 -0
  73. package/dist/drizzle-command.js +91 -0
  74. package/dist/drizzle.d.ts +70 -0
  75. package/dist/drizzle.d.ts.map +1 -0
  76. package/dist/drizzle.js +684 -0
  77. package/dist/files/clickhouse.d.ts.map +1 -1
  78. package/dist/files/clickhouse.js +8 -1
  79. package/dist/files/common.d.ts +13 -0
  80. package/dist/files/common.d.ts.map +1 -1
  81. package/dist/files/common.js +5 -0
  82. package/dist/files/postgres.js +12 -2
  83. package/dist/generated/clickhouse.d.ts +2 -0
  84. package/dist/generated/clickhouse.d.ts.map +1 -1
  85. package/dist/generated/clickhouse.js +2 -0
  86. package/dist/import-parser.d.ts +21 -1
  87. package/dist/import-parser.d.ts.map +1 -1
  88. package/dist/import-parser.js +79 -5
  89. package/dist/index.d.ts +1 -1
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +1 -1
  92. package/dist/integrity.json +6 -5
  93. package/dist/lint/post-synth/audit-entries.d.ts.map +1 -1
  94. package/dist/lint/post-synth/audit-entries.js +1 -0
  95. package/dist/lint/post-synth/index.d.ts.map +1 -1
  96. package/dist/lint/post-synth/index.js +2 -0
  97. package/dist/lint/post-synth/sqlch128.d.ts +18 -0
  98. package/dist/lint/post-synth/sqlch128.d.ts.map +1 -0
  99. package/dist/lint/post-synth/sqlch128.js +222 -0
  100. package/dist/lint/rules/postgres-templates.js +2 -2
  101. package/dist/lsp/postgres-template.d.ts.map +1 -1
  102. package/dist/lsp/postgres-template.js +11 -0
  103. package/dist/manifest.json +1 -1
  104. package/dist/mcp/postgres.js +1 -1
  105. package/dist/meta.json +25 -0
  106. package/dist/migrate/from-postgres/detect.d.ts +4 -0
  107. package/dist/migrate/from-postgres/detect.d.ts.map +1 -0
  108. package/dist/migrate/from-postgres/detect.js +7 -0
  109. package/dist/migrate/from-postgres/emit.d.ts +26 -0
  110. package/dist/migrate/from-postgres/emit.d.ts.map +1 -0
  111. package/dist/migrate/from-postgres/emit.js +86 -0
  112. package/dist/migrate/from-postgres/index.d.ts +51 -0
  113. package/dist/migrate/from-postgres/index.d.ts.map +1 -0
  114. package/dist/migrate/from-postgres/index.js +115 -0
  115. package/dist/migrate/from-postgres/translate.d.ts +73 -0
  116. package/dist/migrate/from-postgres/translate.d.ts.map +1 -0
  117. package/dist/migrate/from-postgres/translate.js +261 -0
  118. package/dist/migrate/from-postgres/types.d.ts +51 -0
  119. package/dist/migrate/from-postgres/types.d.ts.map +1 -0
  120. package/dist/migrate/from-postgres/types.js +211 -0
  121. package/dist/migration-replay.d.ts +73 -0
  122. package/dist/migration-replay.d.ts.map +1 -0
  123. package/dist/migration-replay.js +294 -0
  124. package/dist/okf/index.md +6 -0
  125. package/dist/okf/rules/SQLCH128.md +11 -0
  126. package/dist/okf/types/PostgresForeignDataWrapper.md +9 -0
  127. package/dist/okf/types/PostgresForeignServer.md +9 -0
  128. package/dist/okf/types/PostgresOperator.md +9 -0
  129. package/dist/okf/types/PostgresPublication.md +9 -0
  130. package/dist/okf/types/PostgresStatistics.md +9 -0
  131. package/dist/op/activities/postgres-migration.d.ts.map +1 -1
  132. package/dist/op/activities/postgres-migration.js +4 -0
  133. package/dist/op/activity-contracts.d.ts +20 -0
  134. package/dist/op/activity-contracts.d.ts.map +1 -1
  135. package/dist/op/activity-contracts.js +2 -0
  136. package/dist/plugin.d.ts.map +1 -1
  137. package/dist/plugin.js +36 -2
  138. package/dist/postgres/apply/apply.js +8 -1
  139. package/dist/postgres/apply/statements.d.ts.map +1 -1
  140. package/dist/postgres/apply/statements.js +87 -2
  141. package/dist/postgres/constraint-names.d.ts +30 -0
  142. package/dist/postgres/constraint-names.d.ts.map +1 -0
  143. package/dist/postgres/constraint-names.js +72 -0
  144. package/dist/postgres/entities.d.ts +110 -1
  145. package/dist/postgres/entities.d.ts.map +1 -1
  146. package/dist/postgres/entities.js +146 -0
  147. package/dist/postgres/entity-types.d.ts +5 -0
  148. package/dist/postgres/entity-types.d.ts.map +1 -1
  149. package/dist/postgres/entity-types.js +5 -0
  150. package/dist/postgres/import/generator.d.ts.map +1 -1
  151. package/dist/postgres/import/generator.js +50 -2
  152. package/dist/postgres/import/live-export.d.ts.map +1 -1
  153. package/dist/postgres/import/live-export.js +2 -0
  154. package/dist/postgres/live/catalog-kinds.d.ts +14 -0
  155. package/dist/postgres/live/catalog-kinds.d.ts.map +1 -1
  156. package/dist/postgres/live/catalog-kinds.js +206 -0
  157. package/dist/postgres/live/catalog.d.ts +2 -0
  158. package/dist/postgres/live/catalog.d.ts.map +1 -1
  159. package/dist/postgres/live/catalog.js +3 -1
  160. package/dist/postgres/live/describe-resources.d.ts.map +1 -1
  161. package/dist/postgres/live/describe-resources.js +10 -2
  162. package/dist/postgres/migrate/backfill.d.ts +2 -0
  163. package/dist/postgres/migrate/backfill.d.ts.map +1 -1
  164. package/dist/postgres/migrate/backfill.js +7 -1
  165. package/dist/postgres/migrate/carry.d.ts +45 -1
  166. package/dist/postgres/migrate/carry.d.ts.map +1 -1
  167. package/dist/postgres/migrate/carry.js +72 -8
  168. package/dist/postgres/migrate/observe.d.ts +28 -4
  169. package/dist/postgres/migrate/observe.d.ts.map +1 -1
  170. package/dist/postgres/migrate/observe.js +41 -12
  171. package/dist/postgres/migrate/op.d.ts +26 -1
  172. package/dist/postgres/migrate/op.d.ts.map +1 -1
  173. package/dist/postgres/migrate/op.js +3 -1
  174. package/dist/postgres/migrate/steps.d.ts +35 -2
  175. package/dist/postgres/migrate/steps.d.ts.map +1 -1
  176. package/dist/postgres/migrate/steps.js +158 -12
  177. package/dist/postgres/parser.d.ts +72 -1
  178. package/dist/postgres/parser.d.ts.map +1 -1
  179. package/dist/postgres/parser.js +194 -2
  180. package/dist/postgres/plan/deep.d.ts.map +1 -1
  181. package/dist/postgres/plan/deep.js +29 -1
  182. package/dist/postgres/plan/diff.d.ts.map +1 -1
  183. package/dist/postgres/plan/diff.js +39 -1
  184. package/dist/postgres/plan/normalize.d.ts +17 -2
  185. package/dist/postgres/plan/normalize.d.ts.map +1 -1
  186. package/dist/postgres/plan/normalize.js +109 -1
  187. package/dist/postgres/plan/rules.d.ts +1 -0
  188. package/dist/postgres/plan/rules.d.ts.map +1 -1
  189. package/dist/postgres/plan/rules.js +3 -2
  190. package/dist/postgres/plan/schema.js +1 -1
  191. package/dist/postgres/secret-options.d.ts +10 -0
  192. package/dist/postgres/secret-options.d.ts.map +1 -0
  193. package/dist/postgres/secret-options.js +9 -0
  194. package/dist/postgres/testing/roundtrip-schema.d.ts +3 -2
  195. package/dist/postgres/testing/roundtrip-schema.d.ts.map +1 -1
  196. package/dist/postgres/testing/roundtrip-schema.js +13 -1
  197. package/dist/postgres.d.ts +1 -1
  198. package/dist/postgres.d.ts.map +1 -1
  199. package/dist/postgres.js +1 -1
  200. package/dist/rules/audit-entries.ts +1 -0
  201. package/dist/rules/postgres-templates.ts +2 -2
  202. package/dist/rules/sqlch128.ts +230 -0
  203. package/dist/serializer.d.ts +5 -0
  204. package/dist/serializer.d.ts.map +1 -1
  205. package/dist/serializer.js +13 -2
  206. package/dist/sql-types-command.d.ts +13 -0
  207. package/dist/sql-types-command.d.ts.map +1 -1
  208. package/dist/sql-types-command.js +31 -16
  209. package/dist/sql-types.d.ts +22 -0
  210. package/dist/sql-types.d.ts.map +1 -1
  211. package/dist/sql-types.js +10 -6
  212. package/dist/sqlserver/lexer.d.ts +37 -0
  213. package/dist/sqlserver/lexer.d.ts.map +1 -0
  214. package/dist/sqlserver/lexer.js +254 -0
  215. package/dist/sqlserver/parse.d.ts +185 -0
  216. package/dist/sqlserver/parse.d.ts.map +1 -0
  217. package/dist/sqlserver/parse.js +767 -0
  218. package/dist/sqlserver/translate.d.ts +34 -0
  219. package/dist/sqlserver/translate.d.ts.map +1 -0
  220. package/dist/sqlserver/translate.js +495 -0
  221. package/dist/sqlserver/types.d.ts +44 -0
  222. package/dist/sqlserver/types.d.ts.map +1 -0
  223. package/dist/sqlserver/types.js +133 -0
  224. package/dist/sqlserver/validate.d.ts +31 -0
  225. package/dist/sqlserver/validate.d.ts.map +1 -0
  226. package/dist/sqlserver/validate.js +67 -0
  227. package/dist/validate.d.ts.map +1 -1
  228. package/dist/validate.js +5 -0
  229. package/package.json +2 -2
  230. package/src/change-set.ts +2 -1
  231. package/src/clickhouse/apply/statements.ts +25 -0
  232. package/src/clickhouse/import/live-export.ts +20 -5
  233. package/src/clickhouse/live/named-collections.e2e.test.ts +88 -0
  234. package/src/clickhouse/live/named-collections.ts +61 -0
  235. package/src/clickhouse/live/undeclarable.e2e.test.ts +5 -3
  236. package/src/clickhouse/live/undeclarable.ts +20 -4
  237. package/src/clickhouse/named-collections.test.ts +187 -0
  238. package/src/clickhouse/named-collections.ts +224 -0
  239. package/src/clickhouse/parser.ts +2 -1
  240. package/src/clickhouse/plan/commands.ts +17 -2
  241. package/src/clickhouse/plan/diff.ts +57 -1
  242. package/src/clickhouse/plan/disruption.ts +5 -0
  243. package/src/clickhouse/plan/rebuild-handoff.ts +3 -0
  244. package/src/clickhouse/plan/report.ts +6 -1
  245. package/src/clickhouse/plan/rules.ts +14 -4
  246. package/src/clickhouse/plan/stream-s3queue.e2e.test.ts +148 -0
  247. package/src/clickhouse/plan/stream.test.ts +237 -0
  248. package/src/clickhouse/plan/stream.ts +111 -0
  249. package/src/clickhouse/rebuild/observe.ts +15 -1
  250. package/src/clickhouse/review-catalog.test.ts +181 -0
  251. package/src/clickhouse/review-catalog.ts +489 -0
  252. package/src/codegen/classifier-page.ts +21 -4
  253. package/src/codegen/clickhouse-module.ts +3 -0
  254. package/src/codegen/coverage-page.ts +5 -3
  255. package/src/codegen/docs.ts +1 -1
  256. package/src/codegen/postgres-classifier-page.ts +1 -1
  257. package/src/codegen/registry.ts +5 -0
  258. package/src/composites/catalog.test.ts +6 -1
  259. package/src/composites/catalog.ts +100 -0
  260. package/src/composites/clickhouse.ts +2 -0
  261. package/src/composites/composites.test.ts +1 -1
  262. package/src/composites/otel-tables.test.ts +118 -0
  263. package/src/composites/otel-tables.ts +339 -0
  264. package/src/composites/stream-ingest.test.ts +114 -0
  265. package/src/composites/stream-ingest.ts +82 -0
  266. package/src/core/undeclarable.test.ts +6 -5
  267. package/src/coverage/clickhouse.json +1 -1
  268. package/src/coverage/postgres.json +7 -7
  269. package/src/coverage.test.ts +27 -2
  270. package/src/coverage.ts +18 -7
  271. package/src/drizzle-command.ts +94 -0
  272. package/src/drizzle-kit.e2e.test.ts +89 -0
  273. package/src/drizzle-types.e2e.test.ts +67 -0
  274. package/src/drizzle.test.ts +358 -0
  275. package/src/drizzle.ts +737 -0
  276. package/src/files/clickhouse.ts +8 -1
  277. package/src/files/common.ts +14 -1
  278. package/src/files/postgres.ts +12 -2
  279. package/src/generated/clickhouse.ts +3 -0
  280. package/src/generated/lexicon-sql.json +25 -0
  281. package/src/import-parser.sqlserver.test.ts +92 -0
  282. package/src/import-parser.ts +79 -5
  283. package/src/index.ts +1 -1
  284. package/src/lint/post-synth/audit-entries.ts +1 -0
  285. package/src/lint/post-synth/index.ts +2 -0
  286. package/src/lint/post-synth/sqlch128.test.ts +107 -0
  287. package/src/lint/post-synth/sqlch128.ts +230 -0
  288. package/src/lint/rules/postgres-templates.ts +2 -2
  289. package/src/lsp/postgres-template.ts +11 -0
  290. package/src/mcp/postgres.ts +1 -1
  291. package/src/migrate/from-postgres/cli.test.ts +165 -0
  292. package/src/migrate/from-postgres/detect.ts +7 -0
  293. package/src/migrate/from-postgres/emit.ts +96 -0
  294. package/src/migrate/from-postgres/example.test.ts +205 -0
  295. package/src/migrate/from-postgres/index.ts +122 -0
  296. package/src/migrate/from-postgres/translate.test.ts +242 -0
  297. package/src/migrate/from-postgres/translate.ts +359 -0
  298. package/src/migrate/from-postgres/types.test.ts +116 -0
  299. package/src/migrate/from-postgres/types.ts +236 -0
  300. package/src/migrate/from-postgres/validate.e2e.test.ts +44 -0
  301. package/src/migrate/from-postgres/workspace.e2e.test.ts +114 -0
  302. package/src/migration-replay.e2e.test.ts +155 -0
  303. package/src/migration-replay.test.ts +173 -0
  304. package/src/migration-replay.ts +289 -0
  305. package/src/op/__snapshots__/watch-pipeline.test.ts.snap +2 -2
  306. package/src/op/activities/postgres-migration.ts +4 -0
  307. package/src/op/activity-contracts.ts +2 -0
  308. package/src/plugin.ts +37 -2
  309. package/src/postgres/apply/apply.ts +9 -1
  310. package/src/postgres/apply/statements.ts +74 -1
  311. package/src/postgres/constraint-names.ts +71 -0
  312. package/src/postgres/database-kinds.test.ts +384 -0
  313. package/src/postgres/entities.ts +266 -1
  314. package/src/postgres/entity-types.ts +5 -0
  315. package/src/postgres/import/generator.ts +42 -2
  316. package/src/postgres/import/live-export.ts +1 -0
  317. package/src/postgres/live/catalog-kinds.ts +223 -0
  318. package/src/postgres/live/catalog.ts +6 -1
  319. package/src/postgres/live/database-kinds.e2e.test.ts +164 -0
  320. package/src/postgres/live/describe-resources.ts +11 -2
  321. package/src/postgres/live/undeclarable.e2e.test.ts +13 -6
  322. package/src/postgres/migrate/backfill.ts +13 -1
  323. package/src/postgres/migrate/carry.ts +103 -8
  324. package/src/postgres/migrate/followups.e2e.test.ts +218 -0
  325. package/src/postgres/migrate/followups.test.ts +199 -0
  326. package/src/postgres/migrate/kinds.e2e.test.ts +5 -5
  327. package/src/postgres/migrate/observe.ts +53 -14
  328. package/src/postgres/migrate/op.ts +28 -1
  329. package/src/postgres/migrate/partition.e2e.test.ts +129 -0
  330. package/src/postgres/migrate/partition.test.ts +206 -0
  331. package/src/postgres/migrate/steps.ts +157 -12
  332. package/src/postgres/parser.ts +234 -2
  333. package/src/postgres/plan/deep.ts +28 -1
  334. package/src/postgres/plan/diff.ts +36 -1
  335. package/src/postgres/plan/normalize.ts +122 -1
  336. package/src/postgres/plan/rules.ts +10 -3
  337. package/src/postgres/plan/schema.ts +1 -1
  338. package/src/postgres/secret-options.ts +10 -0
  339. package/src/postgres/testing/roundtrip-schema.ts +13 -1
  340. package/src/postgres.ts +16 -0
  341. package/src/serializer.ts +13 -2
  342. package/src/skills/chant-sql-postgres-migration.md +3 -3
  343. package/src/skills/chant-sql-postgres.md +6 -1
  344. package/src/skills/chant-sql.md +2 -1
  345. package/src/sql-types-command.ts +38 -16
  346. package/src/sql-types.ts +11 -6
  347. package/src/sqlserver/fixture.test.ts +186 -0
  348. package/src/sqlserver/import-cli.test.ts +61 -0
  349. package/src/sqlserver/lexer.ts +260 -0
  350. package/src/sqlserver/parse.ts +865 -0
  351. package/src/sqlserver/translate.test.ts +396 -0
  352. package/src/sqlserver/translate.ts +558 -0
  353. package/src/sqlserver/types.test.ts +102 -0
  354. package/src/sqlserver/types.ts +154 -0
  355. package/src/sqlserver/validate.e2e.test.ts +32 -0
  356. package/src/sqlserver/validate.test.ts +49 -0
  357. package/src/sqlserver/validate.ts +76 -0
  358. package/src/validate.ts +5 -0
  359. package/src/workspace-kinds.test.ts +11 -0
  360. package/workspace-kinds.json +100 -2
@@ -10,6 +10,7 @@ const LABEL: Record<string, string> = {
10
10
  drop: "drop",
11
11
  metadata: "metadata only",
12
12
  rewrite: "background rewrite",
13
+ replace: "replace table",
13
14
  rebuild: "rebuild",
14
15
  };
15
16
 
@@ -22,7 +23,7 @@ export function renderClassifierPage(): string {
22
23
  return `---
23
24
  title: "Planning ClickHouse Changes"
24
25
  label: "Planning and the Change Classifier"
25
- description: "How a ClickHouse schema change is classified as metadata only, a background rewrite or a rebuild, each with the ALTER restriction behind it"
26
+ description: "How a ClickHouse schema change is classified as metadata only, a background rewrite, a replacement or a rebuild, each with the ALTER restriction behind it"
26
27
  diataxis: reference
27
28
  group: "ClickHouse"
28
29
  order: 1
@@ -36,9 +37,10 @@ Every change between two ClickHouse schemas is classified before anything runs:
36
37
  |---|---|
37
38
  | metadata only | the server records the change and touches no existing data |
38
39
  | background rewrite | a mutation rewrites existing parts in the background, with no rollback |
40
+ | replace table | ClickHouse cannot alter a stream-engine table, and it stores no rows, so the applier drops and creates it around the views that read it |
39
41
  | rebuild | ClickHouse cannot make the change to the existing table, and the data has to be copied into a new one; a plan refuses to make it in place |
40
42
 
41
- Two commands report the classification, and \`chant lifecycle plan\` reports it as each update's disruption (metadata only is \`in-place\`, a rewrite \`rolling\`, a rebuild \`replace\`):
43
+ Two commands report the classification, and \`chant lifecycle plan\` reports it as each update's disruption (metadata only is \`in-place\`, a rewrite \`rolling\`, a replacement or a rebuild \`replace\`):
42
44
 
43
45
  \`\`\`bash
44
46
  chant sql diff base.json head.json # two chant build outputs, offline
@@ -47,13 +49,28 @@ chant sql plan prod schema.json # a build output against the prod server
47
49
 
48
50
  Both exit 2 when a change needs a rebuild. \`chant sql diff\` compares a pull request's base and head builds with no server. \`chant sql plan\` reads the server \`sql.profiles.<env>\` binds, and asks that server's formatter about any expression the normalization rules leave different, so the server's own rewriting (\`INTERVAL 1 DAY\` as \`toIntervalDay(1)\`, \`a+b*2\` as \`a + (b * 2)\`) is not reported as a change.
49
51
 
50
- \`chant sql plan\` also exits 2 when a declared database holds an object whose definition it cannot read. It names each one under \`Refused\` (\`unreadable\` in \`--json\`) instead of leaving it out. Dictionaries are read and planned like the other objects: any change but a comment replaces one (SQLCH245).
52
+ \`chant sql plan\` also exits 2 when a declared database holds an object whose definition it cannot read. It names each one under \`Refused\` (\`unreadable\` in \`--json\`) instead of leaving it out. It exits 2 as well when the build names a named collection the server doesn't have, naming each under \`Refused\` (\`namedCollections.missing\` in \`--json\`); see [Named collections](../clickhouse-ddl/#named-collections). Dictionaries are read and planned like the other objects: any change but a comment replaces one (SQLCH245).
51
53
 
52
54
  A clause chant's parser does not know ([Plain .sql Files](../sql-files/#clauses-chant-does-not-read)) is compared as text, and the rest of its object is planned as usual. A change to one is SQLCH290, refused for review with no rebuild Op suggested, since chant cannot tell what the change takes. A clause only the server prints is a hint, not a change: a newer server printing a clause with its default looks the same as a clause removed from the declaration.
53
55
 
56
+ ## Stream tables
57
+
58
+ A table on Kafka, S3Queue, AzureQueue, RabbitMQ, NATS or FileLog stores no rows. It is the consumer that a materialized view reads through, and the position it has reached lives in the broker's committed offsets or in Keeper. There is no \`ALTER\` for its engine arguments, settings or columns, and there is nothing to copy, so a change to one is neither metadata nor a rebuild. It is SQLCH225, in the replace class (\`diffStreamTable\` in \`src/clickhouse/plan/diff.ts\`). The plan refuses nothing for it.
59
+
60
+ The applier makes the change in place, in this order (\`replaceStreamSteps\` in \`src/clickhouse/apply/statements.ts\`): \`DETACH TABLE\` for each materialized view on the server that reads the table, \`DROP TABLE ... SYNC\`, the declared \`CREATE TABLE\`, then \`ATTACH TABLE\` for the same views. The plan names the views in a hint. Messages wait in the broker, and files wait in the bucket, while the views are detached. A change that moves a table to or from a stream engine is still SQLCH223, a rebuild, and \`ClickHouseRebuildOp\` refuses a stream-engine table by name (\`streamRefusal\` in \`src/clickhouse/rebuild/observe.ts\`).
61
+
62
+ Two replacements lose the table's position, and the change carries a note saying so (\`positionWarnings\` in \`src/clickhouse/plan/stream.ts\`):
63
+
64
+ - A different \`kafka_group_name\`, as a setting or as the third engine argument, is a different consumer group. It starts from its own committed offsets, or from the start of the topic when it has none.
65
+ - A different S3Queue \`keeper_path\` is a different record of processed files. Every file already seen is processed again.
66
+
67
+ An apply killed between the detach and the attach leaves the views detached, and a detached view is not in \`system.tables\`. Nothing re-attaches it: run \`ATTACH TABLE\` for each view by hand, then plan again. This has not been run against a server.
68
+
69
+ The \`StreamIngest\` composite declares the stream table, the view and the MergeTree target together: see [Composites](../composites/#streamingest).
70
+
54
71
  ## After the plan
55
72
 
56
- The plan only reports. [\`clickhouseApply\`](../applying/) makes the metadata-only and background-rewrite changes, and refuses a rebuild the same way the plan does, sending nothing for that object. A rebuild runs as \`ClickHouseRebuildOp\`, a gated migration Op that creates the new table, backfills it, verifies it and swaps it in: see [Rebuilding a Table](../rebuild/). Both commands print the Op declaration to start from for each refused table.
73
+ The plan only reports. [\`clickhouseApply\`](../applying/) makes the metadata-only, background-rewrite and stream-table changes, and refuses a rebuild the same way the plan does, sending nothing for that object. A rebuild runs as \`ClickHouseRebuildOp\`, a gated migration Op that creates the new table, backfills it, verifies it and swaps it in: see [Rebuilding a Table](../rebuild/). Both commands print the Op declaration to start from for each refused table.
57
74
 
58
75
  \`chant migrate\` plays no part in any of this. It translates a file from one lexicon's format into another's, such as a GitHub Actions workflow into GitLab CI, and does not run schema migrations.
59
76
 
@@ -269,6 +269,9 @@ export function renderClickHouseModule(catalog: ClickHouseCatalog): RenderedModu
269
269
  `/** The table functions (\`system.table_functions\`): \`numbers\`, \`remote\`, \`s3\`. */`,
270
270
  `export const TABLE_FUNCTIONS: readonly string[] = ${JSON.stringify(catalog.tableFunctions)};`,
271
271
  "",
272
+ `/** The input and output formats (\`system.formats\`): \`Parquet\`, \`JSONEachRow\`. */`,
273
+ `export const FORMATS: readonly string[] = ${JSON.stringify(catalog.formats.map((f) => f.name))};`,
274
+ "",
272
275
  `export const SKIP_INDEX_TYPES: Readonly<Record<SkipIndexType, SkipIndexSpec>> = {`,
273
276
  ...indexLines,
274
277
  "};",
@@ -9,7 +9,7 @@ import type { SqlDialect } from "../dialects";
9
9
 
10
10
  const cell = (s: string) => s.replace(/\|/g, "\\|").replace(/[{}<>]/g, (c) => `\\${c}`);
11
11
 
12
- const STATUS: Record<KindRow["status"], string> = { declared: "declared", refused: "refused", "out-of-scope": "out of scope" };
12
+ const STATUS: Record<KindRow["status"], string> = { declared: "declared", referenced: "referenced", refused: "refused", "out-of-scope": "out of scope" };
13
13
 
14
14
  function table(dialect: SqlDialect): string {
15
15
  const rows = [...KIND_COVERAGE[dialect]].sort((a, b) => (a.command < b.command ? -1 : a.command > b.command ? 1 : 0));
@@ -27,7 +27,8 @@ function table(dialect: SqlDialect): string {
27
27
  function counts(dialect: SqlDialect): string {
28
28
  const rows = KIND_COVERAGE[dialect];
29
29
  const n = (s: KindRow["status"]) => rows.filter((r) => r.status === s).length;
30
- return `${n("declared")} declared, ${n("refused")} refused, ${n("out-of-scope")} out of scope`;
30
+ const referenced = n("referenced") > 0 ? `, ${n("referenced")} referenced` : "";
31
+ return `${n("declared")} declared${referenced}, ${n("refused")} refused, ${n("out-of-scope")} out of scope`;
31
32
  }
32
33
 
33
34
  export function renderCoveragePage(): string {
@@ -36,7 +37,7 @@ export function renderCoveragePage(): string {
36
37
  return `---
37
38
  title: "Object Coverage"
38
39
  label: "Object Coverage"
39
- description: "Every kind of object each pinned Postgres and ClickHouse server can create, marked declared, refused with a reason, or out of scope, and what import does with each"
40
+ description: "Every kind of object each pinned Postgres and ClickHouse server can create, marked declared, referenced, refused with a reason, or out of scope, and what import does with each"
40
41
  diataxis: reference
41
42
  order: 3
42
43
  ---
@@ -46,6 +47,7 @@ order: 3
46
47
  Each row is a \`CREATE\` command a pinned server has, or one form of a command where chant treats the forms apart (\`CREATE TYPE ... AS ENUM\` is declared, \`CREATE TYPE ... AS RANGE\` is not). The commands come from the servers' own sources at each pinned version (\`scripts/sql-create-commands.ts\`), and a test fails when a pinned server has a command with no row here, so a new server release cannot add a kind nobody looked at.
47
48
 
48
49
  - **declared**: a tag declares it, and import writes it as that declaration.
50
+ - **referenced**: the environment's, and never declared: a declaration names one, and chant never reads its values. A ClickHouse named collection is one ([#4395](https://github.com/INTENTIUS/chant/issues/4395)): \`ENGINE = S3(lake_creds, format = 'Parquet')\` names \`lake_creds\`, the build records the name, and \`chant sql plan\` fails when the server has no collection of that name. \`chant import --from <env>\` lists the server's SQL-defined collections as prerequisites and imports the rest. See [Named collections](../clickhouse-ddl/#named-collections).
49
51
  - **refused**: no declaration holds it yet. \`chant import --from <env>\` fails when the server has one, naming every such object (kind, schema, name) at once, and \`chant import schema.sql\` fails on the statement. Nothing is left out without a word.
50
52
  - **out of scope**: the environment's, not a schema's: import never reads it.
51
53
 
@@ -122,7 +122,7 @@ Postgres:
122
122
  - [Getting Started with Postgres](./postgres-getting-started/): declare a
123
123
  schema, apply it to a local server, add a column and an index, and see a
124
124
  rename refused.
125
- - [Declaring Postgres Objects](./postgres-ddl/): the eight tags,
125
+ - [Declaring Postgres Objects](./postgres-ddl/): the tags for every schema-level kind,
126
126
  constraints, \`nextval(\${seq})\`, \`COMMENT ON\` and \`literal()\`.
127
127
  - [Importing a Postgres Server](./postgres-importing/): canonical text from
128
128
  the catalog's printers, and the objects that belong to someone else.
@@ -72,7 +72,7 @@ Two rules change class across the supported majors: a STORED generated column's
72
72
 
73
73
  ## Identity and renames
74
74
 
75
- An object is identified by its export name between two builds, and by its schema-qualified name against a server, which has no export names. Tables, views, materialized views, sequences and indexes share one namespace per schema, types and domains another, and schemas and extensions are matched by name. Functions, procedures and aggregates share a namespace of their own and are told apart by their input parameter types, so an overload is another object; composite and range types share the types' namespace, collations have one of their own, a cast is named by its two types and an event trigger by its name in the database; a trigger is matched by its name on its table.
75
+ An object is identified by its export name between two builds, and by its schema-qualified name against a server, which has no export names. Tables, views, materialized views, sequences and indexes share one namespace per schema, types and domains another, and schemas and extensions are matched by name. Functions, procedures and aggregates share a namespace of their own and are told apart by their input parameter types, so an overload is another object; composite and range types share the types' namespace, collations have one of their own, extended statistics another, an operator by its symbol and operand types, a cast by its two types and an event trigger, a foreign data wrapper, a foreign server and a publication by their names in the database; a trigger is matched by its name on its table.
76
76
 
77
77
  A rename is declared where it happens. Before a CREATE, \`-- previously: <old name>\` says the object had another name; on a column's line, it says the column did:
78
78
 
@@ -39,6 +39,11 @@ const KINDS: Record<string, string> = {
39
39
  PostgresCollation: POSTGRES_ENTITY_TYPES.collation,
40
40
  PostgresCast: POSTGRES_ENTITY_TYPES.cast,
41
41
  PostgresEventTrigger: POSTGRES_ENTITY_TYPES.eventTrigger,
42
+ PostgresOperator: POSTGRES_ENTITY_TYPES.operator,
43
+ PostgresStatistics: POSTGRES_ENTITY_TYPES.statistics,
44
+ PostgresForeignDataWrapper: POSTGRES_ENTITY_TYPES.foreignDataWrapper,
45
+ PostgresForeignServer: POSTGRES_ENTITY_TYPES.foreignServer,
46
+ PostgresPublication: POSTGRES_ENTITY_TYPES.publication,
42
47
  PostgresExtension: POSTGRES_ENTITY_TYPES.extension,
43
48
  PostgresFunction: POSTGRES_ENTITY_TYPES.function,
44
49
  PostgresProcedure: POSTGRES_ENTITY_TYPES.procedure,
@@ -24,11 +24,13 @@ describe("the sql composite catalog", () => {
24
24
  "CdcMirror",
25
25
  "EventsTable",
26
26
  "JoinTable",
27
+ "OtelTables",
27
28
  "RefreshedView",
28
29
  "ReplacingTable",
29
30
  "RollupView",
30
31
  "ShardedTable",
31
32
  "SoftDeleteTable",
33
+ "StreamIngest",
32
34
  "TenantTable",
33
35
  ]);
34
36
  expect(catalogued, "regenerate with `npm run generate:composite-catalogs -- sql`").toEqual(exported);
@@ -47,11 +49,14 @@ describe("the sql composite catalog", () => {
47
49
  ReplacingTable: ["ClickHouseTable"],
48
50
  RollupView: ["ClickHouseTable", "ClickHouseView"],
49
51
  ShardedTable: ["ClickHouseTable"],
52
+ OtelTables: ["ClickHouseTable", "ClickHouseView"],
53
+ StreamIngest: ["ClickHouseTable", "ClickHouseView"],
50
54
  });
51
55
  for (const entry of compositeCatalog) {
52
56
  expect(entry.lexicon, entry.name).toBe("sql");
53
57
  expect(entry.description.length, entry.name).toBeGreaterThan(0);
54
- expect(entry.params.find((p) => p.name === "name")?.required, entry.name).toBe(true);
58
+ // OtelTables declares a fixed set of tables, so it takes no name.
59
+ if (entry.name !== "OtelTables") expect(entry.params.find((p) => p.name === "name")?.required, entry.name).toBe(true);
55
60
  }
56
61
  });
57
62
 
@@ -215,6 +215,41 @@ export const compositeCatalog: CompositeEntry[] = [
215
215
  }
216
216
  ]
217
217
  },
218
+ {
219
+ "name": "OtelTables",
220
+ "lexicon": "sql",
221
+ "description": "The logs, traces and metrics tables the OpenTelemetry Collector's clickhouse exporter writes, as it creates them at v0.130.0.",
222
+ "bundles": [
223
+ "ClickHouseTable",
224
+ "ClickHouseView"
225
+ ],
226
+ "params": [
227
+ {
228
+ "name": "database",
229
+ "type": "string",
230
+ "required": false,
231
+ "description": "The database the tables are created in, the exporter's `database`."
232
+ },
233
+ {
234
+ "name": "ttl",
235
+ "type": "string",
236
+ "required": false,
237
+ "description": "How long rows are kept, as the exporter's `ttl` takes it: a Go duration such as `72h` or `30m`."
238
+ },
239
+ {
240
+ "name": "tables",
241
+ "type": "OtelTableNames",
242
+ "required": false,
243
+ "description": "Table names other than the exporter's defaults, as set on the exporter."
244
+ },
245
+ {
246
+ "name": "traceIdLookup",
247
+ "type": "boolean",
248
+ "required": false,
249
+ "description": "Declare the trace-id lookup table and its materialized view (default true)."
250
+ }
251
+ ]
252
+ },
218
253
  {
219
254
  "name": "RefreshedView",
220
255
  "lexicon": "sql",
@@ -473,6 +508,71 @@ export const compositeCatalog: CompositeEntry[] = [
473
508
  }
474
509
  ]
475
510
  },
511
+ {
512
+ "name": "StreamIngest",
513
+ "lexicon": "sql",
514
+ "description": "A stream table, the materialized view that reads it, and the MergeTree target the view writes.",
515
+ "bundles": [
516
+ "ClickHouseTable",
517
+ "ClickHouseView"
518
+ ],
519
+ "params": [
520
+ {
521
+ "name": "name",
522
+ "type": "string",
523
+ "required": true,
524
+ "description": "The target table's name."
525
+ },
526
+ {
527
+ "name": "columns",
528
+ "type": "string",
529
+ "required": true,
530
+ "description": "The target's columns, as SQL: `ts DateTime, user_id UInt64, kind LowCardinality(String)`."
531
+ },
532
+ {
533
+ "name": "engine",
534
+ "type": "string",
535
+ "required": true,
536
+ "description": "The stream table's engine, with a named collection as its first argument rather than inline credentials: `Kafka(kafka_creds)`, `S3Queue(lake_creds)`."
537
+ },
538
+ {
539
+ "name": "settings",
540
+ "type": "string",
541
+ "required": false,
542
+ "description": "The engine's settings, the body of a `SETTINGS` clause: `kafka_topic_list = 'events', kafka_group_name = 'ingest', kafka_format = 'JSONEachRow'`."
543
+ },
544
+ {
545
+ "name": "streamColumns",
546
+ "type": "string",
547
+ "required": false,
548
+ "description": "The stream table's columns when they differ from the target's: the message as it arrives."
549
+ },
550
+ {
551
+ "name": "select",
552
+ "type": "string",
553
+ "required": false,
554
+ "description": "The view's select list over the stream table, each item aliased to a target column."
555
+ },
556
+ {
557
+ "name": "orderBy",
558
+ "type": "string",
559
+ "required": true,
560
+ "description": "The target's sort key (a column list or an expression)."
561
+ },
562
+ {
563
+ "name": "targetEngine",
564
+ "type": "string",
565
+ "required": false,
566
+ "description": "The target's engine (default `MergeTree`)."
567
+ },
568
+ {
569
+ "name": "partitionBy",
570
+ "type": "string",
571
+ "required": false,
572
+ "description": "The target's partition key."
573
+ }
574
+ ]
575
+ },
476
576
  {
477
577
  "name": "TenantTable",
478
578
  "lexicon": "sql",
@@ -5,3 +5,5 @@ export { EventsTable, type EventsTableProps, type EventsTableMembers } from "./e
5
5
  export { RollupView, type RollupViewProps, type RollupViewMembers } from "./rollup-view";
6
6
  export { CdcMirror, type CdcMirrorProps, type CdcMirrorMembers } from "./cdc-mirror";
7
7
  export { ShardedTable, type ShardedTableProps, type ShardedTableMembers } from "./sharded-table";
8
+ export { OtelTables, OTEL_EXPORTER_DEFAULT_TABLES, otelTtlClause, type OtelTablesProps, type OtelTablesMembers, type OtelTableNames } from "./otel-tables";
9
+ export { StreamIngest, type StreamIngestProps, type StreamIngestMembers } from "./stream-ingest";
@@ -234,7 +234,7 @@ describe("the composites pass the lexicon's post-synth checks", () => {
234
234
  const ids = clickhouse.map((c) => c.id).sort();
235
235
  expect(ids[0]).toBe("SQL101");
236
236
  expect(ids).toContain("SQLCH101");
237
- expect(ids.at(-1)).toBe("SQLCH127");
237
+ expect(ids.at(-1)).toBe("SQLCH128");
238
238
  expect(clickhouse.flatMap((check) => check.check(ctx))).toEqual([]);
239
239
  });
240
240
  });
@@ -0,0 +1,118 @@
1
+ /**
2
+ * `OtelTables` (#4397): the tables the OpenTelemetry Collector's clickhouse
3
+ * exporter writes, as its create statements at contrib v0.130.0 declare them.
4
+ */
5
+
6
+ import { describe, expect, test } from "vitest";
7
+ import { expandComposite } from "@intentius/chant/composite";
8
+ import type { Declarable } from "@intentius/chant/declarable";
9
+ import type { SerializerResult } from "@intentius/chant/serializer";
10
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
11
+ import { CLICKHOUSE_ENTITY_TYPES, type ClickHouseObject, type ClickHouseTable, type TableProps, type ViewProps } from "../clickhouse/entities";
12
+ import { sqlSerializer } from "../serializer";
13
+ import { postSynthChecks } from "../lint/post-synth";
14
+ import { sqlWorkspaceOutputs } from "../workspace-outputs";
15
+ import { OtelTables, otelTtlClause } from "./index";
16
+
17
+ const props = (e: unknown) => (e as ClickHouseObject & { props: TableProps }).props;
18
+ const columns = (e: unknown) => props(e).columns.map((c) => c.name);
19
+
20
+ describe("OtelTables", () => {
21
+ test("defaults: the exporter's seven tables, unqualified, plus the trace-id lookup table and view", () => {
22
+ const t = OtelTables({});
23
+ expect(Object.entries(t).map(([k, e]) => [k, (e as Declarable).entityType, props(e).database, props(e).name])).toEqual([
24
+ ["logs", CLICKHOUSE_ENTITY_TYPES.table, undefined, "otel_logs"],
25
+ ["traces", CLICKHOUSE_ENTITY_TYPES.table, undefined, "otel_traces"],
26
+ ["metricsGauge", CLICKHOUSE_ENTITY_TYPES.table, undefined, "otel_metrics_gauge"],
27
+ ["metricsSum", CLICKHOUSE_ENTITY_TYPES.table, undefined, "otel_metrics_sum"],
28
+ ["metricsSummary", CLICKHOUSE_ENTITY_TYPES.table, undefined, "otel_metrics_summary"],
29
+ ["metricsHistogram", CLICKHOUSE_ENTITY_TYPES.table, undefined, "otel_metrics_histogram"],
30
+ ["metricsExponentialHistogram", CLICKHOUSE_ENTITY_TYPES.table, undefined, "otel_metrics_exponential_histogram"],
31
+ ["traceIdTs", CLICKHOUSE_ENTITY_TYPES.table, undefined, "otel_traces_trace_id_ts"],
32
+ ["traceIdTsView", CLICKHOUSE_ENTITY_TYPES.materializedView, undefined, "otel_traces_trace_id_ts_mv"],
33
+ ]);
34
+ expect(props(t.logs).ttl).toBeUndefined();
35
+ expect(props(t.logs).engine).toEqual({ name: "MergeTree" });
36
+ expect(props(t.logs).settings).toEqual({ index_granularity: "8192", ttl_only_drop_parts: "1" });
37
+ });
38
+
39
+ test("the columns of the exporter's create statements, in their order", () => {
40
+ const t = OtelTables({});
41
+ expect(columns(t.logs)).toEqual([
42
+ "Timestamp", "TimestampTime", "TraceId", "SpanId", "TraceFlags", "SeverityText", "SeverityNumber", "ServiceName", "Body",
43
+ "ResourceSchemaUrl", "ResourceAttributes", "ScopeSchemaUrl", "ScopeName", "ScopeVersion", "ScopeAttributes", "LogAttributes",
44
+ ]);
45
+ expect(columns(t.traces)).toEqual([
46
+ "Timestamp", "TraceId", "SpanId", "ParentSpanId", "TraceState", "SpanName", "SpanKind", "ServiceName", "ResourceAttributes",
47
+ "ScopeName", "ScopeVersion", "SpanAttributes", "Duration", "StatusCode", "StatusMessage", "Events", "Links",
48
+ ]);
49
+ const head = [
50
+ "ResourceAttributes", "ResourceSchemaUrl", "ScopeName", "ScopeVersion", "ScopeAttributes", "ScopeDroppedAttrCount", "ScopeSchemaUrl",
51
+ "ServiceName", "MetricName", "MetricDescription", "MetricUnit", "Attributes", "StartTimeUnix", "TimeUnix",
52
+ ];
53
+ expect(columns(t.metricsGauge)).toEqual([...head, "Value", "Flags", "Exemplars"]);
54
+ expect(columns(t.metricsSum)).toEqual([...head, "Value", "Flags", "Exemplars", "AggregationTemporality", "IsMonotonic"]);
55
+ expect(columns(t.metricsSummary)).toEqual([...head, "Count", "Sum", "ValueAtQuantiles", "Flags"]);
56
+ expect(columns(t.metricsHistogram)).toEqual([...head, "Count", "Sum", "BucketCounts", "ExplicitBounds", "Exemplars", "Flags", "Min", "Max", "AggregationTemporality"]);
57
+ expect(columns(t.metricsExponentialHistogram)).toEqual([
58
+ ...head, "Count", "Sum", "Scale", "ZeroCount", "PositiveOffset", "PositiveBucketCounts", "NegativeOffset", "NegativeBucketCounts",
59
+ "Exemplars", "Flags", "Min", "Max", "AggregationTemporality",
60
+ ]);
61
+ expect(columns(t.traceIdTs)).toEqual(["TraceId", "Start", "End"]);
62
+ expect(props(t.logs).columns.find((c) => c.name === "Timestamp")?.codec).toBe("Delta(8), ZSTD(1)");
63
+ expect(props(t.traces).columns.find((c) => c.name === "Events")?.type?.replace(/\s+/g, " ")).toBe(
64
+ "Nested ( Timestamp DateTime64(9), Name LowCardinality(String), Attributes Map(LowCardinality(String), String) )",
65
+ );
66
+ expect(props(t.logs).indexes.map((i) => i.name)).toEqual([
67
+ "idx_trace_id", "idx_res_attr_key", "idx_res_attr_value", "idx_scope_attr_key", "idx_scope_attr_value", "idx_log_attr_key", "idx_log_attr_value", "idx_body",
68
+ ]);
69
+ });
70
+
71
+ test("database, ttl and table names reach every member; the view reads the traces table into the lookup table", () => {
72
+ const t = OtelTables({ database: "otel", ttl: "72h", tables: { traces: "spans", exponentialHistogram: "otel_metrics_exp_histogram" } });
73
+ expect(props(t.traces)).toMatchObject({ database: "otel", name: "spans", ttl: "toDateTime(Timestamp) + toIntervalDay(3)" });
74
+ expect(props(t.logs).ttl).toBe("TimestampTime + toIntervalDay(3)");
75
+ expect(props(t.metricsExponentialHistogram)).toMatchObject({ name: "otel_metrics_exp_histogram", ttl: "toDateTime(TimeUnix) + toIntervalDay(3)" });
76
+ expect(props(t.traceIdTs)).toMatchObject({ database: "otel", name: "spans_trace_id_ts", ttl: "toDateTime(Start) + toIntervalDay(3)" });
77
+ const view = (t.traceIdTsView as unknown as { props: ViewProps }).props;
78
+ expect(view.name).toBe("spans_trace_id_ts_mv");
79
+ expect(view.to).toBe(t.traceIdTs);
80
+ expect(view.reads).toEqual([t.traces]);
81
+ });
82
+
83
+ test("traceIdLookup: false leaves out the lookup table and view", () => {
84
+ const t = OtelTables({ traceIdLookup: false });
85
+ expect(Object.keys(t)).not.toContain("traceIdTs");
86
+ expect(Object.keys(t)).not.toContain("traceIdTsView");
87
+ });
88
+
89
+ test("the TTL is rendered as the exporter's GenerateTTLExpr renders it", () => {
90
+ expect(otelTtlClause(undefined, "t")).toBe("");
91
+ expect(otelTtlClause("0", "t")).toBe("");
92
+ expect(otelTtlClause("48h", "t")).toBe("TTL t + toIntervalDay(2)");
93
+ expect(otelTtlClause("12h", "t")).toBe("TTL t + toIntervalHour(12)");
94
+ expect(otelTtlClause("1h30m", "t")).toBe("TTL t + toIntervalMinute(90)");
95
+ expect(otelTtlClause("90s", "t")).toBe("TTL t + toIntervalSecond(90)");
96
+ expect(() => otelTtlClause("3d", "t")).toThrow(/not a Go duration/);
97
+ });
98
+
99
+ test("passes the lexicon's post-synth checks, and orders the view after both tables", () => {
100
+ const entities = new Map<string, Declarable>();
101
+ for (const [k, v] of expandComposite("otel", OtelTables({ database: "otel", ttl: "72h" }))) entities.set(k, v);
102
+ const out = sqlSerializer.serialize(entities) as SerializerResult;
103
+ const doc = JSON.parse(out.primary) as { applyOrder: string[] };
104
+ expect(doc.applyOrder.indexOf("otelTraces")).toBeLessThan(doc.applyOrder.indexOf("otelTraceIdTsView"));
105
+ expect(doc.applyOrder.indexOf("otelTraceIdTs")).toBeLessThan(doc.applyOrder.indexOf("otelTraceIdTsView"));
106
+ const ctx = makePostSynthCtx("sql", out.primary, entities);
107
+ const checks = postSynthChecks.filter((c) => c.id.startsWith("SQLCH") || c.id === "SQL101");
108
+ expect(checks.flatMap((check) => check.check(ctx))).toEqual([]);
109
+ });
110
+
111
+ test("its tables and columns are workspace outputs another member can link to", () => {
112
+ const entities = new Map<string, Declarable>();
113
+ for (const [k, v] of expandComposite("otel", OtelTables({ database: "otel" }))) entities.set(k, v);
114
+ const names = sqlWorkspaceOutputs(entities)!.outputs.map((o) => o.name);
115
+ expect(names).toEqual(expect.arrayContaining(["otel.otel_logs", "otel.otel_logs.Body", "otel.otel_traces.Events", "otel.otel_traces_trace_id_ts_mv"]));
116
+ expect((OtelTables({}).logs as ClickHouseTable).entityType).toBe(CLICKHOUSE_ENTITY_TYPES.table);
117
+ });
118
+ });