pipework 0.251.0 → 0.252.1

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 (730) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/core/config/load.d.ts +2 -0
  3. package/dist/core/config/load.d.ts.map +1 -1
  4. package/dist/core/config/load.js +1 -0
  5. package/dist/core/config/load.js.map +1 -1
  6. package/dist/core/config/namespace.d.ts +1 -0
  7. package/dist/core/config/namespace.d.ts.map +1 -1
  8. package/dist/core/config/schema.d.ts +2 -0
  9. package/dist/core/config/schema.d.ts.map +1 -1
  10. package/dist/core/config/schema.js +1 -0
  11. package/dist/core/config/schema.js.map +1 -1
  12. package/dist/core/surface/types.d.ts +1 -0
  13. package/dist/core/surface/types.d.ts.map +1 -1
  14. package/dist/data/db/namespace.d.ts +3 -0
  15. package/dist/data/db/namespace.d.ts.map +1 -1
  16. package/dist/data/db/namespace.js +3 -0
  17. package/dist/data/db/namespace.js.map +1 -1
  18. package/dist/data/db/pool.d.ts.map +1 -1
  19. package/dist/data/db/pool.js +6 -1
  20. package/dist/data/db/pool.js.map +1 -1
  21. package/dist/data/db/query-label.d.ts +5 -0
  22. package/dist/data/db/query-label.d.ts.map +1 -0
  23. package/dist/data/db/query-label.js +11 -0
  24. package/dist/data/db/query-label.js.map +1 -0
  25. package/dist/data/db/query-watch.d.ts +21 -0
  26. package/dist/data/db/query-watch.d.ts.map +1 -0
  27. package/dist/data/db/query-watch.js +90 -0
  28. package/dist/data/db/query-watch.js.map +1 -0
  29. package/dist/data/query/postgres-js/driver.js +1 -1
  30. package/dist/data/query/postgres-js/driver.js.map +1 -1
  31. package/dist/data/query/postgres-js/session.d.ts +5 -1
  32. package/dist/data/query/postgres-js/session.d.ts.map +1 -1
  33. package/dist/data/query/postgres-js/session.js +16 -11
  34. package/dist/data/query/postgres-js/session.js.map +1 -1
  35. package/dist/data/query/utils.d.ts +2 -0
  36. package/dist/data/query/utils.d.ts.map +1 -1
  37. package/dist/data/query/utils.js.map +1 -1
  38. package/dist/infra/credits/schema.d.ts +1 -1
  39. package/dist/test/plugin.d.ts.map +1 -1
  40. package/dist/test/plugin.js +10 -4
  41. package/dist/test/plugin.js.map +1 -1
  42. package/package.json +4 -3
  43. package/src/async/jobs/abortable-delay.ts +18 -0
  44. package/src/async/jobs/claims.ts +52 -0
  45. package/src/async/jobs/cron.ts +179 -0
  46. package/src/async/jobs/errors.ts +56 -0
  47. package/src/async/jobs/exclusion.ts +117 -0
  48. package/src/async/jobs/execute.ts +219 -0
  49. package/src/async/jobs/index.ts +10 -0
  50. package/src/async/jobs/listener.ts +135 -0
  51. package/src/async/jobs/namespace.ts +20 -0
  52. package/src/async/jobs/queue-door.ts +44 -0
  53. package/src/async/jobs/queue.ts +1012 -0
  54. package/src/async/jobs/run-script.ts +67 -0
  55. package/src/async/jobs/scheduler.ts +218 -0
  56. package/src/async/jobs/schedules-table.ts +37 -0
  57. package/src/async/jobs/serialize-error.ts +48 -0
  58. package/src/async/jobs/table.ts +191 -0
  59. package/src/async/pipeline/define.ts +53 -0
  60. package/src/async/pipeline/errors.ts +35 -0
  61. package/src/async/pipeline/execute.ts +53 -0
  62. package/src/async/pipeline/index.ts +13 -0
  63. package/src/async/pipeline/namespace.ts +12 -0
  64. package/src/async/pipeline/resume.ts +67 -0
  65. package/src/async/pipeline/run-steps.ts +98 -0
  66. package/src/async/pipeline/types.ts +57 -0
  67. package/src/async/state-machine/define.ts +64 -0
  68. package/src/async/state-machine/errors.ts +29 -0
  69. package/src/async/state-machine/index.ts +3 -0
  70. package/src/async/state-machine/namespace.ts +12 -0
  71. package/src/async/state-machine/transition.ts +90 -0
  72. package/src/async/state-machine/types.ts +37 -0
  73. package/src/async/steps/errors.ts +31 -0
  74. package/src/async/steps/graph.ts +1214 -0
  75. package/src/async/steps/hash.ts +40 -0
  76. package/src/async/steps/index.ts +7 -0
  77. package/src/async/steps/namespace.ts +7 -0
  78. package/src/async/steps/table.ts +97 -0
  79. package/src/async/steps/types.ts +318 -0
  80. package/src/audit/chain/index.ts +9 -0
  81. package/src/audit/chain/install.ts +113 -0
  82. package/src/audit/chain/retire.ts +52 -0
  83. package/src/audit/chain/verify.ts +257 -0
  84. package/src/audit/query/cursor.ts +37 -0
  85. package/src/audit/query/index.ts +9 -0
  86. package/src/audit/query/query.ts +223 -0
  87. package/src/audit/schema/audit-record-fields.ts +68 -0
  88. package/src/audit/schema/audit-record.ts +23 -0
  89. package/src/auth/auth/audit.ts +31 -0
  90. package/src/auth/auth/chain.ts +84 -0
  91. package/src/auth/auth/cookie.ts +136 -0
  92. package/src/auth/auth/email-links.ts +311 -0
  93. package/src/auth/auth/guard.ts +128 -0
  94. package/src/auth/auth/index.ts +18 -0
  95. package/src/auth/auth/multi-org.ts +337 -0
  96. package/src/auth/auth/namespace.ts +34 -0
  97. package/src/auth/auth/parse-expiry.ts +13 -0
  98. package/src/auth/auth/passwords.ts +110 -0
  99. package/src/auth/auth/schema.ts +110 -0
  100. package/src/auth/auth/sessions.ts +565 -0
  101. package/src/auth/auth/sign-in.ts +156 -0
  102. package/src/auth/auth/signing-keys.ts +69 -0
  103. package/src/auth/auth/types.ts +26 -0
  104. package/src/auth/auth/uuid.ts +10 -0
  105. package/src/auth/rbac/cache.ts +55 -0
  106. package/src/auth/rbac/check.ts +30 -0
  107. package/src/auth/rbac/create.ts +35 -0
  108. package/src/auth/rbac/index.ts +5 -0
  109. package/src/auth/rbac/middleware.ts +20 -0
  110. package/src/auth/rbac/namespace.ts +15 -0
  111. package/src/auth/rbac/resolve.ts +31 -0
  112. package/src/auth/rbac/schema.sql +31 -0
  113. package/src/auth/rbac/seed.ts +67 -0
  114. package/src/auth/rbac/tables.ts +32 -0
  115. package/src/auth/rbac/types.ts +65 -0
  116. package/src/auth/tenant/extract.ts +33 -0
  117. package/src/auth/tenant/in-tenant.ts +49 -0
  118. package/src/auth/tenant/index.ts +7 -0
  119. package/src/auth/tenant/namespace.ts +23 -0
  120. package/src/auth/tenant/propagate.ts +20 -0
  121. package/src/auth/tenant/rls.ts +120 -0
  122. package/src/auth/tenant/scope.ts +33 -0
  123. package/src/auth/tenant/scoped-db.ts +581 -0
  124. package/src/auth/tenant/types.ts +14 -0
  125. package/src/auth/tenant/validate.ts +27 -0
  126. package/src/cli/commands/add.ts +158 -0
  127. package/src/cli/commands/alerts.ts +98 -0
  128. package/src/cli/commands/check.ts +1418 -0
  129. package/src/cli/commands/codemod.ts +78 -0
  130. package/src/cli/commands/db.ts +356 -0
  131. package/src/cli/commands/dev.ts +101 -0
  132. package/src/cli/commands/generate.ts +75 -0
  133. package/src/cli/commands/init.ts +36 -0
  134. package/src/cli/commands/install.ts +28 -0
  135. package/src/cli/commands/lint.ts +62 -0
  136. package/src/cli/commands/migrate.ts +132 -0
  137. package/src/cli/commands/openapi.ts +63 -0
  138. package/src/cli/commands/remove.ts +72 -0
  139. package/src/cli/commands/run.ts +50 -0
  140. package/src/cli/commands/scope.ts +54 -0
  141. package/src/cli/commands/serve.ts +68 -0
  142. package/src/cli/commands/shard.ts +31 -0
  143. package/src/cli/commands/shared/config-pipework-version.ts +28 -0
  144. package/src/cli/commands/shared/find-config.ts +22 -0
  145. package/src/cli/commands/shared/load-config.ts +35 -0
  146. package/src/cli/commands/shared/pnpm-install.ts +95 -0
  147. package/src/cli/commands/shared/report-removed.ts +8 -0
  148. package/src/cli/commands/sync.ts +32 -0
  149. package/src/cli/commands/test.ts +307 -0
  150. package/src/cli/commands/upgrade.ts +48 -0
  151. package/src/cli/dev-bootstrap.ts +24 -0
  152. package/src/cli/errors.ts +10 -0
  153. package/src/cli/index.ts +303 -0
  154. package/src/cli/output.ts +17 -0
  155. package/src/cli/port.ts +15 -0
  156. package/src/cli/surface-kinds.ts +20 -0
  157. package/src/client/index.ts +4 -0
  158. package/src/client/poll.ts +130 -0
  159. package/src/client/report-fault.ts +119 -0
  160. package/src/core/config/app-pool.ts +19 -0
  161. package/src/core/config/aws-env.ts +29 -0
  162. package/src/core/config/base-dir.ts +24 -0
  163. package/src/core/config/discover.ts +64 -0
  164. package/src/core/config/env-resolve.ts +87 -0
  165. package/src/core/config/env-types.ts +116 -0
  166. package/src/core/config/env.ts +55 -0
  167. package/src/core/config/errors.ts +9 -0
  168. package/src/core/config/import-config.ts +40 -0
  169. package/src/core/config/index.ts +8 -0
  170. package/src/core/config/load.ts +417 -0
  171. package/src/core/config/namespace.ts +14 -0
  172. package/src/core/config/resolve.ts +195 -0
  173. package/src/core/config/schema.ts +488 -0
  174. package/src/core/config/statement-observer.ts +48 -0
  175. package/src/core/config/ts-inline-hooks.ts +75 -0
  176. package/src/core/config/ts-register.ts +4 -0
  177. package/src/core/config/ts-resolve-hooks.ts +101 -0
  178. package/src/core/errors/base.ts +49 -0
  179. package/src/core/errors/http.ts +146 -0
  180. package/src/core/errors/index.ts +2 -0
  181. package/src/core/errors/namespace.ts +31 -0
  182. package/src/core/lifecycle/drain.ts +33 -0
  183. package/src/core/lifecycle/health.ts +72 -0
  184. package/src/core/lifecycle/index.ts +4 -0
  185. package/src/core/lifecycle/namespace.ts +7 -0
  186. package/src/core/lifecycle/startup.ts +102 -0
  187. package/src/core/lifecycle/types.ts +36 -0
  188. package/src/core/logging/context.ts +60 -0
  189. package/src/core/logging/error-chain.ts +68 -0
  190. package/src/core/logging/index.ts +5 -0
  191. package/src/core/logging/logger.ts +65 -0
  192. package/src/core/logging/namespace.ts +16 -0
  193. package/src/core/logging/proxy.ts +22 -0
  194. package/src/core/logging/redact-match.ts +24 -0
  195. package/src/core/logging/types.ts +47 -0
  196. package/src/core/pipework.ts +566 -0
  197. package/src/core/runtime/broker.ts +69 -0
  198. package/src/core/surface/http.ts +133 -0
  199. package/src/core/surface/index.ts +11 -0
  200. package/src/core/surface/job-timeout.ts +40 -0
  201. package/src/core/surface/namespace.ts +13 -0
  202. package/src/core/surface/script.ts +33 -0
  203. package/src/core/surface/start.ts +142 -0
  204. package/src/core/surface/types.ts +225 -0
  205. package/src/core/surface/validate.ts +88 -0
  206. package/src/core/surface/worker.ts +528 -0
  207. package/src/core/validation/connectivity.ts +49 -0
  208. package/src/core/validation/domain.ts +99 -0
  209. package/src/core/validation/index.ts +5 -0
  210. package/src/core/validation/queue-tables.ts +312 -0
  211. package/src/core/validation/rls-role.ts +138 -0
  212. package/src/core/validation/startup.ts +51 -0
  213. package/src/core/validation/surfaces.ts +65 -0
  214. package/src/core/validation/types.ts +25 -0
  215. package/src/data/db/advisory-lock.ts +55 -0
  216. package/src/data/db/aggregates.ts +172 -0
  217. package/src/data/db/array-elements.ts +111 -0
  218. package/src/data/db/bulk-set.ts +53 -0
  219. package/src/data/db/col/index.ts +14 -0
  220. package/src/data/db/composed.ts +53 -0
  221. package/src/data/db/db.ts +276 -0
  222. package/src/data/db/excluded.ts +16 -0
  223. package/src/data/db/expressions.ts +473 -0
  224. package/src/data/db/filter.ts +90 -0
  225. package/src/data/db/function-source.ts +114 -0
  226. package/src/data/db/identifiers.ts +16 -0
  227. package/src/data/db/idx/index.ts +9 -0
  228. package/src/data/db/in-list.ts +49 -0
  229. package/src/data/db/index.ts +9 -0
  230. package/src/data/db/insert-split.ts +137 -0
  231. package/src/data/db/instrumentation.ts +82 -0
  232. package/src/data/db/maintenance.ts +28 -0
  233. package/src/data/db/namespace.ts +107 -0
  234. package/src/data/db/owner-labels.ts +9 -0
  235. package/src/data/db/pool.ts +187 -0
  236. package/src/data/db/query-label.ts +13 -0
  237. package/src/data/db/query-watch.ts +116 -0
  238. package/src/data/db/raw-client-warning.ts +37 -0
  239. package/src/data/db/readonly.ts +23 -0
  240. package/src/data/db/reservation.ts +151 -0
  241. package/src/data/db/schema-features.ts +14 -0
  242. package/src/data/db/serializable.ts +83 -0
  243. package/src/data/db/sql.ts +1 -0
  244. package/src/data/db/timeouts.ts +76 -0
  245. package/src/data/db/types.ts +18 -0
  246. package/src/data/db/unbound.ts +33 -0
  247. package/src/data/db/values.ts +29 -0
  248. package/src/data/domain/brand.ts +15 -0
  249. package/src/data/domain/build-factory.ts +193 -0
  250. package/src/data/domain/build-schema.ts +161 -0
  251. package/src/data/domain/build-table.ts +355 -0
  252. package/src/data/domain/define.ts +239 -0
  253. package/src/data/domain/external-registry.ts +34 -0
  254. package/src/data/domain/external.ts +77 -0
  255. package/src/data/domain/field.ts +279 -0
  256. package/src/data/domain/index.ts +13 -0
  257. package/src/data/domain/naming.ts +6 -0
  258. package/src/data/domain/projections.ts +57 -0
  259. package/src/data/domain/trace-safe-projection.ts +31 -0
  260. package/src/data/domain/traits.ts +108 -0
  261. package/src/data/domain/types.ts +289 -0
  262. package/src/data/jsonb/composed.ts +18 -0
  263. package/src/data/jsonb/index.ts +1 -0
  264. package/src/data/jsonb/namespace.ts +30 -0
  265. package/src/data/jsonb/query.ts +86 -0
  266. package/src/data/migrate/append-only-generate.ts +47 -0
  267. package/src/data/migrate/applied.ts +47 -0
  268. package/src/data/migrate/apply.ts +309 -0
  269. package/src/data/migrate/check.ts +119 -0
  270. package/src/data/migrate/diff.ts +357 -0
  271. package/src/data/migrate/door-generate.ts +130 -0
  272. package/src/data/migrate/framework-rls.ts +58 -0
  273. package/src/data/migrate/generate.ts +201 -0
  274. package/src/data/migrate/history.ts +215 -0
  275. package/src/data/migrate/index.ts +9 -0
  276. package/src/data/migrate/internal-definitions.ts +175 -0
  277. package/src/data/migrate/post-process.ts +73 -0
  278. package/src/data/migrate/pragma.ts +73 -0
  279. package/src/data/migrate/provision-framework.ts +147 -0
  280. package/src/data/migrate/rls-generate.ts +61 -0
  281. package/src/data/migrate/run.ts +124 -0
  282. package/src/data/migrate/safety.ts +167 -0
  283. package/src/data/migrate/snapshot.ts +368 -0
  284. package/src/data/migrate/sql-emit.ts +392 -0
  285. package/src/data/migrate/statements.ts +312 -0
  286. package/src/data/query/alias.ts +126 -0
  287. package/src/data/query/batch.ts +8 -0
  288. package/src/data/query/cache/core/cache.ts +78 -0
  289. package/src/data/query/cache/core/index.ts +1 -0
  290. package/src/data/query/cache/core/types.ts +29 -0
  291. package/src/data/query/cache/readme.md +230 -0
  292. package/src/data/query/casing.ts +76 -0
  293. package/src/data/query/collation.ts +11 -0
  294. package/src/data/query/column-builder.ts +370 -0
  295. package/src/data/query/column.ts +150 -0
  296. package/src/data/query/entity.ts +42 -0
  297. package/src/data/query/errors.ts +33 -0
  298. package/src/data/query/index.ts +14 -0
  299. package/src/data/query/logger.ts +47 -0
  300. package/src/data/query/operations.ts +45 -0
  301. package/src/data/query/pg-core/alias.ts +12 -0
  302. package/src/data/query/pg-core/checks.ts +32 -0
  303. package/src/data/query/pg-core/columns/all.ts +71 -0
  304. package/src/data/query/pg-core/columns/bigint.ts +110 -0
  305. package/src/data/query/pg-core/columns/bigserial.ts +128 -0
  306. package/src/data/query/pg-core/columns/boolean.ts +43 -0
  307. package/src/data/query/pg-core/columns/char.ts +85 -0
  308. package/src/data/query/pg-core/columns/cidr.ts +43 -0
  309. package/src/data/query/pg-core/columns/common.ts +366 -0
  310. package/src/data/query/pg-core/columns/custom.ts +232 -0
  311. package/src/data/query/pg-core/columns/date.common.ts +15 -0
  312. package/src/data/query/pg-core/columns/date.ts +112 -0
  313. package/src/data/query/pg-core/columns/double-precision.ts +55 -0
  314. package/src/data/query/pg-core/columns/enum.ts +201 -0
  315. package/src/data/query/pg-core/columns/index.ts +35 -0
  316. package/src/data/query/pg-core/columns/inet.ts +43 -0
  317. package/src/data/query/pg-core/columns/int.common.ts +57 -0
  318. package/src/data/query/pg-core/columns/integer.ts +53 -0
  319. package/src/data/query/pg-core/columns/interval.ts +83 -0
  320. package/src/data/query/pg-core/columns/json.ts +58 -0
  321. package/src/data/query/pg-core/columns/jsonb.ts +56 -0
  322. package/src/data/query/pg-core/columns/line.ts +117 -0
  323. package/src/data/query/pg-core/columns/macaddr.ts +43 -0
  324. package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
  325. package/src/data/query/pg-core/columns/numeric.ts +227 -0
  326. package/src/data/query/pg-core/columns/point.ts +127 -0
  327. package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
  328. package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
  329. package/src/data/query/pg-core/columns/real.ts +58 -0
  330. package/src/data/query/pg-core/columns/serial.ts +55 -0
  331. package/src/data/query/pg-core/columns/smallint.ts +53 -0
  332. package/src/data/query/pg-core/columns/smallserial.ts +60 -0
  333. package/src/data/query/pg-core/columns/text.ts +67 -0
  334. package/src/data/query/pg-core/columns/time.ts +72 -0
  335. package/src/data/query/pg-core/columns/timestamp.ts +163 -0
  336. package/src/data/query/pg-core/columns/uuid.ts +51 -0
  337. package/src/data/query/pg-core/columns/varchar.ts +89 -0
  338. package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
  339. package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
  340. package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
  341. package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
  342. package/src/data/query/pg-core/db.ts +674 -0
  343. package/src/data/query/pg-core/dialect.ts +1404 -0
  344. package/src/data/query/pg-core/expressions.ts +25 -0
  345. package/src/data/query/pg-core/foreign-keys.ts +130 -0
  346. package/src/data/query/pg-core/index.ts +21 -0
  347. package/src/data/query/pg-core/indexes.ts +276 -0
  348. package/src/data/query/pg-core/policies.ts +56 -0
  349. package/src/data/query/pg-core/primary-keys.ts +62 -0
  350. package/src/data/query/pg-core/query-builders/count.ts +86 -0
  351. package/src/data/query/pg-core/query-builders/delete.ts +293 -0
  352. package/src/data/query/pg-core/query-builders/index.ts +7 -0
  353. package/src/data/query/pg-core/query-builders/insert.ts +452 -0
  354. package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
  355. package/src/data/query/pg-core/query-builders/query.ts +157 -0
  356. package/src/data/query/pg-core/query-builders/raw.ts +49 -0
  357. package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
  358. package/src/data/query/pg-core/query-builders/select.ts +1346 -0
  359. package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
  360. package/src/data/query/pg-core/query-builders/update.ts +626 -0
  361. package/src/data/query/pg-core/roles.ts +41 -0
  362. package/src/data/query/pg-core/schema.ts +72 -0
  363. package/src/data/query/pg-core/sequence.ts +41 -0
  364. package/src/data/query/pg-core/session.ts +292 -0
  365. package/src/data/query/pg-core/subquery.ts +46 -0
  366. package/src/data/query/pg-core/table.ts +252 -0
  367. package/src/data/query/pg-core/unique-constraint.ts +73 -0
  368. package/src/data/query/pg-core/utils/array.ts +95 -0
  369. package/src/data/query/pg-core/utils/index.ts +1 -0
  370. package/src/data/query/pg-core/utils.ts +104 -0
  371. package/src/data/query/pg-core/view-base.ts +14 -0
  372. package/src/data/query/pg-core/view-common.ts +1 -0
  373. package/src/data/query/pg-core/view.ts +435 -0
  374. package/src/data/query/pg-core/with-builder.ts +41 -0
  375. package/src/data/query/postgres-js/README.md +46 -0
  376. package/src/data/query/postgres-js/array-parser.ts +45 -0
  377. package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
  378. package/src/data/query/postgres-js/driver.ts +163 -0
  379. package/src/data/query/postgres-js/index.ts +2 -0
  380. package/src/data/query/postgres-js/session.ts +234 -0
  381. package/src/data/query/primary-key.ts +11 -0
  382. package/src/data/query/query-builders/query-builder.ts +19 -0
  383. package/src/data/query/query-builders/select.types.ts +175 -0
  384. package/src/data/query/query-promise.ts +35 -0
  385. package/src/data/query/relations.ts +725 -0
  386. package/src/data/query/runnable-query.ts +12 -0
  387. package/src/data/query/selection-proxy.ts +121 -0
  388. package/src/data/query/session.ts +8 -0
  389. package/src/data/query/sql/expressions/conditions.ts +741 -0
  390. package/src/data/query/sql/expressions/index.ts +2 -0
  391. package/src/data/query/sql/expressions/select.ts +45 -0
  392. package/src/data/query/sql/functions/aggregate.ts +129 -0
  393. package/src/data/query/sql/functions/index.ts +2 -0
  394. package/src/data/query/sql/functions/vector.ts +178 -0
  395. package/src/data/query/sql/index.ts +3 -0
  396. package/src/data/query/sql/sql.ts +794 -0
  397. package/src/data/query/subquery.ts +53 -0
  398. package/src/data/query/table.ts +208 -0
  399. package/src/data/query/table.utils.ts +2 -0
  400. package/src/data/query/tracing-utils.ts +3 -0
  401. package/src/data/query/tracing.ts +11 -0
  402. package/src/data/query/utils.ts +357 -0
  403. package/src/data/query/version.ts +4 -0
  404. package/src/data/query/view-common.ts +1 -0
  405. package/src/data/schema/branded.ts +13 -0
  406. package/src/data/schema/generated/coerce.ts +5 -0
  407. package/src/data/schema/generated/combinator.ts +6 -0
  408. package/src/data/schema/generated/encoding.ts +5 -0
  409. package/src/data/schema/generated/error.ts +6 -0
  410. package/src/data/schema/generated/format.ts +5 -0
  411. package/src/data/schema/generated/type-constructor.ts +10 -0
  412. package/src/data/schema/generated/type.ts +6 -0
  413. package/src/data/schema/index.ts +6 -0
  414. package/src/data/schema/json-schema.ts +33 -0
  415. package/src/data/schema/namespace.ts +55 -0
  416. package/src/data/schema/parse.ts +39 -0
  417. package/src/data/schema/types.ts +39 -0
  418. package/src/data/temporal/append-only.ts +134 -0
  419. package/src/data/temporal/close.ts +27 -0
  420. package/src/data/temporal/columns.ts +10 -0
  421. package/src/data/temporal/definition-queries.ts +70 -0
  422. package/src/data/temporal/errors.ts +10 -0
  423. package/src/data/temporal/get-current.ts +22 -0
  424. package/src/data/temporal/index.ts +9 -0
  425. package/src/data/temporal/namespace.ts +36 -0
  426. package/src/data/temporal/query.ts +25 -0
  427. package/src/data/temporal/resolve.ts +17 -0
  428. package/src/data/temporal/revise.ts +67 -0
  429. package/src/data/temporal/types.ts +22 -0
  430. package/src/data/valve/artifact.ts +33 -0
  431. package/src/data/valve/contract-diff.ts +21 -0
  432. package/src/data/valve/cross.ts +57 -0
  433. package/src/data/valve/crossing-ledger.ts +50 -0
  434. package/src/data/valve/decision.ts +44 -0
  435. package/src/data/valve/durable-crossing.ts +52 -0
  436. package/src/data/valve/execute-crossing.ts +77 -0
  437. package/src/data/valve/faucet.ts +56 -0
  438. package/src/data/valve/gate.ts +114 -0
  439. package/src/data/valve/graph.ts +77 -0
  440. package/src/data/valve/index.ts +53 -0
  441. package/src/data/valve/namespace.ts +57 -0
  442. package/src/data/valve/registry.ts +50 -0
  443. package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
  444. package/src/data/valve/schema/valve-crossing.ts +9 -0
  445. package/src/data/valve/supply.ts +154 -0
  446. package/src/data/valve/types.ts +143 -0
  447. package/src/data/vector/columns.ts +27 -0
  448. package/src/data/vector/index.ts +4 -0
  449. package/src/data/vector/namespace.ts +33 -0
  450. package/src/data/vector/query.ts +85 -0
  451. package/src/data/vector/validate.ts +16 -0
  452. package/src/data/write/audit/actor.ts +15 -0
  453. package/src/data/write/audit/audit-columns.ts +18 -0
  454. package/src/data/write/audit/audit-select.ts +111 -0
  455. package/src/data/write/audit/bound-transaction.ts +14 -0
  456. package/src/data/write/audit/cte-compile.ts +32 -0
  457. package/src/data/write/audit/decode-returning.ts +47 -0
  458. package/src/data/write/audit/final-select.ts +43 -0
  459. package/src/data/write/audit/infra-audit.ts +36 -0
  460. package/src/data/write/audit/primary-key.ts +65 -0
  461. package/src/data/write/audit/projection.ts +41 -0
  462. package/src/data/write/audit/read-touches.ts +86 -0
  463. package/src/data/write/audit/touch-match.ts +78 -0
  464. package/src/data/write/audit/verb-delete.ts +62 -0
  465. package/src/data/write/audit/verb-insert.ts +36 -0
  466. package/src/data/write/audit/verb-select.ts +47 -0
  467. package/src/data/write/audit/verb-update.ts +60 -0
  468. package/src/data/write/audit/verb-upsert.ts +104 -0
  469. package/src/data/write/conflict.ts +43 -0
  470. package/src/data/write/delete.ts +38 -0
  471. package/src/data/write/execute.ts +243 -0
  472. package/src/data/write/index.ts +11 -0
  473. package/src/data/write/insert.ts +63 -0
  474. package/src/data/write/state.ts +43 -0
  475. package/src/data/write/update.ts +54 -0
  476. package/src/data/write/upsert.ts +58 -0
  477. package/src/data/write/values.ts +19 -0
  478. package/src/index.ts +230 -0
  479. package/src/infra/access-links/code.ts +70 -0
  480. package/src/infra/access-links/handle.ts +892 -0
  481. package/src/infra/access-links/index.ts +9 -0
  482. package/src/infra/access-links/namespace.ts +30 -0
  483. package/src/infra/access-links/person-check.ts +177 -0
  484. package/src/infra/access-links/schema.ts +71 -0
  485. package/src/infra/alerts/async-sources.ts +231 -0
  486. package/src/infra/alerts/audit.ts +36 -0
  487. package/src/infra/alerts/beat.ts +123 -0
  488. package/src/infra/alerts/client-faults.ts +111 -0
  489. package/src/infra/alerts/faults.ts +156 -0
  490. package/src/infra/alerts/handle.ts +778 -0
  491. package/src/infra/alerts/http.ts +192 -0
  492. package/src/infra/alerts/index.ts +12 -0
  493. package/src/infra/alerts/infra-sources.ts +180 -0
  494. package/src/infra/alerts/namespace.ts +81 -0
  495. package/src/infra/alerts/redact.ts +21 -0
  496. package/src/infra/alerts/request-faults.ts +41 -0
  497. package/src/infra/alerts/schema.ts +124 -0
  498. package/src/infra/alerts/sinks.ts +125 -0
  499. package/src/infra/alerts/source-options.ts +26 -0
  500. package/src/infra/alerts/sources.ts +503 -0
  501. package/src/infra/alerts/subsystem-sources.ts +137 -0
  502. package/src/infra/audit/emit.ts +87 -0
  503. package/src/infra/audit/index.ts +2 -0
  504. package/src/infra/audit/namespace.ts +22 -0
  505. package/src/infra/audit/schema.sql +35 -0
  506. package/src/infra/audit/types.ts +18 -0
  507. package/src/infra/aws/credentials.ts +147 -0
  508. package/src/infra/aws/sigv4.ts +140 -0
  509. package/src/infra/cache/create.ts +58 -0
  510. package/src/infra/cache/entry.ts +81 -0
  511. package/src/infra/cache/index.ts +4 -0
  512. package/src/infra/cache/namespace.ts +10 -0
  513. package/src/infra/cache/tenant.ts +93 -0
  514. package/src/infra/cache/types.ts +24 -0
  515. package/src/infra/crawl/audit.ts +35 -0
  516. package/src/infra/crawl/errors.ts +25 -0
  517. package/src/infra/crawl/handle.ts +693 -0
  518. package/src/infra/crawl/index.ts +9 -0
  519. package/src/infra/crawl/links.ts +160 -0
  520. package/src/infra/crawl/namespace.ts +36 -0
  521. package/src/infra/crawl/robots.ts +100 -0
  522. package/src/infra/crawl/schema.ts +89 -0
  523. package/src/infra/credit-line/handle.ts +883 -0
  524. package/src/infra/credit-line/index.ts +6 -0
  525. package/src/infra/credit-line/namespace.ts +7 -0
  526. package/src/infra/credit-line/schema.ts +96 -0
  527. package/src/infra/credits/handle.ts +706 -0
  528. package/src/infra/credits/index.ts +5 -0
  529. package/src/infra/credits/namespace.ts +7 -0
  530. package/src/infra/credits/schema.ts +83 -0
  531. package/src/infra/email/audit.ts +36 -0
  532. package/src/infra/email/inbound.ts +622 -0
  533. package/src/infra/email/index.ts +11 -0
  534. package/src/infra/email/mail.ts +517 -0
  535. package/src/infra/email/mime.ts +447 -0
  536. package/src/infra/email/namespace.ts +22 -0
  537. package/src/infra/email/providers.ts +111 -0
  538. package/src/infra/email/schema.ts +96 -0
  539. package/src/infra/email/sns.ts +200 -0
  540. package/src/infra/email/unsubscribe.ts +44 -0
  541. package/src/infra/fetch/address.ts +88 -0
  542. package/src/infra/fetch/connect-retry.ts +87 -0
  543. package/src/infra/fetch/handle.ts +329 -0
  544. package/src/infra/fetch/index.ts +7 -0
  545. package/src/infra/fetch/namespace.ts +70 -0
  546. package/src/infra/idempotency/index.ts +3 -0
  547. package/src/infra/idempotency/middleware.ts +87 -0
  548. package/src/infra/idempotency/store.ts +92 -0
  549. package/src/infra/idempotency/types.ts +30 -0
  550. package/src/infra/join-requests/handle.ts +312 -0
  551. package/src/infra/join-requests/index.ts +2 -0
  552. package/src/infra/join-requests/namespace.ts +7 -0
  553. package/src/infra/join-requests/schema.ts +33 -0
  554. package/src/infra/outbox/core.ts +165 -0
  555. package/src/infra/quota/errors.ts +32 -0
  556. package/src/infra/quota/handle.ts +215 -0
  557. package/src/infra/quota/index.ts +5 -0
  558. package/src/infra/quota/namespace.ts +7 -0
  559. package/src/infra/quota/schema.ts +15 -0
  560. package/src/infra/storage/backend.ts +34 -0
  561. package/src/infra/storage/handle.ts +513 -0
  562. package/src/infra/storage/index.ts +9 -0
  563. package/src/infra/storage/local.ts +104 -0
  564. package/src/infra/storage/namespace.ts +13 -0
  565. package/src/infra/storage/s3.ts +257 -0
  566. package/src/infra/storage/schema.ts +24 -0
  567. package/src/infra/support/handle.ts +854 -0
  568. package/src/infra/support/http.ts +229 -0
  569. package/src/infra/support/index.ts +7 -0
  570. package/src/infra/support/namespace.ts +12 -0
  571. package/src/infra/support/schema.ts +96 -0
  572. package/src/infra/webhook/inbound.ts +45 -0
  573. package/src/infra/webhook/index.ts +5 -0
  574. package/src/infra/webhook/namespace.ts +24 -0
  575. package/src/infra/webhook/outbound.ts +315 -0
  576. package/src/infra/webhook/sign.ts +32 -0
  577. package/src/infra/webhook/verify.ts +82 -0
  578. package/src/invariants/assert.ts +26 -0
  579. package/src/invariants/index.ts +1 -0
  580. package/src/lint/config.ts +56 -0
  581. package/src/lint/doctrine.ts +163 -0
  582. package/src/lint/include.ts +97 -0
  583. package/src/lint/index.ts +3 -0
  584. package/src/lint/preset.ts +10 -0
  585. package/src/lint/resolver.ts +218 -0
  586. package/src/lint/rules/no-reexports.ts +46 -0
  587. package/src/request/behavior/audited.ts +85 -0
  588. package/src/request/behavior/cached.ts +62 -0
  589. package/src/request/behavior/compose.ts +28 -0
  590. package/src/request/behavior/index.ts +5 -0
  591. package/src/request/behavior/namespace.ts +16 -0
  592. package/src/request/behavior/types.ts +26 -0
  593. package/src/request/behavior/versioned.ts +54 -0
  594. package/src/request/context/create.ts +103 -0
  595. package/src/request/context/guard.ts +49 -0
  596. package/src/request/context/index.ts +4 -0
  597. package/src/request/context/run-in-transaction.ts +200 -0
  598. package/src/request/context/store.ts +28 -0
  599. package/src/request/context/types.ts +50 -0
  600. package/src/request/di/builder.ts +535 -0
  601. package/src/request/di/index.ts +8 -0
  602. package/src/request/di/resolve.ts +271 -0
  603. package/src/request/di/types.ts +262 -0
  604. package/src/request/fitting/namespace.ts +7 -0
  605. package/src/request/fixture/batch.ts +71 -0
  606. package/src/request/fixture/builder.ts +26 -0
  607. package/src/request/fixture/errors.ts +10 -0
  608. package/src/request/fixture/index.ts +8 -0
  609. package/src/request/fixture/namespace.ts +23 -0
  610. package/src/request/fixture/paginate.ts +44 -0
  611. package/src/request/fixture/to-handlers.ts +260 -0
  612. package/src/request/fixture/types.ts +79 -0
  613. package/src/request/flow/act-as.ts +78 -0
  614. package/src/request/flow/namespace.ts +17 -0
  615. package/src/request/http/error-step.ts +42 -0
  616. package/src/request/http/file.ts +141 -0
  617. package/src/request/http/index.ts +4 -0
  618. package/src/request/http/middleware.ts +141 -0
  619. package/src/request/http/namespace.ts +5 -0
  620. package/src/request/http/rate-limit-classes.ts +170 -0
  621. package/src/request/http/response.ts +82 -0
  622. package/src/request/http/server.ts +916 -0
  623. package/src/request/http/sniff.ts +261 -0
  624. package/src/request/http/types.ts +250 -0
  625. package/src/request/http/upload.ts +284 -0
  626. package/src/request/internal/text.ts +6 -0
  627. package/src/request/openapi/generate.ts +205 -0
  628. package/src/request/openapi/index.ts +2 -0
  629. package/src/request/openapi/namespace.ts +7 -0
  630. package/src/test/auth.ts +13 -0
  631. package/src/test/auto-setup.ts +45 -0
  632. package/src/test/context.ts +91 -0
  633. package/src/test/crawl-fixture.ts +157 -0
  634. package/src/test/discover-fork.ts +17 -0
  635. package/src/test/fingerprint.ts +135 -0
  636. package/src/test/globals.d.ts +7 -0
  637. package/src/test/index.ts +19 -0
  638. package/src/test/namespace.ts +87 -0
  639. package/src/test/plugin.ts +189 -0
  640. package/src/test/progress.ts +185 -0
  641. package/src/test/reap-after-run.ts +28 -0
  642. package/src/test/reap.ts +286 -0
  643. package/src/test/reset.ts +253 -0
  644. package/src/test/savepoints.ts +172 -0
  645. package/src/test/setup.ts +1422 -0
  646. package/src/test/system-channel.ts +50 -0
  647. package/src/test/vitest-plugin.ts +142 -0
  648. package/src/test/vitest-workspace.ts +507 -0
  649. package/src/test/vitest.ts +333 -0
  650. package/src/test/watch.ts +105 -0
  651. package/src/trace/capture/bounded-serializer.ts +146 -0
  652. package/src/trace/cardinality/analyze.ts +173 -0
  653. package/src/trace/cardinality/branch-context.ts +214 -0
  654. package/src/trace/cardinality/check.ts +33 -0
  655. package/src/trace/cardinality/classify-edge.ts +64 -0
  656. package/src/trace/cardinality/structural-max.ts +107 -0
  657. package/src/trace/check/coverage-check.ts +188 -0
  658. package/src/trace/check/flow-check.ts +103 -0
  659. package/src/trace/check/flow-step-site.ts +234 -0
  660. package/src/trace/check/io-pattern.ts +116 -0
  661. package/src/trace/codemod/add-cardinality.ts +152 -0
  662. package/src/trace/codemod/run.ts +80 -0
  663. package/src/trace/entry/child-trace.ts +21 -0
  664. package/src/trace/entry/close-trace.ts +87 -0
  665. package/src/trace/entry/finalize-trace.ts +28 -0
  666. package/src/trace/entry/open-trace.ts +138 -0
  667. package/src/trace/entry/parent-trace.ts +20 -0
  668. package/src/trace/entry/parse-traceparent.ts +39 -0
  669. package/src/trace/entry/process-start.ts +38 -0
  670. package/src/trace/entry/trace-context.ts +26 -0
  671. package/src/trace/entry/tracing-enabled.ts +10 -0
  672. package/src/trace/external/record.ts +195 -0
  673. package/src/trace/external/report.ts +66 -0
  674. package/src/trace/namespace.ts +19 -0
  675. package/src/trace/partition/day.ts +47 -0
  676. package/src/trace/partition/index.ts +14 -0
  677. package/src/trace/partition/partition-name.ts +23 -0
  678. package/src/trace/partition/plan.ts +82 -0
  679. package/src/trace/partition/schedule.ts +26 -0
  680. package/src/trace/partition/startup-hook.ts +39 -0
  681. package/src/trace/partition/sync.ts +154 -0
  682. package/src/trace/partition/tables.ts +53 -0
  683. package/src/trace/read/tree.ts +83 -0
  684. package/src/trace/retain/copy-on-error.ts +76 -0
  685. package/src/trace/runtime/expire-stale-traces.ts +54 -0
  686. package/src/trace/runtime/flow-step.ts +147 -0
  687. package/src/trace/runtime/flush-steps.ts +31 -0
  688. package/src/trace/runtime/pending-writes.ts +54 -0
  689. package/src/trace/runtime/step-buffer.ts +298 -0
  690. package/src/trace/runtime/step-error.ts +21 -0
  691. package/src/trace/runtime/step-meta.ts +55 -0
  692. package/src/trace/runtime/thenable.ts +12 -0
  693. package/src/trace/runtime/truncate-trace.ts +62 -0
  694. package/src/trace/schema/trace-fields.ts +52 -0
  695. package/src/trace/schema/trace-retained.ts +22 -0
  696. package/src/trace/schema/trace-step-fields.ts +44 -0
  697. package/src/trace/schema/trace-step-retained.ts +25 -0
  698. package/src/trace/schema/trace-step.ts +18 -0
  699. package/src/trace/schema/trace.ts +12 -0
  700. package/src/trace/transformer/apply.ts +79 -0
  701. package/src/trace/transformer/build-meta-literal.ts +30 -0
  702. package/src/trace/transformer/find-flow-step-sites.ts +85 -0
  703. package/src/trace/transformer/inject-flow-step-import.ts +39 -0
  704. package/src/trace/transformer/transform-error.ts +14 -0
  705. package/src/trace/transformer/transform-flow-steps.ts +123 -0
  706. package/src/trace/transformer/wrap-function-declaration.ts +62 -0
  707. package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
  708. package/src/workspace/affected.ts +110 -0
  709. package/src/workspace/changed-files.ts +163 -0
  710. package/src/workspace/check-deps.ts +213 -0
  711. package/src/workspace/checksum.ts +20 -0
  712. package/src/workspace/dependency-graph.ts +67 -0
  713. package/src/workspace/detect-pipework-copies.ts +93 -0
  714. package/src/workspace/discover.ts +206 -0
  715. package/src/workspace/generate.ts +401 -0
  716. package/src/workspace/index.ts +7 -0
  717. package/src/workspace/module-imports-pipework.ts +39 -0
  718. package/src/workspace/module-package-name.ts +12 -0
  719. package/src/workspace/scrub-git-env.ts +23 -0
  720. package/src/workspace/source-paths.ts +36 -0
  721. package/src/workspace/sync.ts +182 -0
  722. package/dist/REFERENCE.md +0 -1477
  723. package/dist/infra/access-links/rate-limit.d.ts +0 -10
  724. package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
  725. package/dist/infra/access-links/rate-limit.js +0 -28
  726. package/dist/infra/access-links/rate-limit.js.map +0 -1
  727. package/dist/infra/email/sigv4.d.ts +0 -24
  728. package/dist/infra/email/sigv4.d.ts.map +0 -1
  729. package/dist/infra/email/sigv4.js +0 -55
  730. package/dist/infra/email/sigv4.js.map +0 -1
@@ -0,0 +1,473 @@
1
+ import { sql } from './sql.js'
2
+ import type { SQL, Column } from './types.js'
3
+ import type { SQLWrapper } from '../query/sql/sql.js'
4
+ import { bindIfParam } from '../query/index.js'
5
+ import { PgArray } from '../query/pg-core/index.js'
6
+ import { quoteCollation, type CollationName } from '../query/collation.js'
7
+ import { is } from '../query/entity.js'
8
+ import { Column as DrizzleColumn } from '../query/column.js'
9
+ import { noopDecoder, SQL as DrizzleSQL } from '../query/sql/sql.js'
10
+
11
+ /** Returns `column + amount`. Use negative amounts for subtraction. */
12
+ export function increment(column: Column | SQL, amount: number): SQL<number> {
13
+ return sql<number>`${column} + ${amount}`
14
+ }
15
+
16
+ /** Returns `column - amount`. Convenience wrapper — equivalent to `increment(column, -amount)`. */
17
+ export function decrement(column: Column | SQL, amount: number): SQL<number> {
18
+ return sql<number>`${column} - ${amount}`
19
+ }
20
+
21
+ /** Returns `left + right` for two SQL expressions. For column + literal number, use `increment`. */
22
+ export function add<T = unknown>(left: Column | SQL, right: Column | SQL): SQL<T> {
23
+ return sql<T>`${left} + ${right}`
24
+ }
25
+
26
+ /** Returns `left - right` for two SQL expressions. For column - literal number, use `decrement`. */
27
+ export function subtract<T = unknown>(left: Column | SQL, right: Column | SQL): SQL<T> {
28
+ return sql<T>`${left} - ${right}`
29
+ }
30
+
31
+ /** Wraps an expression with COALESCE — returns `defaultValue` when the expression is NULL. Given a column, the default is bound the way that column's values are on insert (jsonb as JSON, dates, arrays). */
32
+ export function coalesce<T>(expression: SQL | Column, defaultValue: T): SQL<T> {
33
+ return sql<T>`coalesce(${expression}, ${bindIfParam(defaultValue, expression)})`
34
+ }
35
+
36
+ /** Returns a SQL expression for PostgreSQL `now()` — the current transaction timestamp. */
37
+ export function now(): SQL<Date> {
38
+ return sql<Date>`now()`
39
+ }
40
+
41
+ /** Wraps a select query as a scalar subquery expression, usable in `.values()` and `.set()`. */
42
+ export function scalar<T>(subquery: SQLWrapper): SQL<T> {
43
+ return sql<T>`(${subquery})`
44
+ }
45
+
46
+ /** A PostgreSQL interval/`date_trunc` field unit (`'days'`, `'months'`, …). */
47
+ export type IntervalUnit = 'microseconds' | 'milliseconds' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months' | 'years'
48
+
49
+ /** PostgreSQL type cast: `expression::pgType`. */
50
+ export function cast<T = unknown>(expression: SQL | Column | SQLWrapper, pgType: string): SQL<T> {
51
+ return sql<T>`(${expression})::${sql.raw(pgType)}`
52
+ }
53
+
54
+ /** What `collate` accepts: a text column or an SQL expression typed `string` or `string | null`. */
55
+ export type CollatableOperand = (Column & { _: { data: string } }) | SQL<string> | SQL<string | null>
56
+
57
+ /**
58
+ * `(expr) collate "name"` — sorts, groups and compares the expression under that collation.
59
+ * A string is one quoted identifier, dots included (`'en_US.utf8'` -> `"en_US.utf8"`); a tuple is
60
+ * schema-qualified (`['pg_catalog', 'C']` -> `"pg_catalog"."C"`). A column keeps its decoder, so the selected value decodes as the column does.
61
+ */
62
+ export function collate<E extends CollatableOperand>(
63
+ expr: E,
64
+ collation: CollationName,
65
+ ): SQL<E extends Column ? (E['_']['notNull'] extends true ? E['_']['data'] : E['_']['data'] | null) : E extends SQL<infer T> ? T : unknown> {
66
+ const name = sql.raw(quoteCollation(collation))
67
+ const out = sql`(${expr}) collate ${name}`
68
+ if (is(expr, DrizzleColumn)) out.mapWith(expr as Column)
69
+ else if ((expr as SQL).decoder !== noopDecoder) out.mapWith((expr as SQL).decoder)
70
+ return out as never
71
+ }
72
+
73
+ const INTERVAL_UNIT_SINGULAR: Readonly<Record<IntervalUnit, string>> = {
74
+ microseconds: 'microsecond',
75
+ milliseconds: 'millisecond',
76
+ seconds: 'second',
77
+ minutes: 'minute',
78
+ hours: 'hour',
79
+ days: 'day',
80
+ weeks: 'week',
81
+ months: 'month',
82
+ years: 'year',
83
+ }
84
+
85
+ /** PostgreSQL interval of `amount` units, `amount` bound as a parameter: `($1::double precision * interval '1 minute')`. Throws for a non-finite amount. */
86
+ export function interval(amount: number, unit: IntervalUnit): SQL {
87
+ if (!Number.isFinite(amount)) {
88
+ throw new Error(
89
+ `[pipework] interval() needs a finite amount, got ${String(amount)}.\n\n` +
90
+ ' NaN and Infinity are not valid interval amounts.\n' +
91
+ " Fix: pass a finite number: interval(5, 'minutes').\n",
92
+ )
93
+ }
94
+ return sql`(${amount}::double precision * interval '1 ${sql.raw(INTERVAL_UNIT_SINGULAR[unit])}')`
95
+ }
96
+
97
+ /** PostgreSQL `clock_timestamp()` — the actual wall-clock time, which advances within a transaction (unlike `now()`). */
98
+ export function clockTimestamp(): SQL<Date> {
99
+ return sql<Date>`clock_timestamp()`
100
+ }
101
+
102
+ /** A text operand: a column, an expression, or a string (bound as `$n::text`). */
103
+ export type TextArg = Column | SQL | string
104
+
105
+ function textArg(value: TextArg): SQL {
106
+ return typeof value === 'string' ? sql`${value}::text` : sql`${value}`
107
+ }
108
+
109
+ function intArg(value: number | Column | SQL): SQL {
110
+ return typeof value === 'number' ? sql`${value}::int` : sql`${value}`
111
+ }
112
+
113
+ /** PostgreSQL `strpos(a, b)` — 1-based position of `b` in `a`, 0 when absent. Strings are bound as text, so `%`, `_` and `\` are plain characters. */
114
+ export function strpos(a: TextArg, b: TextArg): SQL<number> {
115
+ return sql<number>`strpos(${textArg(a)}, ${textArg(b)})`
116
+ }
117
+
118
+ /** True when `a` contains the exact text `b`: `strpos(a, b) > 0`. Unlike `like`, no character in `b` is a wildcard. */
119
+ export function textContains(a: TextArg, b: TextArg): SQL<boolean> {
120
+ return sql<boolean>`${strpos(a, b)} > 0`
121
+ }
122
+
123
+ /** PostgreSQL `starts_with(a, prefix)` — true when `a` begins with the exact text `prefix`; no wildcards. */
124
+ export function startsWith(a: TextArg, prefix: TextArg): SQL<boolean> {
125
+ return sql<boolean>`starts_with(${textArg(a)}, ${textArg(prefix)})`
126
+ }
127
+
128
+ /** PostgreSQL `left(a, n)` — the first `n` characters of `a`. */
129
+ export function left(a: TextArg, n: number | Column | SQL): SQL<string> {
130
+ return sql<string>`left(${textArg(a)}, ${intArg(n)})`
131
+ }
132
+
133
+ /** PostgreSQL `right(a, n)` — the last `n` characters of `a`. */
134
+ export function right(a: TextArg, n: number | Column | SQL): SQL<string> {
135
+ return sql<string>`right(${textArg(a)}, ${intArg(n)})`
136
+ }
137
+
138
+ /** PostgreSQL `length(a)` — the number of characters in `a`. */
139
+ export function length(a: TextArg): SQL<number> {
140
+ return sql<number>`length(${textArg(a)})`
141
+ }
142
+
143
+ function wholeNumber(value: number, helper: string, what: string): number {
144
+ if (!Number.isInteger(value)) {
145
+ throw new Error(
146
+ `[pipework] ${helper}() needs a finite integer ${what}, got ${String(value)}.\n\n` +
147
+ ' NaN, Infinity and fractions are not valid positions or counts.\n' +
148
+ ` Fix: pass an integer: ${helper}(..., 1).\n`,
149
+ )
150
+ }
151
+ return value
152
+ }
153
+
154
+ function checkedIntArg(value: number | Column | SQL, helper: string, what: string): SQL {
155
+ return typeof value === 'number' ? sql`${wholeNumber(value, helper, what)}::int` : sql`${value}`
156
+ }
157
+
158
+ /** PostgreSQL `split_part(a, delimiter, n)` — the `n`th (1-based) field of `a`; negative `n` counts from the end (PostgreSQL 14+). `delimiter` is bound. */
159
+ export function splitPart(a: TextArg, delimiter: string, n: number | Column | SQL): SQL<string> {
160
+ return sql<string>`split_part(${textArg(a)}, ${delimiter}::text, ${checkedIntArg(n, 'splitPart', 'field number')})`
161
+ }
162
+
163
+ /** PostgreSQL `lower(a)`. */
164
+ export function lower(a: TextArg): SQL<string> {
165
+ return sql<string>`lower(${textArg(a)})`
166
+ }
167
+
168
+ /** PostgreSQL `upper(a)`. */
169
+ export function upper(a: TextArg): SQL<string> {
170
+ return sql<string>`upper(${textArg(a)})`
171
+ }
172
+
173
+ const TRIM_SIDES: ReadonlySet<string> = new Set(['both', 'leading', 'trailing'])
174
+
175
+ /** Which end of the text `trim` strips. */
176
+ export type TrimSide = 'both' | 'leading' | 'trailing'
177
+
178
+ /** PostgreSQL `trim(<side> [characters] from a)` — strips spaces, or any of `characters` (bound), from the chosen end; `side` defaults to `'both'`. */
179
+ export function trim(a: TextArg, options: { readonly side?: TrimSide; readonly characters?: string } = {}): SQL<string> {
180
+ const side = options.side ?? 'both'
181
+ if (!TRIM_SIDES.has(side)) {
182
+ throw new Error(
183
+ `[pipework] trim() side must be 'both', 'leading' or 'trailing', got ${String(side)}.\n\n` +
184
+ " Fix: trim(column, { side: 'leading' }).\n",
185
+ )
186
+ }
187
+ const kw = sql.raw(side)
188
+ if (options.characters === undefined) return sql<string>`trim(${kw} from ${textArg(a)})`
189
+ return sql<string>`trim(${kw} ${options.characters}::text from ${textArg(a)})`
190
+ }
191
+
192
+ /** PostgreSQL `replace(a, from, to)` — every occurrence of the exact text `from` becomes `to`. */
193
+ export function replace(a: TextArg, from: TextArg, to: TextArg): SQL<string> {
194
+ return sql<string>`replace(${textArg(a)}, ${textArg(from)}, ${textArg(to)})`
195
+ }
196
+
197
+ /** PostgreSQL `substring(a, from[, count])` — 1-based start, optional length. */
198
+ export function substring(a: TextArg, from: number | Column | SQL, count?: number | Column | SQL): SQL<string> {
199
+ const start = checkedIntArg(from, 'substring', 'start')
200
+ if (count === undefined) return sql<string>`substring(${textArg(a)}, ${start})`
201
+ return sql<string>`substring(${textArg(a)}, ${start}, ${checkedIntArg(count, 'substring', 'count')})`
202
+ }
203
+
204
+ /** PostgreSQL `reverse(a)`. */
205
+ export function reverse(a: TextArg): SQL<string> {
206
+ return sql<string>`reverse(${textArg(a)})`
207
+ }
208
+
209
+ /** PostgreSQL `lpad(a, length[, fill])` — pads on the left (or truncates) to `length` characters; `fill` defaults to a space. */
210
+ export function lpad(a: TextArg, length: number | Column | SQL, fill?: string): SQL<string> {
211
+ const len = checkedIntArg(length, 'lpad', 'length')
212
+ if (fill === undefined) return sql<string>`lpad(${textArg(a)}, ${len})`
213
+ return sql<string>`lpad(${textArg(a)}, ${len}, ${fill}::text)`
214
+ }
215
+
216
+ /** PostgreSQL `rpad(a, length[, fill])` — pads on the right (or truncates) to `length` characters; `fill` defaults to a space. */
217
+ export function rpad(a: TextArg, length: number | Column | SQL, fill?: string): SQL<string> {
218
+ const len = checkedIntArg(length, 'rpad', 'length')
219
+ if (fill === undefined) return sql<string>`rpad(${textArg(a)}, ${len})`
220
+ return sql<string>`rpad(${textArg(a)}, ${len}, ${fill}::text)`
221
+ }
222
+
223
+ /** PostgreSQL `regexp_replace(a, pattern, replacement[, flags])` — POSIX regex; `flags` such as `'g'` or `'i'`. Pattern, replacement and flags are bound. */
224
+ export function regexpReplace(a: TextArg, pattern: string, replacement: string, flags?: string): SQL<string> {
225
+ if (flags === undefined) return sql<string>`regexp_replace(${textArg(a)}, ${pattern}::text, ${replacement}::text)`
226
+ return sql<string>`regexp_replace(${textArg(a)}, ${pattern}::text, ${replacement}::text, ${flags}::text)`
227
+ }
228
+
229
+ /** True when `a` matches the POSIX regex `pattern` (bound): `a ~ pattern`, or `a ~* pattern` with `caseInsensitive`. */
230
+ export function regexpMatch(a: TextArg, pattern: string, options: { readonly caseInsensitive?: boolean } = {}): SQL<boolean> {
231
+ const op = options.caseInsensitive === true ? sql.raw('~*') : sql.raw('~')
232
+ return sql<boolean>`${textArg(a)} ${op} ${pattern}::text`
233
+ }
234
+
235
+ /** PostgreSQL `string_to_array(a, delimiter)` — splits `a` into a text array; `delimiter` is bound. An empty `a` gives `{}`. */
236
+ export function stringToArray(a: TextArg, delimiter: string): SQL<string[]> {
237
+ return sql<string[]>`string_to_array(${textArg(a)}, ${delimiter}::text)`
238
+ }
239
+
240
+ /**
241
+ * Text concatenation: `(p1 || p2 || ...)`. Strings are bound as text. A null part makes
242
+ * the whole result null (SQL `||`); wrap such a part in `coalesce` if that is not wanted.
243
+ * Wrap a subquery with `scalar(...)`.
244
+ */
245
+ export function concat(...parts: Array<string | Column | SQL>): SQL<string> {
246
+ if (parts.length < 2) {
247
+ throw new Error(
248
+ `[pipework] concat() needs at least two parts, got ${parts.length}.\n\n` +
249
+ ' A concatenation of fewer than two parts is not a concatenation.\n' +
250
+ " Fix: pass two or more parts: concat('prefix: ', column).\n",
251
+ )
252
+ }
253
+ return sql<string>`(${sql.join(parts.map(textArg), sql` || `)})`
254
+ }
255
+
256
+ function elementType(column: Column, helper: string): string {
257
+ const type = column.getSQLType()
258
+ if (!type.endsWith('[]')) {
259
+ throw new Error(
260
+ `[pipework] ${helper}() needs an array column, got "${column.name}" of type ${type}.\n\n` +
261
+ ' The element type is read from the column, so it must be an array column.\n' +
262
+ ` Fix: pass an array column (for example uuid('ids').array()) to ${helper}().\n`,
263
+ )
264
+ }
265
+ return type.slice(0, -2)
266
+ }
267
+
268
+ /** Binds `value` as one element of an array column, converted by the element column's driver mapping. */
269
+ function element(col: Column, value: unknown): unknown {
270
+ if (value === null || !is(col, PgArray)) return value
271
+ const base = (col as unknown as { baseColumn: { mapToDriverValue(v: unknown): unknown } }).baseColumn
272
+ return sql.param(value, { mapToDriverValue: v => base.mapToDriverValue(v) })
273
+ }
274
+
275
+ type ElementOf<C extends Column> = C['_']['data'] extends ReadonlyArray<infer E> ? E : never
276
+
277
+ /** PostgreSQL `array_replace(col, from, to)` — every element equal to `from` becomes `to`. `from`/`to` are bound and cast to the column's element type. */
278
+ export function arrayReplace<C extends Column>(col: C, from: ElementOf<C>, to: ElementOf<C>): SQL<C['_']['data']> {
279
+ const el = sql.raw(elementType(col, 'arrayReplace'))
280
+ return sql<C['_']['data']>`array_replace(${col}, ${element(col, from)}::${el}, ${element(col, to)}::${el})`
281
+ }
282
+
283
+ /** A column or expression whose value is one element of `C`'s array. */
284
+ type ElementValue<C extends Column> =
285
+ | (Column & { _: { data: ElementOf<C> | null } })
286
+ | SQL<ElementOf<C>>
287
+ | SQL<ElementOf<C> | null>
288
+
289
+ /**
290
+ * True when the array column holds `value`.
291
+ * A JS value is bound and cast to the element type: `$value::<element> = ANY(col)`.
292
+ * A column or SQL expression is used as is, with no bind and no cast: `<value> = ANY(col)`,
293
+ * so the index on `value` can serve a join against the array.
294
+ */
295
+ export function arrayHas<C extends Column>(col: C, value: ElementOf<C>): SQL<boolean>
296
+ export function arrayHas<C extends Column>(col: C, value: ElementValue<C>): SQL<boolean>
297
+ export function arrayHas(col: Column, value: unknown): SQL<boolean> {
298
+ const el = sql.raw(elementType(col, 'arrayHas'))
299
+ if (is(value, DrizzleColumn) || is(value, DrizzleSQL)) return sql<boolean>`${value} = ANY(${col})`
300
+ return sql<boolean>`${element(col, value)}::${el} = ANY(${col})`
301
+ }
302
+
303
+ /** PostgreSQL `cardinality(arr)` — the number of elements; 0 for `'{}'`, NULL for a NULL array. */
304
+ export function cardinality(arr: Column | SQL): SQL<number | null> {
305
+ return sql<number | null>`cardinality(${arr})`
306
+ }
307
+
308
+ /**
309
+ * One element by 1-based index: `(arr)[n]`; a negative `n` counts from the end,
310
+ * `(arr)[cardinality(arr) + n + 1]`. NULL for 0, out of range, or an empty array. `n` is bound.
311
+ */
312
+ export function arrayAt<C extends Column>(arr: C, n: number): SQL<ElementOf<C> | null>
313
+ export function arrayAt<T>(arr: SQL<readonly T[]>, n: number): SQL<T | null>
314
+ export function arrayAt(arr: Column | SQL, n: number): SQL {
315
+ wholeNumber(n, 'arrayAt', 'index')
316
+ if (n < 0) return sql`(${arr})[cardinality(${arr}) + ${n + 1}::int]`
317
+ return sql`(${arr})[${n}::int]`
318
+ }
319
+
320
+ /** PostgreSQL `array_position(col, value)` — 1-based index of the first `value`, NULL when absent. `value` is bound and cast to the element type. */
321
+ export function arrayPosition<C extends Column>(col: C, value: ElementOf<C>): SQL<number | null> {
322
+ const el = sql.raw(elementType(col, 'arrayPosition'))
323
+ return sql<number | null>`array_position(${col}, ${element(col, value)}::${el})`
324
+ }
325
+
326
+ /** Array slice `(col)[from:to]`, 1-based and inclusive; out-of-range bounds are clipped. `from`/`to` are bound. */
327
+ export function arraySlice<C extends Column>(col: C, from: number, to: number): SQL<C['_']['data']> {
328
+ wholeNumber(from, 'arraySlice', 'start')
329
+ wholeNumber(to, 'arraySlice', 'end')
330
+ return sql<C['_']['data']>`(${col})[(${from}::int):(${to}::int)]`
331
+ }
332
+
333
+ /** PostgreSQL `array_to_string(arr, delimiter)` — joins the elements (NULL elements skipped); `delimiter` is bound. */
334
+ export function arrayToString(arr: Column | SQL, delimiter: string): SQL<string> {
335
+ return sql<string>`array_to_string(${arr}, ${delimiter}::text)`
336
+ }
337
+
338
+ /** PostgreSQL `array_append(col, value)` — `value` goes last. `value` is bound and cast to the element type. */
339
+ export function arrayAppend<C extends Column>(col: C, value: ElementOf<C>): SQL<C['_']['data']> {
340
+ const el = sql.raw(elementType(col, 'arrayAppend'))
341
+ return sql<C['_']['data']>`array_append(${col}, ${element(col, value)}::${el})`
342
+ }
343
+
344
+ /** PostgreSQL `array_remove(col, value)` — drops every element equal to `value`. `value` is bound and cast to the element type. */
345
+ export function arrayRemove<C extends Column>(col: C, value: ElementOf<C>): SQL<C['_']['data']> {
346
+ const el = sql.raw(elementType(col, 'arrayRemove'))
347
+ return sql<C['_']['data']>`array_remove(${col}, ${element(col, value)}::${el})`
348
+ }
349
+
350
+ /** PostgreSQL `date_trunc('unit', column)` — truncates a timestamp to the given precision. */
351
+ export function dateTrunc(unit: 'microseconds' | 'milliseconds' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' | 'decade' | 'century' | 'millennium', column: Column | SQL): SQL<Date> {
352
+ return sql<Date>`date_trunc('${sql.raw(unit)}', ${column})`
353
+ }
354
+
355
+ /** PostgreSQL `ROW_NUMBER()` window function. Use with `over()` to apply a window specification. */
356
+ export function rowNumber(): SQL<number> {
357
+ return sql<number>`row_number()`
358
+ }
359
+
360
+ /** PostgreSQL `RANK()` window function. Use with `over()` to apply a window specification. */
361
+ export function rank(): SQL<number> {
362
+ return sql<number>`rank()`
363
+ }
364
+
365
+ /** PostgreSQL `DENSE_RANK()` window function. Use with `over()` to apply a window specification. */
366
+ export function denseRank(): SQL<number> {
367
+ return sql<number>`dense_rank()`
368
+ }
369
+
370
+ /** A window-frame specification — the `PARTITION BY` / `ORDER BY` clauses applied by {@link over}. */
371
+ export interface WindowSpec {
372
+ readonly partitionBy?: Column | SQL | ReadonlyArray<Column | SQL>
373
+ readonly orderBy?: SQL | ReadonlyArray<SQL>
374
+ readonly frame?: WindowFrame
375
+ }
376
+
377
+ /** One end of a window frame. `{ preceding: n }` / `{ following: n }` take a non-negative integer. */
378
+ export type FrameBound = 'unboundedPreceding' | 'currentRow' | 'unboundedFollowing' | { readonly preceding: number } | { readonly following: number }
379
+
380
+ /** A window frame: `rows|range|groups [between] start [and end]`. */
381
+ export interface WindowFrame {
382
+ readonly mode: 'rows' | 'range' | 'groups'
383
+ readonly start: FrameBound
384
+ readonly end?: FrameBound
385
+ }
386
+
387
+ function frameBound(bound: FrameBound): string {
388
+ if (bound === 'unboundedPreceding') return 'unbounded preceding'
389
+ if (bound === 'currentRow') return 'current row'
390
+ if (bound === 'unboundedFollowing') return 'unbounded following'
391
+ const [dir, n] = 'preceding' in bound ? ['preceding', bound.preceding] as const : ['following', bound.following] as const
392
+ if (!Number.isInteger(n) || n < 0) throw new Error(`over: frame ${dir} must be a non-negative integer, got ${String(n)}`)
393
+ return `${n} ${dir}`
394
+ }
395
+
396
+ /** Applies a window specification to a window function or aggregate: `fn OVER (PARTITION BY ... ORDER BY ...)`. */
397
+ export function over<T>(fn: SQL<T>, spec: WindowSpec): SQL<T> {
398
+ const parts: SQL[] = []
399
+ if (spec.partitionBy !== undefined) {
400
+ const cols = Array.isArray(spec.partitionBy) ? spec.partitionBy : [spec.partitionBy]
401
+ parts.push(sql`partition by ${sql.join(cols.map(c => sql`${c}`), sql`, `)}`)
402
+ }
403
+ if (spec.orderBy !== undefined) {
404
+ const cols = Array.isArray(spec.orderBy) ? spec.orderBy : [spec.orderBy]
405
+ parts.push(sql`order by ${sql.join(cols, sql`, `)}`)
406
+ }
407
+ if (spec.frame !== undefined) {
408
+ const { mode, start, end } = spec.frame
409
+ const text = end === undefined ? `${mode} ${frameBound(start)}` : `${mode} between ${frameBound(start)} and ${frameBound(end)}`
410
+ parts.push(sql.raw(text))
411
+ }
412
+ if (parts.length === 0) return sql<T>`${fn} over ()`
413
+ return sql<T>`${fn} over (${sql.join(parts, sql` `)})`
414
+ }
415
+
416
+ /**
417
+ * PostgreSQL quoted identifier. One part renders `"name"`; multiple parts
418
+ * dot-qualify: `identifier('t', 'n')` → `"t"."n"`. Each part is one
419
+ * identifier — a dot inside a part is quoted literally, not a qualifier.
420
+ */
421
+ export function identifier(first: string, ...rest: string[]): SQL {
422
+ let qualified = sql`${sql.identifier(first)}`
423
+ for (const part of rest) {
424
+ qualified = sql`${qualified}.${sql.identifier(part)}`
425
+ }
426
+ return qualified
427
+ }
428
+
429
+ /** PostgreSQL `WITH RECURSIVE alias AS (seed UNION ALL step) finalQuery`. If `finalQuery` is omitted, defaults to `SELECT * FROM alias`. */
430
+ export function withRecursive(alias: string, seed: SQL, step: SQL, finalQuery?: SQL): SQL {
431
+ const cte = sql`WITH RECURSIVE ${sql.identifier(alias)} AS (${seed} UNION ALL ${step})`
432
+ if (finalQuery !== undefined) {
433
+ return sql`${cte} ${finalQuery}`
434
+ }
435
+ return sql`${cte} SELECT * FROM ${sql.identifier(alias)}`
436
+ }
437
+
438
+ /** One `WHEN <when> THEN <then>` branch of a {@link caseWhen} expression. */
439
+ export interface CaseBranch<T = unknown> {
440
+ readonly when: SQL | Column
441
+ readonly then: T | SQL<T> | Column
442
+ }
443
+
444
+ /** PostgreSQL `CASE WHEN .. THEN .. [ELSE ..] END`. Branches evaluate in order; without `elseValue` an unmatched row yields NULL. */
445
+ export function caseWhen<T = unknown>(branches: ReadonlyArray<CaseBranch<T>>, elseValue?: T | SQL<T> | Column): SQL<T> {
446
+ if (branches.length === 0) {
447
+ throw new Error(
448
+ '[pipework] caseWhen() requires at least one branch.\n\n' +
449
+ ' A CASE expression with no WHEN clauses is not valid SQL.\n' +
450
+ " Pass at least one branch: caseWhen([{ when: filter.eq(col, 1), then: 'one' }], 'other').\n",
451
+ )
452
+ }
453
+ const parts: SQL[] = branches.map(b => sql`when ${b.when} then ${b.then}`)
454
+ if (elseValue !== undefined) {
455
+ parts.push(sql`else ${elseValue}`)
456
+ }
457
+ return sql<T>`case ${sql.join(parts, sql` `)} end`
458
+ }
459
+
460
+ /** PostgreSQL `pg_current_wal_lsn()` — returns the current WAL write position on the primary, as text. */
461
+ export function walCurrentLsn(): SQL<string> {
462
+ return sql<string>`pg_current_wal_lsn()::text`
463
+ }
464
+
465
+ /** PostgreSQL `pg_last_wal_replay_lsn()` — returns the last replayed WAL position on a replica, as text. Returns NULL on the primary. */
466
+ export function walReplayLsn(): SQL<string | null> {
467
+ return sql<string | null>`pg_last_wal_replay_lsn()::text`
468
+ }
469
+
470
+ /** PostgreSQL `pg_last_wal_replay_lsn() >= lsn::pg_lsn` — true once a replica has replayed up to the given LSN. Yields NULL (not true) on a primary, where there is no replay position. */
471
+ export function replicaFresh(createdLsn: string | Column | SQL): SQL<boolean | null> {
472
+ return sql<boolean | null>`pg_last_wal_replay_lsn() >= ${createdLsn}::pg_lsn`
473
+ }
@@ -0,0 +1,90 @@
1
+ import {
2
+ and, arrayContained, arrayContains, arrayOverlaps, asc, between, desc, eq, exists, gt, gte,
3
+ ilike, inArray, is, isNotNull, isNull, like, lt, lte, ne, not, notBetween, notExists, notIlike,
4
+ notInArray, notLike, or,
5
+ } from '../query/index.js'
6
+ import { countAgg, countDistinctAgg, sumAgg, sumDistinctAgg, avgAgg, avgDistinctAgg, maxAgg, minAgg, boolAnd, boolOr, arrayAgg, stringAgg, jsonbAgg, jsonbObjectAgg, jsonbBuildObject } from './aggregates.js'
7
+ import { except, exceptAll, intersect, intersectAll, union, unionAll } from '../query/pg-core/index.js'
8
+ import { increment, decrement, add, subtract, coalesce, now, scalar, cast, collate, interval, clockTimestamp, strpos, textContains, startsWith, left, right, length, concat, arrayReplace, arrayHas, splitPart, lower, upper, trim, replace, substring, reverse, lpad, rpad, regexpReplace, regexpMatch, stringToArray, cardinality, arrayAt, arrayPosition, arraySlice, arrayToString, arrayAppend, arrayRemove, dateTrunc, rowNumber, rank, denseRank, over, identifier, withRecursive, caseWhen, walCurrentLsn, walReplayLsn, replicaFresh } from './expressions.js'
9
+ import { ago, castUuid, castJsonb, castTimestamp, castBoolean, castNumeric, castInteger, castText, nextSequence } from './composed.js'
10
+ import { json as jsonbExtract, pathText as jsonbExtractText, contains as jsonbContains, merge as jsonbMerge, remove as jsonbRemove } from '../jsonb/query.js'
11
+ import { arrayAny, arrayAll, jsonbElements } from './array-elements.js'
12
+ import { inList, notInList } from './in-list.js'
13
+
14
+ export const filter = {
15
+ and, arrayContained, arrayContains, arrayOverlaps, asc, between, desc, eq, exists, gt, gte,
16
+ ilike, inArray, is, isNotNull, isNull, like, lt, lte, ne, not, notBetween, notExists, notIlike,
17
+ notInArray, notLike, or,
18
+ avg: avgAgg, avgDistinct: avgDistinctAgg, count: countAgg, countDistinct: countDistinctAgg, max: maxAgg, min: minAgg, sum: sumAgg, sumDistinct: sumDistinctAgg,
19
+ boolAnd, boolOr, arrayAgg, stringAgg, jsonbAgg, jsonbObjectAgg, jsonbBuildObject,
20
+ except, exceptAll, intersect, intersectAll, union, unionAll,
21
+ increment,
22
+ decrement,
23
+ add,
24
+ subtract,
25
+ coalesce,
26
+ now,
27
+ scalar,
28
+ cast,
29
+ collate,
30
+ interval,
31
+ clockTimestamp,
32
+ strpos,
33
+ textContains,
34
+ startsWith,
35
+ left,
36
+ right,
37
+ length,
38
+ concat,
39
+ arrayReplace,
40
+ arrayHas,
41
+ splitPart,
42
+ lower,
43
+ upper,
44
+ trim,
45
+ replace,
46
+ substring,
47
+ reverse,
48
+ lpad,
49
+ rpad,
50
+ regexpReplace,
51
+ regexpMatch,
52
+ stringToArray,
53
+ cardinality,
54
+ arrayAt,
55
+ arrayPosition,
56
+ arraySlice,
57
+ arrayToString,
58
+ arrayAppend,
59
+ arrayRemove,
60
+ dateTrunc,
61
+ rowNumber,
62
+ rank,
63
+ denseRank,
64
+ over,
65
+ identifier,
66
+ withRecursive,
67
+ ago,
68
+ castUuid,
69
+ castJsonb,
70
+ castTimestamp,
71
+ castBoolean,
72
+ castNumeric,
73
+ castInteger,
74
+ castText,
75
+ nextSequence,
76
+ caseWhen,
77
+ walCurrentLsn,
78
+ walReplayLsn,
79
+ replicaFresh,
80
+ jsonbExtract,
81
+ jsonbExtractText,
82
+ jsonbContains,
83
+ jsonbMerge,
84
+ jsonbRemove,
85
+ arrayAny,
86
+ arrayAll,
87
+ jsonbElements,
88
+ inList,
89
+ notInList,
90
+ } as const
@@ -0,0 +1,114 @@
1
+ import { sql } from './sql.js'
2
+ import type { SQL } from './types.js'
3
+ import { Subquery } from '../query/subquery.js'
4
+ import { SelectionProxyHandler } from '../query/selection-proxy.js'
5
+ import { getTableColumns } from '../query/utils.js'
6
+ import { bindIfParam } from '../query/index.js'
7
+ import type { Column } from './types.js'
8
+ import type { InferFieldOutput } from '../domain/brand.js'
9
+ import type { FieldDescriptor } from '../domain/types.js'
10
+ import { projectTable } from '../domain/build-table.js'
11
+ import { camelToSnake } from '../domain/naming.js'
12
+
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- variance-safe bound for descriptors with any output/flags
14
+ type AnyField = FieldDescriptor<any, any>
15
+
16
+ const NAME_PART = /^[a-z_][a-z0-9_]*$/
17
+
18
+ /** Declares a SQL function's argument and result-column shapes. See {@link fn}. */
19
+ export interface FunctionSpec<TArgs extends readonly AnyField[], TColumns extends Record<string, AnyField>> {
20
+ /** One `pipe.field.*` descriptor per argument, in call order. */
21
+ readonly args: readonly [...TArgs]
22
+ /** One `pipe.field.*` descriptor per result column; keys are camelCase, columns are their snake_case. */
23
+ readonly columns: TColumns
24
+ }
25
+
26
+ type ArgValues<TArgs extends readonly AnyField[]> = { [K in keyof TArgs]: InferFieldOutput<TArgs[K]> }
27
+
28
+ /** The selected fields of a function source: each result column as a typed SQL expression. */
29
+ export type FunctionSourceFields<TColumns extends Record<string, AnyField>> = {
30
+ [K in keyof TColumns]: SQL<InferFieldOutput<TColumns[K]>>
31
+ }
32
+
33
+ /** A function call usable in `.from()` and joins; its result columns are properties of it. */
34
+ export type FunctionSource<TAlias extends string, TColumns extends Record<string, AnyField>> =
35
+ & Subquery<TAlias, FunctionSourceFields<TColumns>>
36
+ & FunctionSourceFields<TColumns>
37
+ & {
38
+ /** The same call under another alias — needed to use one function twice in a query. */
39
+ as<TNew extends string>(alias: TNew): FunctionSource<TNew, TColumns>
40
+ }
41
+
42
+ function fail(message: string, fix: string): never {
43
+ throw new Error(`[pipework] ${message}\n\n Fix: ${fix}\n`)
44
+ }
45
+
46
+ function quote(name: string): string {
47
+ return `"${name.replace(/"/g, '""')}"`
48
+ }
49
+
50
+ /**
51
+ * Declares a set-returning SQL function and returns a callable that yields a source for `.from()` and joins.
52
+ * Each argument is bound as a parameter, converted the way a column of that field is on insert (jsonb as JSON text,
53
+ * dates, bigints, arrays), and cast to its declared SQL type: `ext.f($1::uuid, $2::text)`. A null binds SQL NULL.
54
+ * An array argument (`field.uuid().array()`) is one parameter: `ext.f($1::uuid[])`.
55
+ * Result columns are typed from `columns`; the default alias is the function's unqualified name.
56
+ */
57
+ export function fn<const TArgs extends readonly AnyField[], TColumns extends Record<string, AnyField>>(
58
+ name: string,
59
+ spec: FunctionSpec<TArgs, TColumns>,
60
+ ): (...values: ArgValues<TArgs>) => FunctionSource<string, TColumns> {
61
+ const parts = name.split('.')
62
+ if (parts.length > 2 || parts.some(p => !NAME_PART.test(p))) {
63
+ fail(
64
+ `pipe.fn: "${name}" is not a function name.`,
65
+ 'use "fn" or "schema.fn", each part lowercase letters, digits and underscores, not starting with a digit.',
66
+ )
67
+ }
68
+ const keys = Object.keys(spec.columns)
69
+ if (keys.length === 0) fail(`pipe.fn("${name}"): columns is empty.`, 'declare at least one result column.')
70
+ for (const key of keys) {
71
+ if (key === 'as' || key === '_') {
72
+ fail(`pipe.fn("${name}"): a result column cannot be named "${key}".`, 'rename the key; the column name comes from camelToSnake(key).')
73
+ }
74
+ }
75
+
76
+ const argFields: Record<string, AnyField> = {}
77
+ spec.args.forEach((a, i) => { argFields[`a${i}`] = a })
78
+ const argCols = getTableColumns(projectTable('pw_fn_args', argFields, {})) as Record<string, { getSQLType(): string; mapToDriverValue(value: unknown): unknown }>
79
+ const argTypes = spec.args.map((_, i) => {
80
+ const t = argCols[`a${i}`]!.getSQLType()
81
+ return t === 'serial' ? 'integer' : t === 'bigserial' ? 'bigint' : t
82
+ })
83
+
84
+ const fnSql = sql.raw(parts.map(quote).join('.'))
85
+ const defaultAlias = parts[parts.length - 1]!
86
+
87
+ const build = (values: readonly unknown[], alias: string): FunctionSource<string, TColumns> => {
88
+ const columnList = sql.join(keys.map(k => sql.raw(quote(camelToSnake(k)))), sql`, `)
89
+ const argList = sql.join(values.map((v, i) => sql`${bindIfParam(v, argCols[`a${i}`] as unknown as Column)}::${sql.raw(argTypes[i]!)}`), sql`, `)
90
+ const inner = sql`select ${columnList} from ${fnSql}(${argList})`
91
+ const fields: Record<string, SQL> = {}
92
+ for (const k of keys) {
93
+ fields[k] = sql.raw(`${quote(alias)}.${quote(camelToSnake(k))}`)
94
+ }
95
+ const subquery = new Subquery(inner, fields, alias)
96
+ const selection = new SelectionProxyHandler<Subquery>({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' })
97
+ return new Proxy(subquery, {
98
+ get(target, prop) {
99
+ if (prop === 'as') return (next: string) => build(values, next)
100
+ return selection.get(target, prop)
101
+ },
102
+ }) as unknown as FunctionSource<string, TColumns>
103
+ }
104
+
105
+ return (...values: ArgValues<TArgs>) => {
106
+ if (values.length !== spec.args.length) {
107
+ fail(
108
+ `pipe.fn("${name}"): called with ${values.length} argument(s), declared ${spec.args.length}.`,
109
+ 'pass one value per declared argument.',
110
+ )
111
+ }
112
+ return build(values, defaultAlias)
113
+ }
114
+ }