@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
@@ -21,6 +21,7 @@ import { notExtensionOwned, scopeSql } from "./catalog.js";
21
21
  import { POSTGRES_ENTITY_TYPES } from "../entity-types.js";
22
22
  import { quoteIdent } from "../keywords.js";
23
23
  import { stripMarker } from "../../core/ownership.js";
24
+ import { isSecretOption } from "../secret-options.js";
24
25
  const C = 'COLLATE "C"';
25
26
  const str = (v) => (v === null || v === undefined ? undefined : String(v));
26
27
  const literal = (s) => `'${s.replace(/'/g, "''")}'`;
@@ -299,3 +300,454 @@ export async function readRoutineKinds(client, scope) {
299
300
  }
300
301
  return out;
301
302
  }
303
+ /** An operator named by another's COMMUTATOR or NEGATOR, as `OPERATOR(schema.symbol)`. */
304
+ const operatorRef = (column) => `(SELECT 'OPERATOR(' || pg_catalog.quote_ident(rn.nspname) || '.' || r.oprname || ')' FROM pg_catalog.pg_operator r JOIN pg_catalog.pg_namespace rn ON rn.oid = r.oprnamespace WHERE r.oid = ${column})`;
305
+ /**
306
+ * Operators: the ones a schema defines, not the server's own (oids below the
307
+ * first normal object id) or an extension's. Identified by name and operand
308
+ * types, `NONE` for a missing side (`DROP OPERATOR`'s spelling).
309
+ */
310
+ export async function readOperators(client, scope) {
311
+ const s = scopeSql("n.nspname", scope);
312
+ const rows = await client.query(`SELECT o.oid::text AS oid, n.nspname AS schema, o.oprname AS name,
313
+ CASE WHEN o.oprleft <> 0 THEN pg_catalog.format_type(o.oprleft, NULL) END AS leftarg,
314
+ CASE WHEN o.oprright <> 0 THEN pg_catalog.format_type(o.oprright, NULL) END AS rightarg,
315
+ ${proc("o.oprcode::pg_catalog.regproc")} AS func, ${operatorRef("o.oprcom")} AS commutator, ${operatorRef("o.oprnegate")} AS negator,
316
+ ${proc("o.oprrest::pg_catalog.regproc")} AS restrict, ${proc("o.oprjoin::pg_catalog.regproc")} AS join_func,
317
+ o.oprcanhash AS hashes, o.oprcanmerge AS merges,
318
+ pg_catalog.obj_description(o.oid, 'pg_operator') AS comment, ${dependentsOf("pg_operator", "o.oid")} AS dependents
319
+ FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace
320
+ WHERE ${s.sql} AND o.oid >= 16384 AND ${notExtensionOwned("pg_operator", "o.oid")}
321
+ ORDER BY n.nspname ${C}, o.oprname ${C}, pg_catalog.format_type(o.oprleft, NULL) ${C} NULLS FIRST, pg_catalog.format_type(o.oprright, NULL) ${C} NULLS FIRST`, s.params);
322
+ return rows.map((r) => {
323
+ const left = str(r.leftarg);
324
+ const right = str(r.rightarg);
325
+ const signature = `(${left ?? "NONE"},${right ?? "NONE"})`;
326
+ const name = `${quoteIdent(String(r.schema))}.${r.name}`;
327
+ const opts = [`FUNCTION = ${r.func}`];
328
+ if (left)
329
+ opts.push(`LEFTARG = ${left}`);
330
+ if (right)
331
+ opts.push(`RIGHTARG = ${right}`);
332
+ if (str(r.commutator))
333
+ opts.push(`COMMUTATOR = ${r.commutator}`);
334
+ if (str(r.negator))
335
+ opts.push(`NEGATOR = ${r.negator}`);
336
+ if (str(r.restrict))
337
+ opts.push(`RESTRICT = ${r.restrict}`);
338
+ if (str(r.join_func))
339
+ opts.push(`JOIN = ${r.join_func}`);
340
+ if (r.hashes === true)
341
+ opts.push("HASHES");
342
+ if (r.merges === true)
343
+ opts.push("MERGES");
344
+ return {
345
+ type: POSTGRES_ENTITY_TYPES.operator,
346
+ schema: String(r.schema),
347
+ name: String(r.name),
348
+ oid: String(r.oid),
349
+ signature,
350
+ ...withComment(r),
351
+ ...dependents(r),
352
+ statement: [`CREATE OPERATOR ${name} (${opts.join(", ")})`, ...commentOn(`OPERATOR ${name}${signature}`, r.comment)].join(";\n"),
353
+ };
354
+ });
355
+ }
356
+ /** An `OPTIONS (...)` clause from a catalog `text[]` of `name=value`, and the names left out because they hold a credential. */
357
+ function optionsOf(raw) {
358
+ const kept = [];
359
+ const omitted = [];
360
+ for (const entry of raw ?? []) {
361
+ const at = entry.indexOf("=");
362
+ const name = at < 0 ? entry : entry.slice(0, at);
363
+ if (isSecretOption(name))
364
+ omitted.push(name);
365
+ else
366
+ kept.push(`${quoteIdent(name)} ${literal(at < 0 ? "" : entry.slice(at + 1))}`);
367
+ }
368
+ return { clause: kept.length > 0 ? ` OPTIONS (${kept.join(", ")})` : "", omitted };
369
+ }
370
+ const omittedWarning = (omitted) => omitted.length > 0 ? { warnings: [`the option${omitted.length === 1 ? "" : "s"} ${omitted.join(", ")} hold${omitted.length === 1 ? "s" : ""} a credential and ${omitted.length === 1 ? "is" : "are"} left out; the environment supplies it`] } : {};
371
+ /**
372
+ * The kinds of object #3911 adds that belong to the database or hang off a
373
+ * table: extended statistics (printed by the server), foreign data wrappers
374
+ * and servers, and publications, each assembled from its catalog rows. A
375
+ * wrapper, server or publication is the database's, so the schema scope does
376
+ * not narrow it. A credential in an option is left out and said so.
377
+ */
378
+ export async function readDatabaseKinds(client, scope) {
379
+ const out = [...(await readOperators(client, scope))];
380
+ const s = scopeSql("n.nspname", scope);
381
+ const stats = await client.query(`SELECT e.oid::text AS oid, n.nspname AS schema, e.stxname AS name, pg_catalog.pg_get_statisticsobjdef(e.oid) AS def,
382
+ pg_catalog.obj_description(e.oid, 'pg_statistic_ext') AS comment
383
+ FROM pg_catalog.pg_statistic_ext e JOIN pg_catalog.pg_namespace n ON n.oid = e.stxnamespace
384
+ WHERE ${s.sql} AND ${notExtensionOwned("pg_statistic_ext", "e.oid")}
385
+ ORDER BY n.nspname ${C}, e.stxname ${C}`, s.params);
386
+ for (const r of stats) {
387
+ const q = qname(String(r.schema), String(r.name));
388
+ out.push({
389
+ type: POSTGRES_ENTITY_TYPES.statistics,
390
+ schema: String(r.schema),
391
+ name: String(r.name),
392
+ oid: String(r.oid),
393
+ ...withComment(r),
394
+ statement: [String(r.def), ...commentOn(`STATISTICS ${q}`, r.comment)].join(";\n"),
395
+ });
396
+ }
397
+ const wrappers = await client.query(`SELECT w.oid::text AS oid, w.fdwname AS name, ${proc("w.fdwhandler::pg_catalog.regproc")} AS handler, ${proc("w.fdwvalidator::pg_catalog.regproc")} AS validator,
398
+ w.fdwoptions AS options, pg_catalog.obj_description(w.oid, 'pg_foreign_data_wrapper') AS comment, ${dependentsOf("pg_foreign_data_wrapper", "w.oid")} AS dependents
399
+ FROM pg_catalog.pg_foreign_data_wrapper w
400
+ WHERE ${notExtensionOwned("pg_foreign_data_wrapper", "w.oid")}
401
+ ORDER BY w.fdwname ${C}`);
402
+ for (const r of wrappers) {
403
+ const name = quoteIdent(String(r.name));
404
+ const { clause, omitted } = optionsOf(r.options);
405
+ out.push({
406
+ type: POSTGRES_ENTITY_TYPES.foreignDataWrapper,
407
+ name: String(r.name),
408
+ oid: String(r.oid),
409
+ ...withComment(r),
410
+ ...dependents(r),
411
+ ...omittedWarning(omitted),
412
+ statement: [
413
+ `CREATE FOREIGN DATA WRAPPER ${name}${str(r.handler) ? ` HANDLER ${r.handler}` : ""}${str(r.validator) ? ` VALIDATOR ${r.validator}` : ""}${clause}`,
414
+ ...commentOn(`FOREIGN DATA WRAPPER ${name}`, r.comment),
415
+ ].join(";\n"),
416
+ });
417
+ }
418
+ const servers = await client.query(`SELECT v.oid::text AS oid, v.srvname AS name, v.srvtype AS type, v.srvversion AS version, w.fdwname AS wrapper, v.srvoptions AS options,
419
+ pg_catalog.obj_description(v.oid, 'pg_foreign_server') AS comment, ${dependentsOf("pg_foreign_server", "v.oid")} AS dependents
420
+ FROM pg_catalog.pg_foreign_server v JOIN pg_catalog.pg_foreign_data_wrapper w ON w.oid = v.srvfdw
421
+ WHERE ${notExtensionOwned("pg_foreign_server", "v.oid")}
422
+ ORDER BY v.srvname ${C}`);
423
+ for (const r of servers) {
424
+ const name = quoteIdent(String(r.name));
425
+ const { clause, omitted } = optionsOf(r.options);
426
+ out.push({
427
+ type: POSTGRES_ENTITY_TYPES.foreignServer,
428
+ name: String(r.name),
429
+ oid: String(r.oid),
430
+ ...withComment(r),
431
+ ...dependents(r),
432
+ ...omittedWarning(omitted),
433
+ statement: [
434
+ `CREATE SERVER ${name}${str(r.type) ? ` TYPE ${literal(String(r.type))}` : ""}${str(r.version) ? ` VERSION ${literal(String(r.version))}` : ""} FOREIGN DATA WRAPPER ${quoteIdent(String(r.wrapper))}${clause}`,
435
+ ...commentOn(`SERVER ${name}`, r.comment),
436
+ ].join(";\n"),
437
+ });
438
+ }
439
+ out.push(...(await readPublications(client)));
440
+ out.push(...(await readOperatorClasses(client, scope)), ...(await readTextSearch(client, scope)), ...(await readForeignTables(client, scope)));
441
+ return out;
442
+ }
443
+ /** Publications. Column lists, row filters and schema members are 15's; they are read where the catalog has them. */
444
+ async function readPublications(client) {
445
+ const has = async (catalog, column) => {
446
+ const rows = await client.query(column
447
+ ? `SELECT 1 AS x FROM pg_catalog.pg_attribute WHERE attrelid = to_regclass('pg_catalog.${catalog}') AND attname = '${column}' AND NOT attisdropped`
448
+ : `SELECT 1 AS x WHERE to_regclass('pg_catalog.${catalog}') IS NOT NULL`);
449
+ return rows.length > 0;
450
+ };
451
+ const columnLists = await has("pg_publication_rel", "prattrs");
452
+ const schemaMembers = await has("pg_publication_namespace");
453
+ const pubs = await client.query(`SELECT p.oid::text AS oid, p.pubname AS name, p.puballtables AS alltables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate,
454
+ pg_catalog.to_jsonb(p) AS def, pg_catalog.obj_description(p.oid, 'pg_publication') AS comment
455
+ FROM pg_catalog.pg_publication p
456
+ WHERE ${notExtensionOwned("pg_publication", "p.oid")}
457
+ ORDER BY p.pubname ${C}`);
458
+ const out = [];
459
+ for (const r of pubs) {
460
+ const name = quoteIdent(String(r.name));
461
+ const d = (typeof r.def === "string" ? JSON.parse(r.def) : r.def);
462
+ const tables = r.alltables
463
+ ? []
464
+ : await client.query(`SELECT n.nspname AS schema, c.relname AS name,
465
+ ${columnLists ? "ARRAY(SELECT pg_catalog.quote_ident(a.attname) FROM pg_catalog.pg_attribute a WHERE a.attrelid = r.prrelid AND a.attnum = ANY(r.prattrs::pg_catalog.int2[]) ORDER BY a.attnum)" : "NULL::text[]"} AS columns,
466
+ ${columnLists ? "pg_catalog.pg_get_expr(r.prqual, r.prrelid)" : "NULL::text"} AS filter
467
+ FROM pg_catalog.pg_publication_rel r JOIN pg_catalog.pg_class c ON c.oid = r.prrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
468
+ WHERE r.prpubid = $1::oid ORDER BY n.nspname ${C}, c.relname ${C}`, [String(r.oid)]);
469
+ const schemas = schemaMembers && !r.alltables
470
+ ? await client.query(`SELECT n.nspname AS name FROM pg_catalog.pg_publication_namespace pn JOIN pg_catalog.pg_namespace n ON n.oid = pn.pnnspid WHERE pn.pnpubid = $1::oid ORDER BY n.nspname ${C}`, [String(r.oid)])
471
+ : [];
472
+ const members = [
473
+ ...tables.map((t) => {
474
+ const columns = t.columns ?? [];
475
+ return `${qname(String(t.schema), String(t.name))}${columns.length > 0 ? ` (${columns.join(", ")})` : ""}${str(t.filter) ? ` WHERE (${t.filter})` : ""}`;
476
+ }),
477
+ ];
478
+ const clauses = [];
479
+ if (r.alltables)
480
+ clauses.push("FOR ALL TABLES");
481
+ else if (members.length > 0 || schemas.length > 0) {
482
+ const parts = [];
483
+ if (members.length > 0)
484
+ parts.push(`TABLE ${members.join(", ")}`);
485
+ if (schemas.length > 0)
486
+ parts.push(`TABLES IN SCHEMA ${schemas.map((x) => quoteIdent(String(x.name))).join(", ")}`);
487
+ clauses.push(`FOR ${parts.join(", ")}`);
488
+ }
489
+ const publish = [r.pubinsert && "insert", r.pubupdate && "update", r.pubdelete && "delete", r.pubtruncate && "truncate"].filter(Boolean);
490
+ const options = [];
491
+ if (publish.length !== 4)
492
+ options.push(`publish = ${literal(publish.join(", "))}`);
493
+ if (d.pubviaroot === true)
494
+ options.push("publish_via_partition_root = true");
495
+ if (d.pubgencols !== undefined && d.pubgencols !== "n")
496
+ options.push("publish_generated_columns = stored");
497
+ if (options.length > 0)
498
+ clauses.push(`WITH (${options.join(", ")})`);
499
+ out.push({
500
+ type: POSTGRES_ENTITY_TYPES.publication,
501
+ name: String(r.name),
502
+ oid: String(r.oid),
503
+ ...withComment(r),
504
+ statement: [`CREATE PUBLICATION ${name}${clauses.length > 0 ? ` ${clauses.join(" ")}` : ""}`, ...commentOn(`PUBLICATION ${name}`, r.comment)].join(";\n"),
505
+ });
506
+ }
507
+ return out;
508
+ }
509
+ // ── Operator classes and families, text search, foreign tables (#4406) ──
510
+ /** An object named by `schema`.`name` columns, as a clause: a `pg_catalog` one bare. */
511
+ const refName = (schema, name) => `CASE WHEN ${schema} = 'pg_catalog' THEN pg_catalog.quote_ident(${name}) ELSE pg_catalog.quote_ident(${schema}) || '.' || pg_catalog.quote_ident(${name}) END`;
512
+ /** An operand type, `NONE` for the missing side of a prefix operator. */
513
+ const operand = (column) => `CASE WHEN ${column} = 0 THEN 'NONE' ELSE pg_catalog.format_type(${column}, NULL) END`;
514
+ /**
515
+ * Operator classes and families. A class carries its members: the operators
516
+ * and support functions that depend on it (`pg_depend`, a member made by
517
+ * CREATE OPERATOR CLASS depends on the class; one added by ALTER OPERATOR
518
+ * FAMILY ... ADD depends on the family and is "loose"). A family named as its
519
+ * class, in the same schema, is the one CREATE OPERATOR CLASS made for it and
520
+ * is the class's; every other family is read, with a warning when it holds
521
+ * loose members, which a declaration cannot carry.
522
+ */
523
+ async function readOperatorClasses(client, scope) {
524
+ const out = [];
525
+ const s = scopeSql("n.nspname", scope);
526
+ const member = (catalog, alias) => `JOIN pg_catalog.pg_depend dep ON dep.classid = '${catalog}'::pg_catalog.regclass AND dep.objid = ${alias}.oid AND dep.refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass AND dep.refobjid = c.oid`;
527
+ const classes = await client.query(`SELECT c.oid::text AS oid, n.nspname AS schema, c.opcname AS name, am.amname AS method, c.opcdefault AS isdefault,
528
+ pg_catalog.format_type(c.opcintype, NULL) AS type,
529
+ CASE WHEN c.opckeytype <> 0 THEN pg_catalog.format_type(c.opckeytype, NULL) END AS storage,
530
+ CASE WHEN f.opfname = c.opcname AND f.opfnamespace = c.opcnamespace THEN NULL ELSE ${refName("fn.nspname", "f.opfname")} END AS family,
531
+ ARRAY(SELECT 'OPERATOR ' || o.amopstrategy || ' ' || pg_catalog.quote_ident(opn.nspname) || '.' || op.oprname ||
532
+ ' (' || ${operand("o.amoplefttype")} || ', ' || ${operand("o.amoprighttype")} || ')' ||
533
+ CASE WHEN o.amoppurpose = 'o' THEN ' FOR ORDER BY ' || (SELECT pg_catalog.quote_ident(sn.nspname) || '.' || pg_catalog.quote_ident(sf.opfname)
534
+ FROM pg_catalog.pg_opfamily sf JOIN pg_catalog.pg_namespace sn ON sn.oid = sf.opfnamespace WHERE sf.oid = o.amopsortfamily) ELSE '' END
535
+ FROM pg_catalog.pg_amop o ${member("pg_catalog.pg_amop", "o")}
536
+ JOIN pg_catalog.pg_operator op ON op.oid = o.amopopr JOIN pg_catalog.pg_namespace opn ON opn.oid = op.oprnamespace
537
+ ORDER BY o.amopstrategy, o.amoplefttype, o.amoprighttype) AS operators,
538
+ ARRAY(SELECT 'FUNCTION ' || p.amprocnum || ' (' || ${operand("p.amproclefttype")} || ', ' || ${operand("p.amprocrighttype")} || ') ' || p.amproc::pg_catalog.regprocedure::pg_catalog.text
539
+ FROM pg_catalog.pg_amproc p ${member("pg_catalog.pg_amproc", "p")}
540
+ ORDER BY p.amprocnum, p.amproclefttype, p.amprocrighttype) AS functions,
541
+ pg_catalog.obj_description(c.oid, 'pg_opclass') AS comment, ${dependentsOf("pg_opclass", "c.oid")} AS dependents
542
+ FROM pg_catalog.pg_opclass c JOIN pg_catalog.pg_namespace n ON n.oid = c.opcnamespace JOIN pg_catalog.pg_am am ON am.oid = c.opcmethod
543
+ JOIN pg_catalog.pg_opfamily f ON f.oid = c.opcfamily JOIN pg_catalog.pg_namespace fn ON fn.oid = f.opfnamespace
544
+ WHERE ${s.sql} AND c.oid >= 16384 AND ${notExtensionOwned("pg_opclass", "c.oid")}
545
+ ORDER BY n.nspname ${C}, c.opcname ${C}, am.amname ${C}`, s.params);
546
+ for (const r of classes) {
547
+ const q = qname(String(r.schema), String(r.name));
548
+ const method = String(r.method);
549
+ const items = [...(r.operators ?? []), ...(r.functions ?? []), ...(str(r.storage) ? [`STORAGE ${r.storage}`] : [])];
550
+ out.push({
551
+ type: POSTGRES_ENTITY_TYPES.operatorClass,
552
+ schema: String(r.schema),
553
+ name: String(r.name),
554
+ oid: String(r.oid),
555
+ signature: ` USING ${method}`,
556
+ ...withComment(r),
557
+ ...dependents(r),
558
+ ...(items.length === 0 ? { unsupported: "no operator, support function or storage type of it could be read; a CREATE OPERATOR CLASS needs at least one" } : {}),
559
+ statement: [
560
+ `CREATE OPERATOR CLASS ${q}${r.isdefault === true ? " DEFAULT" : ""} FOR TYPE ${r.type} USING ${method}${str(r.family) ? ` FAMILY ${r.family}` : ""} AS\n ${items.join(",\n ")}`,
561
+ ...commentOn(`OPERATOR CLASS ${q} USING ${method}`, r.comment),
562
+ ].join(";\n"),
563
+ });
564
+ }
565
+ const families = await client.query(`SELECT f.oid::text AS oid, n.nspname AS schema, f.opfname AS name, am.amname AS method,
566
+ (SELECT count(*) FROM (SELECT o.oid FROM pg_catalog.pg_amop o WHERE o.amopfamily = f.oid UNION ALL SELECT p.oid FROM pg_catalog.pg_amproc p WHERE p.amprocfamily = f.oid) m
567
+ WHERE NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend dep WHERE dep.classid IN ('pg_catalog.pg_amop'::pg_catalog.regclass, 'pg_catalog.pg_amproc'::pg_catalog.regclass)
568
+ AND dep.objid = m.oid AND dep.refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass)) AS loose,
569
+ pg_catalog.obj_description(f.oid, 'pg_opfamily') AS comment, ${dependentsOf("pg_opfamily", "f.oid")} AS dependents
570
+ FROM pg_catalog.pg_opfamily f JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace JOIN pg_catalog.pg_am am ON am.oid = f.opfmethod
571
+ WHERE ${s.sql} AND f.oid >= 16384 AND ${notExtensionOwned("pg_opfamily", "f.oid")}
572
+ AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_opclass c WHERE c.opcfamily = f.oid AND c.opcname = f.opfname AND c.opcnamespace = f.opfnamespace)
573
+ ORDER BY n.nspname ${C}, f.opfname ${C}, am.amname ${C}`, s.params);
574
+ for (const r of families) {
575
+ const q = qname(String(r.schema), String(r.name));
576
+ const method = String(r.method);
577
+ const loose = Number(r.loose ?? 0);
578
+ out.push({
579
+ type: POSTGRES_ENTITY_TYPES.operatorFamily,
580
+ schema: String(r.schema),
581
+ name: String(r.name),
582
+ oid: String(r.oid),
583
+ signature: ` USING ${method}`,
584
+ ...withComment(r),
585
+ ...dependents(r),
586
+ ...(loose > 0 ? { warnings: [`${loose} loose member${loose === 1 ? "" : "s"} added with ALTER OPERATOR FAMILY ... ADD ${loose === 1 ? "is" : "are"} left out; a declaration holds the family and its classes' members`] } : {}),
587
+ statement: [`CREATE OPERATOR FAMILY ${q} USING ${method}`, ...commentOn(`OPERATOR FAMILY ${q} USING ${method}`, r.comment)].join(";\n"),
588
+ });
589
+ }
590
+ return out;
591
+ }
592
+ /**
593
+ * A dictionary's `dictinitoption`, which the server prints as
594
+ * `name = 'value', ...` (a quote and a backslash doubled in the value), as a
595
+ * list of name and value; undefined when the text is not that form.
596
+ */
597
+ export function parseDictionaryOptions(init) {
598
+ if (init === undefined || init.trim() === "")
599
+ return [];
600
+ const out = [];
601
+ const item = /\s*("(?:[^"]|"")+"|[^\s=,]+)\s*=\s*'((?:[^']|'')*)'\s*(?:,|$)/y;
602
+ let at = 0;
603
+ while (at < init.length) {
604
+ item.lastIndex = at;
605
+ const m = item.exec(init);
606
+ if (!m)
607
+ return undefined;
608
+ const name = m[1].startsWith('"') ? m[1].slice(1, -1).replace(/""/g, '"') : m[1];
609
+ out.push([name, m[2].replace(/''/g, "'").replace(/\\\\/g, "\\")]);
610
+ at = item.lastIndex;
611
+ }
612
+ return out;
613
+ }
614
+ /** Text search dictionaries and configurations; a configuration's mappings are the ALTER ... ADD MAPPING statements after its CREATE. */
615
+ async function readTextSearch(client, scope) {
616
+ const out = [];
617
+ const s = scopeSql("n.nspname", scope);
618
+ const dictionaries = await client.query(`SELECT d.oid::text AS oid, n.nspname AS schema, d.dictname AS name, d.dictinitoption AS init,
619
+ (SELECT ${refName("tn.nspname", "t.tmplname")} FROM pg_catalog.pg_ts_template t JOIN pg_catalog.pg_namespace tn ON tn.oid = t.tmplnamespace WHERE t.oid = d.dicttemplate) AS template,
620
+ pg_catalog.obj_description(d.oid, 'pg_ts_dict') AS comment, ${dependentsOf("pg_ts_dict", "d.oid")} AS dependents
621
+ FROM pg_catalog.pg_ts_dict d JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace
622
+ WHERE ${s.sql} AND d.oid >= 16384 AND ${notExtensionOwned("pg_ts_dict", "d.oid")}
623
+ ORDER BY n.nspname ${C}, d.dictname ${C}`, s.params);
624
+ for (const r of dictionaries) {
625
+ const q = qname(String(r.schema), String(r.name));
626
+ const options = parseDictionaryOptions(str(r.init));
627
+ out.push({
628
+ type: POSTGRES_ENTITY_TYPES.textSearchDictionary,
629
+ schema: String(r.schema),
630
+ name: String(r.name),
631
+ oid: String(r.oid),
632
+ ...withComment(r),
633
+ ...dependents(r),
634
+ ...(options === undefined ? { unsupported: `its options (${str(r.init)}) are not in the form the server writes them` } : {}),
635
+ statement: [
636
+ `CREATE TEXT SEARCH DICTIONARY ${q} (${["TEMPLATE = " + r.template, ...(options ?? []).map(([k, v]) => `${quoteIdent(k)} = ${literal(v)}`)].join(", ")})`,
637
+ ...commentOn(`TEXT SEARCH DICTIONARY ${q}`, r.comment),
638
+ ].join(";\n"),
639
+ });
640
+ }
641
+ const configurations = await client.query(`SELECT c.oid::text AS oid, n.nspname AS schema, c.cfgname AS name,
642
+ (SELECT ${refName("pn.nspname", "p.prsname")} FROM pg_catalog.pg_ts_parser p JOIN pg_catalog.pg_namespace pn ON pn.oid = p.prsnamespace WHERE p.oid = c.cfgparser) AS parser,
643
+ ARRAY(SELECT tt.alias || E'\\t' || pg_catalog.string_agg((SELECT ${refName("dn.nspname", "d.dictname")} FROM pg_catalog.pg_ts_dict d JOIN pg_catalog.pg_namespace dn ON dn.oid = d.dictnamespace WHERE d.oid = m.mapdict), ', ' ORDER BY m.mapseqno)
644
+ FROM pg_catalog.pg_ts_config_map m, pg_catalog.ts_token_type(c.cfgparser) tt WHERE m.mapcfg = c.oid AND tt.tokid = m.maptokentype
645
+ GROUP BY tt.tokid, tt.alias ORDER BY tt.tokid) AS mappings,
646
+ pg_catalog.obj_description(c.oid, 'pg_ts_config') AS comment, ${dependentsOf("pg_ts_config", "c.oid")} AS dependents
647
+ FROM pg_catalog.pg_ts_config c JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace
648
+ WHERE ${s.sql} AND c.oid >= 16384 AND ${notExtensionOwned("pg_ts_config", "c.oid")}
649
+ ORDER BY n.nspname ${C}, c.cfgname ${C}`, s.params);
650
+ for (const r of configurations) {
651
+ const q = qname(String(r.schema), String(r.name));
652
+ // Token types that share their dictionaries share an ADD MAPPING, in the parser's token order.
653
+ const groups = new Map();
654
+ for (const line of r.mappings ?? []) {
655
+ const [token, dictionaries] = line.split("\t");
656
+ groups.set(dictionaries, [...(groups.get(dictionaries) ?? []), quoteIdent(token)]);
657
+ }
658
+ out.push({
659
+ type: POSTGRES_ENTITY_TYPES.textSearchConfiguration,
660
+ schema: String(r.schema),
661
+ name: String(r.name),
662
+ oid: String(r.oid),
663
+ ...withComment(r),
664
+ ...dependents(r),
665
+ statement: [
666
+ `CREATE TEXT SEARCH CONFIGURATION ${q} (PARSER = ${r.parser})`,
667
+ ...[...groups].map(([dicts, tokens]) => `ALTER TEXT SEARCH CONFIGURATION ${q} ADD MAPPING FOR ${tokens.join(", ")} WITH ${dicts}`),
668
+ ...commentOn(`TEXT SEARCH CONFIGURATION ${q}`, r.comment),
669
+ ].join(";\n"),
670
+ });
671
+ }
672
+ return out;
673
+ }
674
+ /**
675
+ * Foreign tables: their columns (type, collation, default, NOT NULL and
676
+ * OPTIONS), CHECK constraints, server and OPTIONS. One that is a partition,
677
+ * inherits or has a generated column is read as unsupported, since a
678
+ * declaration does not hold those. An option that holds a credential is left
679
+ * out and said so.
680
+ */
681
+ async function readForeignTables(client, scope) {
682
+ const s = scopeSql("n.nspname", scope);
683
+ const tables = await client.query(`SELECT c.oid::text AS oid, n.nspname AS schema, c.relname AS name, c.relispartition AS ispartition,
684
+ EXISTS (SELECT 1 FROM pg_catalog.pg_inherits i WHERE i.inhrelid = c.oid) AS inherits,
685
+ fs.srvname AS server, ft.ftoptions AS options,
686
+ pg_catalog.obj_description(c.oid, 'pg_class') AS comment, ${dependentsOf("pg_class", "c.oid")} AS dependents
687
+ FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
688
+ JOIN pg_catalog.pg_foreign_table ft ON ft.ftrelid = c.oid JOIN pg_catalog.pg_foreign_server fs ON fs.oid = ft.ftserver
689
+ WHERE c.relkind = 'f' AND ${s.sql} AND ${notExtensionOwned("pg_class", "c.oid")}
690
+ ORDER BY n.nspname ${C}, c.relname ${C}`, s.params);
691
+ if (tables.length === 0)
692
+ return [];
693
+ const oids = tables.map((t) => String(t.oid));
694
+ const columns = await client.query(`SELECT a.attrelid::text AS rel, a.attname AS name, pg_catalog.format_type(a.atttypid, a.atttypmod) AS type, a.attnotnull AS notnull,
695
+ a.attgenerated::text AS generated, pg_catalog.pg_get_expr(d.adbin, d.adrelid, true) AS dflt,
696
+ CASE WHEN a.attcollation <> 0 AND a.attcollation <> t.typcollation THEN ${collationName("a.attcollation")} END AS collation,
697
+ a.attfdwoptions AS options, pg_catalog.col_description(a.attrelid, a.attnum) AS comment
698
+ FROM pg_catalog.pg_attribute AS a JOIN pg_catalog.pg_type t ON t.oid = a.atttypid
699
+ LEFT JOIN pg_catalog.pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum
700
+ WHERE a.attrelid = ANY($1::oid[]) AND a.attnum > 0 AND NOT a.attisdropped
701
+ ORDER BY a.attrelid, a.attnum`, [oids]);
702
+ const checks = await client.query(`SELECT k.conrelid::text AS rel, k.conname AS name, pg_catalog.pg_get_constraintdef(k.oid, true) AS def, pg_catalog.obj_description(k.oid, 'pg_constraint') AS comment
703
+ FROM pg_catalog.pg_constraint k
704
+ WHERE k.conrelid = ANY($1::oid[]) AND k.contype = 'c' AND k.conislocal
705
+ ORDER BY k.conrelid, k.conname ${C}`, [oids]);
706
+ return tables.map((t) => {
707
+ const rel = String(t.oid);
708
+ const q = qname(String(t.schema), String(t.name));
709
+ const omitted = [];
710
+ const lines = [];
711
+ const commentLines = [];
712
+ let generated = false;
713
+ for (const c of columns.filter((x) => String(x.rel) === rel)) {
714
+ const parts = [quoteIdent(String(c.name)), String(c.type)];
715
+ const opts = optionsOf(c.options);
716
+ omitted.push(...opts.omitted);
717
+ if (opts.clause)
718
+ parts.push(opts.clause.trim());
719
+ if (str(c.collation))
720
+ parts.push(`COLLATE ${c.collation}`);
721
+ if (str(c.generated))
722
+ generated = true;
723
+ else if (str(c.dflt))
724
+ parts.push(`DEFAULT ${c.dflt}`);
725
+ if (c.notnull === true)
726
+ parts.push("NOT NULL");
727
+ lines.push(parts.join(" "));
728
+ commentLines.push(...commentOn(`COLUMN ${q}.${quoteIdent(String(c.name))}`, c.comment));
729
+ }
730
+ for (const k of checks.filter((x) => String(x.rel) === rel)) {
731
+ lines.push(`CONSTRAINT ${quoteIdent(String(k.name))} ${k.def}`);
732
+ commentLines.push(...commentOn(`CONSTRAINT ${quoteIdent(String(k.name))} ON ${q}`, k.comment));
733
+ }
734
+ const { clause, omitted: tableOmitted } = optionsOf(t.options);
735
+ omitted.push(...tableOmitted);
736
+ const unsupported = t.ispartition === true ? "it is a partition of another table (CREATE FOREIGN TABLE ... PARTITION OF is not declared)" : t.inherits === true ? "it inherits from another table (INHERITS is not declared on a foreign table)" : generated ? "it has a generated column (not declared on a foreign table)" : undefined;
737
+ return {
738
+ type: POSTGRES_ENTITY_TYPES.foreignTable,
739
+ schema: String(t.schema),
740
+ name: String(t.name),
741
+ oid: rel,
742
+ ...withComment(t),
743
+ ...dependents(t),
744
+ ...omittedWarning(omitted),
745
+ ...(unsupported ? { unsupported } : {}),
746
+ statement: [
747
+ `CREATE FOREIGN TABLE ${q} (${lines.length > 0 ? `\n ${lines.join(",\n ")}\n` : ""}) SERVER ${quoteIdent(String(t.server))}${clause}`,
748
+ ...commentOn(`FOREIGN TABLE ${q}`, t.comment),
749
+ ...commentLines,
750
+ ].join(";\n"),
751
+ };
752
+ });
753
+ }
@@ -74,6 +74,8 @@ export interface LivePgObject {
74
74
  dependents?: string[];
75
75
  /** Why no declaration can hold this object; it is read so import can say it left it out. */
76
76
  unsupported?: string;
77
+ /** What was left out of an object that is otherwise read (an option that holds a credential), for import to say. */
78
+ warnings?: string[];
77
79
  }
78
80
  /** What {@link readLiveSchema} reads. */
79
81
  export interface SchemaScope {
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/postgres/live/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAyB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAKjF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,iEAAiE;AACjE,eAAO,MAAM,cAAc,UAAmD,CAAC;AAE/E,gHAAgH;AAChH,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,kBAAkB,CAAC;IACzB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uIAAuI;IACvI,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iIAAiI;IACjI,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,4FAA4F;IAC5F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,yCAAyC;AACzC,MAAM,WAAW,WAAW;IAC1B,gHAAgH;IAChH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2GAA2G;IAC3G,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAqBD,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAM/F;AAED,yGAAyG;AACzG,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,EAAE,KAAK,MAAM,KAAG,MAC4F,CAAC;AAa9J,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAQD,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,CAKtH;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,CAa9E;AAcD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA+f7G;AAED,+HAA+H;AAC/H,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,EAAE,YAAY,MAAM,KAAG,MAA6D,CAAC;AAEnK;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,EAAE,QAAQ,EAAE,gBAAgB,GAAG,SAAS,GAAG,YAAY,EAAE,CAW1H"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/postgres/live/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAyB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAKjF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,iEAAiE;AACjE,eAAO,MAAM,cAAc,UAAmD,CAAC;AAE/E,gHAAgH;AAChH,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,kBAAkB,CAAC;IACzB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uIAAuI;IACvI,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iIAAiI;IACjI,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,4FAA4F;IAC5F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oHAAoH;IACpH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,yCAAyC;AACzC,MAAM,WAAW,WAAW;IAC1B,gHAAgH;IAChH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2GAA2G;IAC3G,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAqBD,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAM/F;AAED,yGAAyG;AACzG,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,EAAE,KAAK,MAAM,KAAG,MAC4F,CAAC;AAa9J,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAQD,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,CAKtH;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,CAa9E;AAcD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAkgB7G;AAED,+HAA+H;AAC/H,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,EAAE,YAAY,MAAM,KAAG,MAA6D,CAAC;AAEnK;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,EAAE,QAAQ,EAAE,gBAAgB,GAAG,SAAS,GAAG,YAAY,EAAE,CAW1H"}
@@ -50,7 +50,7 @@ import { hasChantTrailerKey, RECEIPTS_TRAILER_KEY, stripMarker } from "../../cor
50
50
  import { MIGRATION_TRAILER_KEY } from "../migrate/names.js";
51
51
  import { isProviderOwned, providerData } from "../providers/index.js";
52
52
  import { FOREIGN_TABLES } from "../../core/foreign-tables.js";
53
- import { readCollations, readRoutineKinds, readTypeKinds } from "./catalog-kinds.js";
53
+ import { readCollations, readDatabaseKinds, readRoutineKinds, readTypeKinds } from "./catalog-kinds.js";
54
54
  /** The server's own schemas, never part of a declared schema. */
55
55
  export const SYSTEM_SCHEMAS = ["pg_catalog", "information_schema", "pg_toast"];
56
56
  /** Tables another tool keeps its migration history in, by name, with the tool; both dialects share the list. */
@@ -535,6 +535,8 @@ export async function readLiveSchema(client, scope = {}) {
535
535
  }
536
536
  // Aggregates, casts and event triggers, after the functions they call (#3911).
537
537
  out.push(...(await readRoutineKinds(client, scope)));
538
+ // Extended statistics, foreign data wrappers and servers, and publications (#3911).
539
+ out.push(...(await readDatabaseKinds(client, scope)));
538
540
  // Triggers: the ones written by hand, not a foreign key's or a partition's clone of its parent's.
539
541
  {
540
542
  const rows = await client.query(`SELECT t.oid::text AS oid, n.nspname AS schema, c.relname AS table_name, t.tgname AS name, pg_catalog.pg_get_triggerdef(t.oid, true) AS def,
@@ -1 +1 @@
1
- {"version":3,"file":"describe-resources.d.ts","sourceRoot":"","sources":["../../../src/postgres/live/describe-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAGL,KAAK,uBAAuB,EAG7B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAoD,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,QAAQ,CAAC;AAYjH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAAE,aAAa,EAAE,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAiBtK;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG;IAAE,MAAM,EAAE,kBAAkB,GAAG,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQxI;AAED,+HAA+H;AAC/H,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,CAWhJ;AAqDD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE;IACP,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,GACnC,OAAO,CAAC,uBAAuB,CAAC,CAMlC"}
1
+ {"version":3,"file":"describe-resources.d.ts","sourceRoot":"","sources":["../../../src/postgres/live/describe-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAGL,KAAK,uBAAuB,EAG7B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAoD,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,QAAQ,CAAC;AAoBjH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAAE,aAAa,EAAE,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAoBtK;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG;IAAE,MAAM,EAAE,kBAAkB,GAAG,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQxI;AAED,+HAA+H;AAC/H,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,CAWhJ;AAqDD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE;IACP,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,GACnC,OAAO,CAAC,uBAAuB,CAAC,CAMlC"}
@@ -21,6 +21,13 @@ import { POSTGRES_ENTITY_TYPES } from "../entity-types.js";
21
21
  import { isChantManaged, readMarker, stripMarker } from "../../core/ownership.js";
22
22
  import { identValue } from "../parser.js";
23
23
  import { canonicalPgObject } from "../plan/normalize.js";
24
+ /** The entity types that belong to the database, not a schema. */
25
+ const UNPLACED = new Set([
26
+ POSTGRES_ENTITY_TYPES.eventTrigger,
27
+ POSTGRES_ENTITY_TYPES.foreignDataWrapper,
28
+ POSTGRES_ENTITY_TYPES.foreignServer,
29
+ POSTGRES_ENTITY_TYPES.publication,
30
+ ]);
24
31
  /**
25
32
  * The schema and name a declared entity is created as; a bare name is in the
26
33
  * default schema. A routine's parameter types and a trigger's table tell it
@@ -28,7 +35,7 @@ import { canonicalPgObject } from "../plan/normalize.js";
28
35
  */
29
36
  export function declaredAddress(entity, defaultSchema) {
30
37
  const name = String(entity.props.name ?? "");
31
- if (entity.type === POSTGRES_ENTITY_TYPES.schema || entity.type === POSTGRES_ENTITY_TYPES.extension || entity.type === POSTGRES_ENTITY_TYPES.role || entity.type === POSTGRES_ENTITY_TYPES.eventTrigger)
38
+ if (entity.type === POSTGRES_ENTITY_TYPES.schema || entity.type === POSTGRES_ENTITY_TYPES.extension || entity.type === POSTGRES_ENTITY_TYPES.role || UNPLACED.has(entity.type))
32
39
  return { name };
33
40
  // A cast is named by its two types, as the catalog prints them.
34
41
  if (entity.type === POSTGRES_ENTITY_TYPES.cast)
@@ -37,6 +44,9 @@ export function declaredAddress(entity, defaultSchema) {
37
44
  if (entity.type === POSTGRES_ENTITY_TYPES.function ||
38
45
  entity.type === POSTGRES_ENTITY_TYPES.procedure ||
39
46
  entity.type === POSTGRES_ENTITY_TYPES.aggregate ||
47
+ entity.type === POSTGRES_ENTITY_TYPES.operator ||
48
+ entity.type === POSTGRES_ENTITY_TYPES.operatorClass ||
49
+ entity.type === POSTGRES_ENTITY_TYPES.operatorFamily ||
40
50
  entity.type === POSTGRES_ENTITY_TYPES.trigger ||
41
51
  entity.type === POSTGRES_ENTITY_TYPES.policy) {
42
52
  const signature = canonicalPgObject(entity.type, entity.props, defaultSchema).signature;
@@ -66,7 +76,7 @@ export function scopeFor(target, entities) {
66
76
  return undefined;
67
77
  const out = new Set([target.defaultSchema]);
68
78
  // The schema alone: the rest of an address (a routine's parameter types) needs props a caller may not have.
69
- const unplaced = new Set([POSTGRES_ENTITY_TYPES.extension, POSTGRES_ENTITY_TYPES.role, POSTGRES_ENTITY_TYPES.cast, POSTGRES_ENTITY_TYPES.eventTrigger]);
79
+ const unplaced = new Set([POSTGRES_ENTITY_TYPES.extension, POSTGRES_ENTITY_TYPES.role, POSTGRES_ENTITY_TYPES.cast, ...UNPLACED]);
70
80
  for (const e of entities) {
71
81
  if (e.type === POSTGRES_ENTITY_TYPES.schema)
72
82
  out.add(String(e.props.name ?? ""));
@@ -87,6 +87,8 @@ export interface VerifyResult {
87
87
  mismatched: number;
88
88
  /** Rows whose new column is NULL. */
89
89
  nulls: number;
90
+ /** A rename with a type change: rows whose old column differs from `reverse` over the new one. */
91
+ unreversed?: number;
90
92
  /** The sum of a 64-bit hash of every new value, and of every value the expression gives. */
91
93
  checksum: string;
92
94
  expected: string;
@@ -1 +1 @@
1
- {"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/backfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAKH,OAAO,EAA0C,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAwC,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAmD,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAE7F,OAAO,EAAiD,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAEtF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,KAAG,MAAmC,CAAC;AAE7F,8IAA8I;AAC9I,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,CASrG;AAED,mGAAmG;AACnG,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,2CAA2C;IAC3C,eAAe,CAAC,EAAE,OAAO,eAAe,CAAC;CAC1C;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2DlG;AAID,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrC,8GAA8G;IAC9G,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,4FAA4F;IAC5F,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,uDAAuD;AACvD,qBAAa,0BAA2B,SAAQ,KAAK;IAEjD,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC;gBADpD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC,EAC7D,MAAM,EAAE,MAAM;CAKjB;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA0C9E"}
1
+ {"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../../../src/postgres/migrate/backfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAKH,OAAO,EAA0C,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAwC,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAmD,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAE7F,OAAO,EAAiD,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAEtF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,KAAG,MAAmC,CAAC;AAE7F,8IAA8I;AAC9I,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,CASrG;AAED,mGAAmG;AACnG,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,2CAA2C;IAC3C,eAAe,CAAC,EAAE,OAAO,eAAe,CAAC;CAC1C;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2DlG;AAID,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACrC,8GAA8G;IAC9G,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4FAA4F;IAC5F,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,uDAAuD;AACvD,qBAAa,0BAA2B,SAAQ,KAAK;IAEjD,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC;gBADpD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC,EAC7D,MAAM,EAAE,MAAM;CAKjB;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAoD9E"}
@@ -142,6 +142,7 @@ export async function verifyMigration(run) {
142
142
  const nw = col(n.newColumn);
143
143
  const [row] = await inTransaction(run, (exec) => exec(`SELECT count(*)::text AS rows, count(*) FILTER (WHERE ${nw} IS DISTINCT FROM (${o.expression}))::text AS mismatched,
144
144
  count(*) FILTER (WHERE ${nw} IS NULL)::text AS nulls,
145
+ ${o.reverse !== undefined ? `count(*) FILTER (WHERE (${o.reverse}) IS DISTINCT FROM ${col(n.source)})::text` : "'0'"} AS unreversed,
145
146
  COALESCE(sum(pg_catalog.hashtextextended(${nw}::text, 0)), 0)::text AS checksum,
146
147
  COALESCE(sum(pg_catalog.hashtextextended((${o.expression})::text, 0)), 0)::text AS expected
147
148
  FROM ${n.qualifiedTable}`), { scan: true });
@@ -149,6 +150,10 @@ export async function verifyMigration(run) {
149
150
  if (r.mismatched > 0 || r.checksum !== r.expected) {
150
151
  throw new MigrationVerificationError(n.key, { state: o.state, ...r }, `${r.mismatched} of ${r.rows} row(s) have ${n.newColumn} different from ${o.expression} (checksums ${r.checksum} and ${r.expected})`);
151
152
  }
153
+ const unreversed = Number(row?.unreversed ?? 0);
154
+ if (o.reverse !== undefined && unreversed > 0) {
155
+ throw new MigrationVerificationError(n.key, { state: o.state, ...r, unreversed }, `${unreversed} of ${r.rows} row(s) have ${n.source} different from ${o.reverse}, which must give the old value back from the new one (it would write ${n.source} wrongly for a writer of ${n.column})`);
156
+ }
152
157
  if (requiresNotNull(o.column, o.carried) && r.nulls > 0) {
153
158
  throw new MigrationVerificationError(n.key, { state: o.state, ...r }, `${r.nulls} of ${r.rows} row(s) have ${n.newColumn} NULL, and ${n.column} is declared NOT NULL or is in the primary key`);
154
159
  }
@@ -159,12 +164,13 @@ export async function verifyMigration(run) {
159
164
  const carried = o.carried.length > 0 || o.views.length > 0
160
165
  ? `; ${o.carried.map((c) => `${c.kind} ${c.name}${c.target !== c.name ? ` (as ${c.target})` : ""}`).join(", ") || "no index or constraint"} carried over${o.views.length > 0 ? `, view(s) ${o.views.map((v) => v.name).join(", ")} made again at the switch` : ""}`
161
166
  : "";
162
- const summary = `${n.key}: ${r.rows} row(s), ${n.newColumn} equal to ${o.expression} in every one (checksum ${r.checksum})${carried}`;
167
+ const summary = `${n.key}: ${r.rows} row(s), ${n.newColumn} equal to ${o.expression} in every one (checksum ${r.checksum})${o.reverse !== undefined ? `, ${n.source} equal to ${o.reverse} in every one` : ""}${carried}`;
163
168
  run.log(`-- ${summary}`);
164
169
  return {
165
170
  state: o.state,
166
171
  planDigest: computePlanDigest("postgres-migration", { plan: migrationPlanSubject(o), table: o.oid, column: o.newColumn.attnum, verified: { mismatched: 0 } }),
167
172
  ...r,
173
+ ...(o.reverse !== undefined ? { unreversed } : {}),
168
174
  summary,
169
175
  };
170
176
  }