@quereus/quereus 0.16.4 → 0.17.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 (533) hide show
  1. package/README.md +372 -345
  2. package/dist/src/common/errors.d.ts +2 -18
  3. package/dist/src/common/errors.d.ts.map +1 -1
  4. package/dist/src/common/errors.js +6 -29
  5. package/dist/src/common/errors.js.map +1 -1
  6. package/dist/src/common/types.d.ts +8 -0
  7. package/dist/src/common/types.d.ts.map +1 -1
  8. package/dist/src/common/types.js +20 -0
  9. package/dist/src/common/types.js.map +1 -1
  10. package/dist/src/core/database-assertions.d.ts +19 -2
  11. package/dist/src/core/database-assertions.d.ts.map +1 -1
  12. package/dist/src/core/database-assertions.js +113 -32
  13. package/dist/src/core/database-assertions.js.map +1 -1
  14. package/dist/src/core/database-events.d.ts +17 -0
  15. package/dist/src/core/database-events.d.ts.map +1 -1
  16. package/dist/src/core/database-events.js +39 -2
  17. package/dist/src/core/database-events.js.map +1 -1
  18. package/dist/src/core/database-transaction.d.ts +31 -4
  19. package/dist/src/core/database-transaction.d.ts.map +1 -1
  20. package/dist/src/core/database-transaction.js +68 -2
  21. package/dist/src/core/database-transaction.js.map +1 -1
  22. package/dist/src/core/database.d.ts +17 -4
  23. package/dist/src/core/database.d.ts.map +1 -1
  24. package/dist/src/core/database.js +189 -154
  25. package/dist/src/core/database.js.map +1 -1
  26. package/dist/src/core/statement.d.ts +8 -2
  27. package/dist/src/core/statement.d.ts.map +1 -1
  28. package/dist/src/core/statement.js +54 -71
  29. package/dist/src/core/statement.js.map +1 -1
  30. package/dist/src/emit/ast-stringify.d.ts +1 -0
  31. package/dist/src/emit/ast-stringify.d.ts.map +1 -1
  32. package/dist/src/emit/ast-stringify.js +12 -2
  33. package/dist/src/emit/ast-stringify.js.map +1 -1
  34. package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
  35. package/dist/src/func/builtins/builtin-window-functions.js +75 -0
  36. package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
  37. package/dist/src/func/builtins/conversion.js +9 -12
  38. package/dist/src/func/builtins/conversion.js.map +1 -1
  39. package/dist/src/func/builtins/datetime.d.ts +21 -0
  40. package/dist/src/func/builtins/datetime.d.ts.map +1 -1
  41. package/dist/src/func/builtins/datetime.js +452 -368
  42. package/dist/src/func/builtins/datetime.js.map +1 -1
  43. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  44. package/dist/src/func/builtins/explain.js +15 -3
  45. package/dist/src/func/builtins/explain.js.map +1 -1
  46. package/dist/src/func/builtins/index.d.ts.map +1 -1
  47. package/dist/src/func/builtins/index.js +5 -12
  48. package/dist/src/func/builtins/index.js.map +1 -1
  49. package/dist/src/func/builtins/json-helpers.js +1 -1
  50. package/dist/src/func/builtins/json-helpers.js.map +1 -1
  51. package/dist/src/func/builtins/json.d.ts.map +1 -1
  52. package/dist/src/func/builtins/json.js +2 -5
  53. package/dist/src/func/builtins/json.js.map +1 -1
  54. package/dist/src/func/builtins/schema.d.ts.map +1 -1
  55. package/dist/src/func/builtins/schema.js +30 -32
  56. package/dist/src/func/builtins/schema.js.map +1 -1
  57. package/dist/src/func/builtins/string.d.ts.map +1 -1
  58. package/dist/src/func/builtins/string.js +40 -64
  59. package/dist/src/func/builtins/string.js.map +1 -1
  60. package/dist/src/func/builtins/timespan.d.ts.map +1 -1
  61. package/dist/src/func/builtins/timespan.js.map +1 -1
  62. package/dist/src/index.d.ts +2 -2
  63. package/dist/src/index.d.ts.map +1 -1
  64. package/dist/src/index.js +2 -2
  65. package/dist/src/index.js.map +1 -1
  66. package/dist/src/parser/ast.d.ts +9 -2
  67. package/dist/src/parser/ast.d.ts.map +1 -1
  68. package/dist/src/parser/lexer.d.ts +1 -0
  69. package/dist/src/parser/lexer.d.ts.map +1 -1
  70. package/dist/src/parser/lexer.js +3 -0
  71. package/dist/src/parser/lexer.js.map +1 -1
  72. package/dist/src/parser/parser.d.ts +11 -1
  73. package/dist/src/parser/parser.d.ts.map +1 -1
  74. package/dist/src/parser/parser.js +75 -135
  75. package/dist/src/parser/parser.js.map +1 -1
  76. package/dist/src/planner/analysis/const-evaluator.d.ts.map +1 -1
  77. package/dist/src/planner/analysis/const-evaluator.js +6 -3
  78. package/dist/src/planner/analysis/const-evaluator.js.map +1 -1
  79. package/dist/src/planner/analysis/constraint-extractor.d.ts +2 -1
  80. package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
  81. package/dist/src/planner/analysis/constraint-extractor.js +154 -22
  82. package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
  83. package/dist/src/planner/building/alter-table.d.ts.map +1 -1
  84. package/dist/src/planner/building/alter-table.js +18 -1
  85. package/dist/src/planner/building/alter-table.js.map +1 -1
  86. package/dist/src/planner/building/analyze.d.ts +5 -0
  87. package/dist/src/planner/building/analyze.d.ts.map +1 -0
  88. package/dist/src/planner/building/analyze.js +5 -0
  89. package/dist/src/planner/building/analyze.js.map +1 -0
  90. package/dist/src/planner/building/block.d.ts.map +1 -1
  91. package/dist/src/planner/building/block.js +3 -0
  92. package/dist/src/planner/building/block.js.map +1 -1
  93. package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
  94. package/dist/src/planner/building/constraint-builder.js +25 -3
  95. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  96. package/dist/src/planner/building/delete.d.ts.map +1 -1
  97. package/dist/src/planner/building/delete.js +11 -0
  98. package/dist/src/planner/building/delete.js.map +1 -1
  99. package/dist/src/planner/building/drop-assertion.d.ts.map +1 -1
  100. package/dist/src/planner/building/drop-assertion.js +2 -1
  101. package/dist/src/planner/building/drop-assertion.js.map +1 -1
  102. package/dist/src/planner/building/expression.d.ts.map +1 -1
  103. package/dist/src/planner/building/expression.js +55 -7
  104. package/dist/src/planner/building/expression.js.map +1 -1
  105. package/dist/src/planner/building/foreign-key-builder.d.ts +16 -0
  106. package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -0
  107. package/dist/src/planner/building/foreign-key-builder.js +269 -0
  108. package/dist/src/planner/building/foreign-key-builder.js.map +1 -0
  109. package/dist/src/planner/building/function-call.d.ts.map +1 -1
  110. package/dist/src/planner/building/function-call.js +3 -2
  111. package/dist/src/planner/building/function-call.js.map +1 -1
  112. package/dist/src/planner/building/insert.d.ts.map +1 -1
  113. package/dist/src/planner/building/insert.js +91 -10
  114. package/dist/src/planner/building/insert.js.map +1 -1
  115. package/dist/src/planner/building/schema-resolution.d.ts +4 -0
  116. package/dist/src/planner/building/schema-resolution.d.ts.map +1 -1
  117. package/dist/src/planner/building/schema-resolution.js +14 -3
  118. package/dist/src/planner/building/schema-resolution.js.map +1 -1
  119. package/dist/src/planner/building/select-aggregates.d.ts +1 -0
  120. package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
  121. package/dist/src/planner/building/select-aggregates.js +118 -3
  122. package/dist/src/planner/building/select-aggregates.js.map +1 -1
  123. package/dist/src/planner/building/select-modifiers.js +3 -3
  124. package/dist/src/planner/building/select-modifiers.js.map +1 -1
  125. package/dist/src/planner/building/select-window.js +9 -8
  126. package/dist/src/planner/building/select-window.js.map +1 -1
  127. package/dist/src/planner/building/select.d.ts.map +1 -1
  128. package/dist/src/planner/building/select.js +21 -10
  129. package/dist/src/planner/building/select.js.map +1 -1
  130. package/dist/src/planner/building/table.d.ts.map +1 -1
  131. package/dist/src/planner/building/table.js +5 -3
  132. package/dist/src/planner/building/table.js.map +1 -1
  133. package/dist/src/planner/building/update.d.ts.map +1 -1
  134. package/dist/src/planner/building/update.js +30 -1
  135. package/dist/src/planner/building/update.js.map +1 -1
  136. package/dist/src/planner/building/with.js +1 -1
  137. package/dist/src/planner/building/with.js.map +1 -1
  138. package/dist/src/planner/cache/reference-graph.d.ts +1 -1
  139. package/dist/src/planner/cache/reference-graph.js +1 -1
  140. package/dist/src/planner/cost/index.d.ts +10 -3
  141. package/dist/src/planner/cost/index.d.ts.map +1 -1
  142. package/dist/src/planner/cost/index.js +17 -3
  143. package/dist/src/planner/cost/index.js.map +1 -1
  144. package/dist/src/planner/debug.js +1 -1
  145. package/dist/src/planner/debug.js.map +1 -1
  146. package/dist/src/planner/framework/characteristics.d.ts +1 -1
  147. package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
  148. package/dist/src/planner/framework/pass.d.ts +3 -1
  149. package/dist/src/planner/framework/pass.d.ts.map +1 -1
  150. package/dist/src/planner/framework/pass.js +62 -18
  151. package/dist/src/planner/framework/pass.js.map +1 -1
  152. package/dist/src/planner/framework/physical-utils.d.ts +5 -0
  153. package/dist/src/planner/framework/physical-utils.d.ts.map +1 -1
  154. package/dist/src/planner/framework/physical-utils.js +19 -0
  155. package/dist/src/planner/framework/physical-utils.js.map +1 -1
  156. package/dist/src/planner/framework/trace.d.ts.map +1 -1
  157. package/dist/src/planner/framework/trace.js +3 -2
  158. package/dist/src/planner/framework/trace.js.map +1 -1
  159. package/dist/src/planner/nodes/alias-node.d.ts +2 -1
  160. package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
  161. package/dist/src/planner/nodes/alias-node.js +8 -0
  162. package/dist/src/planner/nodes/alias-node.js.map +1 -1
  163. package/dist/src/planner/nodes/alter-table-node.d.ts +42 -0
  164. package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -0
  165. package/dist/src/planner/nodes/alter-table-node.js +55 -0
  166. package/dist/src/planner/nodes/alter-table-node.js.map +1 -0
  167. package/dist/src/planner/nodes/analyze-node.d.ts +25 -0
  168. package/dist/src/planner/nodes/analyze-node.d.ts.map +1 -0
  169. package/dist/src/planner/nodes/analyze-node.js +83 -0
  170. package/dist/src/planner/nodes/analyze-node.js.map +1 -0
  171. package/dist/src/planner/nodes/bloom-join-node.d.ts +66 -0
  172. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -0
  173. package/dist/src/planner/nodes/bloom-join-node.js +200 -0
  174. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -0
  175. package/dist/src/planner/nodes/constraint-check-node.d.ts +1 -1
  176. package/dist/src/planner/nodes/constraint-check-node.d.ts.map +1 -1
  177. package/dist/src/planner/nodes/cte-reference-node.js +7 -7
  178. package/dist/src/planner/nodes/cte-reference-node.js.map +1 -1
  179. package/dist/src/planner/nodes/join-node.d.ts +9 -1
  180. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  181. package/dist/src/planner/nodes/join-node.js +69 -79
  182. package/dist/src/planner/nodes/join-node.js.map +1 -1
  183. package/dist/src/planner/nodes/merge-join-node.d.ts +60 -0
  184. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -0
  185. package/dist/src/planner/nodes/merge-join-node.js +207 -0
  186. package/dist/src/planner/nodes/merge-join-node.js.map +1 -0
  187. package/dist/src/planner/nodes/plan-node-type.d.ts +1 -0
  188. package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
  189. package/dist/src/planner/nodes/plan-node-type.js +1 -0
  190. package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
  191. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  192. package/dist/src/planner/nodes/project-node.js +3 -2
  193. package/dist/src/planner/nodes/project-node.js.map +1 -1
  194. package/dist/src/planner/nodes/reference.d.ts +2 -1
  195. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  196. package/dist/src/planner/nodes/reference.js +6 -2
  197. package/dist/src/planner/nodes/reference.js.map +1 -1
  198. package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
  199. package/dist/src/planner/nodes/returning-node.js +3 -2
  200. package/dist/src/planner/nodes/returning-node.js.map +1 -1
  201. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  202. package/dist/src/planner/nodes/subquery.js.map +1 -1
  203. package/dist/src/planner/nodes/table-access-nodes.js +1 -1
  204. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  205. package/dist/src/planner/nodes/update-node.d.ts +2 -0
  206. package/dist/src/planner/nodes/update-node.d.ts.map +1 -1
  207. package/dist/src/planner/nodes/update-node.js +2 -1
  208. package/dist/src/planner/nodes/update-node.js.map +1 -1
  209. package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
  210. package/dist/src/planner/nodes/window-function.js +7 -7
  211. package/dist/src/planner/nodes/window-function.js.map +1 -1
  212. package/dist/src/planner/nodes/window-node.d.ts +2 -2
  213. package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
  214. package/dist/src/planner/nodes/window-node.js +9 -14
  215. package/dist/src/planner/nodes/window-node.js.map +1 -1
  216. package/dist/src/planner/optimizer.d.ts.map +1 -1
  217. package/dist/src/planner/optimizer.js +40 -2
  218. package/dist/src/planner/optimizer.js.map +1 -1
  219. package/dist/src/planner/planning-context.d.ts.map +1 -1
  220. package/dist/src/planner/planning-context.js +1 -6
  221. package/dist/src/planner/planning-context.js.map +1 -1
  222. package/dist/src/planner/resolve.d.ts.map +1 -1
  223. package/dist/src/planner/resolve.js.map +1 -1
  224. package/dist/src/planner/rules/access/rule-select-access-path.js +157 -28
  225. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  226. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.d.ts.map +1 -1
  227. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js +27 -6
  228. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js.map +1 -1
  229. package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts +19 -0
  230. package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts.map +1 -0
  231. package/dist/src/planner/rules/cache/rule-in-subquery-cache.js +53 -0
  232. package/dist/src/planner/rules/cache/rule-in-subquery-cache.js.map +1 -0
  233. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.d.ts.map +1 -1
  234. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js +5 -0
  235. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js.map +1 -1
  236. package/dist/src/planner/rules/distinct/rule-distinct-elimination.d.ts +18 -0
  237. package/dist/src/planner/rules/distinct/rule-distinct-elimination.d.ts.map +1 -0
  238. package/dist/src/planner/rules/distinct/rule-distinct-elimination.js +37 -0
  239. package/dist/src/planner/rules/distinct/rule-distinct-elimination.js.map +1 -0
  240. package/dist/src/planner/rules/join/rule-join-key-inference.d.ts +8 -3
  241. package/dist/src/planner/rules/join/rule-join-key-inference.d.ts.map +1 -1
  242. package/dist/src/planner/rules/join/rule-join-key-inference.js +28 -17
  243. package/dist/src/planner/rules/join/rule-join-key-inference.js.map +1 -1
  244. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts +16 -0
  245. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -0
  246. package/dist/src/planner/rules/join/rule-join-physical-selection.js +216 -0
  247. package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -0
  248. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
  249. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +34 -4
  250. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  251. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +23 -0
  252. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -0
  253. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +293 -0
  254. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -0
  255. package/dist/src/planner/scopes/multi.d.ts +3 -2
  256. package/dist/src/planner/scopes/multi.d.ts.map +1 -1
  257. package/dist/src/planner/scopes/multi.js +32 -7
  258. package/dist/src/planner/scopes/multi.js.map +1 -1
  259. package/dist/src/planner/scopes/shadow.d.ts +20 -0
  260. package/dist/src/planner/scopes/shadow.d.ts.map +1 -0
  261. package/dist/src/planner/scopes/shadow.js +31 -0
  262. package/dist/src/planner/scopes/shadow.js.map +1 -0
  263. package/dist/src/planner/stats/analyze.d.ts +17 -0
  264. package/dist/src/planner/stats/analyze.d.ts.map +1 -0
  265. package/dist/src/planner/stats/analyze.js +114 -0
  266. package/dist/src/planner/stats/analyze.js.map +1 -0
  267. package/dist/src/planner/stats/catalog-stats.d.ts +80 -0
  268. package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -0
  269. package/dist/src/planner/stats/catalog-stats.js +248 -0
  270. package/dist/src/planner/stats/catalog-stats.js.map +1 -0
  271. package/dist/src/planner/stats/histogram.d.ts +24 -0
  272. package/dist/src/planner/stats/histogram.d.ts.map +1 -0
  273. package/dist/src/planner/stats/histogram.js +142 -0
  274. package/dist/src/planner/stats/histogram.js.map +1 -0
  275. package/dist/src/planner/type-utils.d.ts.map +1 -1
  276. package/dist/src/planner/type-utils.js +8 -2
  277. package/dist/src/planner/type-utils.js.map +1 -1
  278. package/dist/src/planner/util/key-utils.d.ts +48 -2
  279. package/dist/src/planner/util/key-utils.d.ts.map +1 -1
  280. package/dist/src/planner/util/key-utils.js +123 -0
  281. package/dist/src/planner/util/key-utils.js.map +1 -1
  282. package/dist/src/planner/validation/determinism-validator.d.ts +9 -0
  283. package/dist/src/planner/validation/determinism-validator.d.ts.map +1 -1
  284. package/dist/src/planner/validation/determinism-validator.js +11 -0
  285. package/dist/src/planner/validation/determinism-validator.js.map +1 -1
  286. package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
  287. package/dist/src/planner/validation/plan-validator.js +1 -0
  288. package/dist/src/planner/validation/plan-validator.js.map +1 -1
  289. package/dist/src/runtime/context-helpers.d.ts +34 -10
  290. package/dist/src/runtime/context-helpers.d.ts.map +1 -1
  291. package/dist/src/runtime/context-helpers.js +115 -39
  292. package/dist/src/runtime/context-helpers.js.map +1 -1
  293. package/dist/src/runtime/deferred-constraint-queue.d.ts +0 -1
  294. package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
  295. package/dist/src/runtime/deferred-constraint-queue.js +10 -23
  296. package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
  297. package/dist/src/runtime/descriptor-helpers.d.ts +7 -0
  298. package/dist/src/runtime/descriptor-helpers.d.ts.map +1 -0
  299. package/dist/src/runtime/descriptor-helpers.js +24 -0
  300. package/dist/src/runtime/descriptor-helpers.js.map +1 -0
  301. package/dist/src/runtime/emission-context.d.ts +7 -1
  302. package/dist/src/runtime/emission-context.d.ts.map +1 -1
  303. package/dist/src/runtime/emission-context.js +16 -0
  304. package/dist/src/runtime/emission-context.js.map +1 -1
  305. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  306. package/dist/src/runtime/emit/aggregate.js +97 -93
  307. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  308. package/dist/src/runtime/emit/alter-table.d.ts +5 -0
  309. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -0
  310. package/dist/src/runtime/emit/alter-table.js +209 -0
  311. package/dist/src/runtime/emit/alter-table.js.map +1 -0
  312. package/dist/src/runtime/emit/analyze.d.ts +9 -0
  313. package/dist/src/runtime/emit/analyze.d.ts.map +1 -0
  314. package/dist/src/runtime/emit/analyze.js +72 -0
  315. package/dist/src/runtime/emit/analyze.js.map +1 -0
  316. package/dist/src/runtime/emit/array-index.d.ts.map +1 -1
  317. package/dist/src/runtime/emit/array-index.js +4 -2
  318. package/dist/src/runtime/emit/array-index.js.map +1 -1
  319. package/dist/src/runtime/emit/between.d.ts.map +1 -1
  320. package/dist/src/runtime/emit/between.js +8 -20
  321. package/dist/src/runtime/emit/between.js.map +1 -1
  322. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  323. package/dist/src/runtime/emit/binary.js +155 -126
  324. package/dist/src/runtime/emit/binary.js.map +1 -1
  325. package/dist/src/runtime/emit/bloom-join.d.ts +12 -0
  326. package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -0
  327. package/dist/src/runtime/emit/bloom-join.js +114 -0
  328. package/dist/src/runtime/emit/bloom-join.js.map +1 -0
  329. package/dist/src/runtime/emit/cache.js +2 -2
  330. package/dist/src/runtime/emit/cache.js.map +1 -1
  331. package/dist/src/runtime/emit/cast.d.ts.map +1 -1
  332. package/dist/src/runtime/emit/cast.js +31 -117
  333. package/dist/src/runtime/emit/cast.js.map +1 -1
  334. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  335. package/dist/src/runtime/emit/constraint-check.js +2 -24
  336. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  337. package/dist/src/runtime/emit/cte-reference.d.ts.map +1 -1
  338. package/dist/src/runtime/emit/cte-reference.js +11 -5
  339. package/dist/src/runtime/emit/cte-reference.js.map +1 -1
  340. package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
  341. package/dist/src/runtime/emit/distinct.js +21 -12
  342. package/dist/src/runtime/emit/distinct.js.map +1 -1
  343. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  344. package/dist/src/runtime/emit/dml-executor.js +5 -1
  345. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  346. package/dist/src/runtime/emit/drop-assertion.d.ts.map +1 -1
  347. package/dist/src/runtime/emit/drop-assertion.js +2 -0
  348. package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
  349. package/dist/src/runtime/emit/filter.d.ts.map +1 -1
  350. package/dist/src/runtime/emit/filter.js +26 -7
  351. package/dist/src/runtime/emit/filter.js.map +1 -1
  352. package/dist/src/runtime/emit/internal-recursive-cte-ref.d.ts.map +1 -1
  353. package/dist/src/runtime/emit/internal-recursive-cte-ref.js +11 -5
  354. package/dist/src/runtime/emit/internal-recursive-cte-ref.js.map +1 -1
  355. package/dist/src/runtime/emit/join.d.ts +1 -1
  356. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  357. package/dist/src/runtime/emit/join.js +44 -33
  358. package/dist/src/runtime/emit/join.js.map +1 -1
  359. package/dist/src/runtime/emit/merge-join.d.ts +14 -0
  360. package/dist/src/runtime/emit/merge-join.d.ts.map +1 -0
  361. package/dist/src/runtime/emit/merge-join.js +152 -0
  362. package/dist/src/runtime/emit/merge-join.js.map +1 -0
  363. package/dist/src/runtime/emit/parameter.d.ts.map +1 -1
  364. package/dist/src/runtime/emit/parameter.js +10 -32
  365. package/dist/src/runtime/emit/parameter.js.map +1 -1
  366. package/dist/src/runtime/emit/project.d.ts.map +1 -1
  367. package/dist/src/runtime/emit/project.js +22 -12
  368. package/dist/src/runtime/emit/project.js.map +1 -1
  369. package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
  370. package/dist/src/runtime/emit/recursive-cte.js +5 -9
  371. package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
  372. package/dist/src/runtime/emit/returning.d.ts.map +1 -1
  373. package/dist/src/runtime/emit/returning.js +14 -8
  374. package/dist/src/runtime/emit/returning.js.map +1 -1
  375. package/dist/src/runtime/emit/scan.d.ts.map +1 -1
  376. package/dist/src/runtime/emit/scan.js +4 -1
  377. package/dist/src/runtime/emit/scan.js.map +1 -1
  378. package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
  379. package/dist/src/runtime/emit/set-operation.js +8 -5
  380. package/dist/src/runtime/emit/set-operation.js.map +1 -1
  381. package/dist/src/runtime/emit/sort.js +2 -2
  382. package/dist/src/runtime/emit/sort.js.map +1 -1
  383. package/dist/src/runtime/emit/subquery.js +2 -2
  384. package/dist/src/runtime/emit/subquery.js.map +1 -1
  385. package/dist/src/runtime/emit/table-valued-function.d.ts.map +1 -1
  386. package/dist/src/runtime/emit/table-valued-function.js +21 -7
  387. package/dist/src/runtime/emit/table-valued-function.js.map +1 -1
  388. package/dist/src/runtime/emit/transaction.d.ts.map +1 -1
  389. package/dist/src/runtime/emit/transaction.js +18 -46
  390. package/dist/src/runtime/emit/transaction.js.map +1 -1
  391. package/dist/src/runtime/emit/unary.js +2 -2
  392. package/dist/src/runtime/emit/unary.js.map +1 -1
  393. package/dist/src/runtime/emit/update.d.ts.map +1 -1
  394. package/dist/src/runtime/emit/update.js +43 -21
  395. package/dist/src/runtime/emit/update.js.map +1 -1
  396. package/dist/src/runtime/emit/window.d.ts.map +1 -1
  397. package/dist/src/runtime/emit/window.js +368 -126
  398. package/dist/src/runtime/emit/window.js.map +1 -1
  399. package/dist/src/runtime/foreign-key-actions.d.ts +15 -0
  400. package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -0
  401. package/dist/src/runtime/foreign-key-actions.js +109 -0
  402. package/dist/src/runtime/foreign-key-actions.js.map +1 -0
  403. package/dist/src/runtime/register.d.ts.map +1 -1
  404. package/dist/src/runtime/register.js +8 -0
  405. package/dist/src/runtime/register.js.map +1 -1
  406. package/dist/src/runtime/scheduler.d.ts.map +1 -1
  407. package/dist/src/runtime/scheduler.js +4 -1
  408. package/dist/src/runtime/scheduler.js.map +1 -1
  409. package/dist/src/runtime/types.d.ts +6 -5
  410. package/dist/src/runtime/types.d.ts.map +1 -1
  411. package/dist/src/runtime/types.js.map +1 -1
  412. package/dist/src/schema/change-events.d.ts +36 -8
  413. package/dist/src/schema/change-events.d.ts.map +1 -1
  414. package/dist/src/schema/change-events.js.map +1 -1
  415. package/dist/src/schema/column.d.ts +5 -1
  416. package/dist/src/schema/column.d.ts.map +1 -1
  417. package/dist/src/schema/column.js +1 -2
  418. package/dist/src/schema/column.js.map +1 -1
  419. package/dist/src/schema/manager.d.ts +54 -4
  420. package/dist/src/schema/manager.d.ts.map +1 -1
  421. package/dist/src/schema/manager.js +353 -313
  422. package/dist/src/schema/manager.js.map +1 -1
  423. package/dist/src/schema/schema-differ.js +3 -3
  424. package/dist/src/schema/schema-differ.js.map +1 -1
  425. package/dist/src/schema/schema.d.ts +1 -1
  426. package/dist/src/schema/schema.js +2 -2
  427. package/dist/src/schema/schema.js.map +1 -1
  428. package/dist/src/schema/table.d.ts +49 -0
  429. package/dist/src/schema/table.d.ts.map +1 -1
  430. package/dist/src/schema/table.js +30 -11
  431. package/dist/src/schema/table.js.map +1 -1
  432. package/dist/src/types/builtin-types.d.ts.map +1 -1
  433. package/dist/src/types/builtin-types.js +26 -95
  434. package/dist/src/types/builtin-types.js.map +1 -1
  435. package/dist/src/types/index.d.ts +1 -1
  436. package/dist/src/types/index.d.ts.map +1 -1
  437. package/dist/src/types/index.js +1 -1
  438. package/dist/src/types/index.js.map +1 -1
  439. package/dist/src/types/json-type.d.ts.map +1 -1
  440. package/dist/src/types/json-type.js +28 -40
  441. package/dist/src/types/json-type.js.map +1 -1
  442. package/dist/src/types/logical-type.d.ts +6 -0
  443. package/dist/src/types/logical-type.d.ts.map +1 -1
  444. package/dist/src/types/logical-type.js +12 -0
  445. package/dist/src/types/logical-type.js.map +1 -1
  446. package/dist/src/types/temporal-types.d.ts.map +1 -1
  447. package/dist/src/types/temporal-types.js +8 -37
  448. package/dist/src/types/temporal-types.js.map +1 -1
  449. package/dist/src/util/async-iterator.d.ts +30 -0
  450. package/dist/src/util/async-iterator.d.ts.map +1 -0
  451. package/dist/src/util/async-iterator.js +101 -0
  452. package/dist/src/util/async-iterator.js.map +1 -0
  453. package/dist/src/util/coercion.d.ts +4 -5
  454. package/dist/src/util/coercion.d.ts.map +1 -1
  455. package/dist/src/util/coercion.js +10 -14
  456. package/dist/src/util/coercion.js.map +1 -1
  457. package/dist/src/util/comparison.d.ts +34 -21
  458. package/dist/src/util/comparison.d.ts.map +1 -1
  459. package/dist/src/util/comparison.js +77 -43
  460. package/dist/src/util/comparison.js.map +1 -1
  461. package/dist/src/util/environment.d.ts +0 -8
  462. package/dist/src/util/environment.d.ts.map +1 -1
  463. package/dist/src/util/environment.js +0 -12
  464. package/dist/src/util/environment.js.map +1 -1
  465. package/dist/src/util/key-serializer.d.ts +33 -0
  466. package/dist/src/util/key-serializer.d.ts.map +1 -0
  467. package/dist/src/util/key-serializer.js +95 -0
  468. package/dist/src/util/key-serializer.js.map +1 -0
  469. package/dist/src/util/plugin-helper.d.ts.map +1 -1
  470. package/dist/src/util/plugin-helper.js +21 -45
  471. package/dist/src/util/plugin-helper.js.map +1 -1
  472. package/dist/src/util/serialization.d.ts +1 -0
  473. package/dist/src/util/serialization.d.ts.map +1 -1
  474. package/dist/src/util/serialization.js +8 -1
  475. package/dist/src/util/serialization.js.map +1 -1
  476. package/dist/src/util/working-table-iterable.d.ts +6 -5
  477. package/dist/src/util/working-table-iterable.d.ts.map +1 -1
  478. package/dist/src/util/working-table-iterable.js +8 -15
  479. package/dist/src/util/working-table-iterable.js.map +1 -1
  480. package/dist/src/vtab/best-access-plan.d.ts +12 -0
  481. package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
  482. package/dist/src/vtab/best-access-plan.js +22 -0
  483. package/dist/src/vtab/best-access-plan.js.map +1 -1
  484. package/dist/src/vtab/events.d.ts.map +1 -1
  485. package/dist/src/vtab/events.js +6 -3
  486. package/dist/src/vtab/events.js.map +1 -1
  487. package/dist/src/vtab/manifest.d.ts +3 -1
  488. package/dist/src/vtab/manifest.d.ts.map +1 -1
  489. package/dist/src/vtab/memory/index.d.ts +2 -2
  490. package/dist/src/vtab/memory/index.d.ts.map +1 -1
  491. package/dist/src/vtab/memory/index.js +4 -7
  492. package/dist/src/vtab/memory/index.js.map +1 -1
  493. package/dist/src/vtab/memory/layer/base-cursor.d.ts.map +1 -1
  494. package/dist/src/vtab/memory/layer/base-cursor.js +37 -9
  495. package/dist/src/vtab/memory/layer/base-cursor.js.map +1 -1
  496. package/dist/src/vtab/memory/layer/base.js +1 -1
  497. package/dist/src/vtab/memory/layer/base.js.map +1 -1
  498. package/dist/src/vtab/memory/layer/connection.d.ts +11 -7
  499. package/dist/src/vtab/memory/layer/connection.d.ts.map +1 -1
  500. package/dist/src/vtab/memory/layer/connection.js +32 -44
  501. package/dist/src/vtab/memory/layer/connection.js.map +1 -1
  502. package/dist/src/vtab/memory/layer/manager.d.ts +15 -3
  503. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  504. package/dist/src/vtab/memory/layer/manager.js +85 -37
  505. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  506. package/dist/src/vtab/memory/layer/scan-plan.d.ts +2 -0
  507. package/dist/src/vtab/memory/layer/scan-plan.d.ts.map +1 -1
  508. package/dist/src/vtab/memory/layer/scan-plan.js +153 -78
  509. package/dist/src/vtab/memory/layer/scan-plan.js.map +1 -1
  510. package/dist/src/vtab/memory/layer/transaction-cursor.d.ts.map +1 -1
  511. package/dist/src/vtab/memory/layer/transaction-cursor.js +39 -9
  512. package/dist/src/vtab/memory/layer/transaction-cursor.js.map +1 -1
  513. package/dist/src/vtab/memory/layer/transaction.d.ts +1 -0
  514. package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
  515. package/dist/src/vtab/memory/layer/transaction.js +6 -20
  516. package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
  517. package/dist/src/vtab/memory/module.d.ts +14 -24
  518. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  519. package/dist/src/vtab/memory/module.js +88 -283
  520. package/dist/src/vtab/memory/module.js.map +1 -1
  521. package/dist/src/vtab/memory/table.d.ts +9 -0
  522. package/dist/src/vtab/memory/table.d.ts.map +1 -1
  523. package/dist/src/vtab/memory/table.js +121 -18
  524. package/dist/src/vtab/memory/table.js.map +1 -1
  525. package/dist/src/vtab/memory/types.d.ts +1 -0
  526. package/dist/src/vtab/memory/types.d.ts.map +1 -1
  527. package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
  528. package/dist/src/vtab/module.d.ts +13 -0
  529. package/dist/src/vtab/module.d.ts.map +1 -1
  530. package/dist/src/vtab/table.d.ts +9 -0
  531. package/dist/src/vtab/table.d.ts.map +1 -1
  532. package/dist/src/vtab/table.js.map +1 -1
  533. package/package.json +2 -2
@@ -1,461 +1,545 @@
1
- import { createLogger } from '../../common/logger.js'; // Import logger
1
+ import { createLogger } from '../../common/logger.js';
2
2
  import { Temporal } from 'temporal-polyfill';
3
3
  import { StatusCode } from '../../common/types.js';
4
4
  import { createScalarFunction } from '../registration.js';
5
5
  import { quereusError } from '../../common/errors.js';
6
- const log = createLogger('func:builtins:datetime'); // Create logger instance
6
+ const log = createLogger('func:builtins:datetime');
7
7
  const warnLog = log.extend('warn');
8
8
  const errorLog = log.extend('error');
9
9
  // --- Constants ---
10
10
  const MILLIS_PER_DAY = 86400000;
11
+ const MILLIS_PER_SECOND = 1000;
11
12
  const JULIAN_DAY_UNIX_EPOCH = 2440587.5;
12
- const SQLITE_DEFAULT_DATE = { year: 2000, month: 1, day: 1 }; // Used for time-only inputs
13
- // --- Parsing Helper (using Temporal) --- //
13
+ const SQLITE_DEFAULT_DATE = { year: 2000, month: 1, day: 1 };
14
+ // Reasonable epoch-seconds range: approx 1900–3000 AD
15
+ const MIN_EPOCH_SECONDS = -2208988800;
16
+ const MAX_EPOCH_SECONDS = 32503680000;
17
+ // Julian day heuristic bounds
18
+ const MIN_JULIAN_DAY = 1000000;
19
+ const MAX_JULIAN_DAY = 4000000;
20
+ // --- Parsing Helpers --- //
21
+ function instantFromEpochSeconds(seconds) {
22
+ return Temporal.Instant.fromEpochMilliseconds(seconds * MILLIS_PER_SECOND);
23
+ }
24
+ function instantToUtcZoned(instant) {
25
+ return instant.toZonedDateTimeISO('UTC');
26
+ }
27
+ function plainDateTimeToUtcZoned(pdt) {
28
+ return pdt.toZonedDateTime('UTC');
29
+ }
30
+ function isInRange(value, min, max) {
31
+ return value > min && value < max;
32
+ }
33
+ /**
34
+ * Parses a numeric value as a Julian day number, Unix epoch seconds, or Unix
35
+ * epoch milliseconds — using heuristics when `isUnixEpoch` is not set.
36
+ */
37
+ function parseNumericToTemporal(timeVal, isUnixEpoch) {
38
+ if (isUnixEpoch)
39
+ return instantToUtcZoned(instantFromEpochSeconds(timeVal));
40
+ if (isInRange(timeVal, MIN_JULIAN_DAY, MAX_JULIAN_DAY)) {
41
+ const epochMillis = (timeVal - JULIAN_DAY_UNIX_EPOCH) * MILLIS_PER_DAY;
42
+ return instantToUtcZoned(Temporal.Instant.fromEpochMilliseconds(epochMillis));
43
+ }
44
+ // Prioritize seconds if within reasonable range
45
+ if (isInRange(timeVal, MIN_EPOCH_SECONDS, MAX_EPOCH_SECONDS)) {
46
+ try {
47
+ return instantToUtcZoned(instantFromEpochSeconds(timeVal));
48
+ }
49
+ catch { /* fall through to milliseconds */ }
50
+ }
51
+ // Fall back to milliseconds
52
+ if (isInRange(timeVal, MIN_EPOCH_SECONDS * MILLIS_PER_SECOND, MAX_EPOCH_SECONDS * MILLIS_PER_SECOND)) {
53
+ try {
54
+ return instantToUtcZoned(Temporal.Instant.fromEpochMilliseconds(timeVal));
55
+ }
56
+ catch { /* exhausted */ }
57
+ }
58
+ return null;
59
+ }
60
+ /**
61
+ * Attempts parsing the fractional-seconds portion of a manual time match,
62
+ * returning {millisecond, microsecond, nanosecond} components.
63
+ */
64
+ function parseFractionalNanos(fracDigits) {
65
+ const ns = parseInt(fracDigits.padEnd(9, '0').substring(0, 9));
66
+ return {
67
+ millisecond: Math.floor(ns / 1_000_000),
68
+ microsecond: Math.floor((ns % 1_000_000) / 1_000),
69
+ nanosecond: ns % 1_000,
70
+ };
71
+ }
72
+ /** Try parsing with a Temporal type constructor, returning null on failure. */
73
+ function tryParse(parseFn) {
74
+ try {
75
+ return parseFn();
76
+ }
77
+ catch {
78
+ return null;
79
+ }
80
+ }
14
81
  /**
15
82
  * Parses various date/time string formats, Julian day numbers, or Unix timestamps
16
- * into a Temporal object. Tries to mimic SQLite's lenient parsing.
17
- * @param timeVal The input value (string, number, null).
18
- * @param isUnixEpoch Flag indicating if the input number should be treated as Unix epoch seconds.
19
- * @returns A Temporal.ZonedDateTime (usually UTC) or null if parsing fails.
83
+ * into a Temporal.ZonedDateTime. Mimics SQLite's lenient parsing.
20
84
  */
21
85
  function parseToTemporal(timeVal, isUnixEpoch = false) {
22
86
  if (timeVal === null || timeVal === undefined)
23
87
  return null;
24
88
  try {
25
- if (typeof timeVal === 'number') {
26
- if (isUnixEpoch) {
27
- // Assume Unix timestamp in seconds, convert to Instant using milliseconds
28
- const instant = Temporal.Instant.fromEpochMilliseconds(timeVal * 1000);
29
- return instant.toZonedDateTimeISO('UTC');
30
- }
31
- else {
32
- // Check if it looks like a Julian day number
33
- if (timeVal > 1000000 && timeVal < 4000000) { // Heuristic for JD
34
- const epochMillis = (timeVal - JULIAN_DAY_UNIX_EPOCH) * MILLIS_PER_DAY;
35
- const instant = Temporal.Instant.fromEpochMilliseconds(epochMillis);
36
- return instant.toZonedDateTimeISO('UTC');
37
- }
38
- else {
39
- // Try interpreting as Unix timestamp (seconds or milliseconds) - prioritize seconds if reasonable
40
- try {
41
- // Reasonable range check for seconds (approx 1900-3000 AD)
42
- if (timeVal > -2208988800 && timeVal < 32503680000) {
43
- // Use fromEpochMilliseconds for seconds as fromEpochSeconds might not be in polyfill types
44
- const instant = Temporal.Instant.fromEpochMilliseconds(timeVal * 1000);
45
- return instant.toZonedDateTimeISO('UTC');
46
- }
47
- }
48
- catch { /* continue */ }
49
- // Try milliseconds if seconds failed or out of range
50
- try {
51
- // Reasonable range check for milliseconds (approx 1900-3000 AD)
52
- if (timeVal > -2208988800000 && timeVal < 32503680000000) {
53
- const instant = Temporal.Instant.fromEpochMilliseconds(timeVal);
54
- return instant.toZonedDateTimeISO('UTC');
55
- }
56
- }
57
- catch { /* continue */ }
58
- return null; // Unrecognized number format
59
- }
60
- }
61
- }
89
+ if (typeof timeVal === 'number')
90
+ return parseNumericToTemporal(timeVal, isUnixEpoch);
62
91
  if (typeof timeVal !== 'string')
63
92
  return null;
64
- const trimmedVal = timeVal.trim();
65
- const lowerTrimmedVal = trimmedVal.toLowerCase();
66
- if (lowerTrimmedVal === 'now') {
67
- // 'now' typically means the current time in the local timezone in SQL contexts
93
+ const trimmed = timeVal.trim();
94
+ if (trimmed.toLowerCase() === 'now')
68
95
  return Temporal.Now.zonedDateTimeISO();
69
- }
70
- // Attempt direct parsing with Temporal.ZonedDateTime (ISO format with timezone)
71
- try {
72
- if (/^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(trimmedVal)) {
73
- const instant = Temporal.Instant.from(trimmedVal.replace(' ', 'T') + 'Z');
74
- return instant.toZonedDateTimeISO('UTC');
75
- }
76
- const zdt = Temporal.ZonedDateTime.from(trimmedVal);
77
- return zdt;
78
- }
79
- catch { /* continue */ }
80
- // Attempt direct parsing with Temporal.PlainDateTime (ISO format without timezone)
81
- try {
82
- const pdt = Temporal.PlainDateTime.from(trimmedVal.replace(' ', 'T'));
83
- return pdt.toZonedDateTime('UTC');
84
- }
85
- catch { /* continue */ }
86
- // Attempt direct parsing with Temporal.PlainDate (YYYY-MM-DD)
87
- try {
88
- const pd = Temporal.PlainDate.from(trimmedVal);
89
- return pd.toZonedDateTime('UTC'); // Defaults to 00:00:00 UTC
90
- }
91
- catch { /* continue */ }
92
- // Attempt direct parsing with Temporal.PlainTime (HH:MM:SS.SSS)
93
- try {
94
- const pt = Temporal.PlainTime.from(trimmedVal);
95
- // If only time, assume default date (2000-01-01) and UTC
96
- // Access individual properties instead of getISOFields
97
- return Temporal.PlainDateTime.from({
98
- ...SQLITE_DEFAULT_DATE,
99
- hour: pt.hour,
100
- minute: pt.minute,
101
- second: pt.second,
102
- millisecond: pt.millisecond,
103
- microsecond: pt.microsecond,
104
- nanosecond: pt.nanosecond,
105
- }).toZonedDateTime('UTC');
106
- }
107
- catch { /* continue */ }
108
- // --- Fallback Manual Parsing for SQLite Lenient Formats ---
109
- // YYYYMMDD
110
- let match = trimmedVal.match(/^(\d{4})(\d{2})(\d{2})$/);
111
- if (match) {
112
- const pdt = Temporal.PlainDateTime.from({ year: parseInt(match[1]), month: parseInt(match[2]), day: parseInt(match[3]) });
113
- return pdt.toZonedDateTime('UTC');
114
- }
115
- // HH:MM
116
- match = trimmedVal.match(/^(\d{2}):(\d{2})$/);
117
- if (match) {
118
- const ptArgs = { hour: parseInt(match[1]), minute: parseInt(match[2]) };
119
- return Temporal.PlainDateTime.from({ ...SQLITE_DEFAULT_DATE, ...ptArgs }).toZonedDateTime('UTC');
120
- }
121
- // HH:MM:SS
122
- match = trimmedVal.match(/^(\d{2}):(\d{2}):(\d{2})$/);
123
- if (match) {
124
- const ptArgs = { hour: parseInt(match[1]), minute: parseInt(match[2]), second: parseInt(match[3]) };
125
- return Temporal.PlainDateTime.from({ ...SQLITE_DEFAULT_DATE, ...ptArgs }).toZonedDateTime('UTC');
126
- }
127
- // HH:MM:SS.SSS (handle varying ms digits)
128
- match = trimmedVal.match(/^(\d{2}):(\d{2}):(\d{2})\.(\d{1,9})$/);
129
- if (match) {
130
- const ns = parseInt(match[4].padEnd(9, '0').substring(0, 9)); // Pad/truncate to nanoseconds
131
- const ptArgs = {
132
- hour: parseInt(match[1]),
133
- minute: parseInt(match[2]),
134
- second: parseInt(match[3]),
135
- millisecond: Math.floor(ns / 1_000_000),
136
- microsecond: Math.floor((ns % 1_000_000) / 1_000),
137
- nanosecond: ns % 1_000,
138
- };
139
- return Temporal.PlainDateTime.from({ ...SQLITE_DEFAULT_DATE, ...ptArgs }).toZonedDateTime('UTC');
140
- }
141
- warnLog('Failed to parse date/time string with Temporal: %s', timeVal);
142
- return null;
96
+ return parseISOString(trimmed)
97
+ ?? parseLenientFormats(trimmed);
143
98
  }
144
99
  catch (e) {
145
100
  warnLog('Error parsing date/time value "%s": %O', timeVal, e);
146
101
  return null;
147
102
  }
148
103
  }
149
- // --- Modifier Application (using Temporal) --- //
150
- // Regex to parse relative time modifiers like '+1 day', '-3 months'
104
+ /** Matches ISO datetime with an explicit offset (Z or ±HH:MM). */
105
+ const ISO_WITH_OFFSET = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})$/;
106
+ /** Matches ISO datetime without any timezone/offset suffix. */
107
+ const ISO_WITHOUT_OFFSET = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/;
108
+ /**
109
+ * Attempts standard ISO 8601 parsing strategies in priority order:
110
+ * offset datetime, plain datetime, plain date, plain time.
111
+ */
112
+ function parseISOString(s) {
113
+ const normalised = s.replace(' ', 'T');
114
+ // ISO datetime with explicit offset (Z or ±HH:MM) → parse as Instant → UTC
115
+ if (ISO_WITH_OFFSET.test(s)) {
116
+ const instant = tryParse(() => Temporal.Instant.from(normalised));
117
+ if (instant)
118
+ return instantToUtcZoned(instant);
119
+ }
120
+ // ISO datetime without timezone → treat as UTC
121
+ if (ISO_WITHOUT_OFFSET.test(s)) {
122
+ const instant = tryParse(() => Temporal.Instant.from(normalised + 'Z'));
123
+ if (instant)
124
+ return instantToUtcZoned(instant);
125
+ }
126
+ // Full ZonedDateTime (includes bracket timezone notation)
127
+ const zdt = tryParse(() => Temporal.ZonedDateTime.from(s));
128
+ if (zdt)
129
+ return zdt;
130
+ // PlainDateTime
131
+ const pdt = tryParse(() => Temporal.PlainDateTime.from(normalised));
132
+ if (pdt)
133
+ return plainDateTimeToUtcZoned(pdt);
134
+ // PlainDate (YYYY-MM-DD)
135
+ const pd = tryParse(() => Temporal.PlainDate.from(s));
136
+ if (pd)
137
+ return pd.toZonedDateTime('UTC');
138
+ // PlainTime → anchored to default date
139
+ const pt = tryParse(() => Temporal.PlainTime.from(s));
140
+ if (pt)
141
+ return plainTimeToDefaultZoned(pt);
142
+ return null;
143
+ }
144
+ /** Anchors a PlainTime to the SQLite default date (2000-01-01) at UTC. */
145
+ function plainTimeToDefaultZoned(pt) {
146
+ return plainDateTimeToUtcZoned(Temporal.PlainDateTime.from({
147
+ ...SQLITE_DEFAULT_DATE,
148
+ hour: pt.hour,
149
+ minute: pt.minute,
150
+ second: pt.second,
151
+ millisecond: pt.millisecond,
152
+ microsecond: pt.microsecond,
153
+ nanosecond: pt.nanosecond,
154
+ }));
155
+ }
156
+ /**
157
+ * Fallback manual parsing for SQLite lenient formats that Temporal doesn't
158
+ * handle directly: YYYYMMDD, HH:MM, HH:MM:SS, HH:MM:SS.fff
159
+ */
160
+ function parseLenientFormats(s) {
161
+ // YYYYMMDD
162
+ let match = s.match(/^(\d{4})(\d{2})(\d{2})$/);
163
+ if (match) {
164
+ const pdt = Temporal.PlainDateTime.from({
165
+ year: parseInt(match[1]), month: parseInt(match[2]), day: parseInt(match[3]),
166
+ });
167
+ return plainDateTimeToUtcZoned(pdt);
168
+ }
169
+ // HH:MM
170
+ match = s.match(/^(\d{2}):(\d{2})$/);
171
+ if (match) {
172
+ return plainDateTimeToUtcZoned(Temporal.PlainDateTime.from({
173
+ ...SQLITE_DEFAULT_DATE,
174
+ hour: parseInt(match[1]), minute: parseInt(match[2]),
175
+ }));
176
+ }
177
+ // HH:MM:SS
178
+ match = s.match(/^(\d{2}):(\d{2}):(\d{2})$/);
179
+ if (match) {
180
+ return plainDateTimeToUtcZoned(Temporal.PlainDateTime.from({
181
+ ...SQLITE_DEFAULT_DATE,
182
+ hour: parseInt(match[1]), minute: parseInt(match[2]), second: parseInt(match[3]),
183
+ }));
184
+ }
185
+ // HH:MM:SS.fff (variable precision)
186
+ match = s.match(/^(\d{2}):(\d{2}):(\d{2})\.(\d{1,9})$/);
187
+ if (match) {
188
+ return plainDateTimeToUtcZoned(Temporal.PlainDateTime.from({
189
+ ...SQLITE_DEFAULT_DATE,
190
+ hour: parseInt(match[1]), minute: parseInt(match[2]), second: parseInt(match[3]),
191
+ ...parseFractionalNanos(match[4]),
192
+ }));
193
+ }
194
+ warnLog('Failed to parse date/time string: %s', s);
195
+ return null;
196
+ }
197
+ // --- Strict Parsing (for epoch_* functions) --- //
198
+ /**
199
+ * ISO 8601 date/time pattern for strict parsing.
200
+ * Accepts: YYYY-MM-DD, YYYY-MM-DDTHH:MM[:SS[.fff]][Z|±HH:MM], and 'now'.
201
+ * Rejects bare numbers, lenient formats like YYYYMMDD, and time-only strings.
202
+ */
203
+ const STRICT_ISO_PATTERN = /^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?(Z|[+-]\d{2}:\d{2})?)?$/;
204
+ function parseStrictTimestring(timeVal) {
205
+ if (timeVal === null || timeVal === undefined)
206
+ return null;
207
+ if (typeof timeVal !== 'string')
208
+ return null;
209
+ const trimmed = timeVal.trim();
210
+ if (trimmed.toLowerCase() === 'now')
211
+ return Temporal.Now.zonedDateTimeISO();
212
+ if (!STRICT_ISO_PATTERN.test(trimmed))
213
+ return null;
214
+ return parseISOString(trimmed);
215
+ }
216
+ // --- Modifier Application --- //
151
217
  const RELATIVE_MODIFIER_REGEX = /^\s*([+-]?\s*\d+(\.\d+)?)\s+(day|hour|minute|second|month|year)s?\s*$/i;
152
- // Regex for 'weekday N'
153
- const WEEKDAY_MODIFIER_REGEX = /^\s*weekday\s+([0-6])\s*$/i; // 0=Sun, 1=Mon..6=Sat
218
+ const WEEKDAY_MODIFIER_REGEX = /^\s*weekday\s+([0-6])\s*$/i;
219
+ function applyRelativeShift(dt, value, unit) {
220
+ const durationLike = {};
221
+ if (unit === 'year' || unit === 'month' || unit === 'day') {
222
+ durationLike[`${unit}s`] = Math.trunc(value);
223
+ }
224
+ else if (unit === 'second') {
225
+ durationLike.seconds = Math.trunc(value);
226
+ const nanoseconds = Math.round((value % 1) * 1e9);
227
+ if (nanoseconds !== 0)
228
+ durationLike.nanoseconds = nanoseconds;
229
+ }
230
+ else {
231
+ durationLike[`${unit}s`] = value;
232
+ }
233
+ return dt.add(Temporal.Duration.from(durationLike));
234
+ }
235
+ function applyWeekdayAdjustment(dt, targetSqlWeekday) {
236
+ const targetISO = targetSqlWeekday === 0 ? 7 : targetSqlWeekday;
237
+ const daysToAdd = targetISO - dt.dayOfWeek;
238
+ if (daysToAdd > 0)
239
+ return dt.add({ days: daysToAdd - 7 });
240
+ if (daysToAdd < 0)
241
+ return dt.add({ days: daysToAdd });
242
+ return dt;
243
+ }
154
244
  function applyTemporalModifier(dt, modifier) {
155
- const trimmedModifier = modifier.trim().toLowerCase();
156
- // Group 1: Relative Time Shifts
157
- const relativeMatch = trimmedModifier.match(RELATIVE_MODIFIER_REGEX);
245
+ const trimmed = modifier.trim().toLowerCase();
246
+ const relativeMatch = trimmed.match(RELATIVE_MODIFIER_REGEX);
158
247
  if (relativeMatch) {
159
- const valueStr = relativeMatch[1].replace(/\s/g, '');
160
- const value = parseFloat(valueStr);
161
- const unit = relativeMatch[3]; // unit is guaranteed to be a string here
162
- if (isNaN(value)) {
248
+ const value = parseFloat(relativeMatch[1].replace(/\s/g, ''));
249
+ if (isNaN(value))
163
250
  quereusError(`Invalid number in modifier: ${modifier}`, StatusCode.MISUSE);
164
- }
165
- // Use Record<string, number> for better type checking with dynamic keys
166
- const durationLike = {};
167
- if (unit === 'year' || unit === 'month' || unit === 'day') {
168
- durationLike[`${unit}s`] = Math.trunc(value);
169
- }
170
- else if (unit === 'hour' || unit === 'minute' || unit === 'second') {
171
- if (unit === 'second') {
172
- const seconds = Math.trunc(value);
173
- const nanoseconds = Math.round((value % 1) * 1e9);
174
- durationLike.seconds = seconds;
175
- if (nanoseconds !== 0)
176
- durationLike.nanoseconds = nanoseconds;
177
- }
178
- else {
179
- durationLike[`${unit}s`] = value;
180
- }
181
- }
182
- else {
183
- quereusError(`Internal error: Unknown unit ${unit}`, StatusCode.MISUSE);
184
- }
185
- const duration = Temporal.Duration.from(durationLike);
186
- return dt.add(duration);
251
+ return applyRelativeShift(dt, value, relativeMatch[3]);
187
252
  }
188
- // Group 2: Start/End of Unit
189
- switch (trimmedModifier) {
190
- case 'start of day':
191
- return dt.startOfDay();
192
- case 'start of month':
193
- return dt.startOfDay().with({ day: 1 });
194
- case 'start of year':
195
- return dt.startOfDay().with({ month: 1, day: 1 });
253
+ switch (trimmed) {
254
+ case 'start of day': return dt.startOfDay();
255
+ case 'start of month': return dt.startOfDay().with({ day: 1 });
256
+ case 'start of year': return dt.startOfDay().with({ month: 1, day: 1 });
196
257
  }
197
- // Group 3: Weekday Adjustment
198
- const weekdayMatch = trimmedModifier.match(WEEKDAY_MODIFIER_REGEX);
199
- if (weekdayMatch) {
200
- const targetWeekday = parseInt(weekdayMatch[1], 10);
201
- const targetWeekdayISO = targetWeekday === 0 ? 7 : targetWeekday;
202
- const currentWeekdayISO = dt.dayOfWeek;
203
- let daysToAdd = targetWeekdayISO - currentWeekdayISO;
204
- if (daysToAdd > 0) {
205
- daysToAdd -= 7;
206
- }
207
- if (daysToAdd !== 0) {
208
- return dt.add({ days: daysToAdd });
209
- }
210
- return dt;
211
- }
212
- // Group 4: Timezone (Handled before modifier application)
258
+ const weekdayMatch = trimmed.match(WEEKDAY_MODIFIER_REGEX);
259
+ if (weekdayMatch)
260
+ return applyWeekdayAdjustment(dt, parseInt(weekdayMatch[1], 10));
213
261
  warnLog('Modifier not implemented or unrecognized: %s', modifier);
214
262
  return dt;
215
263
  }
216
- // --- Core Logic --- //
264
+ const _CONTROL_MODIFIERS = new Set(['unixepoch', 'localtime', 'utc', 'subsec']);
265
+ /**
266
+ * Core argument processor shared by all datetime functions.
267
+ * Separates control modifiers (unixepoch, localtime, utc, subsec) from
268
+ * arithmetic modifiers, parses the timestring, applies timezone conversion,
269
+ * then applies arithmetic modifiers in order.
270
+ */
217
271
  function processDateTimeArgs(args) {
272
+ if (args.length === 0)
273
+ return { dt: null, subsec: false };
274
+ const { timeVal, isUnixEpoch, subsec, targetTimeZoneId, arithmeticModifiers } = classifyArgs(args);
275
+ let dt = parseToTemporal(timeVal, isUnixEpoch);
276
+ if (!dt)
277
+ return { dt: null, subsec };
278
+ dt = convertTimezone(dt, targetTimeZoneId);
279
+ if (!dt)
280
+ return { dt: null, subsec };
281
+ dt = applyModifiers(dt, arithmeticModifiers);
282
+ return { dt, subsec };
283
+ }
284
+ /**
285
+ * Strict variant for epoch_* functions: only accepts ISO 8601 strings and 'now'.
286
+ * Rejects bare numbers (ambiguous), time-only strings, and YYYYMMDD format.
287
+ */
288
+ function processStrictArgs(args) {
218
289
  if (args.length === 0)
219
290
  return null;
220
- let initialTimeVal = args[0];
221
- let startIndex = 1;
222
- let isUnixEpoch = false;
223
- let modifiers = [];
224
- const unixEpochIndex = args.findIndex(arg => typeof arg === 'string' && arg.trim().toLowerCase() === 'unixepoch');
225
- if (unixEpochIndex !== -1) {
226
- if (unixEpochIndex === 0) {
227
- if (args.length < 2)
228
- return null;
229
- initialTimeVal = args[1];
230
- isUnixEpoch = true;
231
- startIndex = 2;
232
- modifiers = args.slice(startIndex);
233
- }
234
- else {
235
- initialTimeVal = args[0];
236
- isUnixEpoch = true;
237
- if (typeof initialTimeVal !== 'number')
238
- return null;
239
- modifiers = args.slice(1).filter((_, i) => i !== (unixEpochIndex - 1));
240
- startIndex = 1;
241
- }
291
+ const timeVal = args[0];
292
+ const modifiers = args.slice(1).filter((m) => typeof m === 'string');
293
+ let targetTimeZoneId = 'UTC';
294
+ const arithmeticModifiers = [];
295
+ for (const mod of modifiers) {
296
+ const lower = mod.trim().toLowerCase();
297
+ if (lower === 'localtime')
298
+ targetTimeZoneId = Temporal.Now.timeZoneId();
299
+ else if (lower === 'utc')
300
+ targetTimeZoneId = 'UTC';
301
+ else
302
+ arithmeticModifiers.push(mod);
303
+ }
304
+ let dt = parseStrictTimestring(timeVal);
305
+ if (!dt)
306
+ return null;
307
+ dt = convertTimezone(dt, targetTimeZoneId);
308
+ if (!dt)
309
+ return null;
310
+ return applyModifiers(dt, arithmeticModifiers);
311
+ }
312
+ function classifyArgs(args) {
313
+ const hasUnixEpoch = args.some(a => typeof a === 'string' && a.trim().toLowerCase() === 'unixepoch');
314
+ let timeVal;
315
+ let rawModifiers;
316
+ if (hasUnixEpoch && typeof args[0] === 'string' && args[0].trim().toLowerCase() === 'unixepoch') {
317
+ timeVal = args.length > 1 ? args[1] : null;
318
+ rawModifiers = args.slice(2);
242
319
  }
243
320
  else {
244
- initialTimeVal = args[0];
245
- modifiers = args.slice(1);
246
- startIndex = 1;
321
+ timeVal = args[0];
322
+ rawModifiers = args.slice(1);
247
323
  }
248
- // Determine target timezone from modifiers ('localtime' or 'utc')
249
- let targetTimeZoneId = 'UTC'; // Store ID as string, default to UTC
250
- const remainingModifiers = [];
251
- for (const mod of modifiers) {
324
+ let targetTimeZoneId = 'UTC';
325
+ let subsec = false;
326
+ const arithmeticModifiers = [];
327
+ for (const mod of rawModifiers) {
252
328
  if (typeof mod !== 'string')
253
329
  continue;
254
- const lowerMod = mod.trim().toLowerCase();
255
- if (lowerMod === 'localtime') {
330
+ const lower = mod.trim().toLowerCase();
331
+ if (lower === 'unixepoch')
332
+ continue;
333
+ if (lower === 'localtime') {
256
334
  targetTimeZoneId = Temporal.Now.timeZoneId();
335
+ continue;
257
336
  }
258
- else if (lowerMod === 'utc') {
259
- targetTimeZoneId = 'UTC'; // Use string literal
337
+ if (lower === 'utc') {
338
+ targetTimeZoneId = 'UTC';
339
+ continue;
260
340
  }
261
- else {
262
- remainingModifiers.push(mod);
341
+ if (lower === 'subsec') {
342
+ subsec = true;
343
+ continue;
263
344
  }
345
+ arithmeticModifiers.push(mod);
346
+ }
347
+ const isUnixEpoch = hasUnixEpoch && typeof timeVal === 'number';
348
+ return { timeVal, isUnixEpoch, subsec, targetTimeZoneId, arithmeticModifiers };
349
+ }
350
+ function convertTimezone(dt, targetTimeZoneId) {
351
+ if (targetTimeZoneId === dt.timeZoneId)
352
+ return dt;
353
+ try {
354
+ return dt.toInstant().toZonedDateTimeISO(targetTimeZoneId);
264
355
  }
265
- // Parse the initial value
266
- let currentDt = parseToTemporal(initialTimeVal, isUnixEpoch);
267
- if (!currentDt)
356
+ catch (e) {
357
+ warnLog('Failed to convert to timezone "%s": %O', targetTimeZoneId, e);
268
358
  return null;
269
- // Adjust initial ZonedDateTime to the target timezone if necessary
270
- if (targetTimeZoneId !== currentDt.timeZoneId) {
271
- try {
272
- currentDt = currentDt.toInstant().toZonedDateTimeISO(targetTimeZoneId);
273
- }
274
- catch (e) {
275
- warnLog('Failed to convert to timezone "%s": %O', targetTimeZoneId, e);
276
- return null;
277
- }
278
359
  }
279
- // Apply remaining modifiers
280
- for (const modifier of remainingModifiers) {
281
- if (typeof modifier !== 'string')
282
- continue;
360
+ }
361
+ function applyModifiers(dt, modifiers) {
362
+ let current = dt;
363
+ for (const modifier of modifiers) {
283
364
  try {
284
- currentDt = applyTemporalModifier(currentDt, modifier);
365
+ current = applyTemporalModifier(current, modifier);
285
366
  }
286
367
  catch (e) {
287
368
  warnLog('Error applying modifier "%s": %O', modifier, e);
288
369
  return null;
289
370
  }
290
371
  }
291
- return currentDt;
372
+ return current;
373
+ }
374
+ // --- Epoch Conversion Helpers --- //
375
+ function toEpochSeconds(dt) {
376
+ return Math.floor(dt.epochMilliseconds / MILLIS_PER_SECOND);
377
+ }
378
+ function toEpochMilliseconds(dt) {
379
+ return dt.epochMilliseconds;
380
+ }
381
+ function toEpochSecondsFractional(dt) {
382
+ return dt.epochMilliseconds / MILLIS_PER_SECOND;
383
+ }
384
+ function toJulianDay(dt) {
385
+ return (dt.toInstant().epochMilliseconds / MILLIS_PER_DAY) + JULIAN_DAY_UNIX_EPOCH;
386
+ }
387
+ // --- Formatting Helpers --- //
388
+ function formatDate(dt) {
389
+ return dt.toPlainDate().toString();
390
+ }
391
+ function formatTime(dt, subsec) {
392
+ if (subsec)
393
+ return dt.toPlainTime().toString({ smallestUnit: 'millisecond' });
394
+ return dt.toPlainTime().toString({ smallestUnit: 'second' });
395
+ }
396
+ function formatDateTime(dt, subsec) {
397
+ return `${formatDate(dt)} ${formatTime(dt, subsec)}`;
292
398
  }
293
399
  // --- Function Implementations --- //
294
- // date(timestring, modifier, ...)
295
- // NOTE: Marked as non-deterministic because it accepts 'now' as a timestring
400
+ // All date/time functions are non-deterministic because they accept 'now'.
296
401
  export const dateFunc = createScalarFunction({ name: 'date', numArgs: -1, deterministic: false }, (...args) => {
297
- const finalDt = processDateTimeArgs(args);
298
- if (!finalDt)
299
- return null;
300
- return finalDt.toPlainDate().toString();
402
+ const { dt } = processDateTimeArgs(args);
403
+ return dt ? formatDate(dt) : null;
301
404
  });
302
- // time(timestring, modifier, ...)
303
- // NOTE: Marked as non-deterministic because it accepts 'now' as a timestring
304
405
  export const timeFunc = createScalarFunction({ name: 'time', numArgs: -1, deterministic: false }, (...args) => {
305
- const finalDt = processDateTimeArgs(args);
306
- if (!finalDt)
307
- return null;
308
- return finalDt.toPlainTime().toString({ smallestUnit: 'second' });
406
+ const { dt, subsec } = processDateTimeArgs(args);
407
+ return dt ? formatTime(dt, subsec) : null;
309
408
  });
310
- // datetime(timestring, modifier, ...)
311
- // NOTE: Marked as non-deterministic because it accepts 'now' as a timestring
312
409
  export const datetimeFunc = createScalarFunction({ name: 'datetime', numArgs: -1, deterministic: false }, (...args) => {
313
- const finalDt = processDateTimeArgs(args);
314
- if (!finalDt)
315
- return null;
316
- const datePart = finalDt.toPlainDate().toString();
317
- const timePart = finalDt.toPlainTime().toString({ smallestUnit: 'second' });
318
- return `${datePart} ${timePart}`;
410
+ const { dt, subsec } = processDateTimeArgs(args);
411
+ return dt ? formatDateTime(dt, subsec) : null;
319
412
  });
320
- // julianday(timestring, modifier, ...)
321
- // NOTE: Marked as non-deterministic because it accepts 'now' as a timestring
322
413
  export const juliandayFunc = createScalarFunction({ name: 'julianday', numArgs: -1, deterministic: false }, (...args) => {
323
- const finalDt = processDateTimeArgs(args);
324
- if (!finalDt)
325
- return null;
326
- const epochMillis = finalDt.toInstant().epochMilliseconds;
327
- return (epochMillis / MILLIS_PER_DAY) + JULIAN_DAY_UNIX_EPOCH;
414
+ const { dt } = processDateTimeArgs(args);
415
+ return dt ? toJulianDay(dt) : null;
416
+ });
417
+ // --- Epoch Functions --- //
418
+ /**
419
+ * epoch_s(timestring, modifier, ...)
420
+ * Returns INTEGER Unix epoch seconds. Accepts only ISO 8601 strings and 'now';
421
+ * rejects bare numbers to avoid ambiguity. All epoch outputs are UTC-based:
422
+ * the 'localtime' modifier affects how the timestring is interpreted and
423
+ * modifiers applied, but the returned value is always seconds since
424
+ * 1970-01-01 00:00:00 UTC.
425
+ */
426
+ export const epochSFunc = createScalarFunction({ name: 'epoch_s', numArgs: -1, deterministic: false }, (...args) => {
427
+ const dt = processStrictArgs(args);
428
+ return dt ? toEpochSeconds(dt) : null;
328
429
  });
329
- // strftime(format, timestring, modifier, ...)
330
- // NOTE: Marked as non-deterministic because it accepts 'now' as a timestring
430
+ /**
431
+ * epoch_ms(timestring, modifier, ...)
432
+ * Returns INTEGER Unix epoch milliseconds. Same strict parsing as epoch_s.
433
+ * Epoch values are always relative to UTC regardless of timezone modifiers.
434
+ */
435
+ export const epochMsFunc = createScalarFunction({ name: 'epoch_ms', numArgs: -1, deterministic: false }, (...args) => {
436
+ const dt = processStrictArgs(args);
437
+ return dt ? toEpochMilliseconds(dt) : null;
438
+ });
439
+ /**
440
+ * epoch_s_frac(timestring, modifier, ...)
441
+ * Returns REAL Unix epoch seconds with fractional (millisecond) precision.
442
+ * Same strict parsing as epoch_s. Use epoch_s() when integer precision suffices.
443
+ */
444
+ export const epochSFracFunc = createScalarFunction({ name: 'epoch_s_frac', numArgs: -1, deterministic: false }, (...args) => {
445
+ const dt = processStrictArgs(args);
446
+ return dt ? toEpochSecondsFractional(dt) : null;
447
+ });
448
+ // --- strftime --- //
449
+ const ABBREVIATED_MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
450
+ function pad2(n) { return n.toString().padStart(2, '0'); }
451
+ function pad3(n) { return n.toString().padStart(3, '0'); }
452
+ function pad4(n) { return n.toString().padStart(4, '0'); }
453
+ function space2(n) { return n.toString().padStart(2, ' '); }
454
+ function hour12(h) { return h % 12 || 12; }
455
+ function formatStrftimeSpecifier(spec, dt) {
456
+ switch (spec) {
457
+ // Date
458
+ case '%Y': return pad4(dt.year);
459
+ case '%m': return pad2(dt.month);
460
+ case '%d': return pad2(dt.day);
461
+ case '%j': return pad3(dt.dayOfYear);
462
+ case '%F': return `${pad4(dt.year)}-${pad2(dt.month)}-${pad2(dt.day)}`;
463
+ case '%D': return `${pad2(dt.month)}/${pad2(dt.day)}/${dt.year.toString().slice(-2)}`;
464
+ case '%C': return pad2(Math.floor(dt.year / 100));
465
+ case '%y': return dt.year.toString().slice(-2);
466
+ case '%h': return ABBREVIATED_MONTHS[dt.month - 1];
467
+ case '%e': return space2(dt.day);
468
+ // Time
469
+ case '%H': return pad2(dt.hour);
470
+ case '%M': return pad2(dt.minute);
471
+ case '%S': return pad2(dt.second);
472
+ case '%f': return `.${pad3(dt.millisecond)}`;
473
+ case '%s': return toEpochSeconds(dt).toString();
474
+ case '%I': return pad2(hour12(dt.hour));
475
+ case '%k': return space2(dt.hour);
476
+ case '%l': return space2(hour12(dt.hour));
477
+ case '%p': return dt.hour < 12 ? 'AM' : 'PM';
478
+ case '%P': return dt.hour < 12 ? 'am' : 'pm';
479
+ case '%T': return `${pad2(dt.hour)}:${pad2(dt.minute)}:${pad2(dt.second)}`;
480
+ case '%R': return `${pad2(dt.hour)}:${pad2(dt.minute)}`;
481
+ case '%r': return `${pad2(hour12(dt.hour))}:${pad2(dt.minute)}:${pad2(dt.second)} ${dt.hour < 12 ? 'AM' : 'PM'}`;
482
+ // Weekday / Week Number
483
+ case '%w': return (dt.dayOfWeek % 7).toString();
484
+ case '%u': return dt.dayOfWeek.toString();
485
+ case '%W':
486
+ warnLog('strftime %%W not fully implemented');
487
+ return pad2(dt.weekOfYear ?? 0);
488
+ case '%V': return pad2(dt.weekOfYear ?? 0);
489
+ case '%g': return (dt.yearOfWeek ?? dt.year).toString().slice(-2);
490
+ case '%G': return pad4(dt.yearOfWeek ?? dt.year);
491
+ // Julian Day
492
+ case '%J': return toJulianDay(dt).toString();
493
+ // Epoch (new specifiers)
494
+ case '%E': return toEpochSeconds(dt).toString();
495
+ case '%Q': return toEpochMilliseconds(dt).toString();
496
+ // Timezone
497
+ case '%z': {
498
+ const sign = dt.offset.startsWith('-') ? '-' : '+';
499
+ const parts = dt.offset.substring(1).split(':');
500
+ return `${sign}${parts[0].padStart(2, '0')}${parts[1]?.padStart(2, '0') ?? '00'}`;
501
+ }
502
+ // Literal Percent
503
+ case '%%': return '%';
504
+ default:
505
+ warnLog(`Unsupported strftime specifier: ${spec}`);
506
+ return spec;
507
+ }
508
+ }
331
509
  export const strftimeFunc = createScalarFunction({ name: 'strftime', numArgs: -1, deterministic: false }, (format, ...timeArgs) => {
332
510
  if (typeof format !== 'string')
333
511
  return null;
334
- const finalDt = processDateTimeArgs(timeArgs);
335
- if (!finalDt)
512
+ const { dt } = processDateTimeArgs(timeArgs);
513
+ if (!dt)
336
514
  return null;
337
- // Abbreviated month names (SQLite standard)
338
- const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
339
515
  try {
340
- let result = format;
341
- // Use replace with a callback function for better handling
342
- result = result.replace(/%./g, (match) => {
343
- switch (match) {
344
- // Date
345
- case '%Y': return finalDt.year.toString().padStart(4, '0');
346
- case '%m': return finalDt.month.toString().padStart(2, '0');
347
- case '%d': return finalDt.day.toString().padStart(2, '0');
348
- case '%j': return finalDt.dayOfYear.toString().padStart(3, '0');
349
- case '%F': return `${finalDt.year.toString().padStart(4, '0')}-${finalDt.month.toString().padStart(2, '0')}-${finalDt.day.toString().padStart(2, '0')}`;
350
- case '%D': return `${finalDt.month.toString().padStart(2, '0')}/${finalDt.day.toString().padStart(2, '0')}/${finalDt.year.toString().slice(-2)}`;
351
- case '%C': return Math.floor(finalDt.year / 100).toString().padStart(2, '0');
352
- case '%y': return finalDt.year.toString().slice(-2);
353
- case '%h': return months[finalDt.month - 1];
354
- case '%e': return finalDt.day.toString().padStart(2, ' ');
355
- // Time
356
- case '%H': return finalDt.hour.toString().padStart(2, '0');
357
- case '%M': return finalDt.minute.toString().padStart(2, '0');
358
- case '%S': return finalDt.second.toString().padStart(2, '0');
359
- case '%f': { // SQLite %f is .SSS
360
- const msStr = finalDt.millisecond.toString().padStart(3, '0');
361
- return `.${msStr}`;
362
- }
363
- case '%s': return Math.floor(finalDt.epochMilliseconds / 1000).toString();
364
- case '%I': return (finalDt.hour % 12 || 12).toString().padStart(2, '0'); // 12-hour clock
365
- case '%k': return finalDt.hour.toString().padStart(2, ' '); // 24-hour, space padded
366
- case '%l': return (finalDt.hour % 12 || 12).toString().padStart(2, ' '); // 12-hour, space padded
367
- case '%p': return finalDt.hour < 12 ? 'AM' : 'PM';
368
- case '%P': return finalDt.hour < 12 ? 'am' : 'pm';
369
- case '%T': return `${finalDt.hour.toString().padStart(2, '0')}:${finalDt.minute.toString().padStart(2, '0')}:${finalDt.second.toString().padStart(2, '0')}`;
370
- case '%R': return `${finalDt.hour.toString().padStart(2, '0')}:${finalDt.minute.toString().padStart(2, '0')}`;
371
- case '%r': { // 12-hour time hh:mm:ss AM/PM
372
- const hour12 = (finalDt.hour % 12 || 12).toString().padStart(2, '0');
373
- const min = finalDt.minute.toString().padStart(2, '0');
374
- const sec = finalDt.second.toString().padStart(2, '0');
375
- const ampm = finalDt.hour < 12 ? 'AM' : 'PM';
376
- return `${hour12}:${min}:${sec} ${ampm}`;
377
- }
378
- // Weekday / Week Number
379
- case '%w': return (finalDt.dayOfWeek % 7).toString(); // 0=Sunday..6=Saturday (SQLite)
380
- case '%u': return finalDt.dayOfWeek.toString(); // 1=Monday..7=Sunday (ISO)
381
- // Handle potentially undefined weekOfYear (though Temporal usually provides it)
382
- case '%W': // Week number (Sunday start, 00-53) - SQLite specific implementation
383
- warnLog('strftime %W not fully implemented');
384
- return (finalDt.weekOfYear ?? 0).toString().padStart(2, '0'); // Fallback to ISO week
385
- case '%V': return (finalDt.weekOfYear ?? 0).toString().padStart(2, '0'); // ISO 8601 week number
386
- case '%g': // ISO 8601 week-based year, last two digits
387
- return (finalDt.yearOfWeek ?? finalDt.year).toString().slice(-2);
388
- case '%G': // ISO 8601 week-based year, four digits
389
- return (finalDt.yearOfWeek ?? finalDt.year).toString().padStart(4, '0');
390
- // Julian Day
391
- case '%J': {
392
- const epochMillis = finalDt.toInstant().epochMilliseconds;
393
- const jd = (epochMillis / MILLIS_PER_DAY) + JULIAN_DAY_UNIX_EPOCH;
394
- return jd.toString();
395
- }
396
- // Timezone
397
- case '%z': { // +hhmm or -hhmm
398
- const offsetStr = finalDt.offset;
399
- const sign = offsetStr.startsWith('-') ? '-' : '+';
400
- const parts = offsetStr.substring(1).split(':');
401
- return `${sign}${parts[0].padStart(2, '0')}${parts[1]?.padStart(2, '0') ?? '00'}`;
402
- }
403
- case '%:z': // +hh:mm or -hh:mm
404
- return finalDt.offset;
405
- // case '%Z': // Timezone name - Complex, depends on available data. Skip for now.
406
- // Literal Percent
407
- case '%%': return '%';
408
- // Week numbering formats are complex to implement correctly
409
- // Using ISO week numbers as fallback where appropriate
410
- default:
411
- warnLog(`Unsupported strftime specifier: ${match}`);
412
- return match; // Return the specifier itself if unsupported
413
- }
414
- });
415
- return result;
516
+ return format.replace(/%./g, (spec) => formatStrftimeSpecifier(spec, dt));
416
517
  }
417
518
  catch (e) {
418
- errorLog("Error during strftime formatting: %O", e);
519
+ errorLog('Error during strftime formatting: %O', e);
419
520
  return null;
420
521
  }
421
522
  });
422
- // IsISODate(text)
523
+ // --- ISO Validation Functions --- //
423
524
  export const isISODateFunc = createScalarFunction({ name: 'IsISODate', numArgs: 1, deterministic: true }, (value) => {
424
525
  if (typeof value !== 'string')
425
526
  return false;
426
527
  const s = value.trim();
427
528
  if (!/^\d{4}-\d{2}-\d{2}$/.test(s))
428
529
  return false;
429
- try {
430
- const d = Temporal.PlainDate.from(s);
431
- return d.toString() === s;
432
- }
433
- catch {
434
- return false;
435
- }
530
+ const d = tryParse(() => Temporal.PlainDate.from(s));
531
+ return d !== null && d.toString() === s;
436
532
  });
437
- // IsISODateTime(text)
438
533
  export const isISODateTimeFunc = createScalarFunction({ name: 'IsISODateTime', numArgs: 1, deterministic: true }, (value) => {
439
534
  if (typeof value !== 'string')
440
535
  return false;
441
536
  const s = value.trim();
442
- // YYYY-MM-DDTHH:MM[:SS[.fraction]] [timezone]
443
537
  const re = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:\d{2})?$/;
444
538
  if (!re.test(s))
445
539
  return false;
446
540
  const hasZone = /(?:Z|[+-]\d{2}:\d{2})$/.test(s);
447
- try {
448
- if (hasZone) {
449
- // Zoned ISO string
450
- void Temporal.Instant.from(s);
451
- return true;
452
- }
453
- // Plain ISO local date-time
454
- void Temporal.PlainDateTime.from(s);
455
- return true;
456
- }
457
- catch {
458
- return false;
459
- }
541
+ if (hasZone)
542
+ return tryParse(() => Temporal.Instant.from(s)) !== null;
543
+ return tryParse(() => Temporal.PlainDateTime.from(s)) !== null;
460
544
  });
461
545
  //# sourceMappingURL=datetime.js.map