@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
@@ -113,6 +113,8 @@ export interface ColumnNode {
113
113
  notNullName?: string;
114
114
  default?: Span;
115
115
  generated?: { kind: "stored" | "virtual" | "identity"; expr?: Span; always: boolean; options?: Span };
116
+ /** A foreign table column's `OPTIONS (...)`. */
117
+ options?: GenericOption[];
116
118
  /** Column constraints other than NOT NULL, NULL, DEFAULT and GENERATED. */
117
119
  constraints: ConstraintNode[];
118
120
  }
@@ -271,6 +273,129 @@ export interface EventTriggerNode {
271
273
  function: NameNode;
272
274
  }
273
275
 
276
+ /** `CREATE OPERATOR [schema.]symbol (FUNCTION = f, LEFTARG = type, RIGHTARG = type, ...)`. */
277
+ export interface OperatorNode {
278
+ statement: "operator";
279
+ /** The schema, when written, then the operator's symbol. */
280
+ name: NameNode;
281
+ options: DefElem[];
282
+ }
283
+
284
+ /** `CREATE STATISTICS [IF NOT EXISTS] name [(kind, ...)] ON target, ... FROM table`. */
285
+ export interface StatisticsNode {
286
+ statement: "statistics";
287
+ ifNotExists: boolean;
288
+ name: NameNode;
289
+ /** `ndistinct`, `dependencies`, `mcv`, folded; empty when the server picks them all. */
290
+ kinds: string[];
291
+ /** Each column or parenthesized expression. */
292
+ targets: Span[];
293
+ table: NameNode;
294
+ }
295
+
296
+ /** One `name 'value'` of an `OPTIONS (...)` list. */
297
+ export interface GenericOption {
298
+ name: string;
299
+ nameSpan: Span;
300
+ value: Span;
301
+ }
302
+
303
+ /** `CREATE FOREIGN TABLE [IF NOT EXISTS] name (columns) SERVER server [OPTIONS (...)]`. */
304
+ export interface ForeignTableNode {
305
+ statement: "foreignTable";
306
+ /** Clauses the parser does not know (#3872), kept in the DDL as written; absent when there are none. */
307
+ unknown?: UnknownClause[];
308
+ ifNotExists: boolean;
309
+ name: NameNode;
310
+ columns: ColumnNode[];
311
+ constraints: ConstraintNode[];
312
+ server: NameNode;
313
+ options: GenericOption[];
314
+ }
315
+
316
+ /** One member of an operator class: an operator, a support function, or the storage type. */
317
+ export type OperatorClassItem =
318
+ | { kind: "operator"; number: Span; operator: NameNode; types?: Span; orderBy?: NameNode }
319
+ | { kind: "function"; number: Span; types?: Span; function: NameNode; args: Span }
320
+ | { kind: "storage"; type: Span };
321
+
322
+ /** `CREATE OPERATOR CLASS name [DEFAULT] FOR TYPE type USING method [FAMILY family] AS item, ...`. */
323
+ export interface OperatorClassNode {
324
+ statement: "operatorClass";
325
+ name: NameNode;
326
+ default: boolean;
327
+ type: Span;
328
+ /** The index access method, folded. */
329
+ method: string;
330
+ family?: NameNode;
331
+ items: OperatorClassItem[];
332
+ }
333
+
334
+ /** `CREATE OPERATOR FAMILY name USING method`. */
335
+ export interface OperatorFamilyNode {
336
+ statement: "operatorFamily";
337
+ name: NameNode;
338
+ method: string;
339
+ }
340
+
341
+ /** `CREATE TEXT SEARCH DICTIONARY name (TEMPLATE = t [, option = value, ...])`; the template is the `template` option. */
342
+ export interface TextSearchDictionaryNode {
343
+ statement: "textSearchDictionary";
344
+ name: NameNode;
345
+ options: DefElem[];
346
+ }
347
+
348
+ /** `CREATE TEXT SEARCH CONFIGURATION name (PARSER = p)`. */
349
+ export interface TextSearchConfigurationNode {
350
+ statement: "textSearchConfiguration";
351
+ name: NameNode;
352
+ options: DefElem[];
353
+ }
354
+
355
+ /** `ALTER TEXT SEARCH CONFIGURATION name ADD MAPPING FOR token_type, ... WITH dictionary, ...`: a configuration's mapping, written after its CREATE. */
356
+ export interface TextSearchMappingNode {
357
+ statement: "textSearchMapping";
358
+ name: NameNode;
359
+ tokens: Array<{ name: string; span: Span }>;
360
+ dictionaries: NameNode[];
361
+ }
362
+
363
+ /** `CREATE FOREIGN DATA WRAPPER name [HANDLER f | NO HANDLER] [VALIDATOR f | NO VALIDATOR] [OPTIONS (...)]`. */
364
+ export interface ForeignDataWrapperNode {
365
+ statement: "foreignDataWrapper";
366
+ name: NameNode;
367
+ /** The handler function; `null` for `NO HANDLER`. */
368
+ handler?: NameNode | null;
369
+ /** The validator function; `null` for `NO VALIDATOR`. */
370
+ validator?: NameNode | null;
371
+ options: GenericOption[];
372
+ }
373
+
374
+ /** `CREATE SERVER [IF NOT EXISTS] name [TYPE 't'] [VERSION 'v'] FOREIGN DATA WRAPPER w [OPTIONS (...)]`. */
375
+ export interface ForeignServerNode {
376
+ statement: "foreignServer";
377
+ ifNotExists: boolean;
378
+ name: NameNode;
379
+ type?: Span;
380
+ version?: Span;
381
+ wrapper: NameNode;
382
+ options: GenericOption[];
383
+ }
384
+
385
+ /** One member of a publication: a table (with its column list and row filter) or every table of a schema. */
386
+ export type PublicationItem =
387
+ | { kind: "table"; table: NameNode; columns?: Array<{ name: string; span: Span }>; where?: Span }
388
+ | { kind: "schema"; schema: NameNode };
389
+
390
+ /** `CREATE PUBLICATION name [FOR ALL TABLES | FOR TABLE ... | FOR TABLES IN SCHEMA ...] [WITH (...)]`. */
391
+ export interface PublicationNode {
392
+ statement: "publication";
393
+ name: NameNode;
394
+ allTables: boolean;
395
+ items: PublicationItem[];
396
+ options: DefElem[];
397
+ }
398
+
274
399
  export interface DomainNode {
275
400
  statement: "domain";
276
401
  name: NameNode;
@@ -399,6 +524,8 @@ export interface CommentNode {
399
524
  on?: NameNode;
400
525
  /** For `COMMENT ON FUNCTION f(...)` and `AGGREGATE a(...)`: the parameter list, parentheses excluded. */
401
526
  args?: Span;
527
+ /** For `COMMENT ON OPERATOR CLASS c USING m` and `OPERATOR FAMILY`: the index method, folded. */
528
+ using?: string;
402
529
  /** For `COMMENT ON CAST (source AS target)`: the two types. */
403
530
  cast?: { source: Span; target: Span };
404
531
  /** The comment, a string, or undefined for `IS NULL`. */
@@ -418,6 +545,17 @@ export type StatementNode =
418
545
  | CollationNode
419
546
  | CastNode
420
547
  | EventTriggerNode
548
+ | OperatorNode
549
+ | OperatorClassNode
550
+ | OperatorFamilyNode
551
+ | ForeignTableNode
552
+ | TextSearchDictionaryNode
553
+ | TextSearchConfigurationNode
554
+ | TextSearchMappingNode
555
+ | StatisticsNode
556
+ | ForeignDataWrapperNode
557
+ | ForeignServerNode
558
+ | PublicationNode
421
559
  | DomainNode
422
560
  | ExtensionNode
423
561
  | RoutineNode
@@ -503,6 +641,15 @@ export const AGGREGATE_OPTIONS = [
503
641
  /** `CREATE COLLATION`'s options (sql-createcollation). */
504
642
  export const COLLATION_OPTIONS = ["locale", "lc_collate", "lc_ctype", "provider", "deterministic", "rules", "version"];
505
643
 
644
+ /** `CREATE OPERATOR`'s options (sql-createoperator); `procedure` is the old spelling of `function`. */
645
+ export const OPERATOR_OPTIONS = ["function", "procedure", "leftarg", "rightarg", "commutator", "negator", "restrict", "join", "hashes", "merges"];
646
+
647
+ /** `CREATE STATISTICS`'s kinds (sql-createstatistics). */
648
+ export const STATISTICS_KINDS = ["ndistinct", "dependencies", "mcv"];
649
+
650
+ /** `CREATE PUBLICATION ... WITH (...)`'s options (sql-createpublication); `publish_generated_columns` is 18's. */
651
+ export const PUBLICATION_OPTIONS = ["publish", "publish_via_partition_root", "publish_generated_columns"];
652
+
506
653
  /** What may follow `IS` inside a `b_expr`. */
507
654
  const B_EXPR_IS = [["DISTINCT", "FROM"], ["NOT", "DISTINCT", "FROM"], ["DOCUMENT"], ["NOT", "DOCUMENT"]];
508
655
 
@@ -768,7 +915,7 @@ class PgParser extends SqlCursor {
768
915
  return node;
769
916
  }
770
917
 
771
- private column(typed: boolean): ColumnNode {
918
+ private column(typed: boolean, foreign = false): ColumnNode {
772
919
  const { text, span } = this.nameTok("a column name");
773
920
  const col: ColumnNode = { name: text, nameSpan: span, constraints: [] };
774
921
  if (!typed) this.acceptSeq("WITH", "OPTIONS");
@@ -777,7 +924,10 @@ class PgParser extends SqlCursor {
777
924
  if (typed && !bare && !this.stopsAt(COLUMN_CLAUSE)) col.type = this.typeName();
778
925
  else if (typed) this.fail("expected a column type");
779
926
  for (;;) {
780
- if (this.accept("COMPRESSION")) col.compression = this.expr(COLUMN_CLAUSE);
927
+ if (foreign && kw(this.peek(), "OPTIONS") && this.isPunct("(", 1)) {
928
+ this.p++;
929
+ col.options = this.genericOptions();
930
+ } else if (this.accept("COMPRESSION")) col.compression = this.expr(COLUMN_CLAUSE);
781
931
  else if (this.accept("STORAGE")) col.storage = this.expr(COLUMN_CLAUSE);
782
932
  else if (this.accept("COLLATE")) col.collate = this.expr(COLUMN_CLAUSE);
783
933
  else if (!this.columnConstraint(col) && !this.unknownClause(COLUMN_WORDS, { inList: true, column: text || undefined })) break;
@@ -993,6 +1143,7 @@ class PgParser extends SqlCursor {
993
1143
  if (this.accept("GRANT")) return this.grant(false, false);
994
1144
  if (this.accept("REVOKE")) return this.grant(true, false);
995
1145
  if (this.acceptSeq("ALTER", "DEFAULT", "PRIVILEGES")) return this.defaultPrivileges();
1146
+ if (this.acceptSeq("ALTER", "TEXT", "SEARCH", "CONFIGURATION")) return this.textSearchMapping();
996
1147
  if (this.acceptSeq("ALTER", "TABLE")) return this.rowSecurity();
997
1148
  this.expect("CREATE");
998
1149
  const orReplace = this.acceptSeq("OR", "REPLACE");
@@ -1012,6 +1163,24 @@ class PgParser extends SqlCursor {
1012
1163
  if (this.accept("COLLATION")) return this.collation();
1013
1164
  if (this.accept("CAST")) return this.cast();
1014
1165
  if (this.acceptSeq("EVENT", "TRIGGER")) return this.eventTrigger();
1166
+ if (this.accept("OPERATOR")) {
1167
+ // CLASS and FAMILY are words an operator's schema may be named: `class.+` is still an operator.
1168
+ if (kw(this.peek(), "CLASS") && !this.isPunct(".", 1)) {
1169
+ this.p++;
1170
+ return this.operatorClass();
1171
+ }
1172
+ if (kw(this.peek(), "FAMILY") && !this.isPunct(".", 1)) {
1173
+ this.p++;
1174
+ return this.operatorFamily();
1175
+ }
1176
+ return this.operator();
1177
+ }
1178
+ if (this.acceptSeq("TEXT", "SEARCH")) return this.textSearch();
1179
+ if (this.accept("STATISTICS")) return this.statistics();
1180
+ if (this.acceptSeq("FOREIGN", "TABLE")) return this.foreignTable();
1181
+ if (this.acceptSeq("FOREIGN", "DATA", "WRAPPER")) return this.foreignDataWrapper();
1182
+ if (this.accept("SERVER")) return this.foreignServer();
1183
+ if (this.accept("PUBLICATION")) return this.publication();
1015
1184
  if (kw(this.peek(), "UNIQUE", "INDEX")) return this.index();
1016
1185
  }
1017
1186
  const persistence = this.persistence();
@@ -1021,7 +1190,7 @@ class PgParser extends SqlCursor {
1021
1190
  const recursive = this.accept("RECURSIVE");
1022
1191
  if (!orReplace && !recursive && persistence === undefined && this.acceptSeq("MATERIALIZED", "VIEW")) return this.view(true, false, false, false);
1023
1192
  if (this.accept("VIEW")) return this.view(false, orReplace, persistence === "temporary", recursive);
1024
- return this.fail("expected SCHEMA, TABLE, INDEX, VIEW, MATERIALIZED VIEW, SEQUENCE, TYPE, DOMAIN, EXTENSION, FUNCTION, PROCEDURE, AGGREGATE, TRIGGER, EVENT TRIGGER, COLLATION, CAST, POLICY or ROLE");
1193
+ return this.fail("expected SCHEMA, TABLE, INDEX, VIEW, MATERIALIZED VIEW, SEQUENCE, TYPE, DOMAIN, EXTENSION, FUNCTION, PROCEDURE, AGGREGATE, TRIGGER, EVENT TRIGGER, COLLATION, CAST, OPERATOR, OPERATOR CLASS, OPERATOR FAMILY, TEXT SEARCH CONFIGURATION, TEXT SEARCH DICTIONARY, STATISTICS, FOREIGN TABLE, FOREIGN DATA WRAPPER, SERVER, PUBLICATION, POLICY or ROLE");
1025
1194
  }
1026
1195
 
1027
1196
  private schema(): SchemaNode {
@@ -1239,6 +1408,260 @@ class PgParser extends SqlCursor {
1239
1408
  return node;
1240
1409
  }
1241
1410
 
1411
+ /** An unqualified, database-wide object's name (a wrapper, a server, a publication). */
1412
+ private databaseName(what: string): NameNode {
1413
+ const { text, span } = this.nameTok(what);
1414
+ if (this.isPunct(".")) this.fail(`expected ${what} without a schema (it belongs to the database)`);
1415
+ return { pieces: [text], span };
1416
+ }
1417
+
1418
+ /** `( name 'value' [, ...] )`: a foreign data wrapper's or server's options. */
1419
+ private genericOptions(): GenericOption[] {
1420
+ this.expectPunct("(");
1421
+ const out: GenericOption[] = [];
1422
+ const seen = new Set<string>();
1423
+ for (;;) {
1424
+ const t = this.next();
1425
+ if (t.kind !== "ident" && t.kind !== "qident") this.fail("expected an option name", t);
1426
+ const nameSpan = this.span(this.idx(-1), []);
1427
+ const name = identValue(t);
1428
+ if (seen.has(name)) this.fail(`${name} is given twice`, t);
1429
+ seen.add(name);
1430
+ const v = this.next();
1431
+ if (v.kind !== "string" && v.kind !== "ref") this.fail("expected the option's value, a string", v);
1432
+ out.push({ name, nameSpan, value: this.span(this.idx(-1), v.kind === "ref" ? [v.part] : []) });
1433
+ if (this.acceptPunct(",")) continue;
1434
+ this.expectPunct(")");
1435
+ return out;
1436
+ }
1437
+ }
1438
+
1439
+ /** `[schema.]symbol`: an operator's name, its symbol made of operator characters. */
1440
+ private operatorName(): NameNode {
1441
+ const from = this.idx();
1442
+ const refs: number[] = [];
1443
+ const pieces: string[] = [];
1444
+ const symbol = (): void => {
1445
+ const t = this.next();
1446
+ if (t.kind !== "op") this.fail("expected the operator's symbol (operator characters, such as ===)", t);
1447
+ pieces.push(t.text);
1448
+ };
1449
+ if (this.peek()?.kind === "op") symbol();
1450
+ else {
1451
+ const t = this.next();
1452
+ this.colId(t, "a schema name");
1453
+ if (t.kind === "ref") refs.push(t.part);
1454
+ pieces.push(t.kind === "ref" ? "" : identValue(t));
1455
+ this.expectPunct(".");
1456
+ symbol();
1457
+ }
1458
+ return { pieces, span: this.span(from, refs) };
1459
+ }
1460
+
1461
+ private operator(): OperatorNode {
1462
+ const name = this.operatorName();
1463
+ const options = this.definition("an operator option");
1464
+ this.checkDefinition(options, OPERATOR_OPTIONS, [], "an operator");
1465
+ if (!options.some((o) => o.name === "function" || o.name === "procedure")) this.fail("expected FUNCTION (an operator needs the function it calls)", this.lastSeen());
1466
+ return { statement: "operator", name, options };
1467
+ }
1468
+
1469
+ /** The member list of `CREATE OPERATOR CLASS ... AS`: an operator, a support function or the storage type. */
1470
+ private operatorClassItem(): OperatorClassItem {
1471
+ const number = (): Span => {
1472
+ const t = this.next();
1473
+ if (t.kind !== "number" && t.kind !== "ref") this.fail("expected the strategy or support number", t);
1474
+ return this.span(this.idx(-1), t.kind === "ref" ? [t.part] : []);
1475
+ };
1476
+ if (this.accept("OPERATOR")) {
1477
+ const item: Extract<OperatorClassItem, { kind: "operator" }> = { kind: "operator", number: number(), operator: this.operatorName() };
1478
+ if (this.isPunct("(")) item.types = this.parenthesized();
1479
+ if (this.accept("FOR")) {
1480
+ if (this.accept("SEARCH")) return item;
1481
+ if (!this.acceptSeq("ORDER", "BY")) this.fail("expected SEARCH or ORDER BY");
1482
+ item.orderBy = this.qualifiedName("a sort operator family");
1483
+ }
1484
+ return item;
1485
+ }
1486
+ if (this.accept("FUNCTION")) {
1487
+ const n = number();
1488
+ const types = this.isPunct("(") ? this.parenthesized() : undefined;
1489
+ const fn = this.qualifiedName("a function name");
1490
+ if (!this.isPunct("(")) this.fail("expected '(' and the function's argument types");
1491
+ return { kind: "function", number: n, ...(types ? { types } : {}), function: fn, args: this.parenthesized() };
1492
+ }
1493
+ if (this.accept("STORAGE")) return { kind: "storage", type: this.typeName() };
1494
+ return this.fail("expected OPERATOR, FUNCTION or STORAGE");
1495
+ }
1496
+
1497
+ private operatorClass(): OperatorClassNode {
1498
+ const name = this.qualifiedName("an operator class name");
1499
+ const isDefault = this.accept("DEFAULT");
1500
+ this.expect("FOR");
1501
+ this.expect("TYPE");
1502
+ const type = this.typeName();
1503
+ this.expect("USING");
1504
+ const method = this.nameTok("an index access method").text;
1505
+ const node: OperatorClassNode = { statement: "operatorClass", name, default: isDefault, type, method, items: [] };
1506
+ if (this.accept("FAMILY")) node.family = this.qualifiedName("an operator family name");
1507
+ this.expect("AS");
1508
+ do node.items.push(this.operatorClassItem());
1509
+ while (this.acceptPunct(","));
1510
+ return node;
1511
+ }
1512
+
1513
+ private operatorFamily(): OperatorFamilyNode {
1514
+ const name = this.qualifiedName("an operator family name");
1515
+ this.expect("USING");
1516
+ return { statement: "operatorFamily", name, method: this.nameTok("an index access method").text };
1517
+ }
1518
+
1519
+ /** After `CREATE TEXT SEARCH`: a dictionary or a configuration. A parser and a template are C code. */
1520
+ private textSearch(): TextSearchDictionaryNode | TextSearchConfigurationNode {
1521
+ if (this.accept("DICTIONARY")) {
1522
+ const name = this.qualifiedName("a text search dictionary name");
1523
+ const options = this.definition("a dictionary option");
1524
+ // The options past TEMPLATE belong to the template; a name given twice is still wrong.
1525
+ this.checkDefinition(options, options.map((o) => o.name), ["template"], "a text search dictionary");
1526
+ return { statement: "textSearchDictionary", name, options };
1527
+ }
1528
+ if (this.accept("CONFIGURATION")) {
1529
+ const name = this.qualifiedName("a text search configuration name");
1530
+ const options = this.definition("a configuration option");
1531
+ this.checkDefinition(options, ["parser", "copy"], [], "a text search configuration");
1532
+ if (options.some((o) => o.name === "copy")) this.fail("expected PARSER (COPY copies mappings chant does not read; name the parser and write the mappings)", this.tokens[options.find((o) => o.name === "copy")!.nameSpan.from]);
1533
+ if (!options.some((o) => o.name === "parser")) this.fail("expected PARSER (a configuration needs the parser that splits text into tokens)", this.lastSeen());
1534
+ return { statement: "textSearchConfiguration", name, options };
1535
+ }
1536
+ return this.fail("expected DICTIONARY or CONFIGURATION (a text search parser and a text search template are C code an extension installs)");
1537
+ }
1538
+
1539
+ /** `ALTER TEXT SEARCH CONFIGURATION name ADD MAPPING FOR token_type [, ...] WITH dictionary [, ...]`. */
1540
+ private textSearchMapping(): TextSearchMappingNode {
1541
+ const name = this.qualifiedName("a text search configuration name");
1542
+ if (!this.acceptSeq("ADD", "MAPPING")) this.fail("expected ADD MAPPING (a configuration's mappings are declared with ADD MAPPING after its CREATE)");
1543
+ this.expect("FOR");
1544
+ const node: TextSearchMappingNode = { statement: "textSearchMapping", name, tokens: [], dictionaries: [] };
1545
+ do node.tokens.push((({ text, span }) => ({ name: text, span }))(this.nameTok("a token type")));
1546
+ while (this.acceptPunct(","));
1547
+ this.expect("WITH");
1548
+ do node.dictionaries.push(this.qualifiedName("a text search dictionary name"));
1549
+ while (this.acceptPunct(","));
1550
+ return node;
1551
+ }
1552
+
1553
+ /** `CREATE FOREIGN TABLE`: the column list form. A key, a generated column, INHERITS and PARTITION OF are not declared. */
1554
+ private foreignTable(): ForeignTableNode {
1555
+ const ifNotExists = this.ifNotExists();
1556
+ const name = this.qualifiedName("a foreign table name");
1557
+ if (kw(this.peek(), "PARTITION")) this.fail("expected the column list (a foreign table that is a partition, PARTITION OF, is not declared here)");
1558
+ const node: ForeignTableNode = { statement: "foreignTable", ifNotExists, name, columns: [], constraints: [], server: { pieces: [], span: this.span(this.idx(), []) }, options: [] };
1559
+ this.expectPunct("(");
1560
+ if (!this.acceptPunct(")")) {
1561
+ for (;;) {
1562
+ if (kw(this.peek(), "LIKE")) this.fail("LIKE is not declared on a foreign table; write its columns");
1563
+ const c = this.tableConstraint();
1564
+ if (c) node.constraints.push(c);
1565
+ else node.columns.push(this.column(true, true));
1566
+ if (this.acceptPunct(",")) continue;
1567
+ this.expectPunct(")");
1568
+ break;
1569
+ }
1570
+ }
1571
+ if (kw(this.peek(), "INHERITS")) this.fail("expected SERVER (INHERITS is not declared on a foreign table)");
1572
+ this.expect("SERVER");
1573
+ node.server = this.databaseName("a server name");
1574
+ if (this.accept("OPTIONS")) node.options = this.genericOptions();
1575
+ // A foreign table has CHECK and NOT NULL constraints and a default; Postgres refuses the rest, and a generated column is not read.
1576
+ const bad = (c: ConstraintNode, what: string): never => this.fail(`${what} (a foreign table holds CHECK and NOT NULL constraints only; the remote server keeps the rest)`, this.tokens[c.span.from]);
1577
+ for (const c of [...node.constraints, ...node.columns.flatMap((x) => x.constraints)]) {
1578
+ if (c.kind !== "CHECK" && c.kind !== "NOT NULL") bad(c, `expected CHECK or NOT NULL, not ${c.kind}`);
1579
+ if (c.notEnforced !== undefined) bad(c, "ENFORCED and NOT ENFORCED are 18's and are not declared on a foreign table");
1580
+ }
1581
+ for (const col of node.columns) if (col.generated) this.fail(`expected no generated column (${col.name} is GENERATED ${col.generated.kind.toUpperCase()}; a foreign table's generated columns are not declared)`, this.tokens[col.nameSpan.from]);
1582
+ return node;
1583
+ }
1584
+
1585
+ private statistics(): StatisticsNode {
1586
+ const ifNotExists = this.ifNotExists();
1587
+ const name = this.qualifiedName("a statistics name");
1588
+ const kinds: string[] = [];
1589
+ if (this.isPunct("(")) {
1590
+ for (const k of this.nameList("a statistics kind")) {
1591
+ if (!STATISTICS_KINDS.includes(k.name)) this.fail(`expected a statistics kind (${STATISTICS_KINDS.join(", ")})`, this.tokens[k.span.from]);
1592
+ kinds.push(k.name);
1593
+ }
1594
+ }
1595
+ this.expect("ON");
1596
+ const targets: Span[] = [];
1597
+ do targets.push(this.expr(["FROM"]));
1598
+ while (this.acceptPunct(","));
1599
+ this.expect("FROM");
1600
+ const table = this.qualifiedName("a table name");
1601
+ return { statement: "statistics", ifNotExists, name, kinds, targets, table };
1602
+ }
1603
+
1604
+ private foreignDataWrapper(): ForeignDataWrapperNode {
1605
+ const node: ForeignDataWrapperNode = { statement: "foreignDataWrapper", name: this.databaseName("a foreign data wrapper name"), options: [] };
1606
+ for (;;) {
1607
+ if (this.accept("HANDLER")) node.handler = this.qualifiedName("a handler function");
1608
+ else if (this.acceptSeq("NO", "HANDLER")) node.handler = null;
1609
+ else if (this.accept("VALIDATOR")) node.validator = this.qualifiedName("a validator function");
1610
+ else if (this.acceptSeq("NO", "VALIDATOR")) node.validator = null;
1611
+ else if (this.accept("OPTIONS")) node.options = this.genericOptions();
1612
+ else return node;
1613
+ }
1614
+ }
1615
+
1616
+ private foreignServer(): ForeignServerNode {
1617
+ const ifNotExists = this.ifNotExists();
1618
+ const name = this.databaseName("a server name");
1619
+ const node: Partial<ForeignServerNode> & { statement: "foreignServer" } = { statement: "foreignServer", ifNotExists, name, options: [] };
1620
+ const string = (what: string): Span => {
1621
+ const t = this.next();
1622
+ if (t.kind !== "string" && t.kind !== "ref") this.fail(`expected ${what} as a string`, t);
1623
+ return this.span(this.idx(-1), t.kind === "ref" ? [t.part] : []);
1624
+ };
1625
+ if (this.accept("TYPE")) node.type = string("the server type");
1626
+ if (this.accept("VERSION")) node.version = string("the server version");
1627
+ if (!this.acceptSeq("FOREIGN", "DATA", "WRAPPER")) this.fail("expected FOREIGN DATA WRAPPER (a server names the wrapper it is for)");
1628
+ node.wrapper = this.qualifiedName("a foreign data wrapper name");
1629
+ if (this.accept("OPTIONS")) node.options = this.genericOptions();
1630
+ return node as ForeignServerNode;
1631
+ }
1632
+
1633
+ private publication(): PublicationNode {
1634
+ const node: PublicationNode = { statement: "publication", name: this.databaseName("a publication name"), allTables: false, items: [], options: [] };
1635
+ if (this.accept("FOR")) {
1636
+ if (this.acceptSeq("ALL", "TABLES")) node.allTables = true;
1637
+ else {
1638
+ let mode: "table" | "schema" | undefined;
1639
+ do {
1640
+ if (this.accept("TABLE")) mode = "table";
1641
+ else if (this.acceptSeq("TABLES", "IN", "SCHEMA")) mode = "schema";
1642
+ else if (mode === undefined) this.fail("expected ALL TABLES, TABLE or TABLES IN SCHEMA");
1643
+ if (mode === "schema") {
1644
+ node.items.push({ kind: "schema", schema: this.qualifiedName("a schema name") });
1645
+ continue;
1646
+ }
1647
+ this.accept("ONLY");
1648
+ const table = this.qualifiedName("a table name");
1649
+ if (this.isOp("*")) this.p++;
1650
+ const item: PublicationItem = { kind: "table", table };
1651
+ if (this.isPunct("(")) item.columns = this.nameList("a column name");
1652
+ if (this.accept("WHERE")) item.where = this.checkedParens();
1653
+ node.items.push(item);
1654
+ } while (this.acceptPunct(","));
1655
+ }
1656
+ }
1657
+ if (kw(this.peek(), "WITH") && this.isPunct("(", 1)) {
1658
+ this.p++;
1659
+ node.options = this.definition("a publication option");
1660
+ this.checkDefinition(node.options, PUBLICATION_OPTIONS, [], "a publication");
1661
+ }
1662
+ return node;
1663
+ }
1664
+
1242
1665
  private table(persistence: TableNode["persistence"]): TableNode {
1243
1666
  const ifNotExists = this.ifNotExists();
1244
1667
  const node: TableNode = { statement: "table", persistence, ifNotExists, name: this.qualifiedName("a table name"), columns: [], constraints: [], like: [] };
@@ -1850,6 +2273,34 @@ class PgParser extends SqlCursor {
1850
2273
  const node: CommentNode = { statement: "comment", objectType, target, cast: { source, target: castTarget } };
1851
2274
  if (!this.accept("NULL")) node.text = this.commentText();
1852
2275
  return node;
2276
+ } else if (this.acceptSeq("FOREIGN", "DATA", "WRAPPER")) {
2277
+ objectType = "FOREIGN DATA WRAPPER";
2278
+ target = this.qualifiedName("a foreign data wrapper name");
2279
+ } else if (kw(this.peek(), "OPERATOR") && kw(this.peek(1), "CLASS", "FAMILY") && !this.isPunct(".", 2)) {
2280
+ this.p++;
2281
+ objectType = `OPERATOR ${this.next().text.toUpperCase()}`;
2282
+ target = this.qualifiedName(`an ${objectType.toLowerCase()} name`);
2283
+ this.expect("USING");
2284
+ const using = this.nameTok("an index access method").text;
2285
+ this.expect("IS");
2286
+ const node: CommentNode = { statement: "comment", objectType, target, using };
2287
+ if (!this.accept("NULL")) node.text = this.commentText();
2288
+ return node;
2289
+ } else if (this.acceptSeq("TEXT", "SEARCH")) {
2290
+ if (!this.accept("CONFIGURATION", "DICTIONARY")) this.fail("expected CONFIGURATION or DICTIONARY");
2291
+ objectType = `TEXT SEARCH ${this.lastSeen()!.text.toUpperCase()}`;
2292
+ target = this.qualifiedName(`a ${objectType.toLowerCase()} name`);
2293
+ } else if (this.acceptSeq("FOREIGN", "TABLE")) {
2294
+ objectType = "FOREIGN TABLE";
2295
+ target = this.qualifiedName("a foreign table name");
2296
+ } else if (this.accept("OPERATOR")) {
2297
+ objectType = "OPERATOR";
2298
+ target = this.operatorName();
2299
+ if (!this.isPunct("(")) this.fail("expected '(' and the operator's operand types");
2300
+ args = this.parenthesized();
2301
+ } else if (this.accept("SERVER", "PUBLICATION", "STATISTICS")) {
2302
+ objectType = this.lastSeen()!.text.toUpperCase();
2303
+ target = this.qualifiedName(`a ${objectType.toLowerCase()} name`);
1853
2304
  } else if (this.accept("AGGREGATE", "COLLATION")) {
1854
2305
  objectType = this.lastSeen()!.text.toUpperCase();
1855
2306
  target = this.qualifiedName(`an ${objectType.toLowerCase()} name`);
@@ -1861,7 +2312,7 @@ class PgParser extends SqlCursor {
1861
2312
  if (this.acceptSeq("MATERIALIZED", "VIEW")) objectType = "MATERIALIZED VIEW";
1862
2313
  else if (this.accept("TABLE", "COLUMN", "INDEX", "VIEW", "SEQUENCE", "TYPE", "DOMAIN", "SCHEMA", "EXTENSION", "FUNCTION", "PROCEDURE")) {
1863
2314
  objectType = this.tokens[this.idx(-1)]!.text.toUpperCase();
1864
- } else return this.fail("expected TABLE, COLUMN, INDEX, VIEW, MATERIALIZED VIEW, SEQUENCE, TYPE, DOMAIN, SCHEMA, EXTENSION, FUNCTION, PROCEDURE, AGGREGATE, COLLATION, CAST, TRIGGER, EVENT TRIGGER, POLICY, ROLE or CONSTRAINT");
2315
+ } else return this.fail("expected TABLE, COLUMN, INDEX, VIEW, MATERIALIZED VIEW, SEQUENCE, TYPE, DOMAIN, SCHEMA, EXTENSION, FUNCTION, PROCEDURE, AGGREGATE, COLLATION, CAST, OPERATOR, TRIGGER, EVENT TRIGGER, STATISTICS, FOREIGN TABLE, FOREIGN DATA WRAPPER, SERVER, PUBLICATION, OPERATOR CLASS, OPERATOR FAMILY, TEXT SEARCH CONFIGURATION, TEXT SEARCH DICTIONARY, POLICY, ROLE or CONSTRAINT");
1865
2316
  target = this.qualifiedName("an object name");
1866
2317
  if ((objectType === "FUNCTION" || objectType === "PROCEDURE") && this.isPunct("(")) args = this.parenthesized();
1867
2318
  }
@@ -43,6 +43,16 @@ const TAG: Record<string, (s: TemplateStringsArray) => { props: object }> = {
43
43
  [POSTGRES_ENTITY_TYPES.collation]: tags.collation,
44
44
  [POSTGRES_ENTITY_TYPES.cast]: tags.cast,
45
45
  [POSTGRES_ENTITY_TYPES.eventTrigger]: tags.eventTrigger,
46
+ [POSTGRES_ENTITY_TYPES.operator]: tags.operator,
47
+ [POSTGRES_ENTITY_TYPES.operatorClass]: tags.operatorClass,
48
+ [POSTGRES_ENTITY_TYPES.operatorFamily]: tags.operatorFamily,
49
+ [POSTGRES_ENTITY_TYPES.foreignTable]: tags.foreignTable,
50
+ [POSTGRES_ENTITY_TYPES.textSearchConfiguration]: tags.textSearchConfiguration,
51
+ [POSTGRES_ENTITY_TYPES.textSearchDictionary]: tags.textSearchDictionary,
52
+ [POSTGRES_ENTITY_TYPES.statistics]: tags.statistics,
53
+ [POSTGRES_ENTITY_TYPES.foreignDataWrapper]: tags.foreignDataWrapper,
54
+ [POSTGRES_ENTITY_TYPES.foreignServer]: tags.foreignServer,
55
+ [POSTGRES_ENTITY_TYPES.publication]: tags.publication,
46
56
  [POSTGRES_ENTITY_TYPES.extension]: tags.extension,
47
57
  [POSTGRES_ENTITY_TYPES.function]: tags.func,
48
58
  [POSTGRES_ENTITY_TYPES.procedure]: tags.procedure,
@@ -137,6 +147,24 @@ const PROP_OF_FIELD: Record<string, string[]> = {
137
147
  context: ["context"],
138
148
  event: ["event"],
139
149
  tags: ["tags"],
150
+ targets: ["targets"],
151
+ kinds: ["kinds"],
152
+ handler: ["handler", "handlerName", "noHandler"],
153
+ validator: ["validator", "validatorName", "noValidator"],
154
+ serverType: ["serverType"],
155
+ wrapper: ["wrapper", "wrapperName"],
156
+ server: ["serverName"],
157
+ family: ["family"],
158
+ items: ["items"],
159
+ template: ["template"],
160
+ parser: ["parser"],
161
+ mappings: ["mappings"],
162
+ allTables: ["allTables"],
163
+ tables: ["tables"],
164
+ schemas: ["schemas"],
165
+ publish: [],
166
+ viaRoot: [],
167
+ generatedColumns: [],
140
168
  };
141
169
 
142
170
  /** Props keys that hold constraints, by constraint kind. */
@@ -159,6 +187,7 @@ export function inDeclaredVocabulary(declared: Props, live: Props, d: CanonicalP
159
187
  if (d.schema === l.schema) adopt("schema");
160
188
  // An aggregate's argument types and a cast's two types are its identity: the same, they are the declaration's.
161
189
  if (d.kind === "aggregate" && d.signature === l.signature) for (const key of ["args", "orderBy"]) adopt(key);
190
+ if (d.kind === "operator" && d.signature === l.signature) for (const key of ["leftArg", "rightArg"]) adopt(key);
162
191
  if (d.kind === "cast" && d.name === l.name) for (const key of ["sourceType", "targetType"]) adopt(key);
163
192
 
164
193
  const fieldKeys = new Set([...Object.keys(d.fields), ...Object.keys(l.fields)]);
@@ -172,7 +201,7 @@ export function inDeclaredVocabulary(declared: Props, live: Props, d: CanonicalP
172
201
  if (!fieldKeys.has(f)) for (const key of keys) if (f !== "schema" || d.kind === "extension") adopt(key);
173
202
  }
174
203
 
175
- if (d.kind === "table") {
204
+ if (d.kind === "table" || d.kind === "foreignTable") {
176
205
  const declaredColumns = (declared.columns as unknown[] | undefined) ?? [];
177
206
  const liveColumns = (live.columns as unknown[] | undefined) ?? [];
178
207
  // Columns are matched by name and listed in the declaration's order, the
@@ -193,7 +222,16 @@ export function inDeclaredVocabulary(declared: Props, live: Props, d: CanonicalP
193
222
  ].map((c) => c.value);
194
223
  }
195
224
  // An aggregate's or a collation's `options` is the declaration's only when every field read from it is the same (a role's `options` shares the key).
196
- const optionFields = d.kind === "aggregate" ? ["definition"] : d.kind === "collation" ? ["provider", "lcCollate", "lcCtype", "locale", "nondeterministic", "rules"] : undefined;
225
+ const optionFields =
226
+ d.kind === "aggregate" || d.kind === "operator"
227
+ ? ["definition"]
228
+ : d.kind === "collation"
229
+ ? ["provider", "lcCollate", "lcCtype", "locale", "nondeterministic", "rules"]
230
+ : d.kind === "foreignDataWrapper" || d.kind === "foreignServer" || d.kind === "foreignTable" || d.kind === "textSearchDictionary"
231
+ ? ["options"]
232
+ : d.kind === "publication"
233
+ ? ["publish", "viaRoot", "generatedColumns"]
234
+ : undefined;
197
235
  if (optionFields) {
198
236
  if (optionFields.every((f) => JSON.stringify(d.fields[f]) === JSON.stringify(l.fields[f]))) adopt("options");
199
237
  else out.options = live.options;
@@ -203,9 +241,9 @@ export function inDeclaredVocabulary(declared: Props, live: Props, d: CanonicalP
203
241
  out.method = live.method;
204
242
  out.functionArgs = live.functionArgs;
205
243
  }
206
- if (d.kind === "table" || d.kind === "domain") {
244
+ if (d.kind === "table" || d.kind === "domain" || d.kind === "foreignTable") {
207
245
  // A constraint the declaration says the same as the server is the declaration's (its name included or left out).
208
- const kinds = d.kind === "domain" ? ["CHECK"] : Object.keys(CONSTRAINT_PROPS);
246
+ const kinds = d.kind === "table" ? Object.keys(CONSTRAINT_PROPS) : ["CHECK"];
209
247
  for (const kind of kinds) {
210
248
  const key = CONSTRAINT_PROPS[kind]!;
211
249
  const dl = d.constraints.filter((c) => c.kind === kind);