@intentius/chant-lexicon-sql 0.124.46 → 0.124.49

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 (402) 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/statements.d.ts +29 -0
  37. package/dist/clickhouse/plan/statements.d.ts.map +1 -0
  38. package/dist/clickhouse/plan/statements.js +334 -0
  39. package/dist/clickhouse/plan/stream.d.ts +40 -0
  40. package/dist/clickhouse/plan/stream.d.ts.map +1 -0
  41. package/dist/clickhouse/plan/stream.js +107 -0
  42. package/dist/clickhouse/rebuild/observe.d.ts +3 -1
  43. package/dist/clickhouse/rebuild/observe.d.ts.map +1 -1
  44. package/dist/clickhouse/rebuild/observe.js +14 -1
  45. package/dist/clickhouse/review-catalog.d.ts +213 -0
  46. package/dist/clickhouse/review-catalog.d.ts.map +1 -0
  47. package/dist/clickhouse/review-catalog.js +330 -0
  48. package/dist/codegen/classifier-page.d.ts.map +1 -1
  49. package/dist/codegen/classifier-page.js +44 -4
  50. package/dist/codegen/clickhouse-module.d.ts.map +1 -1
  51. package/dist/codegen/clickhouse-module.js +3 -0
  52. package/dist/codegen/coverage-page.d.ts.map +1 -1
  53. package/dist/codegen/coverage-page.js +5 -3
  54. package/dist/codegen/docs.js +1 -1
  55. package/dist/codegen/postgres-classifier-page.js +2 -2
  56. package/dist/codegen/registry.d.ts.map +1 -1
  57. package/dist/codegen/registry.js +10 -0
  58. package/dist/composites/catalog.d.ts.map +1 -1
  59. package/dist/composites/catalog.js +100 -0
  60. package/dist/composites/clickhouse.d.ts +2 -0
  61. package/dist/composites/clickhouse.d.ts.map +1 -1
  62. package/dist/composites/clickhouse.js +2 -0
  63. package/dist/composites/otel-tables.d.ts +100 -0
  64. package/dist/composites/otel-tables.d.ts.map +1 -0
  65. package/dist/composites/otel-tables.js +282 -0
  66. package/dist/composites/stream-ingest.d.ts +63 -0
  67. package/dist/composites/stream-ingest.d.ts.map +1 -0
  68. package/dist/composites/stream-ingest.js +39 -0
  69. package/dist/core/statement-class.d.ts +55 -0
  70. package/dist/core/statement-class.d.ts.map +1 -0
  71. package/dist/core/statement-class.js +43 -0
  72. package/dist/coverage/clickhouse.json +1 -1
  73. package/dist/coverage/postgres.json +12 -12
  74. package/dist/coverage.d.ts +16 -6
  75. package/dist/coverage.d.ts.map +1 -1
  76. package/dist/coverage.js +10 -5
  77. package/dist/drizzle-command.d.ts +17 -0
  78. package/dist/drizzle-command.d.ts.map +1 -0
  79. package/dist/drizzle-command.js +91 -0
  80. package/dist/drizzle.d.ts +70 -0
  81. package/dist/drizzle.d.ts.map +1 -0
  82. package/dist/drizzle.js +689 -0
  83. package/dist/files/clickhouse.d.ts.map +1 -1
  84. package/dist/files/clickhouse.js +8 -1
  85. package/dist/files/common.d.ts +13 -0
  86. package/dist/files/common.d.ts.map +1 -1
  87. package/dist/files/common.js +5 -0
  88. package/dist/files/postgres.d.ts.map +1 -1
  89. package/dist/files/postgres.js +35 -3
  90. package/dist/generated/clickhouse.d.ts +2 -0
  91. package/dist/generated/clickhouse.d.ts.map +1 -1
  92. package/dist/generated/clickhouse.js +2 -0
  93. package/dist/import-parser.d.ts +21 -1
  94. package/dist/import-parser.d.ts.map +1 -1
  95. package/dist/import-parser.js +79 -5
  96. package/dist/index.d.ts +1 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +1 -1
  99. package/dist/integrity.json +7 -6
  100. package/dist/lint/post-synth/audit-entries.d.ts.map +1 -1
  101. package/dist/lint/post-synth/audit-entries.js +1 -0
  102. package/dist/lint/post-synth/index.d.ts.map +1 -1
  103. package/dist/lint/post-synth/index.js +2 -0
  104. package/dist/lint/post-synth/postgres-names.d.ts.map +1 -1
  105. package/dist/lint/post-synth/postgres-names.js +3 -0
  106. package/dist/lint/post-synth/sqlch128.d.ts +18 -0
  107. package/dist/lint/post-synth/sqlch128.d.ts.map +1 -0
  108. package/dist/lint/post-synth/sqlch128.js +222 -0
  109. package/dist/lint/rules/postgres-templates.js +2 -2
  110. package/dist/lsp/postgres-template.d.ts.map +1 -1
  111. package/dist/lsp/postgres-template.js +21 -0
  112. package/dist/manifest.json +1 -1
  113. package/dist/mcp/postgres.js +1 -1
  114. package/dist/meta.json +50 -0
  115. package/dist/migrate/from-postgres/detect.d.ts +4 -0
  116. package/dist/migrate/from-postgres/detect.d.ts.map +1 -0
  117. package/dist/migrate/from-postgres/detect.js +7 -0
  118. package/dist/migrate/from-postgres/emit.d.ts +26 -0
  119. package/dist/migrate/from-postgres/emit.d.ts.map +1 -0
  120. package/dist/migrate/from-postgres/emit.js +86 -0
  121. package/dist/migrate/from-postgres/index.d.ts +51 -0
  122. package/dist/migrate/from-postgres/index.d.ts.map +1 -0
  123. package/dist/migrate/from-postgres/index.js +115 -0
  124. package/dist/migrate/from-postgres/translate.d.ts +73 -0
  125. package/dist/migrate/from-postgres/translate.d.ts.map +1 -0
  126. package/dist/migrate/from-postgres/translate.js +261 -0
  127. package/dist/migrate/from-postgres/types.d.ts +51 -0
  128. package/dist/migrate/from-postgres/types.d.ts.map +1 -0
  129. package/dist/migrate/from-postgres/types.js +211 -0
  130. package/dist/migration-classify.d.ts +23 -0
  131. package/dist/migration-classify.d.ts.map +1 -0
  132. package/dist/migration-classify.js +44 -0
  133. package/dist/migration-replay.d.ts +73 -0
  134. package/dist/migration-replay.d.ts.map +1 -0
  135. package/dist/migration-replay.js +294 -0
  136. package/dist/okf/index.md +11 -0
  137. package/dist/okf/rules/SQLCH128.md +11 -0
  138. package/dist/okf/types/PostgresForeignDataWrapper.md +9 -0
  139. package/dist/okf/types/PostgresForeignServer.md +9 -0
  140. package/dist/okf/types/PostgresForeignTable.md +9 -0
  141. package/dist/okf/types/PostgresOperator.md +9 -0
  142. package/dist/okf/types/PostgresOperatorClass.md +9 -0
  143. package/dist/okf/types/PostgresOperatorFamily.md +9 -0
  144. package/dist/okf/types/PostgresPublication.md +9 -0
  145. package/dist/okf/types/PostgresStatistics.md +9 -0
  146. package/dist/okf/types/PostgresTextSearchConfiguration.md +9 -0
  147. package/dist/okf/types/PostgresTextSearchDictionary.md +9 -0
  148. package/dist/op/activities/postgres-migration.d.ts.map +1 -1
  149. package/dist/op/activities/postgres-migration.js +4 -0
  150. package/dist/op/activity-contracts.d.ts +20 -0
  151. package/dist/op/activity-contracts.d.ts.map +1 -1
  152. package/dist/op/activity-contracts.js +2 -0
  153. package/dist/plugin.d.ts.map +1 -1
  154. package/dist/plugin.js +49 -2
  155. package/dist/postgres/access/acl.js +1 -1
  156. package/dist/postgres/access/import.js +1 -1
  157. package/dist/postgres/apply/apply.js +13 -1
  158. package/dist/postgres/apply/statements.d.ts.map +1 -1
  159. package/dist/postgres/apply/statements.js +243 -4
  160. package/dist/postgres/constraint-names.d.ts +30 -0
  161. package/dist/postgres/constraint-names.d.ts.map +1 -0
  162. package/dist/postgres/constraint-names.js +72 -0
  163. package/dist/postgres/entities.d.ts +229 -2
  164. package/dist/postgres/entities.d.ts.map +1 -1
  165. package/dist/postgres/entities.js +326 -5
  166. package/dist/postgres/entity-types.d.ts +10 -0
  167. package/dist/postgres/entity-types.d.ts.map +1 -1
  168. package/dist/postgres/entity-types.js +10 -0
  169. package/dist/postgres/import/generator.d.ts.map +1 -1
  170. package/dist/postgres/import/generator.js +65 -2
  171. package/dist/postgres/import/live-export.d.ts.map +1 -1
  172. package/dist/postgres/import/live-export.js +2 -0
  173. package/dist/postgres/live/catalog-kinds.d.ts +20 -0
  174. package/dist/postgres/live/catalog-kinds.d.ts.map +1 -1
  175. package/dist/postgres/live/catalog-kinds.js +452 -0
  176. package/dist/postgres/live/catalog.d.ts +2 -0
  177. package/dist/postgres/live/catalog.d.ts.map +1 -1
  178. package/dist/postgres/live/catalog.js +3 -1
  179. package/dist/postgres/live/describe-resources.d.ts.map +1 -1
  180. package/dist/postgres/live/describe-resources.js +12 -2
  181. package/dist/postgres/migrate/backfill.d.ts +2 -0
  182. package/dist/postgres/migrate/backfill.d.ts.map +1 -1
  183. package/dist/postgres/migrate/backfill.js +7 -1
  184. package/dist/postgres/migrate/carry.d.ts +45 -1
  185. package/dist/postgres/migrate/carry.d.ts.map +1 -1
  186. package/dist/postgres/migrate/carry.js +72 -8
  187. package/dist/postgres/migrate/observe.d.ts +28 -4
  188. package/dist/postgres/migrate/observe.d.ts.map +1 -1
  189. package/dist/postgres/migrate/observe.js +45 -13
  190. package/dist/postgres/migrate/op.d.ts +26 -1
  191. package/dist/postgres/migrate/op.d.ts.map +1 -1
  192. package/dist/postgres/migrate/op.js +3 -1
  193. package/dist/postgres/migrate/replication.d.ts +42 -0
  194. package/dist/postgres/migrate/replication.d.ts.map +1 -1
  195. package/dist/postgres/migrate/replication.js +53 -0
  196. package/dist/postgres/migrate/steps.d.ts +35 -2
  197. package/dist/postgres/migrate/steps.d.ts.map +1 -1
  198. package/dist/postgres/migrate/steps.js +158 -12
  199. package/dist/postgres/parser.d.ts +144 -1
  200. package/dist/postgres/parser.d.ts.map +1 -1
  201. package/dist/postgres/parser.js +370 -4
  202. package/dist/postgres/plan/deep.d.ts.map +1 -1
  203. package/dist/postgres/plan/deep.js +43 -4
  204. package/dist/postgres/plan/diff.d.ts.map +1 -1
  205. package/dist/postgres/plan/diff.js +154 -1
  206. package/dist/postgres/plan/normalize.d.ts +28 -2
  207. package/dist/postgres/plan/normalize.d.ts.map +1 -1
  208. package/dist/postgres/plan/normalize.js +260 -1
  209. package/dist/postgres/plan/rules.d.ts +4 -0
  210. package/dist/postgres/plan/rules.d.ts.map +1 -1
  211. package/dist/postgres/plan/rules.js +6 -2
  212. package/dist/postgres/plan/schema.js +1 -1
  213. package/dist/postgres/plan/statements.d.ts +26 -0
  214. package/dist/postgres/plan/statements.d.ts.map +1 -0
  215. package/dist/postgres/plan/statements.js +364 -0
  216. package/dist/postgres/secret-options.d.ts +10 -0
  217. package/dist/postgres/secret-options.d.ts.map +1 -0
  218. package/dist/postgres/secret-options.js +9 -0
  219. package/dist/postgres/testing/roundtrip-schema.d.ts +4 -2
  220. package/dist/postgres/testing/roundtrip-schema.d.ts.map +1 -1
  221. package/dist/postgres/testing/roundtrip-schema.js +24 -1
  222. package/dist/postgres.d.ts +1 -1
  223. package/dist/postgres.d.ts.map +1 -1
  224. package/dist/postgres.js +1 -1
  225. package/dist/rules/audit-entries.ts +1 -0
  226. package/dist/rules/postgres-names.ts +2 -0
  227. package/dist/rules/postgres-templates.ts +2 -2
  228. package/dist/rules/sqlch128.ts +230 -0
  229. package/dist/serializer.d.ts +5 -0
  230. package/dist/serializer.d.ts.map +1 -1
  231. package/dist/serializer.js +13 -2
  232. package/dist/sql-types-command.d.ts +13 -0
  233. package/dist/sql-types-command.d.ts.map +1 -1
  234. package/dist/sql-types-command.js +31 -16
  235. package/dist/sql-types.d.ts +22 -0
  236. package/dist/sql-types.d.ts.map +1 -1
  237. package/dist/sql-types.js +10 -6
  238. package/dist/sqlserver/lexer.d.ts +37 -0
  239. package/dist/sqlserver/lexer.d.ts.map +1 -0
  240. package/dist/sqlserver/lexer.js +254 -0
  241. package/dist/sqlserver/parse.d.ts +185 -0
  242. package/dist/sqlserver/parse.d.ts.map +1 -0
  243. package/dist/sqlserver/parse.js +767 -0
  244. package/dist/sqlserver/translate.d.ts +34 -0
  245. package/dist/sqlserver/translate.d.ts.map +1 -0
  246. package/dist/sqlserver/translate.js +495 -0
  247. package/dist/sqlserver/types.d.ts +44 -0
  248. package/dist/sqlserver/types.d.ts.map +1 -0
  249. package/dist/sqlserver/types.js +133 -0
  250. package/dist/sqlserver/validate.d.ts +31 -0
  251. package/dist/sqlserver/validate.d.ts.map +1 -0
  252. package/dist/sqlserver/validate.js +67 -0
  253. package/dist/validate.d.ts.map +1 -1
  254. package/dist/validate.js +10 -0
  255. package/package.json +2 -2
  256. package/src/change-set.ts +2 -1
  257. package/src/clickhouse/apply/statements.ts +25 -0
  258. package/src/clickhouse/import/live-export.ts +20 -5
  259. package/src/clickhouse/live/named-collections.e2e.test.ts +88 -0
  260. package/src/clickhouse/live/named-collections.ts +61 -0
  261. package/src/clickhouse/live/undeclarable.e2e.test.ts +5 -3
  262. package/src/clickhouse/live/undeclarable.ts +20 -4
  263. package/src/clickhouse/named-collections.test.ts +187 -0
  264. package/src/clickhouse/named-collections.ts +224 -0
  265. package/src/clickhouse/parser.ts +2 -1
  266. package/src/clickhouse/plan/commands.ts +17 -2
  267. package/src/clickhouse/plan/diff.ts +57 -1
  268. package/src/clickhouse/plan/disruption.ts +5 -0
  269. package/src/clickhouse/plan/rebuild-handoff.ts +3 -0
  270. package/src/clickhouse/plan/report.ts +6 -1
  271. package/src/clickhouse/plan/rules.ts +14 -4
  272. package/src/clickhouse/plan/statements.test.ts +61 -0
  273. package/src/clickhouse/plan/statements.ts +306 -0
  274. package/src/clickhouse/plan/stream-s3queue.e2e.test.ts +148 -0
  275. package/src/clickhouse/plan/stream.test.ts +237 -0
  276. package/src/clickhouse/plan/stream.ts +111 -0
  277. package/src/clickhouse/rebuild/observe.ts +15 -1
  278. package/src/clickhouse/review-catalog.test.ts +181 -0
  279. package/src/clickhouse/review-catalog.ts +489 -0
  280. package/src/codegen/classifier-page.ts +44 -4
  281. package/src/codegen/clickhouse-module.ts +3 -0
  282. package/src/codegen/coverage-page.ts +5 -3
  283. package/src/codegen/docs.ts +1 -1
  284. package/src/codegen/postgres-classifier-page.ts +2 -2
  285. package/src/codegen/registry.ts +10 -0
  286. package/src/composites/catalog.test.ts +6 -1
  287. package/src/composites/catalog.ts +100 -0
  288. package/src/composites/clickhouse.ts +2 -0
  289. package/src/composites/composites.test.ts +1 -1
  290. package/src/composites/otel-tables.test.ts +118 -0
  291. package/src/composites/otel-tables.ts +339 -0
  292. package/src/composites/stream-ingest.test.ts +114 -0
  293. package/src/composites/stream-ingest.ts +82 -0
  294. package/src/core/statement-class.ts +88 -0
  295. package/src/core/undeclarable.test.ts +6 -5
  296. package/src/coverage/clickhouse.json +1 -1
  297. package/src/coverage/postgres.json +12 -12
  298. package/src/coverage.test.ts +27 -2
  299. package/src/coverage.ts +18 -7
  300. package/src/drizzle-command.ts +94 -0
  301. package/src/drizzle-kit.e2e.test.ts +89 -0
  302. package/src/drizzle-types.e2e.test.ts +67 -0
  303. package/src/drizzle.test.ts +358 -0
  304. package/src/drizzle.ts +742 -0
  305. package/src/files/clickhouse.ts +8 -1
  306. package/src/files/common.ts +14 -1
  307. package/src/files/postgres.ts +34 -3
  308. package/src/generated/clickhouse.ts +3 -0
  309. package/src/generated/lexicon-sql.json +50 -0
  310. package/src/import-parser.sqlserver.test.ts +92 -0
  311. package/src/import-parser.ts +79 -5
  312. package/src/index.ts +1 -1
  313. package/src/lint/post-synth/audit-entries.ts +1 -0
  314. package/src/lint/post-synth/index.ts +2 -0
  315. package/src/lint/post-synth/postgres-checks.test.ts +8 -1
  316. package/src/lint/post-synth/postgres-names.ts +2 -0
  317. package/src/lint/post-synth/sqlch128.test.ts +107 -0
  318. package/src/lint/post-synth/sqlch128.ts +230 -0
  319. package/src/lint/rules/postgres-templates.ts +2 -2
  320. package/src/lsp/postgres-template.ts +20 -0
  321. package/src/mcp/postgres.ts +1 -1
  322. package/src/migrate/from-postgres/cli.test.ts +165 -0
  323. package/src/migrate/from-postgres/detect.ts +7 -0
  324. package/src/migrate/from-postgres/emit.ts +96 -0
  325. package/src/migrate/from-postgres/example.test.ts +205 -0
  326. package/src/migrate/from-postgres/index.ts +122 -0
  327. package/src/migrate/from-postgres/translate.test.ts +242 -0
  328. package/src/migrate/from-postgres/translate.ts +359 -0
  329. package/src/migrate/from-postgres/types.test.ts +116 -0
  330. package/src/migrate/from-postgres/types.ts +236 -0
  331. package/src/migrate/from-postgres/validate.e2e.test.ts +44 -0
  332. package/src/migrate/from-postgres/workspace.e2e.test.ts +114 -0
  333. package/src/migration-classify.test.ts +150 -0
  334. package/src/migration-classify.ts +45 -0
  335. package/src/migration-replay.e2e.test.ts +155 -0
  336. package/src/migration-replay.test.ts +173 -0
  337. package/src/migration-replay.ts +289 -0
  338. package/src/op/__snapshots__/watch-pipeline.test.ts.snap +2 -2
  339. package/src/op/activities/postgres-migration.ts +4 -0
  340. package/src/op/activity-contracts.ts +2 -0
  341. package/src/op/watch-pipeline.test.ts +8 -1
  342. package/src/plugin.ts +51 -2
  343. package/src/postgres/access/acl.ts +1 -1
  344. package/src/postgres/access/import.ts +1 -1
  345. package/src/postgres/apply/apply.ts +14 -1
  346. package/src/postgres/apply/statements.ts +225 -4
  347. package/src/postgres/constraint-names.ts +71 -0
  348. package/src/postgres/database-kinds.test.ts +865 -0
  349. package/src/postgres/entities.ts +541 -5
  350. package/src/postgres/entity-types.ts +10 -0
  351. package/src/postgres/import/generator.ts +54 -2
  352. package/src/postgres/import/live-export.ts +1 -0
  353. package/src/postgres/live/catalog-kinds.ts +494 -0
  354. package/src/postgres/live/catalog.ts +6 -1
  355. package/src/postgres/live/database-kinds.e2e.test.ts +164 -0
  356. package/src/postgres/live/describe-resources.ts +13 -2
  357. package/src/postgres/live/undeclarable.e2e.test.ts +13 -6
  358. package/src/postgres/migrate/backfill.ts +13 -1
  359. package/src/postgres/migrate/carry.ts +103 -8
  360. package/src/postgres/migrate/followups.e2e.test.ts +218 -0
  361. package/src/postgres/migrate/followups.test.ts +199 -0
  362. package/src/postgres/migrate/kinds.e2e.test.ts +5 -5
  363. package/src/postgres/migrate/observe.ts +56 -15
  364. package/src/postgres/migrate/op.ts +28 -1
  365. package/src/postgres/migrate/partition.e2e.test.ts +129 -0
  366. package/src/postgres/migrate/partition.test.ts +206 -0
  367. package/src/postgres/migrate/replication.ts +66 -0
  368. package/src/postgres/migrate/steps.ts +157 -12
  369. package/src/postgres/migrate/subscriber.e2e.test.ts +141 -0
  370. package/src/postgres/migrate/subscriber.test.ts +59 -0
  371. package/src/postgres/parser.ts +455 -4
  372. package/src/postgres/plan/deep.ts +42 -4
  373. package/src/postgres/plan/diff.ts +137 -1
  374. package/src/postgres/plan/normalize.ts +277 -1
  375. package/src/postgres/plan/rules.ts +32 -4
  376. package/src/postgres/plan/schema.ts +1 -1
  377. package/src/postgres/plan/statements.test.ts +78 -0
  378. package/src/postgres/plan/statements.ts +299 -0
  379. package/src/postgres/secret-options.ts +10 -0
  380. package/src/postgres/testing/roundtrip-schema.ts +24 -1
  381. package/src/postgres.ts +33 -0
  382. package/src/serializer.ts +13 -2
  383. package/src/skills/chant-sql-postgres-migration.md +4 -3
  384. package/src/skills/chant-sql-postgres.md +11 -1
  385. package/src/skills/chant-sql.md +2 -1
  386. package/src/sql-files.test.ts +33 -0
  387. package/src/sql-types-command.ts +38 -16
  388. package/src/sql-types.ts +11 -6
  389. package/src/sqlserver/fixture.test.ts +186 -0
  390. package/src/sqlserver/import-cli.test.ts +61 -0
  391. package/src/sqlserver/lexer.ts +260 -0
  392. package/src/sqlserver/parse.ts +865 -0
  393. package/src/sqlserver/translate.test.ts +396 -0
  394. package/src/sqlserver/translate.ts +558 -0
  395. package/src/sqlserver/types.test.ts +102 -0
  396. package/src/sqlserver/types.ts +154 -0
  397. package/src/sqlserver/validate.e2e.test.ts +32 -0
  398. package/src/sqlserver/validate.test.ts +49 -0
  399. package/src/sqlserver/validate.ts +76 -0
  400. package/src/validate.ts +10 -0
  401. package/src/workspace-kinds.test.ts +11 -0
  402. package/workspace-kinds.json +100 -2
@@ -0,0 +1,115 @@
1
+ /**
2
+ * `chant migrate --from sql/postgres --to sql/clickhouse <file or member>`
3
+ * (#4399): the Postgres tables a CDC pipeline mirrors, as the ClickHouse
4
+ * tables that receive them.
5
+ *
6
+ * ## Naming
7
+ *
8
+ * A `chant migrate` side names a lexicon, and the sql lexicon holds two
9
+ * dialects whose builds never mix, so a side is `<lexicon>/<dialect>`:
10
+ * `sql/postgres` and `sql/clickhouse`. `--to sql/clickhouse` loads the sql
11
+ * lexicon and asks it for `migrationSource("sql/postgres", "sql/clickhouse")`.
12
+ * The same shape would name a later pair (`sql/clickhouse` to `sql/postgres`)
13
+ * without a new flag. A side with no slash is a lexicon alone, as for
14
+ * `--from github --to gitlab`.
15
+ *
16
+ * ## The source
17
+ *
18
+ * - a `.sql` file of Postgres DDL;
19
+ * - a TypeScript file or a member directory of `table` declarations, read by
20
+ * a folded build of the project it belongs to (`chant sql types` reads the
21
+ * same way), so `${shop}.customers` and other interpolations resolve.
22
+ *
23
+ * ## What it writes
24
+ *
25
+ * `--emit ts` (the default here) writes declarations: `table` templates, or
26
+ * `CdcMirror` calls with `--use-composites`. `--emit sql` writes the DDL.
27
+ * Every decision that is not the type map is a finding from the shared
28
+ * catalog (`../../clickhouse/review-catalog.ts`), reported as SARIF with
29
+ * `--report`, and a `warning` fails the run under `--strict`.
30
+ *
31
+ * `links` names the Postgres output each mirrored column reads
32
+ * (`shop.customers.email`). In a workspace, `chant migrate` writes them as
33
+ * `links` of the ClickHouse member (`../../../../packages/core/src/workspace/migrate-links.ts`),
34
+ * so `chant workspace check` fails when the Postgres declaration drops or
35
+ * renames one.
36
+ *
37
+ * `--validate` creates the emitted DDL on a throwaway server of the pinned
38
+ * ClickHouse image (`../../sqlserver/validate.ts` runs it).
39
+ */
40
+ import { existsSync, statSync } from "node:fs";
41
+ import { dirname } from "node:path";
42
+ import { looksLikePostgres } from "./detect.js";
43
+ import { emitSql, emitTs, mirrorObjects } from "./emit.js";
44
+ import { translatePostgres } from "./translate.js";
45
+ export const FROM_POSTGRES = "sql/postgres";
46
+ export const TO_CLICKHOUSE = "sql/clickhouse";
47
+ /** Whether `from` and `to` name this pair. */
48
+ export const isPostgresToClickHouse = (from, to) => from === FROM_POSTGRES && (to === undefined || to === TO_CLICKHOUSE);
49
+ /** The Postgres declarations at `sourceFile`: a `.sql` file read as DDL, else a folded build of its project. */
50
+ export async function loadPostgresEntities(content, sourceFile) {
51
+ const isDir = sourceFile !== undefined && existsSync(sourceFile) && statSync(sourceFile).isDirectory();
52
+ if (!isDir && (sourceFile === undefined || sourceFile.endsWith(".sql"))) {
53
+ const { sqlFileEntities } = await import("../../sql-files.js");
54
+ return sqlFileEntities("postgres", [{ ddl: content, origin: sourceFile ?? "the DDL" }], { known: new Map() });
55
+ }
56
+ const { buildFolded, loadProject } = await import("../../sql-types-command.js");
57
+ const project = await loadProject(isDir ? sourceFile : dirname(sourceFile));
58
+ const result = await buildFolded(project, "chant migrate", "nothing was translated");
59
+ if (!result)
60
+ throw new Error(`the build of ${sourceFile} failed`);
61
+ return new Map(result.entities);
62
+ }
63
+ /** A finding as the lint diagnostic `chant migrate` writes as SARIF. */
64
+ function toDiagnostic(file, d, strict) {
65
+ return {
66
+ file,
67
+ line: d.line ?? 1,
68
+ column: d.column ?? 1,
69
+ ruleId: d.ruleId,
70
+ // Under --strict a warning is an error, which is what fails the run (core reads the severity).
71
+ severity: strict && d.severity === "warning" ? "error" : d.severity,
72
+ message: d.message,
73
+ ...(d.entity ? { entity: d.entity } : {}),
74
+ };
75
+ }
76
+ export async function transform(content, opts) {
77
+ const emit = opts.emit ?? "ts";
78
+ if (emit === "yaml")
79
+ throw new Error("--emit yaml has no meaning here; use --emit ts or --emit sql");
80
+ const composite = opts.useComposites === true;
81
+ const file = opts.sourceFile ?? "schema.sql";
82
+ const entities = await loadPostgresEntities(content, opts.sourceFile);
83
+ const translation = translatePostgres(entities, { composite });
84
+ if (translation.mirrors.length === 0) {
85
+ const refused = translation.diagnostics.filter((d) => d.severity === "error").map((d) => d.message);
86
+ throw new Error(`no Postgres table to mirror in ${file}${refused.length > 0 ? `: ${refused.join(" ")}` : ""}`);
87
+ }
88
+ const output = emit === "sql" ? emitSql(translation.mirrors, composite) : emitTs(translation.mirrors, composite);
89
+ const diagnostics = translation.diagnostics.map((d) => toDiagnostic(file, d, opts.strict === true));
90
+ const provenance = translation.mirrors.map((m) => ({
91
+ sourceKey: `${m.source.schema}.${m.source.table}`,
92
+ rule: composite ? "SQLMIG-CDC-MIRROR" : "SQLMIG-TABLE",
93
+ category: "translated",
94
+ note: `${String(m.columns.length)} columns; ORDER BY ${m.primaryKey.length === 0 ? "tuple()" : `(${m.primaryKey.join(", ")})`}`,
95
+ }));
96
+ return {
97
+ output,
98
+ provenance,
99
+ diagnostics,
100
+ links: translation.outputs,
101
+ validate: async () => {
102
+ const [{ objectsToIR }, { validateOnEmulator }] = await Promise.all([import("../../clickhouse/import/ir.js"), import("../../sqlserver/validate.js")]);
103
+ const found = await validateOnEmulator(objectsToIR(mirrorObjects(translation.mirrors, composite)));
104
+ return found.map((d) => ({ file, line: 1, column: 1, ruleId: d.ruleId, severity: d.severity, message: d.message, ...(d.entity ? { entity: d.entity } : {}) }));
105
+ },
106
+ };
107
+ }
108
+ /** The `migrationSource` of the sql lexicon for this pair. */
109
+ export function postgresToClickHouseSource() {
110
+ return {
111
+ detect: looksLikePostgres,
112
+ directory: true,
113
+ transform,
114
+ };
115
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Postgres tables into the ClickHouse tables a CDC pipeline fills (#4399).
3
+ *
4
+ * The input is the Postgres declarations a build reads (or a `.sql` file read
5
+ * into the same declarations), the output a {@link Mirror} per table: its
6
+ * ClickHouse columns, its sort key and the facts the writers need. Writing
7
+ * the mirror as DDL or as a `CdcMirror` call is `./emit.ts`.
8
+ *
9
+ * What is mechanical makes no finding: the type map in `./types.ts`, names,
10
+ * column order, a `NOT NULL` column keeping its type. Everything else is
11
+ * decided by the shared catalog (`../../clickhouse/review-catalog.ts`): the
12
+ * sort key from the primary key, the `ReplacingMergeTree` engine for a
13
+ * mirror, `Nullable` against a default, `LowCardinality` candidates, and the
14
+ * constraints ClickHouse does not enforce. This file adds what only Postgres
15
+ * has: identity, serial and generated columns, defaults, storage options,
16
+ * indexes that are not carried, and the objects of the file that are not
17
+ * tables.
18
+ *
19
+ * A mirror's columns carry no `DEFAULT`: the pipeline writes every column of
20
+ * a row, so the source's default has already run. That is an `info` finding
21
+ * (SQLRV008), not a `warning`, since it changes nothing a reader of the
22
+ * mirror sees.
23
+ *
24
+ * The Postgres schema is not part of the mirror's name. A pipeline chooses
25
+ * the ClickHouse database it writes to, so `shop.customers` becomes
26
+ * `customers` in that database. Two tables with one name in different
27
+ * schemas keep their schema as a database qualifier (`shop.customers`).
28
+ */
29
+ import type { Declarable } from "@intentius/chant/declarable";
30
+ import type { ImportDiagnostic } from "@intentius/chant/import/parser";
31
+ /** The names of the columns the pipeline adds, and what `CdcMirror` calls them by default. */
32
+ export declare const MIRROR_COLUMNS: {
33
+ readonly version: "_version";
34
+ readonly deleted: "_is_deleted";
35
+ };
36
+ export interface MirrorColumn {
37
+ name: string;
38
+ /** The ClickHouse type, `Nullable` and `LowCardinality` decisions included. */
39
+ type: string;
40
+ comment?: string;
41
+ }
42
+ export interface Mirror {
43
+ /** The export the Postgres table is declared as, or its name when the source has none. */
44
+ export: string;
45
+ /** The ClickHouse table name, qualified with a database only when two tables would collide. */
46
+ name: string;
47
+ /** The Postgres schema and table, for the workspace link. */
48
+ source: {
49
+ schema: string;
50
+ table: string;
51
+ };
52
+ columns: MirrorColumn[];
53
+ /** The sort key; empty means `tuple()`. */
54
+ primaryKey: string[];
55
+ /** MergeTree settings the key needs. */
56
+ settings: Record<string, string>;
57
+ /** `-- ` lines for constraints ClickHouse does not enforce. */
58
+ constraintComments: string[];
59
+ /** The table's description, which `CdcMirror` has no place for. */
60
+ comment?: string;
61
+ }
62
+ export interface Translation {
63
+ mirrors: Mirror[];
64
+ diagnostics: ImportDiagnostic[];
65
+ /** The Postgres outputs each mirrored column reads, as a workspace link names them (`shop.customers.email`). */
66
+ outputs: string[];
67
+ }
68
+ export interface TranslateOptions {
69
+ /** The mirror is a `CdcMirror` call: a table description has no place in it. */
70
+ composite: boolean;
71
+ }
72
+ export declare function translatePostgres(entities: ReadonlyMap<string, Declarable>, opts: TranslateOptions): Translation;
73
+ //# sourceMappingURL=translate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../src/migrate/from-postgres/translate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAgBvE,8FAA8F;AAC9F,eAAO,MAAM,cAAc;;;CAA2D,CAAC;AAEvF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,+DAA+D;IAC/D,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,gHAAgH;IAChH,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,SAAS,EAAE,OAAO,CAAC;CACpB;AAwOD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,IAAI,EAAE,gBAAgB,GAAG,WAAW,CA0ChH"}
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Postgres tables into the ClickHouse tables a CDC pipeline fills (#4399).
3
+ *
4
+ * The input is the Postgres declarations a build reads (or a `.sql` file read
5
+ * into the same declarations), the output a {@link Mirror} per table: its
6
+ * ClickHouse columns, its sort key and the facts the writers need. Writing
7
+ * the mirror as DDL or as a `CdcMirror` call is `./emit.ts`.
8
+ *
9
+ * What is mechanical makes no finding: the type map in `./types.ts`, names,
10
+ * column order, a `NOT NULL` column keeping its type. Everything else is
11
+ * decided by the shared catalog (`../../clickhouse/review-catalog.ts`): the
12
+ * sort key from the primary key, the `ReplacingMergeTree` engine for a
13
+ * mirror, `Nullable` against a default, `LowCardinality` candidates, and the
14
+ * constraints ClickHouse does not enforce. This file adds what only Postgres
15
+ * has: identity, serial and generated columns, defaults, storage options,
16
+ * indexes that are not carried, and the objects of the file that are not
17
+ * tables.
18
+ *
19
+ * A mirror's columns carry no `DEFAULT`: the pipeline writes every column of
20
+ * a row, so the source's default has already run. That is an `info` finding
21
+ * (SQLRV008), not a `warning`, since it changes nothing a reader of the
22
+ * mirror sees.
23
+ *
24
+ * The Postgres schema is not part of the mirror's name. A pipeline chooses
25
+ * the ClickHouse database it writes to, so `shop.customers` becomes
26
+ * `customers` in that database. Two tables with one name in different
27
+ * schemas keep their schema as a database qualifier (`shop.customers`).
28
+ */
29
+ import { constraintReview, engineReview, findingText, lowCardinalityReview, nullableReview, sortKeyReview, } from "../../clickhouse/review-catalog.js";
30
+ import { isPostgresObject, POSTGRES_ENTITY_TYPES } from "../../postgres/entities.js";
31
+ import { mapPostgresType } from "./types.js";
32
+ /** The names of the columns the pipeline adds, and what `CdcMirror` calls them by default. */
33
+ export const MIRROR_COLUMNS = { version: "_version", deleted: "_is_deleted" };
34
+ const DEFAULT_SCHEMA = "public";
35
+ const ident = (name) => (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `\`${name.replace(/\\/g, "\\\\").replace(/`/g, "\\`")}\``);
36
+ const oneLine = (s) => s.replace(/\s+/g, " ").trim();
37
+ class Report {
38
+ constructor() {
39
+ this.diagnostics = [];
40
+ }
41
+ finding(f) {
42
+ this.diagnostics.push({ ruleId: f.ruleId, severity: f.severity, message: findingText(f), entity: f.object });
43
+ }
44
+ /** A finding of this file's own. `error` marks a table the translation refuses; the catalog's findings never are. */
45
+ note(ruleId, severity, object, message, evidence, column, suggestion) {
46
+ const text = findingText({ ruleId, severity: severity === "error" ? "warning" : severity, object, ...(column ? { column } : {}), message, evidence, ...(suggestion ? { suggestion } : {}) });
47
+ this.diagnostics.push({ ruleId, severity, message: text, entity: object });
48
+ }
49
+ }
50
+ const propsOf = (e) => e.props;
51
+ const display = (schema, name) => (schema ? `${schema}.${name}` : name);
52
+ /** The Postgres tables among `entities`, in the order given, with the export each is declared as. */
53
+ function tablesOf(entities) {
54
+ const out = [];
55
+ for (const [key, e] of entities)
56
+ if (isPostgresObject(e) && e.entityType === POSTGRES_ENTITY_TYPES.table)
57
+ out.push({ key, props: propsOf(e) });
58
+ return out;
59
+ }
60
+ /** Whether an index is on this table: its table is named bare, or with the schema, as the DDL wrote it. */
61
+ const tableMatches = (ix, t) => {
62
+ const target = ix.tableName.replace(/"/g, "");
63
+ return target === t.name || target === `${t.schema ?? DEFAULT_SCHEMA}.${t.name}`;
64
+ };
65
+ function translateTable(key, t, indexes, mirrorName, opts, report) {
66
+ const schema = t.schema ?? DEFAULT_SCHEMA;
67
+ const object = display(t.schema, t.name);
68
+ const pk = new Set(t.primaryKey?.columns ?? []);
69
+ for (const reserved of Object.values(MIRROR_COLUMNS)) {
70
+ if (t.columns.some((c) => c.name === reserved)) {
71
+ report.note("SQLRV011", "error", object, `The table is not carried: it already has a column named ${reserved}, which the mirror adds.`, [`column ${reserved} in the source`], reserved, "Rename the source column, or name the pipeline's columns otherwise in the CdcMirror call.");
72
+ return undefined;
73
+ }
74
+ }
75
+ if (opts.composite && !/^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)?$/.test(mirrorName)) {
76
+ report.note("SQLRV011", "error", object, `The table is not carried: CdcMirror writes the name ${mirrorName} unquoted, and it needs quoting.`, [`the name ${mirrorName} is not a plain identifier`], undefined, "Emit without --use-composites to keep the quoted name, or rename the table.");
77
+ return undefined;
78
+ }
79
+ if (t.partitionOf !== undefined) {
80
+ report.note("SQLRV011", "info", object, "A partition is not carried; its rows reach the mirror through the parent table.", [`PARTITION OF ${typeof t.partitionOf === "string" ? t.partitionOf : "the parent"}`]);
81
+ return undefined;
82
+ }
83
+ const unread = [];
84
+ if (t.like.length > 0)
85
+ unread.push(...t.like.map((l) => `LIKE ${l}`));
86
+ if (t.inherits.length > 0)
87
+ unread.push(`INHERITS (${t.inherits.map((i) => (typeof i === "string" ? i : "a declared table")).join(", ")})`);
88
+ if (t.ofType !== undefined)
89
+ unread.push(`OF ${typeof t.ofType === "string" ? t.ofType : "a declared type"}`);
90
+ if (unread.length > 0) {
91
+ report.note("SQLRV011", "warning", object, "Columns that come from LIKE, INHERITS or OF are not read.", unread, undefined, "Add the columns to the CdcMirror call by hand, or declare them in the table.");
92
+ }
93
+ const columnTypes = {};
94
+ const columns = [];
95
+ const maxLengths = new Map();
96
+ const droppedStorage = [];
97
+ for (const col of t.columns) {
98
+ const m = mapPostgresType(col.type ?? "");
99
+ if (m.note)
100
+ report.note("SQLRV007", "warning", object, m.note.message, m.note.evidence, col.name);
101
+ if (m.maxLength !== undefined)
102
+ maxLengths.set(col.name, m.maxLength);
103
+ describeGenerated(col, m.serial === true, object, report);
104
+ if (col.default !== undefined && col.generated === undefined && !(m.serial && /nextval\(/i.test(col.default))) {
105
+ report.note("SQLRV008", "info", object, `The default of ${col.name} is not carried.`, [`DEFAULT ${oneLine(col.default)}`, "the pipeline writes every column of a row, so the source has already run the default"], col.name, "Add a ClickHouse DEFAULT if the table is also written by something other than the pipeline.");
106
+ }
107
+ if (col.collate) {
108
+ report.note("SQLRV007", "warning", object, `Collation ${col.collate} on ${col.name} is not carried.`, ["ClickHouse compares String values as bytes; a Postgres collation orders them by locale"], col.name);
109
+ }
110
+ if (col.compression)
111
+ droppedStorage.push(`column ${col.name} COMPRESSION ${col.compression}`);
112
+ if (col.storage)
113
+ droppedStorage.push(`column ${col.name} STORAGE ${col.storage}`);
114
+ // A primary key column, an identity column and a serial column are NOT NULL whatever the DDL says.
115
+ const forcedNotNull = pk.has(col.name) || col.generated?.kind === "identity" || m.serial === true;
116
+ const sourceNullable = m.array === true ? false : !(col.notNull === true || forcedNotNull);
117
+ const n = nullableReview({ object, column: col.name, type: m.type, sourceNullable, ...(col.default !== undefined && sourceNullable ? { defaultExpr: oneLine(col.default) } : {}) });
118
+ if (n.finding)
119
+ report.finding(n.finding);
120
+ columnTypes[col.name] = n.type;
121
+ const lc = lowCardinalityReview({ object, column: col.name, type: n.type, ...(m.maxLength !== undefined ? { maxLength: m.maxLength } : {}) });
122
+ if (lc)
123
+ report.finding(lc);
124
+ columns.push({ name: col.name, type: n.type, ...(col.comment ? { comment: col.comment } : {}) });
125
+ }
126
+ if (columns.length === 0) {
127
+ report.note("SQLRV011", "error", object, "The table is not carried: it declares no column.", ["the CREATE TABLE lists no column"]);
128
+ return undefined;
129
+ }
130
+ // Sort key: the primary key, else the first unique key.
131
+ const uniqueIndex = indexes.find((i) => i.unique === true && i.elements.every((e) => e.column !== undefined));
132
+ const candidates = [];
133
+ if (t.primaryKey && t.primaryKey.columns.length > 0) {
134
+ candidates.push({ kind: "primary-key", ...(t.primaryKey.name ? { name: t.primaryKey.name } : {}), columns: t.primaryKey.columns, source: `PRIMARY KEY${t.primaryKey.name ? ` ${t.primaryKey.name}` : ""}` });
135
+ }
136
+ const firstUnique = t.uniques[0];
137
+ if (firstUnique)
138
+ candidates.push({ kind: "unique-key", ...(firstUnique.name ? { name: firstUnique.name } : {}), columns: firstUnique.columns, source: `UNIQUE${firstUnique.name ? ` ${firstUnique.name}` : ""}` });
139
+ else if (uniqueIndex)
140
+ candidates.push({ kind: "unique-key", name: uniqueIndex.name, columns: uniqueIndex.elements.map((e) => e.column), source: `CREATE UNIQUE INDEX ${uniqueIndex.name}` });
141
+ const sortKey = sortKeyReview({ object, candidates: candidates.filter((c) => c.columns.every((c2) => c2 in columnTypes)), columnTypes });
142
+ report.finding(sortKey.finding);
143
+ if (opts.composite && Object.keys(sortKey.settings).length > 0) {
144
+ report.note("SQLRV001", "warning", object, `The CdcMirror call has no SETTINGS, so ${Object.keys(sortKey.settings).join(", ")} is not set.`, [`the sort key has a Nullable column and needs ${Object.entries(sortKey.settings).map(([k, v]) => `${k} = ${v}`).join(", ")}`], undefined, "Emit without --use-composites to keep the setting, or make the key columns NOT NULL in Postgres.");
145
+ }
146
+ const engine = engineReview({
147
+ object,
148
+ mode: "cdc",
149
+ cdcColumns: { version: MIRROR_COLUMNS.version, deleted: MIRROR_COLUMNS.deleted },
150
+ ...(sortKey.orderBy.length > 0 ? { uniqueKey: sortKey.orderBy } : {}),
151
+ facts: [`the table is declared in Postgres${t.persistence ? ` as ${t.persistence}` : ""}`],
152
+ });
153
+ report.finding(engine.finding);
154
+ // Constraints ClickHouse does not enforce.
155
+ const facts = [];
156
+ for (const fk of t.foreignKeys) {
157
+ facts.push({ kind: "foreign-key", ...(fk.name ? { name: fk.name } : {}), columns: fk.columns, references: { table: fk.refTable, columns: fk.refColumns } });
158
+ }
159
+ for (const u of t.uniques)
160
+ facts.push({ kind: "unique", ...(u.name ? { name: u.name } : {}), columns: u.columns });
161
+ for (const ix of indexes) {
162
+ if (ix.unique === true && ix.elements.every((e) => e.column !== undefined))
163
+ facts.push({ kind: "unique", name: ix.name, columns: ix.elements.map((e) => e.column) });
164
+ }
165
+ for (const c of t.checks)
166
+ facts.push({ kind: "check", ...(c.name ? { name: c.name } : {}), expression: c.expr });
167
+ for (const x of t.exclusions)
168
+ facts.push({ kind: "exclusion", ...(x.name ? { name: x.name } : {}), expression: `${x.using ? `USING ${x.using} ` : ""}(${x.elements})` });
169
+ const constraints = constraintReview({ object, constraints: facts });
170
+ for (const f of constraints.findings)
171
+ report.finding(f);
172
+ // Indexes that are not carried.
173
+ for (const ix of indexes) {
174
+ if (ix.unique === true && ix.elements.every((e) => e.column !== undefined))
175
+ continue;
176
+ const on = ix.elements.map((e) => e.column ?? oneLine(e.expr)).join(", ");
177
+ report.note("SQLRV009", "warning", object, `${ix.name}${ix.unique ? ", a unique index," : ", an index,"} on (${on}) is not carried.`, [`CREATE ${ix.unique ? "UNIQUE " : ""}INDEX ${ix.name}${ix.method ? ` USING ${ix.method}` : ""}${ix.where ? ` WHERE ${oneLine(ix.where)}` : ""}`], undefined, "The sort key is the only index a MergeTree table has by default. A skip index (minmax, set, bloom_filter) on the column can prune granules.");
178
+ }
179
+ // Storage the source chose.
180
+ const dropped = [...droppedStorage];
181
+ if (t.partitionBy)
182
+ dropped.push(`PARTITION BY ${oneLine(t.partitionBy)}`);
183
+ if (t.with)
184
+ dropped.push(`WITH ${oneLine(t.with)}`);
185
+ if (t.tablespace)
186
+ dropped.push(`TABLESPACE ${t.tablespace}`);
187
+ if (t.using)
188
+ dropped.push(`USING ${t.using}`);
189
+ if (t.persistence)
190
+ dropped.push(t.persistence.toUpperCase());
191
+ if (t.rowSecurity === true)
192
+ dropped.push("ROW LEVEL SECURITY");
193
+ if (dropped.length > 0) {
194
+ report.note("SQLRV009", "warning", object, "Storage options of the source table are not carried.", dropped, undefined, "Choose PARTITION BY for the mirror from how it is queried; a source partition is by the write path, a ClickHouse one by the read path.");
195
+ }
196
+ if (t.comment && opts.composite) {
197
+ report.note("SQLRV011", "info", object, "The table's description is not carried: the CdcMirror call has no place for it.", [`COMMENT ON TABLE: ${oneLine(t.comment)}`], undefined, "Emit without --use-composites to keep it as a COMMENT clause.");
198
+ }
199
+ return {
200
+ export: key,
201
+ name: mirrorName,
202
+ source: { schema, table: t.name },
203
+ columns,
204
+ primaryKey: sortKey.orderBy,
205
+ settings: sortKey.settings,
206
+ constraintComments: constraints.comments,
207
+ ...(t.comment && !opts.composite ? { comment: t.comment } : {}),
208
+ };
209
+ }
210
+ /** Identity, serial and generated columns: plain columns here, said once each. */
211
+ function describeGenerated(col, serial, object, report) {
212
+ if (col.generated?.kind === "identity") {
213
+ report.note("SQLRV006", "info", object, `Identity column ${col.name} is a plain column here.`, [`GENERATED ${col.generated.always ? "ALWAYS" : "BY DEFAULT"} AS IDENTITY${col.generated.options ? ` (${oneLine(col.generated.options)})` : ""}`, "ClickHouse has no auto-increment column, and the pipeline loads the value the source made"], col.name);
214
+ }
215
+ else if (col.generated !== undefined) {
216
+ report.note("SQLRV006", "warning", object, `Generated column ${col.name} is a plain column here.`, [`GENERATED ALWAYS AS (${oneLine(col.generated.expr ?? "")}) ${col.generated.kind.toUpperCase()}`, "the pipeline loads the stored value; a virtual column is not sent by every pipeline"], col.name, col.generated.kind === "virtual" ? "Add the column as ALIAS or MATERIALIZED with the expression rewritten in ClickHouse SQL, if the pipeline does not send it." : undefined);
217
+ }
218
+ else if (serial) {
219
+ report.note("SQLRV006", "info", object, `Serial column ${col.name} is a plain integer column here.`, ["serial draws from a sequence, which ClickHouse does not have, and the pipeline loads the value the source made"], col.name);
220
+ }
221
+ }
222
+ /** What an object of the source that is not a table is called in a finding. */
223
+ function describeObject(e) {
224
+ const props = propsOf(e);
225
+ return `${e.entityType.replace(/^Postgres::/, "").toLowerCase()} ${display(props.schema, props.name ?? "?")}`;
226
+ }
227
+ export function translatePostgres(entities, opts) {
228
+ const report = new Report();
229
+ const tables = tablesOf(entities);
230
+ const indexes = [...entities.values()].filter((e) => isPostgresObject(e) && e.entityType === POSTGRES_ENTITY_TYPES.index).map((e) => propsOf(e));
231
+ // Names: a table keeps its bare name unless another schema has a table of that name.
232
+ const counts = new Map();
233
+ for (const { props } of tables)
234
+ counts.set(props.name, (counts.get(props.name) ?? 0) + 1);
235
+ const schemas = new Set(tables.map(({ props }) => props.schema).filter((s) => s !== undefined && s !== DEFAULT_SCHEMA));
236
+ const mirrors = [];
237
+ for (const { key, props } of tables) {
238
+ const collides = (counts.get(props.name) ?? 0) > 1;
239
+ const name = collides ? display(props.schema ?? DEFAULT_SCHEMA, props.name) : props.name;
240
+ if (collides) {
241
+ report.note("SQLRV011", "info", display(props.schema, props.name), `The table keeps its schema as a database, ${name}, because two schemas declare a table of this name.`, ["the Postgres schema is otherwise not part of the mirror's name"]);
242
+ }
243
+ const mine = indexes.filter((ix) => tableMatches(ix, props));
244
+ const m = translateTable(key, props, mine, name, opts, report);
245
+ if (m)
246
+ mirrors.push(m);
247
+ }
248
+ for (const s of [...schemas].sort()) {
249
+ report.note("SQLRV011", "info", s, `Schema ${s} is not part of the mirror's name.`, ["a pipeline writes to one ClickHouse database, which the profile or the pipeline names"], undefined, `Create the tables in the database your pipeline targets (${s} is a common choice).`);
250
+ }
251
+ // Everything else the source declares: named once, with no decision to make.
252
+ for (const e of entities.values()) {
253
+ if (!isPostgresObject(e))
254
+ continue;
255
+ if (e.entityType === POSTGRES_ENTITY_TYPES.table || e.entityType === POSTGRES_ENTITY_TYPES.index || e.entityType === POSTGRES_ENTITY_TYPES.schema)
256
+ continue;
257
+ report.note("SQLRV011", "info", describeObject(e), `Not carried: ${describeObject(e)}.`, ["a mirror is made of tables; this object is not one"]);
258
+ }
259
+ const outputs = mirrors.flatMap((m) => m.columns.map((c) => `${m.source.schema}.${m.source.table}.${c.name}`));
260
+ return { mirrors, diagnostics: report.diagnostics, outputs };
261
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The Postgres to ClickHouse type map (#4399).
3
+ *
4
+ * A type either maps with no judgment (`note` absent) or carries a `note`
5
+ * naming what the map could not keep. Only the first kind is mechanical: the
6
+ * translator writes no diagnostic for it. A type this file does not know (an
7
+ * enum, a domain, an extension type) maps to `String` with a note, because a
8
+ * mirror still has to hold the value.
9
+ *
10
+ * Source types and defaults are from the Postgres data types chapter
11
+ * (https://www.postgresql.org/docs/current/datatype.html): `timestamp` and
12
+ * `time` take a precision of 0 to 6 and default to microseconds, `numeric`
13
+ * with no precision holds any value, `money` is a fixed-point type with a
14
+ * locale-set scale, `float(n)` is `real` for n up to 24 and `double
15
+ * precision` above.
16
+ *
17
+ * Target types are ClickHouse types of the pinned server (`../../spec/pin.ts`);
18
+ * `types.test.ts` checks every family this file writes against the generated
19
+ * catalog.
20
+ */
21
+ export interface MappedType {
22
+ ok: true;
23
+ /** The ClickHouse type, before `Nullable`. */
24
+ type: string;
25
+ /** The declared maximum length of a character type, when it has one. */
26
+ maxLength?: number;
27
+ /** The column is `serial`, `bigserial` or `smallserial`: an integer with a sequence behind it. */
28
+ serial?: boolean;
29
+ /** The column is an array. ClickHouse cannot make an `Array` `Nullable`. */
30
+ array?: boolean;
31
+ /** Present when the map is a judgment: what was lost or chosen. */
32
+ note?: {
33
+ message: string;
34
+ evidence: string[];
35
+ };
36
+ }
37
+ export type TypeMapping = MappedType;
38
+ interface ParsedType {
39
+ /** Lower case words of the type, schema prefix and quotes removed: `timestamp with time zone`. */
40
+ base: string;
41
+ args: number[];
42
+ /** Array dimensions. */
43
+ dims: number;
44
+ raw: string;
45
+ }
46
+ /** Split a column type as written into its words, its parenthesised arguments and its array dimensions. */
47
+ export declare function parseType(text: string): ParsedType;
48
+ /** Map a column type as the declaration wrote it. */
49
+ export declare function mapPostgresType(text: string): TypeMapping;
50
+ export {};
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/migrate/from-postgres/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,IAAI,CAAC;IACT,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kGAAkG;IAClG,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,mEAAmE;IACnE,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAChD;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC;AAErC,UAAU,UAAU;IAClB,kGAAkG;IAClG,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2GAA2G;AAC3G,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CA6BlD;AA0ID,qDAAqD;AACrD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAoBzD"}