@dotdo/postgres 0.1.0

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 (1129) hide show
  1. package/README.md +868 -0
  2. package/dist/cdc/change-stream.d.ts +44 -0
  3. package/dist/cdc/change-stream.d.ts.map +1 -0
  4. package/dist/cdc/change-stream.js +95 -0
  5. package/dist/cdc/change-stream.js.map +1 -0
  6. package/dist/cdc/filter.d.ts +58 -0
  7. package/dist/cdc/filter.d.ts.map +1 -0
  8. package/dist/cdc/filter.js +520 -0
  9. package/dist/cdc/filter.js.map +1 -0
  10. package/dist/cdc/index.d.ts +47 -0
  11. package/dist/cdc/index.d.ts.map +1 -0
  12. package/dist/cdc/index.js +50 -0
  13. package/dist/cdc/index.js.map +1 -0
  14. package/dist/cdc/resume-token.d.ts +60 -0
  15. package/dist/cdc/resume-token.d.ts.map +1 -0
  16. package/dist/cdc/resume-token.js +228 -0
  17. package/dist/cdc/resume-token.js.map +1 -0
  18. package/dist/cdc/transport/index.d.ts +7 -0
  19. package/dist/cdc/transport/index.d.ts.map +1 -0
  20. package/dist/cdc/transport/index.js +7 -0
  21. package/dist/cdc/transport/index.js.map +1 -0
  22. package/dist/cdc/transport/sse.d.ts +120 -0
  23. package/dist/cdc/transport/sse.d.ts.map +1 -0
  24. package/dist/cdc/transport/sse.js +590 -0
  25. package/dist/cdc/transport/sse.js.map +1 -0
  26. package/dist/cdc/transport/websocket.d.ts +130 -0
  27. package/dist/cdc/transport/websocket.d.ts.map +1 -0
  28. package/dist/cdc/transport/websocket.js +688 -0
  29. package/dist/cdc/transport/websocket.js.map +1 -0
  30. package/dist/cdc/types.d.ts +306 -0
  31. package/dist/cdc/types.d.ts.map +1 -0
  32. package/dist/cdc/types.js +8 -0
  33. package/dist/cdc/types.js.map +1 -0
  34. package/dist/config/index.d.ts +25 -0
  35. package/dist/config/index.d.ts.map +1 -0
  36. package/dist/config/index.js +25 -0
  37. package/dist/config/index.js.map +1 -0
  38. package/dist/config/memory.d.ts +139 -0
  39. package/dist/config/memory.d.ts.map +1 -0
  40. package/dist/config/memory.js +157 -0
  41. package/dist/config/memory.js.map +1 -0
  42. package/dist/config/storage.d.ts +157 -0
  43. package/dist/config/storage.d.ts.map +1 -0
  44. package/dist/config/storage.js +178 -0
  45. package/dist/config/storage.js.map +1 -0
  46. package/dist/config/streaming.d.ts +117 -0
  47. package/dist/config/streaming.d.ts.map +1 -0
  48. package/dist/config/streaming.js +132 -0
  49. package/dist/config/streaming.js.map +1 -0
  50. package/dist/config/timeouts.d.ts +168 -0
  51. package/dist/config/timeouts.d.ts.map +1 -0
  52. package/dist/config/timeouts.js +192 -0
  53. package/dist/config/timeouts.js.map +1 -0
  54. package/dist/extensions/config.d.ts +89 -0
  55. package/dist/extensions/config.d.ts.map +1 -0
  56. package/dist/extensions/config.js +216 -0
  57. package/dist/extensions/config.js.map +1 -0
  58. package/dist/extensions/geo.d.ts +452 -0
  59. package/dist/extensions/geo.d.ts.map +1 -0
  60. package/dist/extensions/geo.js +583 -0
  61. package/dist/extensions/geo.js.map +1 -0
  62. package/dist/extensions/index.d.ts +167 -0
  63. package/dist/extensions/index.d.ts.map +1 -0
  64. package/dist/extensions/index.js +99 -0
  65. package/dist/extensions/index.js.map +1 -0
  66. package/dist/extensions/loader.d.ts +226 -0
  67. package/dist/extensions/loader.d.ts.map +1 -0
  68. package/dist/extensions/loader.js +456 -0
  69. package/dist/extensions/loader.js.map +1 -0
  70. package/dist/extensions/pgmq-lite.d.ts +330 -0
  71. package/dist/extensions/pgmq-lite.d.ts.map +1 -0
  72. package/dist/extensions/pgmq-lite.js +648 -0
  73. package/dist/extensions/pgmq-lite.js.map +1 -0
  74. package/dist/extensions/plugins.d.ts +260 -0
  75. package/dist/extensions/plugins.d.ts.map +1 -0
  76. package/dist/extensions/plugins.js +535 -0
  77. package/dist/extensions/plugins.js.map +1 -0
  78. package/dist/extensions/registry.d.ts +93 -0
  79. package/dist/extensions/registry.d.ts.map +1 -0
  80. package/dist/extensions/registry.js +182 -0
  81. package/dist/extensions/registry.js.map +1 -0
  82. package/dist/extensions/vector.d.ts +106 -0
  83. package/dist/extensions/vector.d.ts.map +1 -0
  84. package/dist/extensions/vector.js +129 -0
  85. package/dist/extensions/vector.js.map +1 -0
  86. package/dist/iceberg/analytics.d.ts +279 -0
  87. package/dist/iceberg/analytics.d.ts.map +1 -0
  88. package/dist/iceberg/analytics.js +448 -0
  89. package/dist/iceberg/analytics.js.map +1 -0
  90. package/dist/iceberg/catalog-api.d.ts +39 -0
  91. package/dist/iceberg/catalog-api.d.ts.map +1 -0
  92. package/dist/iceberg/catalog-api.js +388 -0
  93. package/dist/iceberg/catalog-api.js.map +1 -0
  94. package/dist/iceberg/catalog.d.ts +401 -0
  95. package/dist/iceberg/catalog.d.ts.map +1 -0
  96. package/dist/iceberg/catalog.js +677 -0
  97. package/dist/iceberg/catalog.js.map +1 -0
  98. package/dist/iceberg/duckdb-wasm.d.ts +447 -0
  99. package/dist/iceberg/duckdb-wasm.d.ts.map +1 -0
  100. package/dist/iceberg/duckdb-wasm.js +600 -0
  101. package/dist/iceberg/duckdb-wasm.js.map +1 -0
  102. package/dist/iceberg/index.d.ts +92 -0
  103. package/dist/iceberg/index.d.ts.map +1 -0
  104. package/dist/iceberg/index.js +119 -0
  105. package/dist/iceberg/index.js.map +1 -0
  106. package/dist/iceberg/metadata.d.ts +214 -0
  107. package/dist/iceberg/metadata.d.ts.map +1 -0
  108. package/dist/iceberg/metadata.js +535 -0
  109. package/dist/iceberg/metadata.js.map +1 -0
  110. package/dist/iceberg/optimizer.d.ts +296 -0
  111. package/dist/iceberg/optimizer.d.ts.map +1 -0
  112. package/dist/iceberg/optimizer.js +889 -0
  113. package/dist/iceberg/optimizer.js.map +1 -0
  114. package/dist/iceberg/parquet.d.ts +447 -0
  115. package/dist/iceberg/parquet.d.ts.map +1 -0
  116. package/dist/iceberg/parquet.js +1225 -0
  117. package/dist/iceberg/parquet.js.map +1 -0
  118. package/dist/iceberg/r2-organization.d.ts +422 -0
  119. package/dist/iceberg/r2-organization.d.ts.map +1 -0
  120. package/dist/iceberg/r2-organization.js +672 -0
  121. package/dist/iceberg/r2-organization.js.map +1 -0
  122. package/dist/iceberg/scheduler-do-example.d.ts +158 -0
  123. package/dist/iceberg/scheduler-do-example.d.ts.map +1 -0
  124. package/dist/iceberg/scheduler-do-example.js +261 -0
  125. package/dist/iceberg/scheduler-do-example.js.map +1 -0
  126. package/dist/iceberg/scheduler.d.ts +434 -0
  127. package/dist/iceberg/scheduler.d.ts.map +1 -0
  128. package/dist/iceberg/scheduler.js +818 -0
  129. package/dist/iceberg/scheduler.js.map +1 -0
  130. package/dist/iceberg/schema.d.ts +149 -0
  131. package/dist/iceberg/schema.d.ts.map +1 -0
  132. package/dist/iceberg/schema.js +525 -0
  133. package/dist/iceberg/schema.js.map +1 -0
  134. package/dist/iceberg/snapshot-manager.d.ts +406 -0
  135. package/dist/iceberg/snapshot-manager.d.ts.map +1 -0
  136. package/dist/iceberg/snapshot-manager.js +934 -0
  137. package/dist/iceberg/snapshot-manager.js.map +1 -0
  138. package/dist/iceberg/sql-router.d.ts +194 -0
  139. package/dist/iceberg/sql-router.d.ts.map +1 -0
  140. package/dist/iceberg/sql-router.js +180 -0
  141. package/dist/iceberg/sql-router.js.map +1 -0
  142. package/dist/iceberg/test-fixtures.d.ts +151 -0
  143. package/dist/iceberg/test-fixtures.d.ts.map +1 -0
  144. package/dist/iceberg/test-fixtures.js +446 -0
  145. package/dist/iceberg/test-fixtures.js.map +1 -0
  146. package/dist/iceberg/time-travel-api.d.ts +102 -0
  147. package/dist/iceberg/time-travel-api.d.ts.map +1 -0
  148. package/dist/iceberg/time-travel-api.js +437 -0
  149. package/dist/iceberg/time-travel-api.js.map +1 -0
  150. package/dist/iceberg/time-travel.d.ts +293 -0
  151. package/dist/iceberg/time-travel.d.ts.map +1 -0
  152. package/dist/iceberg/time-travel.js +689 -0
  153. package/dist/iceberg/time-travel.js.map +1 -0
  154. package/dist/iceberg/transformer.d.ts +356 -0
  155. package/dist/iceberg/transformer.d.ts.map +1 -0
  156. package/dist/iceberg/transformer.js +770 -0
  157. package/dist/iceberg/transformer.js.map +1 -0
  158. package/dist/iceberg/types.d.ts +318 -0
  159. package/dist/iceberg/types.d.ts.map +1 -0
  160. package/dist/iceberg/types.js +9 -0
  161. package/dist/iceberg/types.js.map +1 -0
  162. package/dist/iceberg/writer.d.ts +144 -0
  163. package/dist/iceberg/writer.d.ts.map +1 -0
  164. package/dist/iceberg/writer.js +452 -0
  165. package/dist/iceberg/writer.js.map +1 -0
  166. package/dist/index.d.ts +50 -0
  167. package/dist/index.d.ts.map +1 -0
  168. package/dist/index.js +69 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/lineage/index.d.ts +11 -0
  171. package/dist/lineage/index.d.ts.map +1 -0
  172. package/dist/lineage/index.js +11 -0
  173. package/dist/lineage/index.js.map +1 -0
  174. package/dist/lineage/integration.d.ts +134 -0
  175. package/dist/lineage/integration.d.ts.map +1 -0
  176. package/dist/lineage/integration.js +258 -0
  177. package/dist/lineage/integration.js.map +1 -0
  178. package/dist/lineage/tracker.d.ts +189 -0
  179. package/dist/lineage/tracker.d.ts.map +1 -0
  180. package/dist/lineage/tracker.js +1352 -0
  181. package/dist/lineage/tracker.js.map +1 -0
  182. package/dist/lineage/types.d.ts +318 -0
  183. package/dist/lineage/types.d.ts.map +1 -0
  184. package/dist/lineage/types.js +9 -0
  185. package/dist/lineage/types.js.map +1 -0
  186. package/dist/middleware/index.d.ts +11 -0
  187. package/dist/middleware/index.d.ts.map +1 -0
  188. package/dist/middleware/index.js +16 -0
  189. package/dist/middleware/index.js.map +1 -0
  190. package/dist/middleware/rate-limit.d.ts +397 -0
  191. package/dist/middleware/rate-limit.d.ts.map +1 -0
  192. package/dist/middleware/rate-limit.js +507 -0
  193. package/dist/middleware/rate-limit.js.map +1 -0
  194. package/dist/migration-tooling/external-migration.d.ts +601 -0
  195. package/dist/migration-tooling/external-migration.d.ts.map +1 -0
  196. package/dist/migration-tooling/external-migration.js +1612 -0
  197. package/dist/migration-tooling/external-migration.js.map +1 -0
  198. package/dist/migration-tooling/index.d.ts +19 -0
  199. package/dist/migration-tooling/index.d.ts.map +1 -0
  200. package/dist/migration-tooling/index.js +19 -0
  201. package/dist/migration-tooling/index.js.map +1 -0
  202. package/dist/migrations/auto-migrator.d.ts +289 -0
  203. package/dist/migrations/auto-migrator.d.ts.map +1 -0
  204. package/dist/migrations/auto-migrator.js +396 -0
  205. package/dist/migrations/auto-migrator.js.map +1 -0
  206. package/dist/migrations/bulk-orchestrator.d.ts +403 -0
  207. package/dist/migrations/bulk-orchestrator.d.ts.map +1 -0
  208. package/dist/migrations/bulk-orchestrator.js +646 -0
  209. package/dist/migrations/bulk-orchestrator.js.map +1 -0
  210. package/dist/migrations/compatibility.d.ts +216 -0
  211. package/dist/migrations/compatibility.d.ts.map +1 -0
  212. package/dist/migrations/compatibility.js +651 -0
  213. package/dist/migrations/compatibility.js.map +1 -0
  214. package/dist/migrations/do-migrations.d.ts +101 -0
  215. package/dist/migrations/do-migrations.d.ts.map +1 -0
  216. package/dist/migrations/do-migrations.js +1060 -0
  217. package/dist/migrations/do-migrations.js.map +1 -0
  218. package/dist/migrations/do-migrations.types.d.ts +550 -0
  219. package/dist/migrations/do-migrations.types.d.ts.map +1 -0
  220. package/dist/migrations/do-migrations.types.js +15 -0
  221. package/dist/migrations/do-migrations.types.js.map +1 -0
  222. package/dist/migrations/drizzle-compat.d.ts +163 -0
  223. package/dist/migrations/drizzle-compat.d.ts.map +1 -0
  224. package/dist/migrations/drizzle-compat.js +273 -0
  225. package/dist/migrations/drizzle-compat.js.map +1 -0
  226. package/dist/migrations/index.d.ts +109 -0
  227. package/dist/migrations/index.d.ts.map +1 -0
  228. package/dist/migrations/index.js +127 -0
  229. package/dist/migrations/index.js.map +1 -0
  230. package/dist/migrations/migration-api.d.ts +161 -0
  231. package/dist/migrations/migration-api.d.ts.map +1 -0
  232. package/dist/migrations/migration-api.js +499 -0
  233. package/dist/migrations/migration-api.js.map +1 -0
  234. package/dist/migrations/progress-tracker-do.d.ts +195 -0
  235. package/dist/migrations/progress-tracker-do.d.ts.map +1 -0
  236. package/dist/migrations/progress-tracker-do.js +339 -0
  237. package/dist/migrations/progress-tracker-do.js.map +1 -0
  238. package/dist/migrations/progress-tracker-kv.d.ts +103 -0
  239. package/dist/migrations/progress-tracker-kv.d.ts.map +1 -0
  240. package/dist/migrations/progress-tracker-kv.js +231 -0
  241. package/dist/migrations/progress-tracker-kv.js.map +1 -0
  242. package/dist/migrations/progress-tracker.d.ts +320 -0
  243. package/dist/migrations/progress-tracker.d.ts.map +1 -0
  244. package/dist/migrations/progress-tracker.js +443 -0
  245. package/dist/migrations/progress-tracker.js.map +1 -0
  246. package/dist/migrations/registry.d.ts +231 -0
  247. package/dist/migrations/registry.d.ts.map +1 -0
  248. package/dist/migrations/registry.js +376 -0
  249. package/dist/migrations/registry.js.map +1 -0
  250. package/dist/migrations/runner.d.ts +197 -0
  251. package/dist/migrations/runner.d.ts.map +1 -0
  252. package/dist/migrations/runner.js +1167 -0
  253. package/dist/migrations/runner.js.map +1 -0
  254. package/dist/migrations/schema-generator.d.ts +111 -0
  255. package/dist/migrations/schema-generator.d.ts.map +1 -0
  256. package/dist/migrations/schema-generator.js +335 -0
  257. package/dist/migrations/schema-generator.js.map +1 -0
  258. package/dist/migrations/testing.d.ts +321 -0
  259. package/dist/migrations/testing.d.ts.map +1 -0
  260. package/dist/migrations/testing.js +645 -0
  261. package/dist/migrations/testing.js.map +1 -0
  262. package/dist/migrations/types.d.ts +503 -0
  263. package/dist/migrations/types.d.ts.map +1 -0
  264. package/dist/migrations/types.js +11 -0
  265. package/dist/migrations/types.js.map +1 -0
  266. package/dist/migrations/validator.d.ts +215 -0
  267. package/dist/migrations/validator.d.ts.map +1 -0
  268. package/dist/migrations/validator.js +494 -0
  269. package/dist/migrations/validator.js.map +1 -0
  270. package/dist/observability/alerting.d.ts +116 -0
  271. package/dist/observability/alerting.d.ts.map +1 -0
  272. package/dist/observability/alerting.js +353 -0
  273. package/dist/observability/alerting.js.map +1 -0
  274. package/dist/observability/analytics-engine.d.ts +357 -0
  275. package/dist/observability/analytics-engine.d.ts.map +1 -0
  276. package/dist/observability/analytics-engine.js +430 -0
  277. package/dist/observability/analytics-engine.js.map +1 -0
  278. package/dist/observability/cost-metrics.d.ts +269 -0
  279. package/dist/observability/cost-metrics.d.ts.map +1 -0
  280. package/dist/observability/cost-metrics.js +560 -0
  281. package/dist/observability/cost-metrics.js.map +1 -0
  282. package/dist/observability/cross-do-tracing.d.ts +305 -0
  283. package/dist/observability/cross-do-tracing.d.ts.map +1 -0
  284. package/dist/observability/cross-do-tracing.js +431 -0
  285. package/dist/observability/cross-do-tracing.js.map +1 -0
  286. package/dist/observability/error-rate-collector.d.ts +163 -0
  287. package/dist/observability/error-rate-collector.d.ts.map +1 -0
  288. package/dist/observability/error-rate-collector.js +306 -0
  289. package/dist/observability/error-rate-collector.js.map +1 -0
  290. package/dist/observability/exporters.d.ts +231 -0
  291. package/dist/observability/exporters.d.ts.map +1 -0
  292. package/dist/observability/exporters.js +479 -0
  293. package/dist/observability/exporters.js.map +1 -0
  294. package/dist/observability/health-check.d.ts +106 -0
  295. package/dist/observability/health-check.d.ts.map +1 -0
  296. package/dist/observability/health-check.js +243 -0
  297. package/dist/observability/health-check.js.map +1 -0
  298. package/dist/observability/index.d.ts +297 -0
  299. package/dist/observability/index.d.ts.map +1 -0
  300. package/dist/observability/index.js +455 -0
  301. package/dist/observability/index.js.map +1 -0
  302. package/dist/observability/instrumentation.d.ts +222 -0
  303. package/dist/observability/instrumentation.d.ts.map +1 -0
  304. package/dist/observability/instrumentation.js +532 -0
  305. package/dist/observability/instrumentation.js.map +1 -0
  306. package/dist/observability/memory-metrics.d.ts +227 -0
  307. package/dist/observability/memory-metrics.d.ts.map +1 -0
  308. package/dist/observability/memory-metrics.js +688 -0
  309. package/dist/observability/memory-metrics.js.map +1 -0
  310. package/dist/observability/metrics-endpoint.d.ts +91 -0
  311. package/dist/observability/metrics-endpoint.d.ts.map +1 -0
  312. package/dist/observability/metrics-endpoint.js +246 -0
  313. package/dist/observability/metrics-endpoint.js.map +1 -0
  314. package/dist/observability/metrics.d.ts +88 -0
  315. package/dist/observability/metrics.d.ts.map +1 -0
  316. package/dist/observability/metrics.js +253 -0
  317. package/dist/observability/metrics.js.map +1 -0
  318. package/dist/observability/observability-features.d.ts +488 -0
  319. package/dist/observability/observability-features.d.ts.map +1 -0
  320. package/dist/observability/observability-features.js +773 -0
  321. package/dist/observability/observability-features.js.map +1 -0
  322. package/dist/observability/prometheus.d.ts +39 -0
  323. package/dist/observability/prometheus.d.ts.map +1 -0
  324. package/dist/observability/prometheus.js +120 -0
  325. package/dist/observability/prometheus.js.map +1 -0
  326. package/dist/observability/propagation.d.ts +126 -0
  327. package/dist/observability/propagation.d.ts.map +1 -0
  328. package/dist/observability/propagation.js +234 -0
  329. package/dist/observability/propagation.js.map +1 -0
  330. package/dist/observability/query-latency.d.ts +243 -0
  331. package/dist/observability/query-latency.d.ts.map +1 -0
  332. package/dist/observability/query-latency.js +292 -0
  333. package/dist/observability/query-latency.js.map +1 -0
  334. package/dist/observability/query-performance.d.ts +169 -0
  335. package/dist/observability/query-performance.d.ts.map +1 -0
  336. package/dist/observability/query-performance.js +290 -0
  337. package/dist/observability/query-performance.js.map +1 -0
  338. package/dist/observability/storage-tier-metrics.d.ts +174 -0
  339. package/dist/observability/storage-tier-metrics.d.ts.map +1 -0
  340. package/dist/observability/storage-tier-metrics.js +306 -0
  341. package/dist/observability/storage-tier-metrics.js.map +1 -0
  342. package/dist/observability/tier-cost-optimizer.d.ts +155 -0
  343. package/dist/observability/tier-cost-optimizer.d.ts.map +1 -0
  344. package/dist/observability/tier-cost-optimizer.js +536 -0
  345. package/dist/observability/tier-cost-optimizer.js.map +1 -0
  346. package/dist/observability/tracer.d.ts +149 -0
  347. package/dist/observability/tracer.d.ts.map +1 -0
  348. package/dist/observability/tracer.js +435 -0
  349. package/dist/observability/tracer.js.map +1 -0
  350. package/dist/observability/types.d.ts +402 -0
  351. package/dist/observability/types.d.ts.map +1 -0
  352. package/dist/observability/types.js +103 -0
  353. package/dist/observability/types.js.map +1 -0
  354. package/dist/pglite/workers-pglite.d.ts +138 -0
  355. package/dist/pglite/workers-pglite.d.ts.map +1 -0
  356. package/dist/pglite/workers-pglite.js +143 -0
  357. package/dist/pglite/workers-pglite.js.map +1 -0
  358. package/dist/pglite-assets/pglite.data +0 -0
  359. package/dist/pglite-assets/pglite.wasm +0 -0
  360. package/dist/playground/index.d.ts +52 -0
  361. package/dist/playground/index.d.ts.map +1 -0
  362. package/dist/playground/index.js +55 -0
  363. package/dist/playground/index.js.map +1 -0
  364. package/dist/playground/keyboard-shortcuts.d.ts +116 -0
  365. package/dist/playground/keyboard-shortcuts.d.ts.map +1 -0
  366. package/dist/playground/keyboard-shortcuts.js +588 -0
  367. package/dist/playground/keyboard-shortcuts.js.map +1 -0
  368. package/dist/playground/playground.d.ts +82 -0
  369. package/dist/playground/playground.d.ts.map +1 -0
  370. package/dist/playground/playground.js +271 -0
  371. package/dist/playground/playground.js.map +1 -0
  372. package/dist/playground/query-executor.d.ts +115 -0
  373. package/dist/playground/query-executor.d.ts.map +1 -0
  374. package/dist/playground/query-executor.js +558 -0
  375. package/dist/playground/query-executor.js.map +1 -0
  376. package/dist/playground/query-history.d.ts +92 -0
  377. package/dist/playground/query-history.d.ts.map +1 -0
  378. package/dist/playground/query-history.js +259 -0
  379. package/dist/playground/query-history.js.map +1 -0
  380. package/dist/playground/result-formatter.d.ts +59 -0
  381. package/dist/playground/result-formatter.d.ts.map +1 -0
  382. package/dist/playground/result-formatter.js +341 -0
  383. package/dist/playground/result-formatter.js.map +1 -0
  384. package/dist/playground/sample-datasets.d.ts +77 -0
  385. package/dist/playground/sample-datasets.d.ts.map +1 -0
  386. package/dist/playground/sample-datasets.js +641 -0
  387. package/dist/playground/sample-datasets.js.map +1 -0
  388. package/dist/playground/sample-queries.d.ts +73 -0
  389. package/dist/playground/sample-queries.d.ts.map +1 -0
  390. package/dist/playground/sample-queries.js +1095 -0
  391. package/dist/playground/sample-queries.js.map +1 -0
  392. package/dist/playground/schema-explorer.d.ts +55 -0
  393. package/dist/playground/schema-explorer.d.ts.map +1 -0
  394. package/dist/playground/schema-explorer.js +473 -0
  395. package/dist/playground/schema-explorer.js.map +1 -0
  396. package/dist/playground/types.d.ts +430 -0
  397. package/dist/playground/types.d.ts.map +1 -0
  398. package/dist/playground/types.js +10 -0
  399. package/dist/playground/types.js.map +1 -0
  400. package/dist/readonly/cache-reader.d.ts +145 -0
  401. package/dist/readonly/cache-reader.d.ts.map +1 -0
  402. package/dist/readonly/cache-reader.js +198 -0
  403. package/dist/readonly/cache-reader.js.map +1 -0
  404. package/dist/readonly/config.d.ts +74 -0
  405. package/dist/readonly/config.d.ts.map +1 -0
  406. package/dist/readonly/config.js +67 -0
  407. package/dist/readonly/config.js.map +1 -0
  408. package/dist/readonly/index.d.ts +22 -0
  409. package/dist/readonly/index.d.ts.map +1 -0
  410. package/dist/readonly/index.js +17 -0
  411. package/dist/readonly/index.js.map +1 -0
  412. package/dist/readonly/pglite-wrapper.d.ts +82 -0
  413. package/dist/readonly/pglite-wrapper.d.ts.map +1 -0
  414. package/dist/readonly/pglite-wrapper.js +123 -0
  415. package/dist/readonly/pglite-wrapper.js.map +1 -0
  416. package/dist/readonly/worker.d.ts +142 -0
  417. package/dist/readonly/worker.d.ts.map +1 -0
  418. package/dist/readonly/worker.js +187 -0
  419. package/dist/readonly/worker.js.map +1 -0
  420. package/dist/readonly/write-blocker.d.ts +47 -0
  421. package/dist/readonly/write-blocker.d.ts.map +1 -0
  422. package/dist/readonly/write-blocker.js +136 -0
  423. package/dist/readonly/write-blocker.js.map +1 -0
  424. package/dist/recovery/disaster-recovery.d.ts +326 -0
  425. package/dist/recovery/disaster-recovery.d.ts.map +1 -0
  426. package/dist/recovery/disaster-recovery.js +799 -0
  427. package/dist/recovery/disaster-recovery.js.map +1 -0
  428. package/dist/recovery/index.d.ts +12 -0
  429. package/dist/recovery/index.d.ts.map +1 -0
  430. package/dist/recovery/index.js +12 -0
  431. package/dist/recovery/index.js.map +1 -0
  432. package/dist/recovery/parquet-parser.d.ts +321 -0
  433. package/dist/recovery/parquet-parser.d.ts.map +1 -0
  434. package/dist/recovery/parquet-parser.js +797 -0
  435. package/dist/recovery/parquet-parser.js.map +1 -0
  436. package/dist/retention/index.d.ts +50 -0
  437. package/dist/retention/index.d.ts.map +1 -0
  438. package/dist/retention/index.js +50 -0
  439. package/dist/retention/index.js.map +1 -0
  440. package/dist/retention/policy.d.ts +344 -0
  441. package/dist/retention/policy.d.ts.map +1 -0
  442. package/dist/retention/policy.js +472 -0
  443. package/dist/retention/policy.js.map +1 -0
  444. package/dist/retention/purger.d.ts +187 -0
  445. package/dist/retention/purger.d.ts.map +1 -0
  446. package/dist/retention/purger.js +411 -0
  447. package/dist/retention/purger.js.map +1 -0
  448. package/dist/rls/auth-integration.d.ts +280 -0
  449. package/dist/rls/auth-integration.d.ts.map +1 -0
  450. package/dist/rls/auth-integration.js +399 -0
  451. package/dist/rls/auth-integration.js.map +1 -0
  452. package/dist/rls/generator.d.ts +249 -0
  453. package/dist/rls/generator.d.ts.map +1 -0
  454. package/dist/rls/generator.js +495 -0
  455. package/dist/rls/generator.js.map +1 -0
  456. package/dist/rls/index.d.ts +26 -0
  457. package/dist/rls/index.d.ts.map +1 -0
  458. package/dist/rls/index.js +58 -0
  459. package/dist/rls/index.js.map +1 -0
  460. package/dist/rls/policy.d.ts +116 -0
  461. package/dist/rls/policy.d.ts.map +1 -0
  462. package/dist/rls/policy.js +77 -0
  463. package/dist/rls/policy.js.map +1 -0
  464. package/dist/rls/validator.d.ts +155 -0
  465. package/dist/rls/validator.d.ts.map +1 -0
  466. package/dist/rls/validator.js +792 -0
  467. package/dist/rls/validator.js.map +1 -0
  468. package/dist/routing/adaptive-router.d.ts +317 -0
  469. package/dist/routing/adaptive-router.d.ts.map +1 -0
  470. package/dist/routing/adaptive-router.js +554 -0
  471. package/dist/routing/adaptive-router.js.map +1 -0
  472. package/dist/routing/circuit-breaker.d.ts +339 -0
  473. package/dist/routing/circuit-breaker.d.ts.map +1 -0
  474. package/dist/routing/circuit-breaker.js +620 -0
  475. package/dist/routing/circuit-breaker.js.map +1 -0
  476. package/dist/routing/cost-metrics.d.ts +133 -0
  477. package/dist/routing/cost-metrics.d.ts.map +1 -0
  478. package/dist/routing/cost-metrics.js +259 -0
  479. package/dist/routing/cost-metrics.js.map +1 -0
  480. package/dist/routing/do-connection-pool.d.ts +243 -0
  481. package/dist/routing/do-connection-pool.d.ts.map +1 -0
  482. package/dist/routing/do-connection-pool.js +572 -0
  483. package/dist/routing/do-connection-pool.js.map +1 -0
  484. package/dist/routing/index.d.ts +59 -0
  485. package/dist/routing/index.d.ts.map +1 -0
  486. package/dist/routing/index.js +59 -0
  487. package/dist/routing/index.js.map +1 -0
  488. package/dist/routing/query-complexity-estimator.d.ts +73 -0
  489. package/dist/routing/query-complexity-estimator.d.ts.map +1 -0
  490. package/dist/routing/query-complexity-estimator.js +327 -0
  491. package/dist/routing/query-complexity-estimator.js.map +1 -0
  492. package/dist/routing/request-coalescing.d.ts +178 -0
  493. package/dist/routing/request-coalescing.d.ts.map +1 -0
  494. package/dist/routing/request-coalescing.js +325 -0
  495. package/dist/routing/request-coalescing.js.map +1 -0
  496. package/dist/routing/runtime-router.d.ts +107 -0
  497. package/dist/routing/runtime-router.d.ts.map +1 -0
  498. package/dist/routing/runtime-router.js +246 -0
  499. package/dist/routing/runtime-router.js.map +1 -0
  500. package/dist/routing/tenant-router.d.ts +848 -0
  501. package/dist/routing/tenant-router.d.ts.map +1 -0
  502. package/dist/routing/tenant-router.js +1056 -0
  503. package/dist/routing/tenant-router.js.map +1 -0
  504. package/dist/routing/websocket-pool.d.ts +119 -0
  505. package/dist/routing/websocket-pool.d.ts.map +1 -0
  506. package/dist/routing/websocket-pool.js +436 -0
  507. package/dist/routing/websocket-pool.js.map +1 -0
  508. package/dist/storage/cache-layer.d.ts +159 -0
  509. package/dist/storage/cache-layer.d.ts.map +1 -0
  510. package/dist/storage/cache-layer.js +245 -0
  511. package/dist/storage/cache-layer.js.map +1 -0
  512. package/dist/storage/cost-aware-tiering.d.ts +258 -0
  513. package/dist/storage/cost-aware-tiering.d.ts.map +1 -0
  514. package/dist/storage/cost-aware-tiering.js +526 -0
  515. package/dist/storage/cost-aware-tiering.js.map +1 -0
  516. package/dist/storage/index.d.ts +87 -0
  517. package/dist/storage/index.d.ts.map +1 -0
  518. package/dist/storage/index.js +78 -0
  519. package/dist/storage/index.js.map +1 -0
  520. package/dist/storage/interfaces.d.ts +856 -0
  521. package/dist/storage/interfaces.d.ts.map +1 -0
  522. package/dist/storage/interfaces.js +69 -0
  523. package/dist/storage/interfaces.js.map +1 -0
  524. package/dist/storage/r2-layer.d.ts +226 -0
  525. package/dist/storage/r2-layer.d.ts.map +1 -0
  526. package/dist/storage/r2-layer.js +307 -0
  527. package/dist/storage/r2-layer.js.map +1 -0
  528. package/dist/storage/r2-overflow.d.ts +344 -0
  529. package/dist/storage/r2-overflow.d.ts.map +1 -0
  530. package/dist/storage/r2-overflow.js +730 -0
  531. package/dist/storage/r2-overflow.js.map +1 -0
  532. package/dist/storage/r2-page-vfs.d.ts +374 -0
  533. package/dist/storage/r2-page-vfs.d.ts.map +1 -0
  534. package/dist/storage/r2-page-vfs.js +754 -0
  535. package/dist/storage/r2-page-vfs.js.map +1 -0
  536. package/dist/storage/swr-cache.d.ts +181 -0
  537. package/dist/storage/swr-cache.d.ts.map +1 -0
  538. package/dist/storage/swr-cache.js +295 -0
  539. package/dist/storage/swr-cache.js.map +1 -0
  540. package/dist/storage/tiered-orchestrator.d.ts +951 -0
  541. package/dist/storage/tiered-orchestrator.d.ts.map +1 -0
  542. package/dist/storage/tiered-orchestrator.js +1731 -0
  543. package/dist/storage/tiered-orchestrator.js.map +1 -0
  544. package/dist/storage/tiered-vfs-swr.d.ts +279 -0
  545. package/dist/storage/tiered-vfs-swr.d.ts.map +1 -0
  546. package/dist/storage/tiered-vfs-swr.js +584 -0
  547. package/dist/storage/tiered-vfs-swr.js.map +1 -0
  548. package/dist/storage/tiered-vfs.d.ts +405 -0
  549. package/dist/storage/tiered-vfs.d.ts.map +1 -0
  550. package/dist/storage/tiered-vfs.js +833 -0
  551. package/dist/storage/tiered-vfs.js.map +1 -0
  552. package/dist/streaming/backpressure-controller.d.ts +173 -0
  553. package/dist/streaming/backpressure-controller.d.ts.map +1 -0
  554. package/dist/streaming/backpressure-controller.js +344 -0
  555. package/dist/streaming/backpressure-controller.js.map +1 -0
  556. package/dist/streaming/buffer-pool.d.ts +241 -0
  557. package/dist/streaming/buffer-pool.d.ts.map +1 -0
  558. package/dist/streaming/buffer-pool.js +381 -0
  559. package/dist/streaming/buffer-pool.js.map +1 -0
  560. package/dist/streaming/cdc-iceberg-connector.d.ts +272 -0
  561. package/dist/streaming/cdc-iceberg-connector.d.ts.map +1 -0
  562. package/dist/streaming/cdc-iceberg-connector.js +408 -0
  563. package/dist/streaming/cdc-iceberg-connector.js.map +1 -0
  564. package/dist/streaming/index.d.ts +111 -0
  565. package/dist/streaming/index.d.ts.map +1 -0
  566. package/dist/streaming/index.js +128 -0
  567. package/dist/streaming/index.js.map +1 -0
  568. package/dist/streaming/live-cdc-stream.d.ts +400 -0
  569. package/dist/streaming/live-cdc-stream.d.ts.map +1 -0
  570. package/dist/streaming/live-cdc-stream.js +703 -0
  571. package/dist/streaming/live-cdc-stream.js.map +1 -0
  572. package/dist/streaming/memory-bounded-stream.d.ts +207 -0
  573. package/dist/streaming/memory-bounded-stream.d.ts.map +1 -0
  574. package/dist/streaming/memory-bounded-stream.js +340 -0
  575. package/dist/streaming/memory-bounded-stream.js.map +1 -0
  576. package/dist/streaming/query-streamer.d.ts +379 -0
  577. package/dist/streaming/query-streamer.d.ts.map +1 -0
  578. package/dist/streaming/query-streamer.js +495 -0
  579. package/dist/streaming/query-streamer.js.map +1 -0
  580. package/dist/streaming/response-streaming.d.ts +203 -0
  581. package/dist/streaming/response-streaming.d.ts.map +1 -0
  582. package/dist/streaming/response-streaming.js +449 -0
  583. package/dist/streaming/response-streaming.js.map +1 -0
  584. package/dist/types/branded.d.ts +859 -0
  585. package/dist/types/branded.d.ts.map +1 -0
  586. package/dist/types/branded.js +891 -0
  587. package/dist/types/branded.js.map +1 -0
  588. package/dist/types/utilities.d.ts +757 -0
  589. package/dist/types/utilities.d.ts.map +1 -0
  590. package/dist/types/utilities.js +447 -0
  591. package/dist/types/utilities.js.map +1 -0
  592. package/dist/wal/replay-engine.d.ts +344 -0
  593. package/dist/wal/replay-engine.d.ts.map +1 -0
  594. package/dist/wal/replay-engine.js +975 -0
  595. package/dist/wal/replay-engine.js.map +1 -0
  596. package/dist/worker/__mocks__/capnweb.d.ts +13 -0
  597. package/dist/worker/__mocks__/capnweb.d.ts.map +1 -0
  598. package/dist/worker/__mocks__/capnweb.js +15 -0
  599. package/dist/worker/__mocks__/capnweb.js.map +1 -0
  600. package/dist/worker/__mocks__/cloudflare-workers.d.ts +31 -0
  601. package/dist/worker/__mocks__/cloudflare-workers.d.ts.map +1 -0
  602. package/dist/worker/__mocks__/cloudflare-workers.js +33 -0
  603. package/dist/worker/__mocks__/cloudflare-workers.js.map +1 -0
  604. package/dist/worker/__mocks__/pglite.data.d.ts +3 -0
  605. package/dist/worker/__mocks__/pglite.data.d.ts.map +1 -0
  606. package/dist/worker/__mocks__/pglite.data.js +20 -0
  607. package/dist/worker/__mocks__/pglite.data.js.map +1 -0
  608. package/dist/worker/__mocks__/pglite.wasm.d.ts +3 -0
  609. package/dist/worker/__mocks__/pglite.wasm.d.ts.map +1 -0
  610. package/dist/worker/__mocks__/pglite.wasm.js +30 -0
  611. package/dist/worker/__mocks__/pglite.wasm.js.map +1 -0
  612. package/dist/worker/auth-rate-limiter.d.ts +270 -0
  613. package/dist/worker/auth-rate-limiter.d.ts.map +1 -0
  614. package/dist/worker/auth-rate-limiter.js +332 -0
  615. package/dist/worker/auth-rate-limiter.js.map +1 -0
  616. package/dist/worker/auth.d.ts +345 -0
  617. package/dist/worker/auth.d.ts.map +1 -0
  618. package/dist/worker/auth.js +837 -0
  619. package/dist/worker/auth.js.map +1 -0
  620. package/dist/worker/cdc-backpressure.d.ts +338 -0
  621. package/dist/worker/cdc-backpressure.d.ts.map +1 -0
  622. package/dist/worker/cdc-backpressure.js +619 -0
  623. package/dist/worker/cdc-backpressure.js.map +1 -0
  624. package/dist/worker/cdc-sse.d.ts +277 -0
  625. package/dist/worker/cdc-sse.d.ts.map +1 -0
  626. package/dist/worker/cdc-sse.js +528 -0
  627. package/dist/worker/cdc-sse.js.map +1 -0
  628. package/dist/worker/cdc-websocket.d.ts +252 -0
  629. package/dist/worker/cdc-websocket.d.ts.map +1 -0
  630. package/dist/worker/cdc-websocket.js +940 -0
  631. package/dist/worker/cdc-websocket.js.map +1 -0
  632. package/dist/worker/cdc.d.ts +95 -0
  633. package/dist/worker/cdc.d.ts.map +1 -0
  634. package/dist/worker/cdc.js +211 -0
  635. package/dist/worker/cdc.js.map +1 -0
  636. package/dist/worker/concerns/auth-concern.d.ts +50 -0
  637. package/dist/worker/concerns/auth-concern.d.ts.map +1 -0
  638. package/dist/worker/concerns/auth-concern.js +131 -0
  639. package/dist/worker/concerns/auth-concern.js.map +1 -0
  640. package/dist/worker/concerns/cdc-concern.d.ts +99 -0
  641. package/dist/worker/concerns/cdc-concern.d.ts.map +1 -0
  642. package/dist/worker/concerns/cdc-concern.js +137 -0
  643. package/dist/worker/concerns/cdc-concern.js.map +1 -0
  644. package/dist/worker/concerns/index.d.ts +22 -0
  645. package/dist/worker/concerns/index.d.ts.map +1 -0
  646. package/dist/worker/concerns/index.js +13 -0
  647. package/dist/worker/concerns/index.js.map +1 -0
  648. package/dist/worker/concerns/query-execution-concern.d.ts +104 -0
  649. package/dist/worker/concerns/query-execution-concern.d.ts.map +1 -0
  650. package/dist/worker/concerns/query-execution-concern.js +95 -0
  651. package/dist/worker/concerns/query-execution-concern.js.map +1 -0
  652. package/dist/worker/concerns/storage-orchestration-concern.d.ts +78 -0
  653. package/dist/worker/concerns/storage-orchestration-concern.d.ts.map +1 -0
  654. package/dist/worker/concerns/storage-orchestration-concern.js +240 -0
  655. package/dist/worker/concerns/storage-orchestration-concern.js.map +1 -0
  656. package/dist/worker/do-auth-manager.d.ts +108 -0
  657. package/dist/worker/do-auth-manager.d.ts.map +1 -0
  658. package/dist/worker/do-auth-manager.js +212 -0
  659. package/dist/worker/do-auth-manager.js.map +1 -0
  660. package/dist/worker/do-pglite-manager.d.ts +137 -0
  661. package/dist/worker/do-pglite-manager.d.ts.map +1 -0
  662. package/dist/worker/do-pglite-manager.js +228 -0
  663. package/dist/worker/do-pglite-manager.js.map +1 -0
  664. package/dist/worker/do.d.ts +556 -0
  665. package/dist/worker/do.d.ts.map +1 -0
  666. package/dist/worker/do.js +1441 -0
  667. package/dist/worker/do.js.map +1 -0
  668. package/dist/worker/entry.d.ts +23 -0
  669. package/dist/worker/entry.d.ts.map +1 -0
  670. package/dist/worker/entry.js +362 -0
  671. package/dist/worker/entry.js.map +1 -0
  672. package/dist/worker/errors.d.ts +106 -0
  673. package/dist/worker/errors.d.ts.map +1 -0
  674. package/dist/worker/errors.js +178 -0
  675. package/dist/worker/errors.js.map +1 -0
  676. package/dist/worker/health-check-manager.d.ts +141 -0
  677. package/dist/worker/health-check-manager.d.ts.map +1 -0
  678. package/dist/worker/health-check-manager.js +145 -0
  679. package/dist/worker/health-check-manager.js.map +1 -0
  680. package/dist/worker/index.d.ts +60 -0
  681. package/dist/worker/index.d.ts.map +1 -0
  682. package/dist/worker/index.js +67 -0
  683. package/dist/worker/index.js.map +1 -0
  684. package/dist/worker/memory-pressure.d.ts +892 -0
  685. package/dist/worker/memory-pressure.d.ts.map +1 -0
  686. package/dist/worker/memory-pressure.js +1990 -0
  687. package/dist/worker/memory-pressure.js.map +1 -0
  688. package/dist/worker/migration-manager.d.ts +153 -0
  689. package/dist/worker/migration-manager.d.ts.map +1 -0
  690. package/dist/worker/migration-manager.js +461 -0
  691. package/dist/worker/migration-manager.js.map +1 -0
  692. package/dist/worker/plugin-manager.d.ts +147 -0
  693. package/dist/worker/plugin-manager.d.ts.map +1 -0
  694. package/dist/worker/plugin-manager.js +408 -0
  695. package/dist/worker/plugin-manager.js.map +1 -0
  696. package/dist/worker/proxy.d.ts +330 -0
  697. package/dist/worker/proxy.d.ts.map +1 -0
  698. package/dist/worker/proxy.js +504 -0
  699. package/dist/worker/proxy.js.map +1 -0
  700. package/dist/worker/query-execution-manager.d.ts +107 -0
  701. package/dist/worker/query-execution-manager.d.ts.map +1 -0
  702. package/dist/worker/query-execution-manager.js +155 -0
  703. package/dist/worker/query-execution-manager.js.map +1 -0
  704. package/dist/worker/query-executor.d.ts +163 -0
  705. package/dist/worker/query-executor.d.ts.map +1 -0
  706. package/dist/worker/query-executor.js +413 -0
  707. package/dist/worker/query-executor.js.map +1 -0
  708. package/dist/worker/query-stats-manager.d.ts +117 -0
  709. package/dist/worker/query-stats-manager.d.ts.map +1 -0
  710. package/dist/worker/query-stats-manager.js +162 -0
  711. package/dist/worker/query-stats-manager.js.map +1 -0
  712. package/dist/worker/result-handler.d.ts +192 -0
  713. package/dist/worker/result-handler.d.ts.map +1 -0
  714. package/dist/worker/result-handler.js +346 -0
  715. package/dist/worker/result-handler.js.map +1 -0
  716. package/dist/worker/routes.d.ts +135 -0
  717. package/dist/worker/routes.d.ts.map +1 -0
  718. package/dist/worker/routes.js +460 -0
  719. package/dist/worker/routes.js.map +1 -0
  720. package/dist/worker/rpc-methods-manager.d.ts +142 -0
  721. package/dist/worker/rpc-methods-manager.d.ts.map +1 -0
  722. package/dist/worker/rpc-methods-manager.js +195 -0
  723. package/dist/worker/rpc-methods-manager.js.map +1 -0
  724. package/dist/worker/rpc.d.ts +259 -0
  725. package/dist/worker/rpc.d.ts.map +1 -0
  726. package/dist/worker/rpc.js +398 -0
  727. package/dist/worker/rpc.js.map +1 -0
  728. package/dist/worker/schema-version.d.ts +209 -0
  729. package/dist/worker/schema-version.d.ts.map +1 -0
  730. package/dist/worker/schema-version.js +450 -0
  731. package/dist/worker/schema-version.js.map +1 -0
  732. package/dist/worker/session-manager.d.ts +282 -0
  733. package/dist/worker/session-manager.d.ts.map +1 -0
  734. package/dist/worker/session-manager.js +523 -0
  735. package/dist/worker/session-manager.js.map +1 -0
  736. package/dist/worker/shutdown-manager.d.ts +188 -0
  737. package/dist/worker/shutdown-manager.d.ts.map +1 -0
  738. package/dist/worker/shutdown-manager.js +347 -0
  739. package/dist/worker/shutdown-manager.js.map +1 -0
  740. package/dist/worker/sql-transform.d.ts +61 -0
  741. package/dist/worker/sql-transform.d.ts.map +1 -0
  742. package/dist/worker/sql-transform.js +312 -0
  743. package/dist/worker/sql-transform.js.map +1 -0
  744. package/dist/worker/types.d.ts +738 -0
  745. package/dist/worker/types.d.ts.map +1 -0
  746. package/dist/worker/types.js +6 -0
  747. package/dist/worker/types.js.map +1 -0
  748. package/dist/worker/user-routes.d.ts +76 -0
  749. package/dist/worker/user-routes.d.ts.map +1 -0
  750. package/dist/worker/user-routes.js +188 -0
  751. package/dist/worker/user-routes.js.map +1 -0
  752. package/dist/worker/wal-facade.d.ts +138 -0
  753. package/dist/worker/wal-facade.d.ts.map +1 -0
  754. package/dist/worker/wal-facade.js +184 -0
  755. package/dist/worker/wal-facade.js.map +1 -0
  756. package/dist/worker/wal-r2.d.ts +271 -0
  757. package/dist/worker/wal-r2.d.ts.map +1 -0
  758. package/dist/worker/wal-r2.js +689 -0
  759. package/dist/worker/wal-r2.js.map +1 -0
  760. package/dist/worker/wal-replay.d.ts +361 -0
  761. package/dist/worker/wal-replay.d.ts.map +1 -0
  762. package/dist/worker/wal-replay.js +628 -0
  763. package/dist/worker/wal-replay.js.map +1 -0
  764. package/dist/worker/wal-retention.d.ts +389 -0
  765. package/dist/worker/wal-retention.d.ts.map +1 -0
  766. package/dist/worker/wal-retention.js +763 -0
  767. package/dist/worker/wal-retention.js.map +1 -0
  768. package/dist/worker/wal.d.ts +278 -0
  769. package/dist/worker/wal.d.ts.map +1 -0
  770. package/dist/worker/wal.js +467 -0
  771. package/dist/worker/wal.js.map +1 -0
  772. package/dist/worker/websocket.d.ts +85 -0
  773. package/dist/worker/websocket.d.ts.map +1 -0
  774. package/dist/worker/websocket.js +227 -0
  775. package/dist/worker/websocket.js.map +1 -0
  776. package/package.json +108 -0
  777. package/src/cdc/change-stream.ts +137 -0
  778. package/src/cdc/filter.ts +646 -0
  779. package/src/cdc/index.ts +112 -0
  780. package/src/cdc/resume-token.ts +280 -0
  781. package/src/cdc/transport/index.ts +7 -0
  782. package/src/cdc/transport/sse.ts +723 -0
  783. package/src/cdc/transport/websocket.ts +873 -0
  784. package/src/cdc/types.ts +346 -0
  785. package/src/config/index.ts +25 -0
  786. package/src/config/memory.ts +177 -0
  787. package/src/config/storage.ts +204 -0
  788. package/src/config/streaming.ts +147 -0
  789. package/src/config/timeouts.ts +221 -0
  790. package/src/extensions/config.test.ts +187 -0
  791. package/src/extensions/config.ts +278 -0
  792. package/src/extensions/geo.test.ts +455 -0
  793. package/src/extensions/geo.ts +858 -0
  794. package/src/extensions/index.test.ts +259 -0
  795. package/src/extensions/index.ts +227 -0
  796. package/src/extensions/loader.test.ts +555 -0
  797. package/src/extensions/loader.ts +588 -0
  798. package/src/extensions/pgmq-lite.test.ts +727 -0
  799. package/src/extensions/pgmq-lite.ts +770 -0
  800. package/src/extensions/plugins.test.ts +528 -0
  801. package/src/extensions/plugins.ts +718 -0
  802. package/src/extensions/registry.test.ts +202 -0
  803. package/src/extensions/registry.ts +267 -0
  804. package/src/extensions/vector.test.ts +195 -0
  805. package/src/extensions/vector.ts +217 -0
  806. package/src/iceberg/SCHEDULER.md +580 -0
  807. package/src/iceberg/analytics.test.ts +703 -0
  808. package/src/iceberg/analytics.ts +727 -0
  809. package/src/iceberg/catalog-api.test.ts +838 -0
  810. package/src/iceberg/catalog-api.ts +520 -0
  811. package/src/iceberg/catalog.test.ts +680 -0
  812. package/src/iceberg/catalog.ts +1007 -0
  813. package/src/iceberg/iceberg.test.ts +705 -0
  814. package/src/iceberg/index.ts +406 -0
  815. package/src/iceberg/metadata.test.ts +632 -0
  816. package/src/iceberg/metadata.ts +649 -0
  817. package/src/iceberg/optimizer.test.ts +868 -0
  818. package/src/iceberg/optimizer.ts +1287 -0
  819. package/src/iceberg/parquet.test.ts +899 -0
  820. package/src/iceberg/parquet.ts +1640 -0
  821. package/src/iceberg/r2-organization.test.ts +615 -0
  822. package/src/iceberg/r2-organization.ts +951 -0
  823. package/src/iceberg/scheduler-do-example.ts +364 -0
  824. package/src/iceberg/scheduler.test.ts +861 -0
  825. package/src/iceberg/scheduler.ts +1201 -0
  826. package/src/iceberg/schema.test.ts +547 -0
  827. package/src/iceberg/schema.ts +616 -0
  828. package/src/iceberg/snapshot-manager.test.ts +919 -0
  829. package/src/iceberg/snapshot-manager.ts +1369 -0
  830. package/src/iceberg/sql-router.test.ts +334 -0
  831. package/src/iceberg/sql-router.ts +337 -0
  832. package/src/iceberg/test-fixtures.ts +605 -0
  833. package/src/iceberg/time-travel-api.test.ts +1029 -0
  834. package/src/iceberg/time-travel-api.ts +731 -0
  835. package/src/iceberg/time-travel.test.ts +1218 -0
  836. package/src/iceberg/time-travel.ts +1052 -0
  837. package/src/iceberg/transformer.test.ts +689 -0
  838. package/src/iceberg/transformer.ts +1029 -0
  839. package/src/iceberg/types.ts +373 -0
  840. package/src/iceberg/writer.test.ts +716 -0
  841. package/src/iceberg/writer.ts +590 -0
  842. package/src/index.ts +212 -0
  843. package/src/lineage/index.ts +42 -0
  844. package/src/lineage/integration.ts +334 -0
  845. package/src/lineage/tracker.ts +1618 -0
  846. package/src/lineage/types.ts +354 -0
  847. package/src/middleware/index.ts +36 -0
  848. package/src/middleware/rate-limit-concurrent.test.ts +794 -0
  849. package/src/middleware/rate-limit.test.ts +1568 -0
  850. package/src/middleware/rate-limit.ts +840 -0
  851. package/src/migration-tooling/external-migration.test.ts +1864 -0
  852. package/src/migration-tooling/external-migration.ts +2355 -0
  853. package/src/migration-tooling/index.ts +19 -0
  854. package/src/migrations/ARCHITECTURE.md +474 -0
  855. package/src/migrations/PROGRESS_TRACKING.md +485 -0
  856. package/src/migrations/auto-migrator.test.ts +732 -0
  857. package/src/migrations/auto-migrator.ts +531 -0
  858. package/src/migrations/bulk-orchestrator.test.ts +801 -0
  859. package/src/migrations/bulk-orchestrator.ts +1039 -0
  860. package/src/migrations/compatibility.test.ts +958 -0
  861. package/src/migrations/compatibility.ts +902 -0
  862. package/src/migrations/do-migrations.test.ts +2620 -0
  863. package/src/migrations/do-migrations.ts +1289 -0
  864. package/src/migrations/do-migrations.types.ts +715 -0
  865. package/src/migrations/drizzle-compat.test.ts +210 -0
  866. package/src/migrations/drizzle-compat.ts +337 -0
  867. package/src/migrations/index.ts +334 -0
  868. package/src/migrations/migration-api.test.ts +438 -0
  869. package/src/migrations/migration-api.ts +704 -0
  870. package/src/migrations/progress-tracker-do.ts +518 -0
  871. package/src/migrations/progress-tracker-kv.ts +305 -0
  872. package/src/migrations/progress-tracker.test.ts +937 -0
  873. package/src/migrations/progress-tracker.ts +665 -0
  874. package/src/migrations/registry.test.ts +331 -0
  875. package/src/migrations/registry.ts +468 -0
  876. package/src/migrations/rollback.test.ts +644 -0
  877. package/src/migrations/runner.test.ts +807 -0
  878. package/src/migrations/runner.test.ts.backup +759 -0
  879. package/src/migrations/runner.ts +1459 -0
  880. package/src/migrations/schema-generator.test.ts +649 -0
  881. package/src/migrations/schema-generator.ts +513 -0
  882. package/src/migrations/testing.ts +1037 -0
  883. package/src/migrations/types.ts +573 -0
  884. package/src/migrations/validator.test.ts +660 -0
  885. package/src/migrations/validator.ts +741 -0
  886. package/src/observability/alerting.test.ts +1133 -0
  887. package/src/observability/alerting.ts +455 -0
  888. package/src/observability/analytics-engine.ts +733 -0
  889. package/src/observability/cost-metrics.ts +804 -0
  890. package/src/observability/cross-do-tracing.test.ts +516 -0
  891. package/src/observability/cross-do-tracing.ts +588 -0
  892. package/src/observability/dashboards/postgres-do-overview.json +1656 -0
  893. package/src/observability/error-rate-collector.test.ts +977 -0
  894. package/src/observability/error-rate-collector.ts +518 -0
  895. package/src/observability/exporters.test.ts +365 -0
  896. package/src/observability/exporters.ts +650 -0
  897. package/src/observability/health-check.test.ts +353 -0
  898. package/src/observability/health-check.ts +341 -0
  899. package/src/observability/index.test.ts +298 -0
  900. package/src/observability/index.ts +885 -0
  901. package/src/observability/instrumentation.test.ts +428 -0
  902. package/src/observability/instrumentation.ts +788 -0
  903. package/src/observability/memory-metrics.test.ts +355 -0
  904. package/src/observability/memory-metrics.ts +990 -0
  905. package/src/observability/metrics-endpoint.test.ts +402 -0
  906. package/src/observability/metrics-endpoint.ts +374 -0
  907. package/src/observability/metrics.test.ts +291 -0
  908. package/src/observability/metrics.ts +315 -0
  909. package/src/observability/observability-features.ts +1296 -0
  910. package/src/observability/prometheus.test.ts +292 -0
  911. package/src/observability/prometheus.ts +170 -0
  912. package/src/observability/propagation.test.ts +417 -0
  913. package/src/observability/propagation.ts +294 -0
  914. package/src/observability/query-latency.ts +586 -0
  915. package/src/observability/query-performance.test.ts +406 -0
  916. package/src/observability/query-performance.ts +491 -0
  917. package/src/observability/storage-tier-metrics.test.ts +633 -0
  918. package/src/observability/storage-tier-metrics.ts +570 -0
  919. package/src/observability/tier-cost-optimizer.ts +740 -0
  920. package/src/observability/tracer.test.ts +346 -0
  921. package/src/observability/tracer.ts +585 -0
  922. package/src/observability/types.test.ts +726 -0
  923. package/src/observability/types.ts +434 -0
  924. package/src/pglite/auto-demotion.test.ts +477 -0
  925. package/src/pglite/auto-demotion.ts +385 -0
  926. package/src/pglite/auto-promotion.test.ts +824 -0
  927. package/src/pglite/auto-promotion.ts +547 -0
  928. package/src/pglite/cache-layer.test.ts +469 -0
  929. package/src/pglite/cache-layer.ts +271 -0
  930. package/src/pglite/cold-start-manager.ts +1260 -0
  931. package/src/pglite/cold-start-optimizer.test.ts +937 -0
  932. package/src/pglite/cold-start-optimizer.ts +1895 -0
  933. package/src/pglite/dovfs-adapter.ts +1122 -0
  934. package/src/pglite/dovfs.ts +1258 -0
  935. package/src/pglite/etag-cache.test.ts +844 -0
  936. package/src/pglite/etag-cache.ts +526 -0
  937. package/src/pglite/index.ts +442 -0
  938. package/src/pglite/init.test.ts +455 -0
  939. package/src/pglite/init.ts +574 -0
  940. package/src/pglite/lifecycle.test.ts +599 -0
  941. package/src/pglite/lifecycle.ts +704 -0
  942. package/src/pglite/parallel-loader.test.ts +586 -0
  943. package/src/pglite/parallel-loader.ts +481 -0
  944. package/src/pglite/production-pglite.test.ts +666 -0
  945. package/src/pglite/production-pglite.ts +537 -0
  946. package/src/pglite/query-executor.ts +614 -0
  947. package/src/pglite/r2-layer.test.ts +501 -0
  948. package/src/pglite/r2-layer.ts +322 -0
  949. package/src/pglite/tiered-init.test.ts +725 -0
  950. package/src/pglite/tiered-init.ts +556 -0
  951. package/src/pglite/tiered-vfs.test.ts +726 -0
  952. package/src/pglite/tiered-vfs.ts +33 -0
  953. package/src/pglite/tiering-stats.test.ts +531 -0
  954. package/src/pglite/tiering-stats.ts +407 -0
  955. package/src/pglite/transaction-hooks.ts +343 -0
  956. package/src/pglite/warm-loader.test.ts +1701 -0
  957. package/src/pglite/warm-loader.ts +528 -0
  958. package/src/pglite/workers-pglite.ts +224 -0
  959. package/src/pglite-assets/pglite.data +0 -0
  960. package/src/pglite-assets/pglite.wasm +0 -0
  961. package/src/pglite.d.ts +47 -0
  962. package/src/playground/index.ts +137 -0
  963. package/src/playground/keyboard-shortcuts.ts +677 -0
  964. package/src/playground/playground.ts +323 -0
  965. package/src/playground/query-executor.ts +669 -0
  966. package/src/playground/query-history.ts +328 -0
  967. package/src/playground/result-formatter.ts +420 -0
  968. package/src/playground/sample-datasets.ts +674 -0
  969. package/src/playground/sample-queries.ts +1168 -0
  970. package/src/playground/schema-explorer.ts +558 -0
  971. package/src/playground/types.ts +518 -0
  972. package/src/readonly/cache-reader.test.ts +460 -0
  973. package/src/readonly/cache-reader.ts +313 -0
  974. package/src/readonly/config.test.ts +187 -0
  975. package/src/readonly/config.ts +128 -0
  976. package/src/readonly/index.ts +50 -0
  977. package/src/readonly/pglite-wrapper.test.ts +278 -0
  978. package/src/readonly/pglite-wrapper.ts +184 -0
  979. package/src/readonly/worker.test.ts +533 -0
  980. package/src/readonly/worker.ts +341 -0
  981. package/src/readonly/write-blocker.test.ts +459 -0
  982. package/src/readonly/write-blocker.ts +175 -0
  983. package/src/recovery/disaster-recovery.test.ts +618 -0
  984. package/src/recovery/disaster-recovery.ts +1181 -0
  985. package/src/recovery/index.ts +43 -0
  986. package/src/recovery/parquet-parser.ts +974 -0
  987. package/src/retention/index.ts +74 -0
  988. package/src/retention/policy.test.ts +571 -0
  989. package/src/retention/policy.ts +774 -0
  990. package/src/retention/purger.test.ts +465 -0
  991. package/src/retention/purger.ts +558 -0
  992. package/src/rls/auth-integration.test.ts +752 -0
  993. package/src/rls/auth-integration.ts +533 -0
  994. package/src/rls/generator.test.ts +829 -0
  995. package/src/rls/generator.ts +573 -0
  996. package/src/rls/index.ts +128 -0
  997. package/src/rls/policy.ts +208 -0
  998. package/src/rls/rls.test.ts +1071 -0
  999. package/src/rls/validator.test.ts +930 -0
  1000. package/src/rls/validator.ts +895 -0
  1001. package/src/routing/adaptive-router.test.ts +884 -0
  1002. package/src/routing/adaptive-router.ts +845 -0
  1003. package/src/routing/circuit-breaker.test.ts +1505 -0
  1004. package/src/routing/circuit-breaker.ts +852 -0
  1005. package/src/routing/cost-metrics.test.ts +565 -0
  1006. package/src/routing/cost-metrics.ts +408 -0
  1007. package/src/routing/do-connection-pool.test.ts +1109 -0
  1008. package/src/routing/do-connection-pool.ts +828 -0
  1009. package/src/routing/index.ts +158 -0
  1010. package/src/routing/query-complexity-estimator.test.ts +356 -0
  1011. package/src/routing/query-complexity-estimator.ts +444 -0
  1012. package/src/routing/request-coalescing.test.ts +738 -0
  1013. package/src/routing/request-coalescing.ts +475 -0
  1014. package/src/routing/runtime-router.test.ts +436 -0
  1015. package/src/routing/runtime-router.ts +357 -0
  1016. package/src/routing/tenant-router.test.ts +2493 -0
  1017. package/src/routing/tenant-router.ts +1908 -0
  1018. package/src/routing/websocket-pool.test.ts +551 -0
  1019. package/src/routing/websocket-pool.ts +577 -0
  1020. package/src/storage/access-pattern-tracker.test.ts +874 -0
  1021. package/src/storage/cache-layer.test.ts +560 -0
  1022. package/src/storage/cache-layer.ts +328 -0
  1023. package/src/storage/cost-aware-tiering.test.ts +652 -0
  1024. package/src/storage/cost-aware-tiering.ts +794 -0
  1025. package/src/storage/do-sqlite-blobs.test.ts +937 -0
  1026. package/src/storage/index.ts +272 -0
  1027. package/src/storage/interfaces.ts +974 -0
  1028. package/src/storage/r2-layer.test.ts +653 -0
  1029. package/src/storage/r2-layer.ts +434 -0
  1030. package/src/storage/r2-overflow.ts +920 -0
  1031. package/src/storage/r2-page-vfs.test.ts +2348 -0
  1032. package/src/storage/r2-page-vfs.ts +1054 -0
  1033. package/src/storage/swr-cache.test.ts +832 -0
  1034. package/src/storage/swr-cache.ts +398 -0
  1035. package/src/storage/swr-tiered-integration.test.ts +617 -0
  1036. package/src/storage/tiered-orchestrator.test.ts +2441 -0
  1037. package/src/storage/tiered-orchestrator.ts +2081 -0
  1038. package/src/storage/tiered-vfs-swr.test.ts +736 -0
  1039. package/src/storage/tiered-vfs-swr.ts +735 -0
  1040. package/src/storage/tiered-vfs.test.ts +793 -0
  1041. package/src/storage/tiered-vfs.ts +1082 -0
  1042. package/src/streaming/backpressure-controller.ts +452 -0
  1043. package/src/streaming/buffer-pool.ts +484 -0
  1044. package/src/streaming/cdc-iceberg-connector.ts +605 -0
  1045. package/src/streaming/index.ts +225 -0
  1046. package/src/streaming/live-cdc-stream.ts +985 -0
  1047. package/src/streaming/memory-bounded-stream.ts +443 -0
  1048. package/src/streaming/query-streamer.ts +662 -0
  1049. package/src/streaming/response-streaming.ts +557 -0
  1050. package/src/types/branded.ts +1075 -0
  1051. package/src/types/branded.ts.backup +273 -0
  1052. package/src/types/utilities.ts +1023 -0
  1053. package/src/types/wasm.d.ts +30 -0
  1054. package/src/validation/typed-errors.test.ts +420 -0
  1055. package/src/wal/replay-engine.ts +1264 -0
  1056. package/src/worker/__mocks__/capnweb.ts +15 -0
  1057. package/src/worker/__mocks__/pglite.data.ts +22 -0
  1058. package/src/worker/__mocks__/pglite.wasm.ts +33 -0
  1059. package/src/worker/auth-rate-limiter.test.ts +272 -0
  1060. package/src/worker/auth-rate-limiter.ts +448 -0
  1061. package/src/worker/auth.security-red.test.ts +1236 -0
  1062. package/src/worker/auth.security.test.ts +822 -0
  1063. package/src/worker/auth.test.ts +469 -0
  1064. package/src/worker/auth.ts +1104 -0
  1065. package/src/worker/cdc-backpressure.test.ts +726 -0
  1066. package/src/worker/cdc-backpressure.ts +866 -0
  1067. package/src/worker/cdc-sse.test.ts +780 -0
  1068. package/src/worker/cdc-sse.ts +728 -0
  1069. package/src/worker/cdc-websocket.ts +1229 -0
  1070. package/src/worker/cdc-ws.test.ts +1009 -0
  1071. package/src/worker/cdc.test.ts +327 -0
  1072. package/src/worker/cdc.ts +289 -0
  1073. package/src/worker/concerns/auth-concern.ts +179 -0
  1074. package/src/worker/concerns/cdc-concern.ts +247 -0
  1075. package/src/worker/concerns/index.ts +58 -0
  1076. package/src/worker/concerns/query-execution-concern.ts +194 -0
  1077. package/src/worker/concerns/storage-orchestration-concern.ts +373 -0
  1078. package/src/worker/discriminated-types.test.ts +280 -0
  1079. package/src/worker/do-auth-manager.ts +257 -0
  1080. package/src/worker/do-decomposition.test.ts +1236 -0
  1081. package/src/worker/do-pglite-manager.ts +302 -0
  1082. package/src/worker/do.test.ts +2254 -0
  1083. package/src/worker/do.ts +1878 -0
  1084. package/src/worker/entry.ts +417 -0
  1085. package/src/worker/errors.ts +285 -0
  1086. package/src/worker/health-check-manager.test.ts +261 -0
  1087. package/src/worker/health-check-manager.ts +231 -0
  1088. package/src/worker/index.ts +389 -0
  1089. package/src/worker/memory-pressure.test.ts +1460 -0
  1090. package/src/worker/memory-pressure.ts +2650 -0
  1091. package/src/worker/migration-manager.ts +582 -0
  1092. package/src/worker/neon-compat.test.ts +332 -0
  1093. package/src/worker/plugin-manager.ts +485 -0
  1094. package/src/worker/postgres.do-rpc.d.ts +76 -0
  1095. package/src/worker/proxy.ts +694 -0
  1096. package/src/worker/query-execution-manager.test.ts +303 -0
  1097. package/src/worker/query-execution-manager.ts +219 -0
  1098. package/src/worker/query-executor.test.ts +282 -0
  1099. package/src/worker/query-executor.ts +560 -0
  1100. package/src/worker/query-stats-manager.ts +229 -0
  1101. package/src/worker/result-handler.test.ts +364 -0
  1102. package/src/worker/result-handler.ts +510 -0
  1103. package/src/worker/routes.test.ts +795 -0
  1104. package/src/worker/routes.ts +650 -0
  1105. package/src/worker/rpc-methods-manager.test.ts +326 -0
  1106. package/src/worker/rpc-methods-manager.ts +276 -0
  1107. package/src/worker/rpc.ts +524 -0
  1108. package/src/worker/schema-version.ts +605 -0
  1109. package/src/worker/session-manager.test.ts +506 -0
  1110. package/src/worker/session-manager.ts +732 -0
  1111. package/src/worker/shutdown-manager.ts +469 -0
  1112. package/src/worker/sql-transform.test.ts +286 -0
  1113. package/src/worker/sql-transform.ts +368 -0
  1114. package/src/worker/supabase-compat.test.ts +621 -0
  1115. package/src/worker/types.test.ts +292 -0
  1116. package/src/worker/types.ts +873 -0
  1117. package/src/worker/user-routes.test.ts +703 -0
  1118. package/src/worker/user-routes.ts +303 -0
  1119. package/src/worker/wal-facade.ts +235 -0
  1120. package/src/worker/wal-r2.test.ts +570 -0
  1121. package/src/worker/wal-r2.ts +930 -0
  1122. package/src/worker/wal-replay.test.ts +845 -0
  1123. package/src/worker/wal-replay.ts +897 -0
  1124. package/src/worker/wal-retention.test.ts +758 -0
  1125. package/src/worker/wal-retention.ts +1075 -0
  1126. package/src/worker/wal.test.ts +618 -0
  1127. package/src/worker/wal.ts +697 -0
  1128. package/src/worker/websocket.test.ts +296 -0
  1129. package/src/worker/websocket.ts +284 -0
@@ -0,0 +1,2254 @@
1
+ /**
2
+ * RED PHASE: PostgresDO Core Tests
3
+ * Task: postgres-6u6.3 - PostgresDO Core (constructor, initPGlite, executeQuery, fetch handler)
4
+ *
5
+ * These tests verify the Durable Object core functionality.
6
+ */
7
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
8
+ import {
9
+ createMockPGlite,
10
+ createMockDurableObjectState,
11
+ } from '../__tests__/utils'
12
+
13
+ // Mock cloudflare:workers before importing modules that depend on it
14
+ vi.mock('cloudflare:workers', () => ({
15
+ DurableObject: class DurableObject {
16
+ ctx: unknown
17
+ env: unknown
18
+ constructor(ctx: unknown, env: unknown) {
19
+ this.ctx = ctx
20
+ this.env = env
21
+ }
22
+ },
23
+ }))
24
+
25
+ // Mock WASM and data imports that Vite can't handle in test environment
26
+ vi.mock('../pglite-assets/pglite.wasm', () => ({ default: {} }))
27
+ vi.mock('../pglite-assets/pglite.data', () => ({ default: {} }))
28
+
29
+ // Mock the workers-pglite module to avoid WASM dependencies
30
+ vi.mock('../pglite/workers-pglite', () => ({
31
+ createWorkersPGLite: vi.fn(),
32
+ WorkersPGLite: class {},
33
+ }))
34
+
35
+ import { PostgresDO, createPostgresDO } from './do'
36
+ import type { Env, QueryRequest, QueryResponse, PostgresConfig } from './types'
37
+
38
+ // Local wrapper to match existing test expectations (uses shared utility)
39
+ const createMockState = () => createMockDurableObjectState({
40
+ id: 'test-do-id',
41
+ name: 'test-database',
42
+ })
43
+
44
+ // Mock Env
45
+ const createMockEnv = (): Env => ({
46
+ POSTGRES_DO: {} as DurableObjectNamespace,
47
+ POSTGRES_DEFAULT_DB: 'postgres',
48
+ })
49
+
50
+ // MOCK REDUCTION HELPERS (postgres-6qei)
51
+ // These helpers use dependency injection via getPGLiteManager().injectInstance()
52
+ // instead of spying on internal createPGliteInstance method.
53
+
54
+ function createTestDO(options?: {
55
+ config?: PostgresConfig
56
+ mockPGliteSetup?: (mock: ReturnType<typeof createMockPGlite>) => void
57
+ }) {
58
+ const state = createMockState()
59
+ const env = createMockEnv()
60
+ const doo = new PostgresDO(state as any, env, options?.config)
61
+ const mockPGlite = createMockPGlite()
62
+ if (options?.mockPGliteSetup) {
63
+ options.mockPGliteSetup(mockPGlite)
64
+ }
65
+ doo.getPGLiteManager().injectInstance(mockPGlite)
66
+ return { doo, mockPGlite, state, env }
67
+ }
68
+
69
+ function createTestDOWithFactory(options?: {
70
+ config?: PostgresConfig
71
+ mockPGliteSetup?: (mock: ReturnType<typeof createMockPGlite>) => void
72
+ }) {
73
+ const state = createMockState()
74
+ const env = createMockEnv()
75
+ const doo = new PostgresDO(state as any, env, options?.config)
76
+ const mockPGlite = createMockPGlite()
77
+ if (options?.mockPGliteSetup) {
78
+ options.mockPGliteSetup(mockPGlite)
79
+ }
80
+ doo.getPGLiteManager().setCreatePGLite(() => Promise.resolve(mockPGlite))
81
+ return { doo, mockPGlite, state, env }
82
+ }
83
+
84
+ describe('PostgresDO Core', () => {
85
+ describe('constructor', () => {
86
+ it('should create a PostgresDO instance', () => {
87
+ const state = createMockState()
88
+ const env = createMockEnv()
89
+ const doo = new PostgresDO(state as any, env)
90
+ expect(doo).toBeInstanceOf(PostgresDO)
91
+ })
92
+
93
+ it('should store state reference', () => {
94
+ const state = createMockState()
95
+ const env = createMockEnv()
96
+ const doo = new PostgresDO(state as any, env)
97
+ expect(doo.getState()).toBe(state)
98
+ })
99
+
100
+ it('should store env reference', () => {
101
+ const state = createMockState()
102
+ const env = createMockEnv()
103
+ const doo = new PostgresDO(state as any, env)
104
+ expect(doo.getEnv()).toBe(env)
105
+ })
106
+ })
107
+
108
+ describe('initPGlite', () => {
109
+ it('should initialize PGlite on first call', async () => {
110
+ const state = createMockState()
111
+ const env = createMockEnv()
112
+ const doo = new PostgresDO(state as any, env)
113
+
114
+ // Mock the PGlite initialization
115
+ const mockPGlite = createMockPGlite()
116
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
117
+
118
+ await doo.initPGlite()
119
+ expect(doo.isInitialized()).toBe(true)
120
+ })
121
+
122
+ it('should not reinitialize if already initialized', async () => {
123
+ const state = createMockState()
124
+ const env = createMockEnv()
125
+ const doo = new PostgresDO(state as any, env)
126
+
127
+ const mockPGlite = createMockPGlite()
128
+ const createSpy = vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
129
+
130
+ await doo.initPGlite()
131
+ await doo.initPGlite()
132
+
133
+ expect(createSpy).toHaveBeenCalledTimes(1)
134
+ })
135
+
136
+ it('should use blockConcurrencyWhile for initialization', async () => {
137
+ const state = createMockState()
138
+ const env = createMockEnv()
139
+ const doo = new PostgresDO(state as any, env)
140
+
141
+ const mockPGlite = createMockPGlite()
142
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
143
+
144
+ await doo.initPGlite()
145
+ expect(state.blockConcurrencyWhile).toHaveBeenCalled()
146
+ })
147
+ })
148
+
149
+ describe('executeQuery', () => {
150
+ it('should execute a simple SELECT query', async () => {
151
+ const state = createMockState()
152
+ const env = createMockEnv()
153
+ const doo = new PostgresDO(state as any, env)
154
+
155
+ const mockPGlite = createMockPGlite()
156
+ mockPGlite.query.mockResolvedValue({
157
+ rows: [{ id: 1, name: 'Alice' }],
158
+ fields: [
159
+ { name: 'id', dataTypeID: 23 },
160
+ { name: 'name', dataTypeID: 25 },
161
+ ],
162
+ affectedRows: 1,
163
+ })
164
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
165
+
166
+ const request: QueryRequest = { sql: 'SELECT * FROM users' }
167
+ const result = await doo.executeQuery(request)
168
+
169
+ expect(result.rows).toEqual([{ id: 1, name: 'Alice' }])
170
+ expect(result.fields).toHaveLength(2)
171
+ expect(result.rowCount).toBe(1)
172
+ })
173
+
174
+ it('should pass parameters to PGlite', async () => {
175
+ const state = createMockState()
176
+ const env = createMockEnv()
177
+ const doo = new PostgresDO(state as any, env)
178
+
179
+ const mockPGlite = createMockPGlite()
180
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
181
+
182
+ const request: QueryRequest = {
183
+ sql: 'SELECT * FROM users WHERE id = $1',
184
+ params: [42],
185
+ }
186
+ await doo.executeQuery(request)
187
+
188
+ expect(mockPGlite.query).toHaveBeenCalledWith(
189
+ 'SELECT * FROM users WHERE id = $1',
190
+ [42]
191
+ )
192
+ })
193
+
194
+ it('should apply SQL transform when preserveCase is true', async () => {
195
+ const state = createMockState()
196
+ const env = createMockEnv()
197
+ const doo = new PostgresDO(state as any, env)
198
+
199
+ const mockPGlite = createMockPGlite()
200
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
201
+
202
+ const request: QueryRequest = {
203
+ sql: 'SELECT userId FROM users',
204
+ preserveCase: true,
205
+ }
206
+ await doo.executeQuery(request)
207
+
208
+ // The SQL should be transformed to quote identifiers
209
+ const calledSql = mockPGlite.query.mock.calls[0]?.[0] as string
210
+ expect(calledSql).toContain('"userId"')
211
+ expect(calledSql).toContain('"users"')
212
+ })
213
+
214
+ it('should track query duration', async () => {
215
+ const state = createMockState()
216
+ const env = createMockEnv()
217
+ const doo = new PostgresDO(state as any, env)
218
+
219
+ const mockPGlite = createMockPGlite()
220
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
221
+
222
+ const request: QueryRequest = { sql: 'SELECT 1' }
223
+ const result = await doo.executeQuery(request)
224
+
225
+ expect(result.durationMs).toBeDefined()
226
+ expect(typeof result.durationMs).toBe('number')
227
+ })
228
+
229
+ it('should throw error for invalid SQL', async () => {
230
+ const state = createMockState()
231
+ const env = createMockEnv()
232
+ const doo = new PostgresDO(state as any, env)
233
+
234
+ const mockPGlite = createMockPGlite()
235
+ mockPGlite.query.mockRejectedValue(new Error('syntax error at position 1'))
236
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
237
+
238
+ const request: QueryRequest = { sql: 'SELEC * FROM users' }
239
+
240
+ await expect(doo.executeQuery(request)).rejects.toThrow('syntax error')
241
+ })
242
+
243
+ it('should auto-initialize PGlite if not initialized', async () => {
244
+ const state = createMockState()
245
+ const env = createMockEnv()
246
+ const doo = new PostgresDO(state as any, env)
247
+
248
+ const mockPGlite = createMockPGlite()
249
+ const initSpy = vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
250
+
251
+ expect(doo.isInitialized()).toBe(false)
252
+
253
+ await doo.executeQuery({ sql: 'SELECT 1' })
254
+
255
+ expect(initSpy).toHaveBeenCalled()
256
+ expect(doo.isInitialized()).toBe(true)
257
+ })
258
+ })
259
+
260
+ describe('executeBatch', () => {
261
+ it('should execute multiple queries', async () => {
262
+ const state = createMockState()
263
+ const env = createMockEnv()
264
+ const doo = new PostgresDO(state as any, env)
265
+
266
+ const mockPGlite = createMockPGlite()
267
+ mockPGlite.query
268
+ .mockResolvedValueOnce({ rows: [{ a: 1 }], fields: [], affectedRows: 1 })
269
+ .mockResolvedValueOnce({ rows: [{ b: 2 }], fields: [], affectedRows: 1 })
270
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
271
+
272
+ const results = await doo.executeBatch({
273
+ queries: [
274
+ { sql: 'SELECT 1 AS a' },
275
+ { sql: 'SELECT 2 AS b' },
276
+ ],
277
+ })
278
+
279
+ expect(results.results).toHaveLength(2)
280
+ expect(results.results[0].rows).toEqual([{ a: 1 }])
281
+ expect(results.results[1].rows).toEqual([{ b: 2 }])
282
+ })
283
+
284
+ it('should wrap in transaction when transaction=true', async () => {
285
+ const state = createMockState()
286
+ const env = createMockEnv()
287
+ const doo = new PostgresDO(state as any, env)
288
+
289
+ const mockPGlite = createMockPGlite()
290
+ const queryCalls: string[] = []
291
+ mockPGlite.query.mockImplementation((sql?: string) => {
292
+ queryCalls.push(sql ?? '')
293
+ return Promise.resolve({ rows: [], fields: [], affectedRows: 0 })
294
+ })
295
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
296
+
297
+ await doo.executeBatch({
298
+ queries: [{ sql: 'SELECT 1' }],
299
+ transaction: true,
300
+ })
301
+
302
+ expect(queryCalls[0]).toBe('BEGIN')
303
+ expect(queryCalls[queryCalls.length - 1]).toBe('COMMIT')
304
+ })
305
+
306
+ it('should rollback on error when transaction=true', async () => {
307
+ const state = createMockState()
308
+ const env = createMockEnv()
309
+ const doo = new PostgresDO(state as any, env)
310
+
311
+ const mockPGlite = createMockPGlite()
312
+ const queryCalls: string[] = []
313
+ mockPGlite.query.mockImplementation((sql?: string) => {
314
+ queryCalls.push(sql ?? '')
315
+ if (sql === 'SELECT 1') {
316
+ return Promise.reject(new Error('test error'))
317
+ }
318
+ return Promise.resolve({ rows: [], fields: [], affectedRows: 0 })
319
+ })
320
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
321
+
322
+ await expect(doo.executeBatch({
323
+ queries: [{ sql: 'SELECT 1' }],
324
+ transaction: true,
325
+ })).rejects.toThrow('test error')
326
+
327
+ expect(queryCalls).toContain('ROLLBACK')
328
+ })
329
+ })
330
+
331
+ describe('getConfig', () => {
332
+ it('should return current configuration', async () => {
333
+ const state = createMockState()
334
+ const env = createMockEnv()
335
+ const doo = new PostgresDO(state as any, env)
336
+
337
+ const config = doo.getConfig()
338
+ expect(config).toBeDefined()
339
+ expect(config.database).toBeDefined()
340
+ })
341
+ })
342
+
343
+ describe('getStats', () => {
344
+ it('should return query statistics', async () => {
345
+ const state = createMockState()
346
+ const env = createMockEnv()
347
+ const doo = new PostgresDO(state as any, env)
348
+
349
+ const mockPGlite = createMockPGlite()
350
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
351
+
352
+ await doo.executeQuery({ sql: 'SELECT 1' })
353
+ await doo.executeQuery({ sql: 'SELECT 2' })
354
+
355
+ const stats = doo.getStats()
356
+ expect(stats.queryCount).toBe(2)
357
+ expect(stats.totalDurationMs).toBeGreaterThanOrEqual(0)
358
+ })
359
+ })
360
+
361
+ describe('createPostgresDO factory', () => {
362
+ it('should create a PostgresDO class with custom config', () => {
363
+ const PostgresDOClass = createPostgresDO({
364
+ database: 'mydb',
365
+ extensions: ['vector'],
366
+ preserveCase: true,
367
+ })
368
+
369
+ const state = createMockState()
370
+ const env = createMockEnv()
371
+ const doo = new PostgresDOClass(state as any, env)
372
+
373
+ expect(doo).toBeInstanceOf(PostgresDO)
374
+ expect(doo.getConfig().database).toBe('mydb')
375
+ expect(doo.getConfig().extensions).toContain('vector')
376
+ expect(doo.getConfig().preserveCase).toBe(true)
377
+ })
378
+ })
379
+
380
+ describe('Graceful Shutdown and Connection Draining', () => {
381
+ describe('shutdown status', () => {
382
+ it('should start with running status', () => {
383
+ const state = createMockState()
384
+ const env = createMockEnv()
385
+ const doo = new PostgresDO(state as any, env)
386
+
387
+ expect(doo.getShutdownStatus()).toBe('running')
388
+ expect(doo.isShuttingDown()).toBe(false)
389
+ })
390
+
391
+ it('should track active query count', async () => {
392
+ const state = createMockState()
393
+ const env = createMockEnv()
394
+ const doo = new PostgresDO(state as any, env)
395
+
396
+ // Create a slow mock PGlite that delays query execution
397
+ const mockPGlite = createMockPGlite()
398
+ let resolveQuery: () => void
399
+ const queryPromise = new Promise<void>((resolve) => {
400
+ resolveQuery = resolve
401
+ })
402
+ mockPGlite.query.mockImplementation(async () => {
403
+ await queryPromise
404
+ return { rows: [], fields: [], affectedRows: 0 }
405
+ })
406
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
407
+
408
+ // Start a query but don't await it
409
+ const queryExecution = doo.executeQuery({ sql: 'SELECT pg_sleep(1)' })
410
+
411
+ // Give time for query to start
412
+ await new Promise((r) => setTimeout(r, 10))
413
+
414
+ expect(doo.getActiveQueryCount()).toBe(1)
415
+
416
+ // Resolve the query and wait for it
417
+ resolveQuery!()
418
+ await queryExecution
419
+
420
+ expect(doo.getActiveQueryCount()).toBe(0)
421
+ })
422
+
423
+ it('should return active query info', async () => {
424
+ const state = createMockState()
425
+ const env = createMockEnv()
426
+ const doo = new PostgresDO(state as any, env)
427
+
428
+ const mockPGlite = createMockPGlite()
429
+ let resolveQuery: () => void
430
+ const queryPromise = new Promise<void>((resolve) => {
431
+ resolveQuery = resolve
432
+ })
433
+ mockPGlite.query.mockImplementation(async () => {
434
+ await queryPromise
435
+ return { rows: [], fields: [], affectedRows: 0 }
436
+ })
437
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
438
+
439
+ const queryExecution = doo.executeQuery({ sql: 'SELECT * FROM users WHERE id = 1' })
440
+ await new Promise((r) => setTimeout(r, 10))
441
+
442
+ const activeQueries = doo.getActiveQueries()
443
+ expect(activeQueries.length).toBe(1)
444
+ expect(activeQueries[0].sql).toContain('SELECT * FROM users')
445
+ expect(activeQueries[0].durationMs).toBeGreaterThanOrEqual(0)
446
+
447
+ resolveQuery!()
448
+ await queryExecution
449
+ })
450
+ })
451
+
452
+ describe('shutdown configuration', () => {
453
+ it('should have default shutdown config', () => {
454
+ const state = createMockState()
455
+ const env = createMockEnv()
456
+ const doo = new PostgresDO(state as any, env)
457
+
458
+ const config = doo.getShutdownConfig()
459
+ expect(config.gracePeriodMs).toBe(30000)
460
+ expect(config.drainCheckIntervalMs).toBe(100)
461
+ expect(config.closeTimeoutMs).toBe(5000)
462
+ })
463
+
464
+ it('should allow setting shutdown config', () => {
465
+ const state = createMockState()
466
+ const env = createMockEnv()
467
+ const doo = new PostgresDO(state as any, env)
468
+
469
+ doo.setShutdownConfig({
470
+ gracePeriodMs: 60000,
471
+ drainCheckIntervalMs: 50,
472
+ })
473
+
474
+ const config = doo.getShutdownConfig()
475
+ expect(config.gracePeriodMs).toBe(60000)
476
+ expect(config.drainCheckIntervalMs).toBe(50)
477
+ expect(config.closeTimeoutMs).toBe(5000) // unchanged
478
+ })
479
+ })
480
+
481
+ describe('shutdown event listeners', () => {
482
+ it('should register and unregister event listeners', () => {
483
+ const state = createMockState()
484
+ const env = createMockEnv()
485
+ const doo = new PostgresDO(state as any, env)
486
+
487
+ const listener = vi.fn()
488
+ const unsubscribe = doo.onShutdownEvent(listener)
489
+
490
+ expect(typeof unsubscribe).toBe('function')
491
+
492
+ // Unsubscribe and verify no errors
493
+ unsubscribe()
494
+ })
495
+
496
+ it('should prevent memory leak by limiting listener count', () => {
497
+ const state = createMockState()
498
+ const env = createMockEnv()
499
+ const doo = new PostgresDO(state as any, env)
500
+
501
+ // Simulate adding many listeners without cleanup (memory leak scenario)
502
+ const listenerCount = 150 // More than the default limit of 100
503
+ const cleanupFns: (() => void)[] = []
504
+
505
+ for (let i = 0; i < listenerCount; i++) {
506
+ const cleanup = doo.onShutdownEvent(() => {})
507
+ cleanupFns.push(cleanup)
508
+ }
509
+
510
+ // The listener count should be capped at maxListeners (default: 100)
511
+ const actualListenerCount = doo.getShutdownListenerCount()
512
+ expect(actualListenerCount).toBeLessThanOrEqual(100)
513
+ })
514
+
515
+ it('should warn when approaching listener limit', () => {
516
+ const state = createMockState()
517
+ const env = createMockEnv()
518
+ const doo = new PostgresDO(state as any, env)
519
+
520
+ const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
521
+
522
+ // Add listeners to reach 80% of the limit (80 out of 100)
523
+ for (let i = 0; i < 85; i++) {
524
+ doo.onShutdownEvent(() => {})
525
+ }
526
+
527
+ // Should have warned about approaching limit
528
+ expect(consoleSpy).toHaveBeenCalledWith(
529
+ expect.stringContaining('Approaching shutdown event listener limit')
530
+ )
531
+
532
+ consoleSpy.mockRestore()
533
+ })
534
+
535
+ it('should support configurable maxListeners', () => {
536
+ const state = createMockState()
537
+ const env = createMockEnv()
538
+ const doo = new PostgresDO(state as any, env)
539
+
540
+ // Configure custom max listeners
541
+ doo.setShutdownConfig({ maxListeners: 50 })
542
+
543
+ // Add more listeners than the custom limit
544
+ for (let i = 0; i < 60; i++) {
545
+ doo.onShutdownEvent(() => {})
546
+ }
547
+
548
+ // Should be capped at custom limit
549
+ const actualListenerCount = doo.getShutdownListenerCount()
550
+ expect(actualListenerCount).toBeLessThanOrEqual(50)
551
+ })
552
+
553
+ it('should emit shutdown events', async () => {
554
+ const state = createMockState()
555
+ const env = createMockEnv()
556
+ const doo = new PostgresDO(state as any, env)
557
+
558
+ const mockPGlite = createMockPGlite()
559
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
560
+ await doo.initPGlite()
561
+
562
+ const events: { type: string; details?: Record<string, unknown> }[] = []
563
+ doo.onShutdownEvent((event) => {
564
+ events.push({ type: event.type, details: event.details })
565
+ })
566
+
567
+ await doo.shutdown({ gracePeriodMs: 100 })
568
+
569
+ expect(events.some((e) => e.type === 'shutdown_initiated')).toBe(true)
570
+ expect(events.some((e) => e.type === 'drain_started')).toBe(true)
571
+ expect(events.some((e) => e.type === 'drain_completed')).toBe(true)
572
+ expect(events.some((e) => e.type === 'shutdown_completed')).toBe(true)
573
+ })
574
+ })
575
+
576
+ describe('graceful shutdown', () => {
577
+ it('should set status to draining then shutdown', async () => {
578
+ const state = createMockState()
579
+ const env = createMockEnv()
580
+ const doo = new PostgresDO(state as any, env)
581
+
582
+ const mockPGlite = createMockPGlite()
583
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
584
+ await doo.initPGlite()
585
+
586
+ const statuses: string[] = []
587
+ doo.onShutdownEvent((event) => {
588
+ statuses.push(doo.getShutdownStatus())
589
+ })
590
+
591
+ await doo.shutdown({ gracePeriodMs: 100 })
592
+
593
+ expect(doo.getShutdownStatus()).toBe('shutdown')
594
+ expect(statuses).toContain('draining')
595
+ })
596
+
597
+ it('should close PGlite during shutdown', async () => {
598
+ const state = createMockState()
599
+ const env = createMockEnv()
600
+ const doo = new PostgresDO(state as any, env)
601
+
602
+ const mockPGlite = createMockPGlite()
603
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
604
+ await doo.initPGlite()
605
+
606
+ await doo.shutdown({ gracePeriodMs: 100 })
607
+
608
+ expect(mockPGlite.close).toHaveBeenCalled()
609
+ })
610
+
611
+ it('should reject new queries after shutdown', async () => {
612
+ const state = createMockState()
613
+ const env = createMockEnv()
614
+ const doo = new PostgresDO(state as any, env)
615
+
616
+ const mockPGlite = createMockPGlite()
617
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
618
+ await doo.initPGlite()
619
+
620
+ await doo.shutdown({ gracePeriodMs: 100 })
621
+
622
+ await expect(doo.executeQuery({ sql: 'SELECT 1' })).rejects.toThrow(
623
+ 'PostgresDO is shut down and cannot accept new requests'
624
+ )
625
+ })
626
+
627
+ it('should only perform shutdown once if called multiple times', async () => {
628
+ const state = createMockState()
629
+ const env = createMockEnv()
630
+ const doo = new PostgresDO(state as any, env)
631
+
632
+ const mockPGlite = createMockPGlite()
633
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
634
+ await doo.initPGlite()
635
+
636
+ const shutdownEvents: string[] = []
637
+ doo.onShutdownEvent((event) => shutdownEvents.push(event.type))
638
+
639
+ // Call shutdown multiple times
640
+ const promise1 = doo.shutdown({ gracePeriodMs: 100 })
641
+ const promise2 = doo.shutdown()
642
+ const promise3 = doo.shutdown({ gracePeriodMs: 200 })
643
+
644
+ // Wait for all to complete
645
+ await Promise.all([promise1, promise2, promise3])
646
+
647
+ // Verify shutdown_initiated only happened once
648
+ const initiatedCount = shutdownEvents.filter((e) => e === 'shutdown_initiated').length
649
+ expect(initiatedCount).toBe(1)
650
+
651
+ // Verify shutdown_completed only happened once
652
+ const completedCount = shutdownEvents.filter((e) => e === 'shutdown_completed').length
653
+ expect(completedCount).toBe(1)
654
+
655
+ // Verify PGlite.close was only called once
656
+ expect(mockPGlite.close).toHaveBeenCalledTimes(1)
657
+ })
658
+ })
659
+
660
+ describe('connection draining', () => {
661
+ it('should wait for in-flight queries to complete', async () => {
662
+ const state = createMockState()
663
+ const env = createMockEnv()
664
+ const doo = new PostgresDO(state as any, env)
665
+
666
+ const mockPGlite = createMockPGlite()
667
+ let resolveQuery: () => void
668
+ const queryPromise = new Promise<void>((resolve) => {
669
+ resolveQuery = resolve
670
+ })
671
+ mockPGlite.query.mockImplementation(async () => {
672
+ await queryPromise
673
+ return { rows: [], fields: [], affectedRows: 0 }
674
+ })
675
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
676
+ await doo.initPGlite()
677
+
678
+ // Start a query but don't await it yet
679
+ const queryExecution = doo.executeQuery({ sql: 'SELECT 1' })
680
+ await new Promise((r) => setTimeout(r, 10))
681
+
682
+ expect(doo.getActiveQueryCount()).toBe(1)
683
+
684
+ // Start shutdown (won't complete until query finishes)
685
+ const shutdownPromise = doo.shutdown({ gracePeriodMs: 5000 })
686
+
687
+ expect(doo.getShutdownStatus()).toBe('draining')
688
+
689
+ // Resolve the query
690
+ resolveQuery!()
691
+ await queryExecution
692
+
693
+ // Now shutdown should complete
694
+ await shutdownPromise
695
+
696
+ expect(doo.getShutdownStatus()).toBe('shutdown')
697
+ })
698
+
699
+ it('should force shutdown after grace period', async () => {
700
+ const state = createMockState()
701
+ const env = createMockEnv()
702
+ const doo = new PostgresDO(state as any, env)
703
+
704
+ const mockPGlite = createMockPGlite()
705
+ // This query will never resolve
706
+ mockPGlite.query.mockImplementation(() => new Promise(() => {}))
707
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
708
+ await doo.initPGlite()
709
+
710
+ // Start a query that never completes
711
+ doo.executeQuery({ sql: 'SELECT pg_sleep(9999)' }).catch(() => {})
712
+ await new Promise((r) => setTimeout(r, 10))
713
+
714
+ expect(doo.getActiveQueryCount()).toBe(1)
715
+
716
+ const events: string[] = []
717
+ doo.onShutdownEvent((event) => events.push(event.type))
718
+
719
+ // Shutdown with very short grace period
720
+ await doo.shutdown({
721
+ gracePeriodMs: 50,
722
+ drainCheckIntervalMs: 10,
723
+ })
724
+
725
+ expect(events).toContain('forced_shutdown')
726
+ expect(doo.getShutdownStatus()).toBe('shutdown')
727
+ })
728
+
729
+ it('should emit query_completed_during_drain event', async () => {
730
+ const state = createMockState()
731
+ const env = createMockEnv()
732
+ const doo = new PostgresDO(state as any, env)
733
+
734
+ const mockPGlite = createMockPGlite()
735
+ let resolveQuery: () => void
736
+ const queryPromise = new Promise<void>((resolve) => {
737
+ resolveQuery = resolve
738
+ })
739
+ mockPGlite.query.mockImplementation(async () => {
740
+ await queryPromise
741
+ return { rows: [], fields: [], affectedRows: 0 }
742
+ })
743
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
744
+ await doo.initPGlite()
745
+
746
+ // Start a query
747
+ const queryExecution = doo.executeQuery({ sql: 'SELECT 1' })
748
+ await new Promise((r) => setTimeout(r, 10))
749
+
750
+ const events: { type: string; details?: Record<string, unknown> }[] = []
751
+ doo.onShutdownEvent((event) => events.push({ type: event.type, details: event.details }))
752
+
753
+ // Start shutdown
754
+ const shutdownPromise = doo.shutdown({ gracePeriodMs: 5000 })
755
+
756
+ // Wait for draining to start
757
+ await new Promise((r) => setTimeout(r, 20))
758
+
759
+ // Complete the query
760
+ resolveQuery!()
761
+ await queryExecution
762
+
763
+ await shutdownPromise
764
+
765
+ const drainEvent = events.find((e) => e.type === 'query_completed_during_drain')
766
+ expect(drainEvent).toBeDefined()
767
+ expect(drainEvent?.details?.remainingQueries).toBe(0)
768
+ })
769
+ })
770
+
771
+ describe('websocket handling during shutdown', () => {
772
+ it('should close websockets during shutdown', async () => {
773
+ const mockWebSocket = {
774
+ close: vi.fn(),
775
+ }
776
+ const state = createMockState()
777
+ state.getWebSockets.mockReturnValue([mockWebSocket])
778
+
779
+ const env = createMockEnv()
780
+ const doo = new PostgresDO(state as any, env)
781
+
782
+ const mockPGlite = createMockPGlite()
783
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
784
+ await doo.initPGlite()
785
+
786
+ await doo.shutdown({ gracePeriodMs: 100 })
787
+
788
+ expect(mockWebSocket.close).toHaveBeenCalledWith(1001, 'Server shutting down')
789
+ })
790
+
791
+ it('should emit websocket_closed_during_drain event', async () => {
792
+ const mockWebSocket = {
793
+ close: vi.fn(),
794
+ }
795
+ const state = createMockState()
796
+ state.getWebSockets.mockReturnValue([mockWebSocket])
797
+
798
+ const env = createMockEnv()
799
+ const doo = new PostgresDO(state as any, env)
800
+
801
+ const mockPGlite = createMockPGlite()
802
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
803
+ await doo.initPGlite()
804
+
805
+ const events: string[] = []
806
+ doo.onShutdownEvent((event) => events.push(event.type))
807
+
808
+ await doo.shutdown({ gracePeriodMs: 100 })
809
+
810
+ expect(events).toContain('websocket_closed_during_drain')
811
+ })
812
+
813
+ it('should handle websockets that are already closed', async () => {
814
+ const mockWebSocket = {
815
+ close: vi.fn(() => {
816
+ throw new Error('WebSocket already closed')
817
+ }),
818
+ }
819
+ const state = createMockState()
820
+ state.getWebSockets.mockReturnValue([mockWebSocket])
821
+
822
+ const env = createMockEnv()
823
+ const doo = new PostgresDO(state as any, env)
824
+
825
+ const mockPGlite = createMockPGlite()
826
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
827
+ await doo.initPGlite()
828
+
829
+ // Should not throw
830
+ await doo.shutdown({ gracePeriodMs: 100 })
831
+
832
+ expect(doo.getShutdownStatus()).toBe('shutdown')
833
+ })
834
+ })
835
+
836
+ describe('PGlite close timeout', () => {
837
+ it('should timeout PGlite close if it takes too long', async () => {
838
+ const state = createMockState()
839
+ const env = createMockEnv()
840
+ const doo = new PostgresDO(state as any, env)
841
+
842
+ const mockPGlite = createMockPGlite()
843
+ // PGlite close that never resolves
844
+ mockPGlite.close.mockImplementation(() => new Promise(() => {}))
845
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
846
+ await doo.initPGlite()
847
+
848
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
849
+
850
+ await doo.shutdown({
851
+ gracePeriodMs: 50,
852
+ closeTimeoutMs: 50,
853
+ })
854
+
855
+ expect(doo.getShutdownStatus()).toBe('shutdown')
856
+ consoleSpy.mockRestore()
857
+ })
858
+ })
859
+
860
+ describe('isShuttingDown', () => {
861
+ it('should return true when draining', async () => {
862
+ const state = createMockState()
863
+ const env = createMockEnv()
864
+ const doo = new PostgresDO(state as any, env)
865
+
866
+ const mockPGlite = createMockPGlite()
867
+ let resolveClose: () => void
868
+ mockPGlite.close.mockImplementation(
869
+ () =>
870
+ new Promise((resolve) => {
871
+ resolveClose = resolve as () => void
872
+ })
873
+ )
874
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
875
+ await doo.initPGlite()
876
+
877
+ const shutdownPromise = doo.shutdown({ gracePeriodMs: 100 })
878
+ await new Promise((r) => setTimeout(r, 10))
879
+
880
+ expect(doo.isShuttingDown()).toBe(true)
881
+
882
+ resolveClose!()
883
+ await shutdownPromise
884
+ })
885
+
886
+ it('should return true when shutdown', async () => {
887
+ const state = createMockState()
888
+ const env = createMockEnv()
889
+ const doo = new PostgresDO(state as any, env)
890
+
891
+ const mockPGlite = createMockPGlite()
892
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
893
+ await doo.initPGlite()
894
+
895
+ await doo.shutdown({ gracePeriodMs: 100 })
896
+
897
+ expect(doo.isShuttingDown()).toBe(true)
898
+ expect(doo.getShutdownStatus()).toBe('shutdown')
899
+ })
900
+ })
901
+ })
902
+
903
+ describe('Auto-Migration on First Connection', () => {
904
+ describe('schema version tracking', () => {
905
+ it('should return version 0 for fresh database', async () => {
906
+ const state = createMockState()
907
+ state.storage.get.mockResolvedValue(undefined)
908
+ const env = createMockEnv()
909
+ const doo = new PostgresDO(state as any, env)
910
+
911
+ const version = await doo.getSchemaVersion()
912
+ expect(version).toBe(0)
913
+ })
914
+
915
+ it('should return stored version', async () => {
916
+ const state = createMockState()
917
+ state.storage.get.mockResolvedValue(5)
918
+ const env = createMockEnv()
919
+ const doo = new PostgresDO(state as any, env)
920
+
921
+ const version = await doo.getSchemaVersion()
922
+ expect(version).toBe(5)
923
+ })
924
+
925
+ it('should detect fresh database', async () => {
926
+ const state = createMockState()
927
+ state.storage.get.mockResolvedValue(undefined)
928
+ const env = createMockEnv()
929
+ const doo = new PostgresDO(state as any, env)
930
+
931
+ const isFresh = await doo.isFreshDatabase()
932
+ expect(isFresh).toBe(true)
933
+ })
934
+
935
+ it('should detect non-fresh database', async () => {
936
+ const state = createMockState()
937
+ state.storage.get.mockResolvedValue(1)
938
+ const env = createMockEnv()
939
+ const doo = new PostgresDO(state as any, env)
940
+
941
+ const isFresh = await doo.isFreshDatabase()
942
+ expect(isFresh).toBe(false)
943
+ })
944
+ })
945
+
946
+ describe('ensureMigrated', () => {
947
+ it('should return null when no migrations configured', async () => {
948
+ const state = createMockState()
949
+ const env = createMockEnv()
950
+ const doo = new PostgresDO(state as any, env)
951
+
952
+ const mockPGlite = createMockPGlite()
953
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
954
+ await doo.initPGlite()
955
+
956
+ const result = await doo.ensureMigrated()
957
+ expect(result).toBeNull()
958
+ expect(doo.isMigrated()).toBe(true)
959
+ })
960
+
961
+ it('should run migrations on fresh database', async () => {
962
+ const state = createMockState()
963
+ state.storage.get.mockResolvedValue(undefined) // Fresh DB
964
+ const env = createMockEnv()
965
+ const config: PostgresConfig = {
966
+ database: 'test',
967
+ migrations: {
968
+ autoMigrate: false, // Disable auto-migrate to test ensureMigrated directly
969
+ migrations: [
970
+ {
971
+ id: '001_initial',
972
+ name: 'Initial schema',
973
+ version: 1,
974
+ sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY)',
975
+ },
976
+ ],
977
+ },
978
+ }
979
+ const doo = new PostgresDO(state as any, env, config)
980
+
981
+ const mockPGlite = createMockPGlite()
982
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
983
+ await doo.initPGlite()
984
+
985
+ const result = await doo.ensureMigrated()
986
+
987
+ expect(result).not.toBeNull()
988
+ expect(result?.success).toBe(true)
989
+ expect(result?.migrationsRun).toBe(1)
990
+ expect(state.storage.put).toHaveBeenCalledWith('__postgres_schema_version__', 1)
991
+ })
992
+
993
+ it('should skip already applied migrations', async () => {
994
+ const state = createMockState()
995
+ state.storage.get.mockResolvedValue(1) // Already at version 1
996
+ const env = createMockEnv()
997
+ const config: PostgresConfig = {
998
+ database: 'test',
999
+ migrations: {
1000
+ autoMigrate: false, // Disable auto-migrate to test ensureMigrated directly
1001
+ migrations: [
1002
+ {
1003
+ id: '001_initial',
1004
+ name: 'Initial schema',
1005
+ version: 1,
1006
+ sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY)',
1007
+ },
1008
+ ],
1009
+ },
1010
+ }
1011
+ const doo = new PostgresDO(state as any, env, config)
1012
+
1013
+ const mockPGlite = createMockPGlite()
1014
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1015
+ await doo.initPGlite()
1016
+
1017
+ const result = await doo.ensureMigrated()
1018
+
1019
+ expect(result).not.toBeNull()
1020
+ expect(result?.success).toBe(true)
1021
+ expect(result?.migrationsSkipped).toBe(1)
1022
+ expect(result?.migrationsRun).toBe(0)
1023
+ })
1024
+
1025
+ it('should run only pending migrations', async () => {
1026
+ const state = createMockState()
1027
+ // Track the schema version in storage
1028
+ let storedVersion: number = 1
1029
+ state.storage.get.mockImplementation(async (key: string) => {
1030
+ if (key === '__postgres_schema_version__') return storedVersion
1031
+ return undefined
1032
+ })
1033
+ state.storage.put.mockImplementation(async (key: string, value: unknown) => {
1034
+ if (key === '__postgres_schema_version__') storedVersion = value as number
1035
+ })
1036
+ const env = createMockEnv()
1037
+ const config: PostgresConfig = {
1038
+ database: 'test',
1039
+ migrations: {
1040
+ autoMigrate: false, // Disable auto-migrate to test ensureMigrated directly
1041
+ migrations: [
1042
+ {
1043
+ id: '001_initial',
1044
+ name: 'Initial schema',
1045
+ version: 1,
1046
+ sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY)',
1047
+ },
1048
+ {
1049
+ id: '002_add_email',
1050
+ name: 'Add email column',
1051
+ version: 2,
1052
+ sql: 'ALTER TABLE users ADD COLUMN email TEXT',
1053
+ },
1054
+ ],
1055
+ },
1056
+ }
1057
+ const doo = new PostgresDO(state as any, env, config)
1058
+
1059
+ const mockPGlite = createMockPGlite()
1060
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1061
+ await doo.initPGlite()
1062
+
1063
+ const result = await doo.ensureMigrated()
1064
+
1065
+ expect(result?.success).toBe(true)
1066
+ expect(result?.migrationsRun).toBe(1) // Only migration 2
1067
+ expect(result?.migrationsSkipped).toBe(1) // Migration 1 skipped
1068
+ expect(result?.fromVersion).toBe(1)
1069
+ expect(result?.toVersion).toBe(2)
1070
+ })
1071
+ })
1072
+
1073
+ describe('migration error handling', () => {
1074
+ it('should handle migration failures gracefully', async () => {
1075
+ const state = createMockState()
1076
+ state.storage.get.mockResolvedValue(undefined)
1077
+ const env = createMockEnv()
1078
+ const config: PostgresConfig = {
1079
+ database: 'test',
1080
+ migrations: {
1081
+ migrations: [
1082
+ {
1083
+ id: '001_bad',
1084
+ name: 'Bad migration',
1085
+ version: 1,
1086
+ sql: 'INVALID SQL SYNTAX',
1087
+ },
1088
+ ],
1089
+ },
1090
+ }
1091
+ const doo = new PostgresDO(state as any, env, config)
1092
+
1093
+ const mockPGlite = createMockPGlite()
1094
+ mockPGlite.exec.mockRejectedValue(new Error('syntax error'))
1095
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1096
+ await doo.initPGlite()
1097
+
1098
+ const result = await doo.ensureMigrated()
1099
+
1100
+ expect(result?.success).toBe(false)
1101
+ expect(result?.results[0].success).toBe(false)
1102
+ expect(result?.results[0].error).toContain('syntax error')
1103
+ expect(doo.isMigrated()).toBe(false)
1104
+ })
1105
+
1106
+ it('should rollback on migration failure', async () => {
1107
+ const state = createMockState()
1108
+ state.storage.get.mockResolvedValue(undefined)
1109
+ const env = createMockEnv()
1110
+ const config: PostgresConfig = {
1111
+ database: 'test',
1112
+ migrations: {
1113
+ migrations: [
1114
+ {
1115
+ id: '001_bad',
1116
+ name: 'Bad migration',
1117
+ version: 1,
1118
+ sql: 'INVALID SQL',
1119
+ },
1120
+ ],
1121
+ },
1122
+ }
1123
+ const doo = new PostgresDO(state as any, env, config)
1124
+
1125
+ const mockPGlite = createMockPGlite()
1126
+ const queryCalls: string[] = []
1127
+ mockPGlite.query.mockImplementation((sql?: string) => {
1128
+ queryCalls.push(sql ?? '')
1129
+ return Promise.resolve({ rows: [], fields: [], affectedRows: 0 })
1130
+ })
1131
+ mockPGlite.exec.mockRejectedValue(new Error('syntax error'))
1132
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1133
+ await doo.initPGlite()
1134
+
1135
+ await doo.ensureMigrated()
1136
+
1137
+ expect(queryCalls).toContain('BEGIN')
1138
+ expect(queryCalls).toContain('ROLLBACK')
1139
+ })
1140
+ })
1141
+
1142
+ describe('migration progress callbacks', () => {
1143
+ it('should call onProgress for each migration phase', async () => {
1144
+ const state = createMockState()
1145
+ state.storage.get.mockResolvedValue(undefined)
1146
+ const env = createMockEnv()
1147
+
1148
+ const progressEvents: Array<{ phase: string; migration: { id: string } }> = []
1149
+ const config: PostgresConfig = {
1150
+ database: 'test',
1151
+ migrations: {
1152
+ migrations: [
1153
+ {
1154
+ id: '001_initial',
1155
+ name: 'Initial schema',
1156
+ version: 1,
1157
+ sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY)',
1158
+ },
1159
+ ],
1160
+ onProgress: (event) => {
1161
+ progressEvents.push({ phase: event.phase, migration: { id: event.migration.id } })
1162
+ },
1163
+ },
1164
+ }
1165
+ const doo = new PostgresDO(state as any, env, config)
1166
+
1167
+ const mockPGlite = createMockPGlite()
1168
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1169
+ await doo.initPGlite()
1170
+
1171
+ await doo.ensureMigrated()
1172
+
1173
+ expect(progressEvents.some((e) => e.phase === 'starting')).toBe(true)
1174
+ expect(progressEvents.some((e) => e.phase === 'executing')).toBe(true)
1175
+ expect(progressEvents.some((e) => e.phase === 'completed')).toBe(true)
1176
+ })
1177
+
1178
+ it('should call onProgress with failed phase on error', async () => {
1179
+ const state = createMockState()
1180
+ state.storage.get.mockResolvedValue(undefined)
1181
+ const env = createMockEnv()
1182
+
1183
+ const progressEvents: Array<{ phase: string; error?: string }> = []
1184
+ const config: PostgresConfig = {
1185
+ database: 'test',
1186
+ migrations: {
1187
+ migrations: [
1188
+ {
1189
+ id: '001_bad',
1190
+ name: 'Bad migration',
1191
+ version: 1,
1192
+ sql: 'INVALID SQL',
1193
+ },
1194
+ ],
1195
+ onProgress: (event) => {
1196
+ progressEvents.push({ phase: event.phase, error: event.error })
1197
+ },
1198
+ },
1199
+ }
1200
+ const doo = new PostgresDO(state as any, env, config)
1201
+
1202
+ const mockPGlite = createMockPGlite()
1203
+ mockPGlite.exec.mockRejectedValue(new Error('syntax error'))
1204
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1205
+ await doo.initPGlite()
1206
+
1207
+ await doo.ensureMigrated()
1208
+
1209
+ const failedEvent = progressEvents.find((e) => e.phase === 'failed')
1210
+ expect(failedEvent).toBeDefined()
1211
+ expect(failedEvent?.error).toContain('syntax error')
1212
+ })
1213
+ })
1214
+
1215
+ describe('auto-migration during initialization', () => {
1216
+ it('should run migrations automatically when autoMigrate is not set (defaults to true)', async () => {
1217
+ const state = createMockState()
1218
+ state.storage.get.mockResolvedValue(undefined)
1219
+ const env = createMockEnv()
1220
+ const config: PostgresConfig = {
1221
+ database: 'test',
1222
+ migrations: {
1223
+ migrations: [
1224
+ {
1225
+ id: '001_initial',
1226
+ name: 'Initial schema',
1227
+ version: 1,
1228
+ sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY)',
1229
+ },
1230
+ ],
1231
+ },
1232
+ }
1233
+ const doo = new PostgresDO(state as any, env, config)
1234
+
1235
+ const mockPGlite = createMockPGlite()
1236
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1237
+
1238
+ await doo.initPGlite()
1239
+
1240
+ // Migration should have run automatically
1241
+ expect(doo.isMigrated()).toBe(true)
1242
+ expect(state.storage.put).toHaveBeenCalledWith('__postgres_schema_version__', 1)
1243
+ })
1244
+
1245
+ it('should skip auto-migration when autoMigrate is false', async () => {
1246
+ const state = createMockState()
1247
+ state.storage.get.mockResolvedValue(undefined)
1248
+ const env = createMockEnv()
1249
+ const config: PostgresConfig = {
1250
+ database: 'test',
1251
+ migrations: {
1252
+ autoMigrate: false,
1253
+ migrations: [
1254
+ {
1255
+ id: '001_initial',
1256
+ name: 'Initial schema',
1257
+ version: 1,
1258
+ sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY)',
1259
+ },
1260
+ ],
1261
+ },
1262
+ }
1263
+ const doo = new PostgresDO(state as any, env, config)
1264
+
1265
+ const mockPGlite = createMockPGlite()
1266
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1267
+
1268
+ await doo.initPGlite()
1269
+
1270
+ // Migration should NOT have run
1271
+ expect(doo.isMigrated()).toBe(false)
1272
+ expect(state.storage.put).not.toHaveBeenCalledWith('__postgres_schema_version__', 1)
1273
+ })
1274
+ })
1275
+
1276
+ describe('concurrent migration protection', () => {
1277
+ it('should deduplicate concurrent ensureMigrated calls', async () => {
1278
+ const state = createMockState()
1279
+ state.storage.get.mockResolvedValue(undefined)
1280
+ const env = createMockEnv()
1281
+ const config: PostgresConfig = {
1282
+ database: 'test',
1283
+ migrations: {
1284
+ autoMigrate: false, // Disable auto-migrate to control manually
1285
+ migrations: [
1286
+ {
1287
+ id: '001_initial',
1288
+ name: 'Initial schema',
1289
+ version: 1,
1290
+ sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY)',
1291
+ },
1292
+ ],
1293
+ },
1294
+ }
1295
+ const doo = new PostgresDO(state as any, env, config)
1296
+
1297
+ const mockPGlite = createMockPGlite()
1298
+ let execCallCount = 0
1299
+ mockPGlite.exec.mockImplementation(async () => {
1300
+ execCallCount++
1301
+ await new Promise((r) => setTimeout(r, 10))
1302
+ return { rows: [], fields: [] }
1303
+ })
1304
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1305
+
1306
+ await doo.initPGlite()
1307
+
1308
+ // Call ensureMigrated multiple times concurrently
1309
+ const [result1, result2, result3] = await Promise.all([
1310
+ doo.ensureMigrated(),
1311
+ doo.ensureMigrated(),
1312
+ doo.ensureMigrated(),
1313
+ ])
1314
+
1315
+ // All should return the same result (first two return the running promise)
1316
+ // The migration SQL should only be executed once
1317
+ expect(execCallCount).toBe(1)
1318
+
1319
+ // Results should be consistent
1320
+ expect(result1?.success || result1 === null).toBe(true)
1321
+ })
1322
+ })
1323
+ })
1324
+
1325
+ describe('WAL Initialization Race Condition', () => {
1326
+ describe('initWAL concurrent calls', () => {
1327
+ it('should only initialize WAL once when called concurrently', async () => {
1328
+ const state = createMockState()
1329
+ const env = createMockEnv()
1330
+ const doo = new PostgresDO(state as any, env)
1331
+
1332
+ // Spy on the WAL facade's initialize method
1333
+ let initializeCallCount = 0
1334
+ const mockWALFacade = {
1335
+ initialize: vi.fn(async () => {
1336
+ initializeCallCount++
1337
+ // Add small delay to simulate async work and increase race window
1338
+ await new Promise((r) => setTimeout(r, 20))
1339
+ }),
1340
+ isEnabled: vi.fn(() => true),
1341
+ setEnabled: vi.fn(),
1342
+ getConfig: vi.fn(() => ({})),
1343
+ setConfig: vi.fn(),
1344
+ getStats: vi.fn(() => ({ entriesInBuffer: 0, totalEntriesFlushed: 0, lastFlushAt: null })),
1345
+ }
1346
+
1347
+ vi.spyOn(doo, 'getWALFacade').mockReturnValue(mockWALFacade as any)
1348
+
1349
+ // Call initWAL concurrently 10 times
1350
+ const promises = Array.from({ length: 10 }, () => doo.initWAL())
1351
+ await Promise.all(promises)
1352
+
1353
+ // Assert: initialize() should only be called ONCE
1354
+ expect(initializeCallCount).toBe(1)
1355
+ expect(mockWALFacade.initialize).toHaveBeenCalledTimes(1)
1356
+ })
1357
+
1358
+ it('should return the same promise for concurrent calls', async () => {
1359
+ const state = createMockState()
1360
+ const env = createMockEnv()
1361
+ const doo = new PostgresDO(state as any, env)
1362
+
1363
+ let initializeCallCount = 0
1364
+ const mockWALFacade = {
1365
+ initialize: vi.fn(async () => {
1366
+ initializeCallCount++
1367
+ await new Promise((r) => setTimeout(r, 10))
1368
+ }),
1369
+ isEnabled: vi.fn(() => true),
1370
+ setEnabled: vi.fn(),
1371
+ getConfig: vi.fn(() => ({})),
1372
+ setConfig: vi.fn(),
1373
+ getStats: vi.fn(() => ({ entriesInBuffer: 0, totalEntriesFlushed: 0, lastFlushAt: null })),
1374
+ }
1375
+
1376
+ vi.spyOn(doo, 'getWALFacade').mockReturnValue(mockWALFacade as any)
1377
+
1378
+ // Start multiple initWAL calls before any complete
1379
+ const promise1 = doo.initWAL()
1380
+ const promise2 = doo.initWAL()
1381
+ const promise3 = doo.initWAL()
1382
+
1383
+ // All promises should complete successfully
1384
+ await Promise.all([promise1, promise2, promise3])
1385
+
1386
+ // Only one actual initialization should have occurred
1387
+ expect(initializeCallCount).toBe(1)
1388
+ })
1389
+
1390
+ it('should allow re-initialization after previous completes if needed', async () => {
1391
+ const state = createMockState()
1392
+ const env = createMockEnv()
1393
+ const doo = new PostgresDO(state as any, env)
1394
+
1395
+ let initializeCallCount = 0
1396
+ const mockWALFacade = {
1397
+ initialize: vi.fn(async () => {
1398
+ initializeCallCount++
1399
+ }),
1400
+ isEnabled: vi.fn(() => true),
1401
+ setEnabled: vi.fn(),
1402
+ getConfig: vi.fn(() => ({})),
1403
+ setConfig: vi.fn(),
1404
+ getStats: vi.fn(() => ({ entriesInBuffer: 0, totalEntriesFlushed: 0, lastFlushAt: null })),
1405
+ }
1406
+
1407
+ vi.spyOn(doo, 'getWALFacade').mockReturnValue(mockWALFacade as any)
1408
+
1409
+ // First call
1410
+ await doo.initWAL()
1411
+ expect(initializeCallCount).toBe(1)
1412
+
1413
+ // Second call after first completes - should still only have 1 init
1414
+ // (because the guard pattern caches the promise)
1415
+ await doo.initWAL()
1416
+ expect(initializeCallCount).toBe(1)
1417
+ })
1418
+ })
1419
+ })
1420
+
1421
+ describe('Lazy Migration (on-demand strategy)', () => {
1422
+ describe('getMigrationStrategy', () => {
1423
+ it('should return "on-create" by default', () => {
1424
+ const state = createMockState()
1425
+ const env = createMockEnv()
1426
+ const doo = new PostgresDO(state as any, env)
1427
+
1428
+ expect(doo.getMigrationStrategy()).toBe('on-create')
1429
+ })
1430
+
1431
+ it('should return configured strategy', () => {
1432
+ const state = createMockState()
1433
+ const env = createMockEnv()
1434
+ const config: PostgresConfig = {
1435
+ database: 'test',
1436
+ migrations: {
1437
+ migrations: [],
1438
+ strategy: 'on-demand',
1439
+ },
1440
+ }
1441
+ const doo = new PostgresDO(state as any, env, config)
1442
+
1443
+ expect(doo.getMigrationStrategy()).toBe('on-demand')
1444
+ })
1445
+ })
1446
+
1447
+ describe('getMigrationState', () => {
1448
+ it('should return null when no state exists', async () => {
1449
+ const state = createMockState()
1450
+ state.storage.get.mockResolvedValue(undefined)
1451
+ const env = createMockEnv()
1452
+ const doo = new PostgresDO(state as any, env)
1453
+
1454
+ const migrationState = await doo.getMigrationState()
1455
+ expect(migrationState).toBeNull()
1456
+ })
1457
+
1458
+ it('should return stored migration state', async () => {
1459
+ const state = createMockState()
1460
+ const storedState = {
1461
+ status: 'completed',
1462
+ version: 3,
1463
+ lastAttemptAt: '2024-01-01T00:00:00Z',
1464
+ durationMs: 150,
1465
+ }
1466
+ state.storage.get.mockResolvedValue(storedState)
1467
+ const env = createMockEnv()
1468
+ const doo = new PostgresDO(state as any, env)
1469
+
1470
+ const migrationState = await doo.getMigrationState()
1471
+ expect(migrationState).toEqual(storedState)
1472
+ })
1473
+ })
1474
+
1475
+ describe('needsLazyMigration', () => {
1476
+ it('should return false for on-create strategy', async () => {
1477
+ const state = createMockState()
1478
+ const env = createMockEnv()
1479
+ const config: PostgresConfig = {
1480
+ database: 'test',
1481
+ migrations: {
1482
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'SELECT 1' }],
1483
+ strategy: 'on-create',
1484
+ },
1485
+ }
1486
+ const doo = new PostgresDO(state as any, env, config)
1487
+
1488
+ const needs = await doo.needsLazyMigration()
1489
+ expect(needs).toBe(false)
1490
+ })
1491
+
1492
+ it('should return false when no migrations configured', async () => {
1493
+ const state = createMockState()
1494
+ const env = createMockEnv()
1495
+ const config: PostgresConfig = {
1496
+ database: 'test',
1497
+ migrations: {
1498
+ migrations: [],
1499
+ strategy: 'on-demand',
1500
+ },
1501
+ }
1502
+ const doo = new PostgresDO(state as any, env, config)
1503
+
1504
+ const needs = await doo.needsLazyMigration()
1505
+ expect(needs).toBe(false)
1506
+ })
1507
+
1508
+ it('should return true when no migration state exists', async () => {
1509
+ const state = createMockState()
1510
+ state.storage.get.mockResolvedValue(undefined)
1511
+ const env = createMockEnv()
1512
+ const config: PostgresConfig = {
1513
+ database: 'test',
1514
+ migrations: {
1515
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'SELECT 1' }],
1516
+ strategy: 'on-demand',
1517
+ },
1518
+ }
1519
+ const doo = new PostgresDO(state as any, env, config)
1520
+
1521
+ const needs = await doo.needsLazyMigration()
1522
+ expect(needs).toBe(true)
1523
+ })
1524
+
1525
+ it('should return false when migrations completed and up to date', async () => {
1526
+ const state = createMockState()
1527
+ state.storage.get.mockResolvedValue({
1528
+ status: 'completed',
1529
+ version: 1,
1530
+ lastAttemptAt: '2024-01-01T00:00:00Z',
1531
+ })
1532
+ const env = createMockEnv()
1533
+ const config: PostgresConfig = {
1534
+ database: 'test',
1535
+ migrations: {
1536
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'SELECT 1' }],
1537
+ strategy: 'on-demand',
1538
+ },
1539
+ }
1540
+ const doo = new PostgresDO(state as any, env, config)
1541
+
1542
+ const needs = await doo.needsLazyMigration()
1543
+ expect(needs).toBe(false)
1544
+ })
1545
+
1546
+ it('should return true when new migrations available', async () => {
1547
+ const state = createMockState()
1548
+ state.storage.get.mockResolvedValue({
1549
+ status: 'completed',
1550
+ version: 1,
1551
+ lastAttemptAt: '2024-01-01T00:00:00Z',
1552
+ })
1553
+ const env = createMockEnv()
1554
+ const config: PostgresConfig = {
1555
+ database: 'test',
1556
+ migrations: {
1557
+ migrations: [
1558
+ { id: '1', name: 'test1', version: 1, sql: 'SELECT 1' },
1559
+ { id: '2', name: 'test2', version: 2, sql: 'SELECT 2' },
1560
+ ],
1561
+ strategy: 'on-demand',
1562
+ },
1563
+ }
1564
+ const doo = new PostgresDO(state as any, env, config)
1565
+
1566
+ const needs = await doo.needsLazyMigration()
1567
+ expect(needs).toBe(true)
1568
+ })
1569
+
1570
+ it('should return true when previous migration failed', async () => {
1571
+ const state = createMockState()
1572
+ state.storage.get.mockResolvedValue({
1573
+ status: 'failed',
1574
+ version: 0,
1575
+ lastAttemptAt: '2024-01-01T00:00:00Z',
1576
+ error: 'Previous error',
1577
+ })
1578
+ const env = createMockEnv()
1579
+ const config: PostgresConfig = {
1580
+ database: 'test',
1581
+ migrations: {
1582
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'SELECT 1' }],
1583
+ strategy: 'on-demand',
1584
+ },
1585
+ }
1586
+ const doo = new PostgresDO(state as any, env, config)
1587
+
1588
+ const needs = await doo.needsLazyMigration()
1589
+ expect(needs).toBe(true)
1590
+ })
1591
+ })
1592
+
1593
+ describe('on-demand migration during query', () => {
1594
+ it('should skip migrations during initPGlite for on-demand strategy', async () => {
1595
+ const state = createMockState()
1596
+ state.storage.get.mockResolvedValue(undefined) // No schema version
1597
+ const env = createMockEnv()
1598
+ const config: PostgresConfig = {
1599
+ database: 'test',
1600
+ migrations: {
1601
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'CREATE TABLE test (id INT)' }],
1602
+ strategy: 'on-demand',
1603
+ },
1604
+ }
1605
+ const doo = new PostgresDO(state as any, env, config)
1606
+
1607
+ const mockPGlite = createMockPGlite()
1608
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1609
+
1610
+ await doo.initPGlite()
1611
+
1612
+ // Migration should NOT have been called during init
1613
+ // The exec/query should not have been called for migration SQL
1614
+ const queryCalls = mockPGlite.query.mock.calls as [string, unknown[]][]
1615
+ const migrationQueries = queryCalls.filter(([sql]) =>
1616
+ sql && (sql.includes('CREATE TABLE test') || sql.includes('BEGIN'))
1617
+ )
1618
+ expect(migrationQueries).toHaveLength(0)
1619
+ })
1620
+
1621
+ it('should run migrations on first query for on-demand strategy', async () => {
1622
+ const state = createMockState()
1623
+ let storageData: Record<string, unknown> = {}
1624
+ state.storage.get.mockImplementation((key: string) => Promise.resolve(storageData[key]))
1625
+ state.storage.put.mockImplementation((key: string, value: unknown) => {
1626
+ storageData[key] = value
1627
+ return Promise.resolve()
1628
+ })
1629
+ const env = createMockEnv()
1630
+ const config: PostgresConfig = {
1631
+ database: 'test',
1632
+ migrations: {
1633
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'CREATE TABLE test (id INT)' }],
1634
+ strategy: 'on-demand',
1635
+ },
1636
+ }
1637
+ const doo = new PostgresDO(state as any, env, config)
1638
+
1639
+ const mockPGlite = createMockPGlite()
1640
+ // Mock all queries that migrations need - BEGIN, the migration SQL, COMMIT
1641
+ mockPGlite.query.mockResolvedValue({ rows: [], fields: [], affectedRows: 0 })
1642
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1643
+
1644
+ // Initialize without running migrations
1645
+ await doo.initPGlite()
1646
+
1647
+ // First query should trigger migrations
1648
+ await doo.executeQuery({ sql: 'SELECT 1' })
1649
+
1650
+ // Migration state should now be saved
1651
+ const migrationState = storageData['__postgres_migration_state__'] as { status: string; version: number }
1652
+ expect(migrationState).toBeDefined()
1653
+ expect(migrationState.status).toBe('completed')
1654
+ expect(migrationState.version).toBe(1)
1655
+ })
1656
+
1657
+ it('should not run migrations on subsequent queries', async () => {
1658
+ const state = createMockState()
1659
+ let storageData: Record<string, unknown> = {
1660
+ '__postgres_migration_state__': {
1661
+ status: 'completed',
1662
+ version: 1,
1663
+ lastAttemptAt: '2024-01-01T00:00:00Z',
1664
+ },
1665
+ }
1666
+ state.storage.get.mockImplementation((key: string) => Promise.resolve(storageData[key]))
1667
+ state.storage.put.mockImplementation((key: string, value: unknown) => {
1668
+ storageData[key] = value
1669
+ return Promise.resolve()
1670
+ })
1671
+ const env = createMockEnv()
1672
+ const config: PostgresConfig = {
1673
+ database: 'test',
1674
+ migrations: {
1675
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'CREATE TABLE test (id INT)' }],
1676
+ strategy: 'on-demand',
1677
+ },
1678
+ }
1679
+ const doo = new PostgresDO(state as any, env, config)
1680
+
1681
+ const mockPGlite = createMockPGlite()
1682
+ let execCallCount = 0
1683
+ mockPGlite.exec.mockImplementation(() => {
1684
+ execCallCount++
1685
+ return Promise.resolve({ rows: [], fields: [] })
1686
+ })
1687
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1688
+
1689
+ await doo.initPGlite()
1690
+
1691
+ // Run multiple queries
1692
+ await doo.executeQuery({ sql: 'SELECT 1' })
1693
+ await doo.executeQuery({ sql: 'SELECT 2' })
1694
+ await doo.executeQuery({ sql: 'SELECT 3' })
1695
+
1696
+ // exec should NOT have been called for migrations (already completed)
1697
+ expect(execCallCount).toBe(0)
1698
+ })
1699
+ })
1700
+
1701
+ describe('rpcQuery with on-demand migrations', () => {
1702
+ it('should run migrations before first RPC query', async () => {
1703
+ const state = createMockState()
1704
+ let storageData: Record<string, unknown> = {}
1705
+ state.storage.get.mockImplementation((key: string) => Promise.resolve(storageData[key]))
1706
+ state.storage.put.mockImplementation((key: string, value: unknown) => {
1707
+ storageData[key] = value
1708
+ return Promise.resolve()
1709
+ })
1710
+ const env = createMockEnv()
1711
+ const config: PostgresConfig = {
1712
+ database: 'test',
1713
+ migrations: {
1714
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'CREATE TABLE test (id INT)' }],
1715
+ strategy: 'on-demand',
1716
+ },
1717
+ }
1718
+ const doo = new PostgresDO(state as any, env, config)
1719
+
1720
+ const mockPGlite = createMockPGlite()
1721
+ // Mock all queries that migrations need
1722
+ mockPGlite.query.mockResolvedValue({ rows: [], fields: [], affectedRows: 0 })
1723
+ vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1724
+
1725
+ await doo.initPGlite()
1726
+
1727
+ // RPC query should trigger migrations
1728
+ await doo.rpcQuery('SELECT 1')
1729
+
1730
+ // Migration state should be saved
1731
+ const migrationState = storageData['__postgres_migration_state__'] as { status: string }
1732
+ expect(migrationState).toBeDefined()
1733
+ expect(migrationState.status).toBe('completed')
1734
+ })
1735
+ })
1736
+ })
1737
+
1738
+ // ============================================================================
1739
+ // RED PHASE: Initialization Decoupling Tests
1740
+ // Task: postgres-ud8w.1 - [RED] Add tests for initialization decoupling
1741
+ //
1742
+ // Tests for decoupling DO and PGLite initialization:
1743
+ // 1. DO can be created without PGLite
1744
+ // 2. PGLite can be created without DO context
1745
+ // 3. Lazy initialization of PGLite
1746
+ // 4. Proper initialization ordering
1747
+ // 5. Error handling when dependencies missing
1748
+ // 6. Dependency injection for testability
1749
+ // 7. Factory pattern for PGLite creation
1750
+ // ============================================================================
1751
+
1752
+ describe('Initialization Decoupling', () => {
1753
+ describe('DO creation without PGLite', () => {
1754
+ it('should create DO instance without initializing PGLite', () => {
1755
+ const state = createMockState()
1756
+ const env = createMockEnv()
1757
+ const doo = new PostgresDO(state as any, env)
1758
+
1759
+ // DO should be created
1760
+ expect(doo).toBeInstanceOf(PostgresDO)
1761
+ // PGLite should NOT be initialized
1762
+ expect(doo.isInitialized()).toBe(false)
1763
+ })
1764
+
1765
+ it('should allow accessing DO methods before PGLite initialization', () => {
1766
+ const state = createMockState()
1767
+ const env = createMockEnv()
1768
+ const doo = new PostgresDO(state as any, env)
1769
+
1770
+ // These methods should work without PGLite
1771
+ expect(doo.getState()).toBe(state)
1772
+ expect(doo.getEnv()).toBe(env)
1773
+ expect(doo.getConfig()).toBeDefined()
1774
+ expect(doo.getShutdownStatus()).toBe('running')
1775
+ expect(doo.isInitialized()).toBe(false)
1776
+ })
1777
+
1778
+ it('should return null from getPGLiteManager.getInstanceOrNull() before initialization', () => {
1779
+ const state = createMockState()
1780
+ const env = createMockEnv()
1781
+ const doo = new PostgresDO(state as any, env)
1782
+
1783
+ const manager = doo.getPGLiteManager()
1784
+ expect(manager.getInstanceOrNull()).toBeNull()
1785
+ })
1786
+
1787
+ it('should throw from getPGLiteManager.getInstance() before initialization', () => {
1788
+ const state = createMockState()
1789
+ const env = createMockEnv()
1790
+ const doo = new PostgresDO(state as any, env)
1791
+
1792
+ const manager = doo.getPGLiteManager()
1793
+ expect(() => manager.getInstance()).toThrow('PGLite not initialized')
1794
+ })
1795
+ })
1796
+
1797
+ describe('PGLiteManager independence from DO', () => {
1798
+ it('should allow creating PGLiteManager without DO context', async () => {
1799
+ // Import PGLiteManager directly
1800
+ const { PGLiteManager } = await import('./do-pglite-manager')
1801
+
1802
+ // Create manager without any DO
1803
+ const manager = new PGLiteManager({
1804
+ database: 'test-db',
1805
+ debug: false,
1806
+ })
1807
+
1808
+ expect(manager).toBeDefined()
1809
+ expect(manager.isInitialized()).toBe(false)
1810
+ })
1811
+
1812
+ it('should allow injecting custom PGLite factory for testing', async () => {
1813
+ const { PGLiteManager } = await import('./do-pglite-manager')
1814
+ const mockPGlite = createMockPGlite()
1815
+
1816
+ const manager = new PGLiteManager({
1817
+ database: 'test-db',
1818
+ createPGLite: () => Promise.resolve(mockPGlite),
1819
+ })
1820
+
1821
+ await manager.initialize()
1822
+
1823
+ expect(manager.isInitialized()).toBe(true)
1824
+ expect(manager.getInstance()).toBe(mockPGlite)
1825
+ })
1826
+
1827
+ it('should allow injecting pre-created PGLite instance', async () => {
1828
+ const { PGLiteManager } = await import('./do-pglite-manager')
1829
+ const mockPGlite = createMockPGlite()
1830
+
1831
+ const manager = new PGLiteManager({ database: 'test-db' })
1832
+ manager.injectInstance(mockPGlite)
1833
+
1834
+ expect(manager.isInitialized()).toBe(true)
1835
+ expect(manager.getInstance()).toBe(mockPGlite)
1836
+ })
1837
+
1838
+ it('should allow setting factory after construction', async () => {
1839
+ const { PGLiteManager } = await import('./do-pglite-manager')
1840
+ const mockPGlite = createMockPGlite()
1841
+
1842
+ const manager = new PGLiteManager({ database: 'test-db' })
1843
+ manager.setCreatePGLite(() => Promise.resolve(mockPGlite))
1844
+ await manager.initialize()
1845
+
1846
+ expect(manager.isInitialized()).toBe(true)
1847
+ expect(manager.getInstance()).toBe(mockPGlite)
1848
+ })
1849
+ })
1850
+
1851
+ describe('Lazy initialization', () => {
1852
+ it('should defer PGLite creation until first use', async () => {
1853
+ const state = createMockState()
1854
+ const env = createMockEnv()
1855
+ const doo = new PostgresDO(state as any, env)
1856
+
1857
+ const mockPGlite = createMockPGlite()
1858
+ const createSpy = vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1859
+
1860
+ // PGLite should not be created yet
1861
+ expect(createSpy).not.toHaveBeenCalled()
1862
+ expect(doo.isInitialized()).toBe(false)
1863
+
1864
+ // First query triggers initialization
1865
+ await doo.executeQuery({ sql: 'SELECT 1' })
1866
+
1867
+ // Now PGLite should be created
1868
+ expect(createSpy).toHaveBeenCalledTimes(1)
1869
+ expect(doo.isInitialized()).toBe(true)
1870
+ })
1871
+
1872
+ it('should not re-initialize on subsequent queries', async () => {
1873
+ const state = createMockState()
1874
+ const env = createMockEnv()
1875
+ const doo = new PostgresDO(state as any, env)
1876
+
1877
+ const mockPGlite = createMockPGlite()
1878
+ const createSpy = vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1879
+
1880
+ // Multiple queries
1881
+ await doo.executeQuery({ sql: 'SELECT 1' })
1882
+ await doo.executeQuery({ sql: 'SELECT 2' })
1883
+ await doo.executeQuery({ sql: 'SELECT 3' })
1884
+
1885
+ // Should only initialize once
1886
+ expect(createSpy).toHaveBeenCalledTimes(1)
1887
+ })
1888
+
1889
+ it('should support explicit initialization before first use', async () => {
1890
+ const state = createMockState()
1891
+ const env = createMockEnv()
1892
+ const doo = new PostgresDO(state as any, env)
1893
+
1894
+ const mockPGlite = createMockPGlite()
1895
+ const createSpy = vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
1896
+
1897
+ // Explicit initialization
1898
+ await doo.initPGlite()
1899
+
1900
+ expect(doo.isInitialized()).toBe(true)
1901
+ expect(createSpy).toHaveBeenCalledTimes(1)
1902
+
1903
+ // Subsequent query should not re-initialize
1904
+ await doo.executeQuery({ sql: 'SELECT 1' })
1905
+ expect(createSpy).toHaveBeenCalledTimes(1)
1906
+ })
1907
+ })
1908
+
1909
+ describe('Initialization ordering', () => {
1910
+ it('should initialize components in correct order: factory -> plugins -> migrations', async () => {
1911
+ const state = createMockState()
1912
+ state.storage.get.mockResolvedValue(undefined)
1913
+ const env = createMockEnv()
1914
+ const config: PostgresConfig = {
1915
+ database: 'test',
1916
+ plugins: { vector: true },
1917
+ migrations: {
1918
+ migrations: [{ id: '1', name: 'test', version: 1, sql: 'SELECT 1' }],
1919
+ },
1920
+ }
1921
+ const doo = new PostgresDO(state as any, env, config)
1922
+
1923
+ const executionOrder: string[] = []
1924
+ const mockPGlite = createMockPGlite()
1925
+
1926
+ // Track when PGLite is created
1927
+ vi.spyOn(doo as any, 'createPGliteInstance').mockImplementation(async () => {
1928
+ executionOrder.push('pglite_created')
1929
+ return mockPGlite
1930
+ })
1931
+
1932
+ // Track when plugins are loaded
1933
+ vi.spyOn(doo as any, 'runPluginAutoCreate').mockImplementation(async () => {
1934
+ executionOrder.push('plugins_loaded')
1935
+ })
1936
+
1937
+ await doo.initPGlite()
1938
+
1939
+ // PGLite should be created before plugins
1940
+ expect(executionOrder.indexOf('pglite_created')).toBeLessThan(
1941
+ executionOrder.indexOf('plugins_loaded')
1942
+ )
1943
+ })
1944
+
1945
+ it('should handle concurrent initialization calls safely', async () => {
1946
+ const state = createMockState()
1947
+ const env = createMockEnv()
1948
+ const doo = new PostgresDO(state as any, env)
1949
+
1950
+ const mockPGlite = createMockPGlite()
1951
+ let initCount = 0
1952
+ vi.spyOn(doo as any, 'createPGliteInstance').mockImplementation(async () => {
1953
+ initCount++
1954
+ await new Promise((r) => setTimeout(r, 10))
1955
+ return mockPGlite
1956
+ })
1957
+
1958
+ // Start multiple concurrent initializations
1959
+ const promises = [
1960
+ doo.initPGlite(),
1961
+ doo.initPGlite(),
1962
+ doo.initPGlite(),
1963
+ ]
1964
+
1965
+ await Promise.all(promises)
1966
+
1967
+ // Should only actually initialize once
1968
+ expect(initCount).toBe(1)
1969
+ })
1970
+ })
1971
+
1972
+ describe('Dependency injection for testability', () => {
1973
+ it('should allow injecting mock PGLite via manager', async () => {
1974
+ const state = createMockState()
1975
+ const env = createMockEnv()
1976
+ const doo = new PostgresDO(state as any, env)
1977
+
1978
+ const mockPGlite = createMockPGlite()
1979
+ mockPGlite.query.mockResolvedValue({
1980
+ rows: [{ result: 42 }],
1981
+ fields: [{ name: 'result', dataTypeID: 23 }],
1982
+ affectedRows: 1,
1983
+ })
1984
+
1985
+ // Inject mock directly into manager
1986
+ doo.getPGLiteManager().injectInstance(mockPGlite)
1987
+
1988
+ // Query should use the injected mock
1989
+ const result = await doo.executeQuery({ sql: 'SELECT 42 as result' })
1990
+
1991
+ expect(result.rows).toEqual([{ result: 42 }])
1992
+ expect(mockPGlite.query).toHaveBeenCalled()
1993
+ })
1994
+
1995
+ it('should allow setting factory function on manager', async () => {
1996
+ const state = createMockState()
1997
+ const env = createMockEnv()
1998
+ const doo = new PostgresDO(state as any, env)
1999
+
2000
+ const mockPGlite = createMockPGlite()
2001
+ let factoryCalled = false
2002
+
2003
+ doo.getPGLiteManager().setCreatePGLite(async () => {
2004
+ factoryCalled = true
2005
+ return mockPGlite
2006
+ })
2007
+
2008
+ await doo.initPGlite()
2009
+
2010
+ expect(factoryCalled).toBe(true)
2011
+ expect(doo.isInitialized()).toBe(true)
2012
+ })
2013
+
2014
+ it('should override default WASM loading with custom factory', async () => {
2015
+ const state = createMockState()
2016
+ const env = createMockEnv()
2017
+ const doo = new PostgresDO(state as any, env)
2018
+
2019
+ const mockPGlite = createMockPGlite()
2020
+ const customFactory = vi.fn().mockResolvedValue(mockPGlite)
2021
+
2022
+ doo.getPGLiteManager().setCreatePGLite(customFactory)
2023
+ await doo.initPGlite()
2024
+
2025
+ // Custom factory should be used instead of default WASM loading
2026
+ expect(customFactory).toHaveBeenCalled()
2027
+ })
2028
+ })
2029
+
2030
+ describe('Error handling when dependencies missing', () => {
2031
+ it('should throw descriptive error when trying to execute query without initialization and factory fails', async () => {
2032
+ const state = createMockState()
2033
+ const env = createMockEnv()
2034
+ const doo = new PostgresDO(state as any, env)
2035
+
2036
+ vi.spyOn(doo as any, 'createPGliteInstance').mockRejectedValue(
2037
+ new Error('WASM module not found')
2038
+ )
2039
+
2040
+ await expect(doo.executeQuery({ sql: 'SELECT 1' })).rejects.toThrow(
2041
+ 'WASM module not found'
2042
+ )
2043
+ })
2044
+
2045
+ it('should provide clear error when getInstance called before init', async () => {
2046
+ const { PGLiteManager } = await import('./do-pglite-manager')
2047
+ const manager = new PGLiteManager({ database: 'test' })
2048
+
2049
+ expect(() => manager.getInstance()).toThrow('PGLite not initialized')
2050
+ })
2051
+
2052
+ it('should handle factory returning null gracefully', async () => {
2053
+ const { PGLiteManager } = await import('./do-pglite-manager')
2054
+ const manager = new PGLiteManager({
2055
+ database: 'test',
2056
+ createPGLite: () => Promise.resolve(null as any),
2057
+ })
2058
+
2059
+ // Should throw during initialization when factory returns null
2060
+ await expect(manager.initialize()).rejects.toThrow()
2061
+ })
2062
+
2063
+ it('should propagate factory errors with context', async () => {
2064
+ const state = createMockState()
2065
+ const env = createMockEnv()
2066
+ const doo = new PostgresDO(state as any, env)
2067
+
2068
+ const originalError = new Error('Custom factory failed')
2069
+ doo.getPGLiteManager().setCreatePGLite(() => Promise.reject(originalError))
2070
+
2071
+ try {
2072
+ await doo.initPGlite()
2073
+ expect.fail('Should have thrown')
2074
+ } catch (error) {
2075
+ expect(error).toBe(originalError)
2076
+ }
2077
+ })
2078
+ })
2079
+
2080
+ describe('Manager reset and cleanup', () => {
2081
+ it('should allow resetting manager state', async () => {
2082
+ const { PGLiteManager } = await import('./do-pglite-manager')
2083
+ const mockPGlite = createMockPGlite()
2084
+
2085
+ const manager = new PGLiteManager({
2086
+ database: 'test',
2087
+ createPGLite: () => Promise.resolve(mockPGlite),
2088
+ })
2089
+
2090
+ await manager.initialize()
2091
+ expect(manager.isInitialized()).toBe(true)
2092
+
2093
+ manager.reset()
2094
+ expect(manager.isInitialized()).toBe(false)
2095
+ expect(manager.getInstanceOrNull()).toBeNull()
2096
+ })
2097
+
2098
+ it('should allow re-initialization after reset', async () => {
2099
+ const { PGLiteManager } = await import('./do-pglite-manager')
2100
+ const mockPGlite1 = createMockPGlite()
2101
+ const mockPGlite2 = createMockPGlite()
2102
+ let callCount = 0
2103
+
2104
+ const manager = new PGLiteManager({
2105
+ database: 'test',
2106
+ createPGLite: () => Promise.resolve(callCount++ === 0 ? mockPGlite1 : mockPGlite2),
2107
+ })
2108
+
2109
+ // First initialization
2110
+ await manager.initialize()
2111
+ expect(manager.getInstance()).toBe(mockPGlite1)
2112
+
2113
+ // Reset
2114
+ manager.reset()
2115
+
2116
+ // Re-initialize
2117
+ await manager.initialize()
2118
+ expect(manager.getInstance()).toBe(mockPGlite2)
2119
+ })
2120
+
2121
+ it('should close PGLite instance on manager close', async () => {
2122
+ const { PGLiteManager } = await import('./do-pglite-manager')
2123
+ const mockPGlite = createMockPGlite()
2124
+
2125
+ const manager = new PGLiteManager({
2126
+ database: 'test',
2127
+ createPGLite: () => Promise.resolve(mockPGlite),
2128
+ })
2129
+
2130
+ await manager.initialize()
2131
+ await manager.close()
2132
+
2133
+ expect(mockPGlite.close).toHaveBeenCalled()
2134
+ expect(manager.isInitialized()).toBe(false)
2135
+ })
2136
+ })
2137
+
2138
+ describe('Liveness check without full initialization', () => {
2139
+ it('should return false for liveness check before initialization', async () => {
2140
+ const { PGLiteManager } = await import('./do-pglite-manager')
2141
+ const manager = new PGLiteManager({ database: 'test' })
2142
+
2143
+ const isAlive = await manager.checkLiveness()
2144
+ expect(isAlive).toBe(false)
2145
+ })
2146
+
2147
+ it('should return true for liveness check after successful initialization', async () => {
2148
+ const { PGLiteManager } = await import('./do-pglite-manager')
2149
+ const mockPGlite = createMockPGlite()
2150
+ mockPGlite.query.mockResolvedValue({
2151
+ rows: [{ alive: 1 }],
2152
+ fields: [],
2153
+ affectedRows: 0,
2154
+ })
2155
+
2156
+ const manager = new PGLiteManager({
2157
+ database: 'test',
2158
+ createPGLite: () => Promise.resolve(mockPGlite),
2159
+ })
2160
+
2161
+ await manager.initialize()
2162
+ const isAlive = await manager.checkLiveness()
2163
+ expect(isAlive).toBe(true)
2164
+ })
2165
+
2166
+ it('should return false for liveness check if query fails', async () => {
2167
+ const { PGLiteManager } = await import('./do-pglite-manager')
2168
+ const mockPGlite = createMockPGlite()
2169
+ mockPGlite.query.mockRejectedValue(new Error('Query failed'))
2170
+
2171
+ const manager = new PGLiteManager({
2172
+ database: 'test',
2173
+ createPGLite: () => Promise.resolve(mockPGlite),
2174
+ })
2175
+
2176
+ await manager.initialize()
2177
+ const isAlive = await manager.checkLiveness()
2178
+ expect(isAlive).toBe(false)
2179
+ })
2180
+ })
2181
+ })
2182
+ })
2183
+
2184
+ // MOCK REDUCTION EXAMPLES (postgres-6qei)
2185
+ // These tests demonstrate the recommended pattern using helper functions.
2186
+ describe('PostgresDO with Mock Reduction Helpers', () => {
2187
+ describe('Query execution (using createTestDO)', () => {
2188
+ it('should execute queries using injected mock', async () => {
2189
+ const { doo } = createTestDO({
2190
+ mockPGliteSetup: (mock) => {
2191
+ mock.query.mockResolvedValue({
2192
+ rows: [{ id: 1, name: 'Alice' }],
2193
+ fields: [{ name: 'id', dataTypeID: 23 }],
2194
+ affectedRows: 1,
2195
+ })
2196
+ },
2197
+ })
2198
+ const result = await doo.executeQuery({ sql: 'SELECT * FROM users' })
2199
+ expect(result.rows).toEqual([{ id: 1, name: 'Alice' }])
2200
+ })
2201
+
2202
+ it('should pass parameters correctly', async () => {
2203
+ const { doo, mockPGlite } = createTestDO()
2204
+ await doo.executeQuery({
2205
+ sql: 'SELECT * FROM users WHERE id = $1',
2206
+ params: [42],
2207
+ })
2208
+ expect(mockPGlite.query).toHaveBeenCalledWith(
2209
+ 'SELECT * FROM users WHERE id = $1',
2210
+ [42]
2211
+ )
2212
+ })
2213
+ })
2214
+
2215
+ describe('Initialization (using createTestDOWithFactory)', () => {
2216
+ it('should initialize PGlite on first call', async () => {
2217
+ const { doo } = createTestDOWithFactory()
2218
+ expect(doo.isInitialized()).toBe(false)
2219
+ await doo.initPGlite()
2220
+ expect(doo.isInitialized()).toBe(true)
2221
+ })
2222
+
2223
+ it('should prevent double initialization', async () => {
2224
+ let factoryCallCount = 0
2225
+ const state = createMockState()
2226
+ const env = createMockEnv()
2227
+ const doo = new PostgresDO(state as any, env)
2228
+ const mockPGlite = createMockPGlite()
2229
+ doo.getPGLiteManager().setCreatePGLite(async () => {
2230
+ factoryCallCount++
2231
+ return mockPGlite
2232
+ })
2233
+ await doo.initPGlite()
2234
+ await doo.initPGlite()
2235
+ expect(factoryCallCount).toBe(1)
2236
+ })
2237
+ })
2238
+
2239
+ describe('Shutdown (using createTestDO)', () => {
2240
+ it('should close PGlite during shutdown', async () => {
2241
+ const { doo, mockPGlite } = createTestDO()
2242
+ await doo.shutdown({ gracePeriodMs: 100 })
2243
+ expect(mockPGlite.close).toHaveBeenCalled()
2244
+ expect(doo.getShutdownStatus()).toBe('shutdown')
2245
+ })
2246
+
2247
+ it('should reject queries after shutdown', async () => {
2248
+ const { doo } = createTestDO()
2249
+ await doo.shutdown({ gracePeriodMs: 100 })
2250
+ await expect(doo.executeQuery({ sql: 'SELECT 1' }))
2251
+ .rejects.toThrow('PostgresDO is shut down')
2252
+ })
2253
+ })
2254
+ })