@intentius/chant-lexicon-sql 0.124.45 → 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
@@ -0,0 +1,222 @@
1
+ import { DATABASE_ENGINES, FORMATS, TABLE_ENGINES } from "../../generated/clickhouse.js";
2
+ import { parseEngineSyntax } from "../../clickhouse/engine-syntax.js";
3
+ import { COLLECTION_ENGINES, engineCollection } from "../../clickhouse/named-collections.js";
4
+ import { isTrivia, tokenizeText } from "../../clickhouse/tokens.js";
5
+ import { checkOf, splitTop } from "./clickhouse-helpers.js";
6
+ import { clickhouseObjects } from "./sql-helpers.js";
7
+ /** A syntax-line argument that holds a secret: `password`, `secret_access_key`, `account_key`, `session_token`, `oauth_token`. */
8
+ const SECRET_ARGUMENT = /password|secret|account_key|session_token|oauth_token/i;
9
+ /** A `key = value` argument or a setting that holds a secret: the above, and `kafka_sasl_password`, `nats_token`. */
10
+ const SECRET_KEY = /password|secret|account_key|session_token|oauth_token|(?:^|_)token$|private_key/i;
11
+ /** Credentials written inside another value: a URL's `user:password@`, an Azure connection string's key or signature. */
12
+ const EMBEDDED = [
13
+ { re: /^[a-z][a-z0-9+.-]*:\/\/[^/@:\s]+:[^/@\s]+@/i, what: "a URL with a password in it" },
14
+ { re: /(?:^|;)\s*(?:AccountKey|SharedAccessSignature)\s*=/i, what: "a connection string with an account key or signature in it" },
15
+ ];
16
+ /** Compression methods the integration engines take after the format. */
17
+ const COMPRESSION = new Set(["none", "auto", "gzip", "gz", "deflate", "br", "brotli", "xz", "lzma", "zstd", "zst", "lz4", "bz2", "snappy"]);
18
+ const FORMAT_NAMES = new Set(FORMATS.map((f) => f.toLowerCase()));
19
+ /** The table functions whose arguments follow an engine's syntax line, lower case, by engine. */
20
+ const FUNCTION_ENGINE = {
21
+ s3: "S3",
22
+ gcs: "S3",
23
+ oss: "S3",
24
+ cosn: "S3",
25
+ url: "URL",
26
+ mysql: "MySQL",
27
+ postgresql: "PostgreSQL",
28
+ mongodb: "MongoDB",
29
+ azureblobstorage: "AzureBlobStorage",
30
+ iceberg: "Iceberg",
31
+ icebergs3: "IcebergS3",
32
+ icebergazure: "IcebergAzure",
33
+ deltalake: "DeltaLake",
34
+ deltalakes3: "DeltaLakeS3",
35
+ deltalakeazure: "DeltaLakeAzure",
36
+ hudi: "Hudi",
37
+ paimon: "Paimon",
38
+ paimons3: "PaimonS3",
39
+ arrowflight: "ArrowFlight",
40
+ ytsaurus: "YTsaurus",
41
+ };
42
+ /** `remote('addresses', db, table, 'user', 'password')`: no syntax line says it, so its password's position is written here. */
43
+ const FUNCTION_SECRETS = {
44
+ remote: [{ name: "password", position: 4 }],
45
+ remotesecure: [{ name: "password", position: 4 }],
46
+ };
47
+ const ENGINE_SYNTAX = { ...TABLE_ENGINES, ...DATABASE_ENGINES };
48
+ /** The secret arguments an engine's syntax line names, with their positions. */
49
+ function secretPositions(engine) {
50
+ const syntax = ENGINE_SYNTAX[engine]?.syntax;
51
+ const parsed = syntax ? parseEngineSyntax(syntax) : undefined;
52
+ if (!parsed)
53
+ return [];
54
+ return parsed.args
55
+ .filter((a) => !a.named && a.name.split("|").some((n) => SECRET_ARGUMENT.test(n)))
56
+ .map((a) => ({ name: a.name.split("|").find((n) => SECRET_ARGUMENT.test(n)), position: a.position }));
57
+ }
58
+ /** The text of a string literal, or undefined for anything else. */
59
+ function stringValue(text) {
60
+ const t = text.trim();
61
+ if (!/^'(?:[^'\\]|\\.|'')*'$/.test(t))
62
+ return undefined;
63
+ return t.slice(1, -1).replace(/\\(.)/g, "$1").replace(/''/g, "'");
64
+ }
65
+ /**
66
+ * Whether the arguments before `position` leave it where the syntax line puts
67
+ * it. An optional group (`[, access_key_id, secret_access_key]`) may be left
68
+ * out, and the format and compression move up into its place:
69
+ * `S3('url', 'Parquet', 'gzip')`. When a format, a compression method or
70
+ * `NOSIGN` comes earlier, the position says nothing.
71
+ */
72
+ function aligned(args, position) {
73
+ for (const a of args.slice(1, position)) {
74
+ const t = a.trim();
75
+ if (t.toUpperCase() === "NOSIGN")
76
+ return false;
77
+ const v = stringValue(t)?.toLowerCase();
78
+ if (v !== undefined && (FORMAT_NAMES.has(v) || COMPRESSION.has(v)))
79
+ return false;
80
+ }
81
+ return true;
82
+ }
83
+ /** The literal credentials in one engine's or table function's arguments. */
84
+ function argumentFindings(label, args, secrets, collection) {
85
+ const out = [];
86
+ const add = (where, what, value) => out.push({ where, what, masked: value === "[HIDDEN]" });
87
+ // After a named collection, the arguments are `key = value` overrides, not positions.
88
+ if (!collection) {
89
+ for (const s of secrets) {
90
+ const arg = args[s.position];
91
+ const value = arg !== undefined ? stringValue(arg) : undefined;
92
+ if (value && aligned(args, s.position))
93
+ add(`${label} argument ${s.name}`, "a literal credential", value);
94
+ }
95
+ }
96
+ args.forEach((arg, i) => {
97
+ const kv = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([\s\S]+)$/.exec(arg);
98
+ if (kv) {
99
+ const value = stringValue(kv[2]);
100
+ if (value && SECRET_KEY.test(kv[1]))
101
+ add(`${label} argument ${kv[1]}`, "a literal credential", value);
102
+ return;
103
+ }
104
+ const value = stringValue(arg);
105
+ if (!value)
106
+ return;
107
+ for (const e of EMBEDDED)
108
+ if (e.re.test(value))
109
+ add(`${label} argument ${i + 1}`, e.what, value);
110
+ });
111
+ return out;
112
+ }
113
+ /** Each table function call in a SQL text, with its arguments as written. */
114
+ function functionCalls(text) {
115
+ let tokens;
116
+ try {
117
+ tokens = tokenizeText(text, 0);
118
+ }
119
+ catch {
120
+ return [];
121
+ }
122
+ const sig = tokens.map((t, i) => ({ t, i })).filter(({ t }) => !isTrivia(t));
123
+ const out = [];
124
+ for (let k = 0; k + 1 < sig.length; k++) {
125
+ const fn = sig[k].t;
126
+ const open = sig[k + 1];
127
+ if (fn.kind !== "ident" || open.t.kind !== "punct" || open.t.text !== "(")
128
+ continue;
129
+ const lower = fn.text.toLowerCase();
130
+ const base = lower.endsWith("cluster") ? lower.slice(0, -"cluster".length) : lower;
131
+ if (!(base in FUNCTION_ENGINE) && !(base in FUNCTION_SECRETS))
132
+ continue;
133
+ let depth = 0;
134
+ let end = open.i;
135
+ for (let j = open.i; j < tokens.length; j++) {
136
+ const t = tokens[j];
137
+ if (t.kind === "punct" && t.text === "(")
138
+ depth++;
139
+ else if (t.kind === "punct" && t.text === ")" && --depth === 0) {
140
+ end = j;
141
+ break;
142
+ }
143
+ }
144
+ const inner = tokens
145
+ .slice(open.i + 1, end)
146
+ .map((t) => t.text)
147
+ .join("");
148
+ out.push({ name: fn.text, args: inner.trim() === "" ? [] : splitTop(inner) });
149
+ }
150
+ return out;
151
+ }
152
+ /** The literal credentials in each table function call a SQL text makes. */
153
+ function callFindings(text) {
154
+ return functionCalls(text).flatMap((call) => {
155
+ const lower = call.name.toLowerCase();
156
+ const clustered = lower.endsWith("cluster") && !(lower in FUNCTION_ENGINE);
157
+ const base = clustered ? lower.slice(0, -"cluster".length) : lower;
158
+ // `s3Cluster(cluster, url, ...)`: the cluster comes first.
159
+ const args = clustered ? call.args.slice(1) : call.args;
160
+ const engine = FUNCTION_ENGINE[base];
161
+ const secrets = engine ? secretPositions(engine) : (FUNCTION_SECRETS[base] ?? []);
162
+ const collection = args[0] !== undefined && /^\s*(?:[A-Za-z_][A-Za-z0-9_]*|`[^`]+`)\s*$/.test(args[0]) && args[0].trim().toUpperCase() !== "NOSIGN";
163
+ return argumentFindings(`${call.name}()`, args, secrets, collection);
164
+ });
165
+ }
166
+ /** The literal credentials in a table's or database's engine and its settings. */
167
+ function engineFindings(o) {
168
+ const engine = o.engine;
169
+ if (!engine)
170
+ return [];
171
+ const out = argumentFindings(`ENGINE = ${engine.name}`, engine.args ?? [], secretPositions(engine.name), engineCollection(engine) !== undefined);
172
+ if (COLLECTION_ENGINES.has(engine.name)) {
173
+ for (const [key, raw] of Object.entries(o.settings ?? {})) {
174
+ const value = stringValue(raw);
175
+ if (value && SECRET_KEY.test(key))
176
+ out.push({ where: `${engine.name} setting ${key}`, what: "a literal credential", masked: value === "[HIDDEN]" });
177
+ }
178
+ }
179
+ return out;
180
+ }
181
+ /** `PASSWORD 'secret'` in a dictionary's source. */
182
+ function sourceFindings(dataSource) {
183
+ const m = /\bPASSWORD\s+('(?:[^'\\]|\\.|'')*')/i.exec(dataSource);
184
+ const value = m ? stringValue(m[1]) : undefined;
185
+ return value ? [{ where: "SOURCE PASSWORD", what: "a literal credential", masked: value === "[HIDDEN]" }] : [];
186
+ }
187
+ /**
188
+ * SQLCH128: an integration engine's or table function's argument holds a
189
+ * literal credential (#4395): `ENGINE = S3('https://...', 'AKIA...', 'secret')`,
190
+ * `mysql('db:3306', 'shop', 'orders', 'app', 'secret')`, a Kafka table's
191
+ * `kafka_sasl_password` setting, a dictionary source's `PASSWORD`.
192
+ *
193
+ * A credential is the environment's, so it does not belong in a declaration,
194
+ * the build output or `clickhouse.sql`, as `IDENTIFIED BY` does not on a
195
+ * user (`../../clickhouse/access.ts`). The secret arguments are found by name
196
+ * from each engine's syntax line in the pinned catalog (`password`,
197
+ * `secret_access_key`, `account_key`, `session_token`, `oauth_token`), as
198
+ * `key = value` overrides and settings by the same names, and inside a URL
199
+ * (`user:password@`) or an Azure connection string (`AccountKey=`). The fix
200
+ * is a named collection the environment creates, named in place of the
201
+ * arguments: `ENGINE = S3(lake_creds, format = 'Parquet')`.
202
+ */
203
+ export const sqlch128 = checkOf({ id: "SQLCH128", description: "An integration engine or table function argument holds a literal credential" }, (ctx, report) => {
204
+ for (const o of clickhouseObjects(ctx)) {
205
+ const props = o;
206
+ const findings = [
207
+ ...engineFindings(props),
208
+ ...(props.asFunction ? callFindings(props.asFunction) : []),
209
+ ...(props.select ? callFindings(props.select) : []),
210
+ ...(props.dataSource ? sourceFindings(props.dataSource) : []),
211
+ ];
212
+ for (const f of findings) {
213
+ const held = f.masked ? "holds '[HIDDEN]', the server's mask for a credential, in place of one" : `holds ${f.what}, which is the environment's`;
214
+ report({
215
+ severity: "error",
216
+ message: `${o.export} (${o.name}): ${f.where} ${held}. ` +
217
+ "Create a named collection with the credentials on the server and name it in place of the arguments (ENGINE = S3(lake_creds, format = 'Parquet'), s3(lake_creds), SOURCE(MYSQL(NAME mysql_creds))); chant sql plan checks that it exists",
218
+ entity: o.export,
219
+ });
220
+ }
221
+ }
222
+ });
@@ -12,12 +12,12 @@ export const POSTGRES_TEMPLATE_SOURCES = [
12
12
  {
13
13
  dialect: "postgres",
14
14
  modules: ["@intentius/chant-lexicon-sql/postgres"],
15
- tags: ["schema", "table", "index", "view", "sequence", "type", "domain", "extension", "func", "procedure", "aggregate", "trigger", "eventTrigger", "collation", "cast", "policy", "role", "grant"],
15
+ tags: ["schema", "table", "index", "view", "sequence", "type", "domain", "extension", "func", "procedure", "aggregate", "trigger", "eventTrigger", "operator", "statistics", "foreignDataWrapper", "foreignServer", "publication", "collation", "cast", "policy", "role", "grant"],
16
16
  },
17
17
  {
18
18
  dialect: "postgres",
19
19
  modules: ["@intentius/chant-lexicon-sql"],
20
- tags: ["schema", "index", "sequence", "type", "domain", "extension", "func", "procedure", "aggregate", "trigger", "eventTrigger", "collation", "cast", "policy", "role", "grant"],
20
+ tags: ["schema", "index", "sequence", "type", "domain", "extension", "func", "procedure", "aggregate", "trigger", "eventTrigger", "operator", "statistics", "foreignDataWrapper", "foreignServer", "publication", "collation", "cast", "policy", "role", "grant"],
21
21
  },
22
22
  ];
23
23
  /** Every Postgres template in the file. */
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-template.d.ts","sourceRoot":"","sources":["../../src/lsp/postgres-template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAsB,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAoD,KAAK,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAChI,OAAO,EAAY,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE/E,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;AAEvD,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,eAAe,GAAG,SAAS,CAE7G;AAED,wHAAwH;AACxH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,SAAS,CAOpH;AAED,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,cAAc,GAAG,MAAM,GAAG,mBAAmB,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AASnI,6FAA6F;AAC7F,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,WAAW,GAAG,cAAc,GAAG,SAAS,CAoCvG;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,CAQ7E;AAID,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,WAAW,CAAC;IACjB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAWD,qGAAqG;AACrG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,gBAAgB,EAAE,CAsE9F"}
1
+ {"version":3,"file":"postgres-template.d.ts","sourceRoot":"","sources":["../../src/lsp/postgres-template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAsB,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAoD,KAAK,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAChI,OAAO,EAAY,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE/E,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;AAEvD,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,eAAe,GAAG,SAAS,CAE7G;AAED,wHAAwH;AACxH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,SAAS,CAOpH;AAED,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,cAAc,GAAG,MAAM,GAAG,mBAAmB,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AASnI,6FAA6F;AAC7F,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,WAAW,GAAG,cAAc,GAAG,SAAS,CAoCvG;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,CAQ7E;AAID,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,WAAW,CAAC;IACjB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAWD,qGAAqG;AACrG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,gBAAgB,EAAE,CAiF9F"}
@@ -139,6 +139,17 @@ export function postgresDeclarations(content, fileName = "file.ts") {
139
139
  sqlName = text(node.name.span);
140
140
  kind = "event trigger";
141
141
  break;
142
+ case "operator":
143
+ sqlName = text(node.name.span);
144
+ kind = "operator";
145
+ break;
146
+ case "statistics":
147
+ case "foreignDataWrapper":
148
+ case "foreignServer":
149
+ case "publication":
150
+ sqlName = text(node.name.span);
151
+ kind = { statistics: "statistics", foreignDataWrapper: "foreign data wrapper", foreignServer: "foreign server", publication: "publication" }[node.statement];
152
+ break;
142
153
  case "index":
143
154
  sqlName = node.name ? text(node.name.span) : undefined;
144
155
  break;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sql",
3
- "version": "0.124.45",
3
+ "version": "0.124.48",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "SQL",
6
6
  "intrinsics": [],
@@ -75,7 +75,7 @@ export function postgresSearch(params) {
75
75
  results: hits.slice(0, limit).map((r) => ({ name: r.name, ...(r.summary ? { summary: r.summary } : {}), ...(r.since ? { since: r.since } : {}), ...(r.until ? { until: r.until } : {}) })),
76
76
  };
77
77
  }
78
- const TAGS = { schema: pg.schema, table: pg.table, index: pg.index, view: pg.view, sequence: pg.sequence, type: pg.type, domain: pg.domain, extension: pg.extension, func: pg.func, procedure: pg.procedure, aggregate: pg.aggregate, trigger: pg.trigger, eventTrigger: pg.eventTrigger, collation: pg.collation, cast: pg.cast, policy: pg.policy, role: pg.role, grant: pg.grant };
78
+ const TAGS = { schema: pg.schema, table: pg.table, index: pg.index, view: pg.view, sequence: pg.sequence, type: pg.type, domain: pg.domain, extension: pg.extension, func: pg.func, procedure: pg.procedure, aggregate: pg.aggregate, trigger: pg.trigger, eventTrigger: pg.eventTrigger, operator: pg.operator, statistics: pg.statistics, foreignDataWrapper: pg.foreignDataWrapper, foreignServer: pg.foreignServer, publication: pg.publication, collation: pg.collation, cast: pg.cast, policy: pg.policy, role: pg.role, grant: pg.grant };
79
79
  export const POSTGRES_TAGS = Object.keys(TAGS);
80
80
  /** Parse one statement with the Postgres tag; an error comes back as SQLPG001 with its line and column. */
81
81
  export function postgresParse(tag, ddl, position) {
package/dist/meta.json CHANGED
@@ -129,6 +129,31 @@
129
129
  "kind": "resource",
130
130
  "lexicon": "sql"
131
131
  },
132
+ "PostgresOperator": {
133
+ "resourceType": "Postgres::Operator",
134
+ "kind": "resource",
135
+ "lexicon": "sql"
136
+ },
137
+ "PostgresStatistics": {
138
+ "resourceType": "Postgres::Statistics",
139
+ "kind": "resource",
140
+ "lexicon": "sql"
141
+ },
142
+ "PostgresForeignDataWrapper": {
143
+ "resourceType": "Postgres::ForeignDataWrapper",
144
+ "kind": "resource",
145
+ "lexicon": "sql"
146
+ },
147
+ "PostgresForeignServer": {
148
+ "resourceType": "Postgres::ForeignServer",
149
+ "kind": "resource",
150
+ "lexicon": "sql"
151
+ },
152
+ "PostgresPublication": {
153
+ "resourceType": "Postgres::Publication",
154
+ "kind": "resource",
155
+ "lexicon": "sql"
156
+ },
132
157
  "PostgresExtension": {
133
158
  "resourceType": "Postgres::Extension",
134
159
  "kind": "resource",
@@ -0,0 +1,4 @@
1
+ /** Kept apart from the translator so the plugin can ask it without loading the translator. */
2
+ /** Text that looks like Postgres DDL or like a Postgres declaration, and not like ClickHouse or T-SQL. */
3
+ export declare function looksLikePostgres(content: string): boolean;
4
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/migrate/from-postgres/detect.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAE9F,0GAA0G;AAC1G,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG1D"}
@@ -0,0 +1,7 @@
1
+ /** Kept apart from the translator so the plugin can ask it without loading the translator. */
2
+ /** Text that looks like Postgres DDL or like a Postgres declaration, and not like ClickHouse or T-SQL. */
3
+ export function looksLikePostgres(content) {
4
+ if (/\bENGINE\s*=/i.test(content) || /^\s*GO\s*$/im.test(content))
5
+ return false;
6
+ return /\bCREATE\s+(?:UNLOGGED\s+|TEMP(?:ORARY)?\s+)?TABLE\b/i.test(content) || /@intentius\/chant-lexicon-sql\/postgres/.test(content);
7
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * A {@link Mirror} as text: ClickHouse DDL, the TypeScript declarations that
3
+ * write it, or the statements a server runs (#4399).
4
+ *
5
+ * With `composite`, a mirror is a `CdcMirror` call (`../../composites/cdc-mirror.ts`)
6
+ * that adds the version and deleted columns and the view of live rows
7
+ * itself. Without it, a mirror is a `table` declaration with the engine and
8
+ * the two columns written out, and no view.
9
+ */
10
+ import type { ImportedObject } from "../../clickhouse/import/ir.js";
11
+ import { type Mirror } from "./translate.js";
12
+ /** `id Int64`, `email String COMMENT '...'`. */
13
+ export declare const columnSql: (c: Mirror["columns"][number]) => string;
14
+ /** The sort key as `CdcMirror`'s `primaryKey` and `ORDER BY` write it. */
15
+ export declare const orderBySql: (m: Mirror) => string;
16
+ /** The `columns` string of a `CdcMirror` call. */
17
+ export declare const mirrorColumns: (m: Mirror) => string;
18
+ /** The table as a bare `CREATE TABLE`, constraint comments first. */
19
+ export declare function tableSql(m: Mirror): string;
20
+ /** The statements a server runs for the mirrors, in creation order. */
21
+ export declare function mirrorObjects(mirrors: readonly Mirror[], composite: boolean): ImportedObject[];
22
+ /** `--emit sql`: the statements, each ended with a semicolon. */
23
+ export declare function emitSql(mirrors: readonly Mirror[], composite: boolean): string;
24
+ /** `--emit ts`: the declarations, as a file of `CdcMirror` calls or of `table` templates. */
25
+ export declare function emitTs(mirrors: readonly Mirror[], composite: boolean): string;
26
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/migrate/from-postgres/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,EAAkB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAM1D,gDAAgD;AAChD,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAG,MAAoG,CAAC;AAE9J,0EAA0E;AAC1E,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,KAAG,MAAmJ,CAAC;AAE3L,kDAAkD;AAClD,eAAO,MAAM,aAAa,GAAI,GAAG,MAAM,KAAG,MAA6C,CAAC;AAExF,qEAAqE;AACrE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAc1C;AAOD,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,cAAc,EAAE,CAa9F;AAED,iEAAiE;AACjE,wBAAgB,OAAO,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAK9E;AAKD,6FAA6F;AAC7F,wBAAgB,MAAM,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAgB7E"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * A {@link Mirror} as text: ClickHouse DDL, the TypeScript declarations that
3
+ * write it, or the statements a server runs (#4399).
4
+ *
5
+ * With `composite`, a mirror is a `CdcMirror` call (`../../composites/cdc-mirror.ts`)
6
+ * that adds the version and deleted columns and the view of live rows
7
+ * itself. Without it, a mirror is a `table` declaration with the engine and
8
+ * the two columns written out, and no view.
9
+ */
10
+ import { CdcMirror } from "../../composites/cdc-mirror.js";
11
+ import { CLICKHOUSE_ENTITY_TYPES } from "../../clickhouse/entities.js";
12
+ import { engineReview } from "../../clickhouse/review-catalog.js";
13
+ import { MIRROR_COLUMNS } from "./translate.js";
14
+ const ident = (name) => (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `\`${name.replace(/\\/g, "\\\\").replace(/`/g, "\\`")}\``);
15
+ const chString = (s) => `'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
16
+ const oneLine = (s) => s.replace(/\s+/g, " ").trim();
17
+ /** `id Int64`, `email String COMMENT '...'`. */
18
+ export const columnSql = (c) => `${ident(c.name)} ${c.type}${c.comment ? ` COMMENT ${chString(oneLine(c.comment))}` : ""}`;
19
+ /** The sort key as `CdcMirror`'s `primaryKey` and `ORDER BY` write it. */
20
+ export const orderBySql = (m) => (m.primaryKey.length === 0 ? "tuple()" : m.primaryKey.length === 1 ? ident(m.primaryKey[0]) : `(${m.primaryKey.map(ident).join(", ")})`);
21
+ /** The `columns` string of a `CdcMirror` call. */
22
+ export const mirrorColumns = (m) => m.columns.map(columnSql).join(", ");
23
+ /** The table as a bare `CREATE TABLE`, constraint comments first. */
24
+ export function tableSql(m) {
25
+ const engine = engineReview({ object: m.name, mode: "cdc", cdcColumns: { version: MIRROR_COLUMNS.version, deleted: MIRROR_COLUMNS.deleted } });
26
+ const settings = Object.entries(m.settings).map(([k, v]) => `${k} = ${v}`);
27
+ return [
28
+ ...m.constraintComments,
29
+ `CREATE TABLE ${ident(m.name)}`,
30
+ "(",
31
+ [...m.columns.map(columnSql), ...engine.extraColumns.map((c) => `${c.name} ${c.type}`)].map((l) => ` ${l}`).join(",\n"),
32
+ ")",
33
+ `ENGINE = ${engine.engine}`,
34
+ `ORDER BY ${orderBySql(m)}`,
35
+ ...(settings.length > 0 ? [`SETTINGS ${settings.join(", ")}`] : []),
36
+ ...(m.comment ? [`COMMENT ${chString(oneLine(m.comment))}`] : []),
37
+ ].join("\n");
38
+ }
39
+ /** The call's props, for `CdcMirror` and for the TypeScript that writes it. */
40
+ function callProps(m) {
41
+ return { name: m.name, columns: mirrorColumns(m), primaryKey: orderBySql(m) };
42
+ }
43
+ /** The statements a server runs for the mirrors, in creation order. */
44
+ export function mirrorObjects(mirrors, composite) {
45
+ const out = [];
46
+ for (const m of mirrors) {
47
+ if (!composite) {
48
+ out.push({ type: CLICKHOUSE_ENTITY_TYPES.table, name: m.name, ddl: tableSql(m) });
49
+ continue;
50
+ }
51
+ // The composite writes the DDL: what is validated is what `chant build` makes of the call.
52
+ const { table, current } = CdcMirror(callProps(m));
53
+ out.push({ type: CLICKHOUSE_ENTITY_TYPES.table, name: m.name, ddl: table.props.ddl });
54
+ out.push({ type: CLICKHOUSE_ENTITY_TYPES.view, name: `${m.name}_current`, ddl: current.props.ddl });
55
+ }
56
+ return out;
57
+ }
58
+ /** `--emit sql`: the statements, each ended with a semicolon. */
59
+ export function emitSql(mirrors, composite) {
60
+ const objects = mirrorObjects(mirrors, composite);
61
+ // A constraint comment sits in the table's own text, so a statement is the object's ddl as it is.
62
+ const comments = composite ? new Map(mirrors.map((m) => [m.name, m.constraintComments])) : new Map();
63
+ return `${objects.map((o) => `${(comments.get(o.name) ?? []).map((c) => `${c}\n`).join("")}${o.ddl.replace(/\s+$/, "")};`).join("\n\n")}\n`;
64
+ }
65
+ const str = (s) => JSON.stringify(s);
66
+ const templateSafe = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
67
+ /** `--emit ts`: the declarations, as a file of `CdcMirror` calls or of `table` templates. */
68
+ export function emitTs(mirrors, composite) {
69
+ const lines = [];
70
+ if (composite) {
71
+ lines.push(`import { CdcMirror } from "@intentius/chant-lexicon-sql/clickhouse";`, "");
72
+ for (const m of mirrors) {
73
+ for (const c of m.constraintComments)
74
+ lines.push(`//${c.slice(2)}`);
75
+ const p = callProps(m);
76
+ lines.push(`export const ${m.export} = CdcMirror({`, ` name: ${str(p.name)},`, ` columns: ${str(p.columns)},`, ` primaryKey: ${str(p.primaryKey)},`, `});`, "");
77
+ }
78
+ }
79
+ else {
80
+ lines.push(`import { table } from "@intentius/chant-lexicon-sql/clickhouse";`, "");
81
+ for (const m of mirrors) {
82
+ lines.push(`export const ${m.export} = table\``, ...tableSql(m).split("\n").map((l) => ` ${templateSafe(l)}`), "`;", "");
83
+ }
84
+ }
85
+ return `${lines.join("\n").replace(/\n+$/, "")}\n`;
86
+ }
@@ -0,0 +1,51 @@
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 type { Declarable } from "@intentius/chant/declarable";
41
+ import type { MigrateOptions, MigrationResult, MigrationSource } from "@intentius/chant/lexicon";
42
+ export declare const FROM_POSTGRES = "sql/postgres";
43
+ export declare const TO_CLICKHOUSE = "sql/clickhouse";
44
+ /** Whether `from` and `to` name this pair. */
45
+ export declare const isPostgresToClickHouse: (from: string, to?: string) => boolean;
46
+ /** The Postgres declarations at `sourceFile`: a `.sql` file read as DDL, else a folded build of its project. */
47
+ export declare function loadPostgresEntities(content: string, sourceFile: string | undefined): Promise<Map<string, Declarable>>;
48
+ export declare function transform(content: string, opts: MigrateOptions): Promise<MigrationResult>;
49
+ /** The `migrationSource` of the sql lexicon for this pair. */
50
+ export declare function postgresToClickHouseSource(): MigrationSource;
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrate/from-postgres/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAKjG,eAAO,MAAM,aAAa,iBAAiB,CAAC;AAC5C,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAE9C,8CAA8C;AAC9C,eAAO,MAAM,sBAAsB,GAAI,MAAM,MAAM,EAAE,KAAK,MAAM,KAAG,OAA+E,CAAC;AAEnJ,gHAAgH;AAChH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAW5H;AAgBD,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CA8B/F;AAED,8DAA8D;AAC9D,wBAAgB,0BAA0B,IAAI,eAAe,CAM5D"}
@@ -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
+ }