@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.
- package/README.md +372 -345
- package/dist/src/common/errors.d.ts +2 -18
- package/dist/src/common/errors.d.ts.map +1 -1
- package/dist/src/common/errors.js +6 -29
- package/dist/src/common/errors.js.map +1 -1
- package/dist/src/common/types.d.ts +8 -0
- package/dist/src/common/types.d.ts.map +1 -1
- package/dist/src/common/types.js +20 -0
- package/dist/src/common/types.js.map +1 -1
- package/dist/src/core/database-assertions.d.ts +19 -2
- package/dist/src/core/database-assertions.d.ts.map +1 -1
- package/dist/src/core/database-assertions.js +113 -32
- package/dist/src/core/database-assertions.js.map +1 -1
- package/dist/src/core/database-events.d.ts +17 -0
- package/dist/src/core/database-events.d.ts.map +1 -1
- package/dist/src/core/database-events.js +39 -2
- package/dist/src/core/database-events.js.map +1 -1
- package/dist/src/core/database-transaction.d.ts +31 -4
- package/dist/src/core/database-transaction.d.ts.map +1 -1
- package/dist/src/core/database-transaction.js +68 -2
- package/dist/src/core/database-transaction.js.map +1 -1
- package/dist/src/core/database.d.ts +17 -4
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +189 -154
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/statement.d.ts +8 -2
- package/dist/src/core/statement.d.ts.map +1 -1
- package/dist/src/core/statement.js +54 -71
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/emit/ast-stringify.d.ts +1 -0
- package/dist/src/emit/ast-stringify.d.ts.map +1 -1
- package/dist/src/emit/ast-stringify.js +12 -2
- package/dist/src/emit/ast-stringify.js.map +1 -1
- package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
- package/dist/src/func/builtins/builtin-window-functions.js +75 -0
- package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
- package/dist/src/func/builtins/conversion.js +9 -12
- package/dist/src/func/builtins/conversion.js.map +1 -1
- package/dist/src/func/builtins/datetime.d.ts +21 -0
- package/dist/src/func/builtins/datetime.d.ts.map +1 -1
- package/dist/src/func/builtins/datetime.js +452 -368
- package/dist/src/func/builtins/datetime.js.map +1 -1
- package/dist/src/func/builtins/explain.d.ts.map +1 -1
- package/dist/src/func/builtins/explain.js +15 -3
- package/dist/src/func/builtins/explain.js.map +1 -1
- package/dist/src/func/builtins/index.d.ts.map +1 -1
- package/dist/src/func/builtins/index.js +5 -12
- package/dist/src/func/builtins/index.js.map +1 -1
- package/dist/src/func/builtins/json-helpers.js +1 -1
- package/dist/src/func/builtins/json-helpers.js.map +1 -1
- package/dist/src/func/builtins/json.d.ts.map +1 -1
- package/dist/src/func/builtins/json.js +2 -5
- package/dist/src/func/builtins/json.js.map +1 -1
- package/dist/src/func/builtins/schema.d.ts.map +1 -1
- package/dist/src/func/builtins/schema.js +30 -32
- package/dist/src/func/builtins/schema.js.map +1 -1
- package/dist/src/func/builtins/string.d.ts.map +1 -1
- package/dist/src/func/builtins/string.js +40 -64
- package/dist/src/func/builtins/string.js.map +1 -1
- package/dist/src/func/builtins/timespan.d.ts.map +1 -1
- package/dist/src/func/builtins/timespan.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/ast.d.ts +9 -2
- package/dist/src/parser/ast.d.ts.map +1 -1
- package/dist/src/parser/lexer.d.ts +1 -0
- package/dist/src/parser/lexer.d.ts.map +1 -1
- package/dist/src/parser/lexer.js +3 -0
- package/dist/src/parser/lexer.js.map +1 -1
- package/dist/src/parser/parser.d.ts +11 -1
- package/dist/src/parser/parser.d.ts.map +1 -1
- package/dist/src/parser/parser.js +75 -135
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/planner/analysis/const-evaluator.d.ts.map +1 -1
- package/dist/src/planner/analysis/const-evaluator.js +6 -3
- package/dist/src/planner/analysis/const-evaluator.js.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.d.ts +2 -1
- package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
- package/dist/src/planner/analysis/constraint-extractor.js +154 -22
- package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
- package/dist/src/planner/building/alter-table.d.ts.map +1 -1
- package/dist/src/planner/building/alter-table.js +18 -1
- package/dist/src/planner/building/alter-table.js.map +1 -1
- package/dist/src/planner/building/analyze.d.ts +5 -0
- package/dist/src/planner/building/analyze.d.ts.map +1 -0
- package/dist/src/planner/building/analyze.js +5 -0
- package/dist/src/planner/building/analyze.js.map +1 -0
- package/dist/src/planner/building/block.d.ts.map +1 -1
- package/dist/src/planner/building/block.js +3 -0
- package/dist/src/planner/building/block.js.map +1 -1
- package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
- package/dist/src/planner/building/constraint-builder.js +25 -3
- package/dist/src/planner/building/constraint-builder.js.map +1 -1
- package/dist/src/planner/building/delete.d.ts.map +1 -1
- package/dist/src/planner/building/delete.js +11 -0
- package/dist/src/planner/building/delete.js.map +1 -1
- package/dist/src/planner/building/drop-assertion.d.ts.map +1 -1
- package/dist/src/planner/building/drop-assertion.js +2 -1
- package/dist/src/planner/building/drop-assertion.js.map +1 -1
- package/dist/src/planner/building/expression.d.ts.map +1 -1
- package/dist/src/planner/building/expression.js +55 -7
- package/dist/src/planner/building/expression.js.map +1 -1
- package/dist/src/planner/building/foreign-key-builder.d.ts +16 -0
- package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -0
- package/dist/src/planner/building/foreign-key-builder.js +269 -0
- package/dist/src/planner/building/foreign-key-builder.js.map +1 -0
- package/dist/src/planner/building/function-call.d.ts.map +1 -1
- package/dist/src/planner/building/function-call.js +3 -2
- package/dist/src/planner/building/function-call.js.map +1 -1
- package/dist/src/planner/building/insert.d.ts.map +1 -1
- package/dist/src/planner/building/insert.js +91 -10
- package/dist/src/planner/building/insert.js.map +1 -1
- package/dist/src/planner/building/schema-resolution.d.ts +4 -0
- package/dist/src/planner/building/schema-resolution.d.ts.map +1 -1
- package/dist/src/planner/building/schema-resolution.js +14 -3
- package/dist/src/planner/building/schema-resolution.js.map +1 -1
- package/dist/src/planner/building/select-aggregates.d.ts +1 -0
- package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
- package/dist/src/planner/building/select-aggregates.js +118 -3
- package/dist/src/planner/building/select-aggregates.js.map +1 -1
- package/dist/src/planner/building/select-modifiers.js +3 -3
- package/dist/src/planner/building/select-modifiers.js.map +1 -1
- package/dist/src/planner/building/select-window.js +9 -8
- package/dist/src/planner/building/select-window.js.map +1 -1
- package/dist/src/planner/building/select.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +21 -10
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/building/table.d.ts.map +1 -1
- package/dist/src/planner/building/table.js +5 -3
- package/dist/src/planner/building/table.js.map +1 -1
- package/dist/src/planner/building/update.d.ts.map +1 -1
- package/dist/src/planner/building/update.js +30 -1
- package/dist/src/planner/building/update.js.map +1 -1
- package/dist/src/planner/building/with.js +1 -1
- package/dist/src/planner/building/with.js.map +1 -1
- package/dist/src/planner/cache/reference-graph.d.ts +1 -1
- package/dist/src/planner/cache/reference-graph.js +1 -1
- package/dist/src/planner/cost/index.d.ts +10 -3
- package/dist/src/planner/cost/index.d.ts.map +1 -1
- package/dist/src/planner/cost/index.js +17 -3
- package/dist/src/planner/cost/index.js.map +1 -1
- package/dist/src/planner/debug.js +1 -1
- package/dist/src/planner/debug.js.map +1 -1
- package/dist/src/planner/framework/characteristics.d.ts +1 -1
- package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
- package/dist/src/planner/framework/pass.d.ts +3 -1
- package/dist/src/planner/framework/pass.d.ts.map +1 -1
- package/dist/src/planner/framework/pass.js +62 -18
- package/dist/src/planner/framework/pass.js.map +1 -1
- package/dist/src/planner/framework/physical-utils.d.ts +5 -0
- package/dist/src/planner/framework/physical-utils.d.ts.map +1 -1
- package/dist/src/planner/framework/physical-utils.js +19 -0
- package/dist/src/planner/framework/physical-utils.js.map +1 -1
- package/dist/src/planner/framework/trace.d.ts.map +1 -1
- package/dist/src/planner/framework/trace.js +3 -2
- package/dist/src/planner/framework/trace.js.map +1 -1
- package/dist/src/planner/nodes/alias-node.d.ts +2 -1
- package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/alias-node.js +8 -0
- package/dist/src/planner/nodes/alias-node.js.map +1 -1
- package/dist/src/planner/nodes/alter-table-node.d.ts +42 -0
- package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/alter-table-node.js +55 -0
- package/dist/src/planner/nodes/alter-table-node.js.map +1 -0
- package/dist/src/planner/nodes/analyze-node.d.ts +25 -0
- package/dist/src/planner/nodes/analyze-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/analyze-node.js +83 -0
- package/dist/src/planner/nodes/analyze-node.js.map +1 -0
- package/dist/src/planner/nodes/bloom-join-node.d.ts +66 -0
- package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/bloom-join-node.js +200 -0
- package/dist/src/planner/nodes/bloom-join-node.js.map +1 -0
- package/dist/src/planner/nodes/constraint-check-node.d.ts +1 -1
- package/dist/src/planner/nodes/constraint-check-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-reference-node.js +7 -7
- package/dist/src/planner/nodes/cte-reference-node.js.map +1 -1
- package/dist/src/planner/nodes/join-node.d.ts +9 -1
- package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/join-node.js +69 -79
- package/dist/src/planner/nodes/join-node.js.map +1 -1
- package/dist/src/planner/nodes/merge-join-node.d.ts +60 -0
- package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/merge-join-node.js +207 -0
- package/dist/src/planner/nodes/merge-join-node.js.map +1 -0
- package/dist/src/planner/nodes/plan-node-type.d.ts +1 -0
- package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.js +1 -0
- package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
- package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/project-node.js +3 -2
- package/dist/src/planner/nodes/project-node.js.map +1 -1
- package/dist/src/planner/nodes/reference.d.ts +2 -1
- package/dist/src/planner/nodes/reference.d.ts.map +1 -1
- package/dist/src/planner/nodes/reference.js +6 -2
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/returning-node.js +3 -2
- package/dist/src/planner/nodes/returning-node.js.map +1 -1
- package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
- package/dist/src/planner/nodes/subquery.js.map +1 -1
- package/dist/src/planner/nodes/table-access-nodes.js +1 -1
- package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
- package/dist/src/planner/nodes/update-node.d.ts +2 -0
- package/dist/src/planner/nodes/update-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/update-node.js +2 -1
- package/dist/src/planner/nodes/update-node.js.map +1 -1
- package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-function.js +7 -7
- package/dist/src/planner/nodes/window-function.js.map +1 -1
- package/dist/src/planner/nodes/window-node.d.ts +2 -2
- package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/window-node.js +9 -14
- package/dist/src/planner/nodes/window-node.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +40 -2
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/planning-context.d.ts.map +1 -1
- package/dist/src/planner/planning-context.js +1 -6
- package/dist/src/planner/planning-context.js.map +1 -1
- package/dist/src/planner/resolve.d.ts.map +1 -1
- package/dist/src/planner/resolve.js.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +157 -28
- package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
- package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.d.ts.map +1 -1
- package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js +27 -6
- package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js.map +1 -1
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts +19 -0
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts.map +1 -0
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.js +53 -0
- package/dist/src/planner/rules/cache/rule-in-subquery-cache.js.map +1 -0
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.d.ts.map +1 -1
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js +5 -0
- package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js.map +1 -1
- package/dist/src/planner/rules/distinct/rule-distinct-elimination.d.ts +18 -0
- package/dist/src/planner/rules/distinct/rule-distinct-elimination.d.ts.map +1 -0
- package/dist/src/planner/rules/distinct/rule-distinct-elimination.js +37 -0
- package/dist/src/planner/rules/distinct/rule-distinct-elimination.js.map +1 -0
- package/dist/src/planner/rules/join/rule-join-key-inference.d.ts +8 -3
- package/dist/src/planner/rules/join/rule-join-key-inference.d.ts.map +1 -1
- package/dist/src/planner/rules/join/rule-join-key-inference.js +28 -17
- package/dist/src/planner/rules/join/rule-join-key-inference.js.map +1 -1
- package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts +16 -0
- package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -0
- package/dist/src/planner/rules/join/rule-join-physical-selection.js +216 -0
- package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -0
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +34 -4
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +23 -0
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -0
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +293 -0
- package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -0
- package/dist/src/planner/scopes/multi.d.ts +3 -2
- package/dist/src/planner/scopes/multi.d.ts.map +1 -1
- package/dist/src/planner/scopes/multi.js +32 -7
- package/dist/src/planner/scopes/multi.js.map +1 -1
- package/dist/src/planner/scopes/shadow.d.ts +20 -0
- package/dist/src/planner/scopes/shadow.d.ts.map +1 -0
- package/dist/src/planner/scopes/shadow.js +31 -0
- package/dist/src/planner/scopes/shadow.js.map +1 -0
- package/dist/src/planner/stats/analyze.d.ts +17 -0
- package/dist/src/planner/stats/analyze.d.ts.map +1 -0
- package/dist/src/planner/stats/analyze.js +114 -0
- package/dist/src/planner/stats/analyze.js.map +1 -0
- package/dist/src/planner/stats/catalog-stats.d.ts +80 -0
- package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -0
- package/dist/src/planner/stats/catalog-stats.js +248 -0
- package/dist/src/planner/stats/catalog-stats.js.map +1 -0
- package/dist/src/planner/stats/histogram.d.ts +24 -0
- package/dist/src/planner/stats/histogram.d.ts.map +1 -0
- package/dist/src/planner/stats/histogram.js +142 -0
- package/dist/src/planner/stats/histogram.js.map +1 -0
- package/dist/src/planner/type-utils.d.ts.map +1 -1
- package/dist/src/planner/type-utils.js +8 -2
- package/dist/src/planner/type-utils.js.map +1 -1
- package/dist/src/planner/util/key-utils.d.ts +48 -2
- package/dist/src/planner/util/key-utils.d.ts.map +1 -1
- package/dist/src/planner/util/key-utils.js +123 -0
- package/dist/src/planner/util/key-utils.js.map +1 -1
- package/dist/src/planner/validation/determinism-validator.d.ts +9 -0
- package/dist/src/planner/validation/determinism-validator.d.ts.map +1 -1
- package/dist/src/planner/validation/determinism-validator.js +11 -0
- package/dist/src/planner/validation/determinism-validator.js.map +1 -1
- package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
- package/dist/src/planner/validation/plan-validator.js +1 -0
- package/dist/src/planner/validation/plan-validator.js.map +1 -1
- package/dist/src/runtime/context-helpers.d.ts +34 -10
- package/dist/src/runtime/context-helpers.d.ts.map +1 -1
- package/dist/src/runtime/context-helpers.js +115 -39
- package/dist/src/runtime/context-helpers.js.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.d.ts +0 -1
- package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.js +10 -23
- package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
- package/dist/src/runtime/descriptor-helpers.d.ts +7 -0
- package/dist/src/runtime/descriptor-helpers.d.ts.map +1 -0
- package/dist/src/runtime/descriptor-helpers.js +24 -0
- package/dist/src/runtime/descriptor-helpers.js.map +1 -0
- package/dist/src/runtime/emission-context.d.ts +7 -1
- package/dist/src/runtime/emission-context.d.ts.map +1 -1
- package/dist/src/runtime/emission-context.js +16 -0
- package/dist/src/runtime/emission-context.js.map +1 -1
- package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
- package/dist/src/runtime/emit/aggregate.js +97 -93
- package/dist/src/runtime/emit/aggregate.js.map +1 -1
- package/dist/src/runtime/emit/alter-table.d.ts +5 -0
- package/dist/src/runtime/emit/alter-table.d.ts.map +1 -0
- package/dist/src/runtime/emit/alter-table.js +209 -0
- package/dist/src/runtime/emit/alter-table.js.map +1 -0
- package/dist/src/runtime/emit/analyze.d.ts +9 -0
- package/dist/src/runtime/emit/analyze.d.ts.map +1 -0
- package/dist/src/runtime/emit/analyze.js +72 -0
- package/dist/src/runtime/emit/analyze.js.map +1 -0
- package/dist/src/runtime/emit/array-index.d.ts.map +1 -1
- package/dist/src/runtime/emit/array-index.js +4 -2
- package/dist/src/runtime/emit/array-index.js.map +1 -1
- package/dist/src/runtime/emit/between.d.ts.map +1 -1
- package/dist/src/runtime/emit/between.js +8 -20
- package/dist/src/runtime/emit/between.js.map +1 -1
- package/dist/src/runtime/emit/binary.d.ts.map +1 -1
- package/dist/src/runtime/emit/binary.js +155 -126
- package/dist/src/runtime/emit/binary.js.map +1 -1
- package/dist/src/runtime/emit/bloom-join.d.ts +12 -0
- package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -0
- package/dist/src/runtime/emit/bloom-join.js +114 -0
- package/dist/src/runtime/emit/bloom-join.js.map +1 -0
- package/dist/src/runtime/emit/cache.js +2 -2
- package/dist/src/runtime/emit/cache.js.map +1 -1
- package/dist/src/runtime/emit/cast.d.ts.map +1 -1
- package/dist/src/runtime/emit/cast.js +31 -117
- package/dist/src/runtime/emit/cast.js.map +1 -1
- package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
- package/dist/src/runtime/emit/constraint-check.js +2 -24
- package/dist/src/runtime/emit/constraint-check.js.map +1 -1
- package/dist/src/runtime/emit/cte-reference.d.ts.map +1 -1
- package/dist/src/runtime/emit/cte-reference.js +11 -5
- package/dist/src/runtime/emit/cte-reference.js.map +1 -1
- package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
- package/dist/src/runtime/emit/distinct.js +21 -12
- package/dist/src/runtime/emit/distinct.js.map +1 -1
- package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
- package/dist/src/runtime/emit/dml-executor.js +5 -1
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- package/dist/src/runtime/emit/drop-assertion.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-assertion.js +2 -0
- package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
- package/dist/src/runtime/emit/filter.d.ts.map +1 -1
- package/dist/src/runtime/emit/filter.js +26 -7
- package/dist/src/runtime/emit/filter.js.map +1 -1
- package/dist/src/runtime/emit/internal-recursive-cte-ref.d.ts.map +1 -1
- package/dist/src/runtime/emit/internal-recursive-cte-ref.js +11 -5
- package/dist/src/runtime/emit/internal-recursive-cte-ref.js.map +1 -1
- package/dist/src/runtime/emit/join.d.ts +1 -1
- package/dist/src/runtime/emit/join.d.ts.map +1 -1
- package/dist/src/runtime/emit/join.js +44 -33
- package/dist/src/runtime/emit/join.js.map +1 -1
- package/dist/src/runtime/emit/merge-join.d.ts +14 -0
- package/dist/src/runtime/emit/merge-join.d.ts.map +1 -0
- package/dist/src/runtime/emit/merge-join.js +152 -0
- package/dist/src/runtime/emit/merge-join.js.map +1 -0
- package/dist/src/runtime/emit/parameter.d.ts.map +1 -1
- package/dist/src/runtime/emit/parameter.js +10 -32
- package/dist/src/runtime/emit/parameter.js.map +1 -1
- package/dist/src/runtime/emit/project.d.ts.map +1 -1
- package/dist/src/runtime/emit/project.js +22 -12
- package/dist/src/runtime/emit/project.js.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
- package/dist/src/runtime/emit/recursive-cte.js +5 -9
- package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
- package/dist/src/runtime/emit/returning.d.ts.map +1 -1
- package/dist/src/runtime/emit/returning.js +14 -8
- package/dist/src/runtime/emit/returning.js.map +1 -1
- package/dist/src/runtime/emit/scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/scan.js +4 -1
- package/dist/src/runtime/emit/scan.js.map +1 -1
- package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
- package/dist/src/runtime/emit/set-operation.js +8 -5
- package/dist/src/runtime/emit/set-operation.js.map +1 -1
- package/dist/src/runtime/emit/sort.js +2 -2
- package/dist/src/runtime/emit/sort.js.map +1 -1
- package/dist/src/runtime/emit/subquery.js +2 -2
- package/dist/src/runtime/emit/subquery.js.map +1 -1
- package/dist/src/runtime/emit/table-valued-function.d.ts.map +1 -1
- package/dist/src/runtime/emit/table-valued-function.js +21 -7
- package/dist/src/runtime/emit/table-valued-function.js.map +1 -1
- package/dist/src/runtime/emit/transaction.d.ts.map +1 -1
- package/dist/src/runtime/emit/transaction.js +18 -46
- package/dist/src/runtime/emit/transaction.js.map +1 -1
- package/dist/src/runtime/emit/unary.js +2 -2
- package/dist/src/runtime/emit/unary.js.map +1 -1
- package/dist/src/runtime/emit/update.d.ts.map +1 -1
- package/dist/src/runtime/emit/update.js +43 -21
- package/dist/src/runtime/emit/update.js.map +1 -1
- package/dist/src/runtime/emit/window.d.ts.map +1 -1
- package/dist/src/runtime/emit/window.js +368 -126
- package/dist/src/runtime/emit/window.js.map +1 -1
- package/dist/src/runtime/foreign-key-actions.d.ts +15 -0
- package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -0
- package/dist/src/runtime/foreign-key-actions.js +109 -0
- package/dist/src/runtime/foreign-key-actions.js.map +1 -0
- package/dist/src/runtime/register.d.ts.map +1 -1
- package/dist/src/runtime/register.js +8 -0
- package/dist/src/runtime/register.js.map +1 -1
- package/dist/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/src/runtime/scheduler.js +4 -1
- package/dist/src/runtime/scheduler.js.map +1 -1
- package/dist/src/runtime/types.d.ts +6 -5
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.js.map +1 -1
- package/dist/src/schema/change-events.d.ts +36 -8
- package/dist/src/schema/change-events.d.ts.map +1 -1
- package/dist/src/schema/change-events.js.map +1 -1
- package/dist/src/schema/column.d.ts +5 -1
- package/dist/src/schema/column.d.ts.map +1 -1
- package/dist/src/schema/column.js +1 -2
- package/dist/src/schema/column.js.map +1 -1
- package/dist/src/schema/manager.d.ts +54 -4
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +353 -313
- package/dist/src/schema/manager.js.map +1 -1
- package/dist/src/schema/schema-differ.js +3 -3
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/schema/schema.d.ts +1 -1
- package/dist/src/schema/schema.js +2 -2
- package/dist/src/schema/schema.js.map +1 -1
- package/dist/src/schema/table.d.ts +49 -0
- package/dist/src/schema/table.d.ts.map +1 -1
- package/dist/src/schema/table.js +30 -11
- package/dist/src/schema/table.js.map +1 -1
- package/dist/src/types/builtin-types.d.ts.map +1 -1
- package/dist/src/types/builtin-types.js +26 -95
- package/dist/src/types/builtin-types.js.map +1 -1
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +1 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/json-type.d.ts.map +1 -1
- package/dist/src/types/json-type.js +28 -40
- package/dist/src/types/json-type.js.map +1 -1
- package/dist/src/types/logical-type.d.ts +6 -0
- package/dist/src/types/logical-type.d.ts.map +1 -1
- package/dist/src/types/logical-type.js +12 -0
- package/dist/src/types/logical-type.js.map +1 -1
- package/dist/src/types/temporal-types.d.ts.map +1 -1
- package/dist/src/types/temporal-types.js +8 -37
- package/dist/src/types/temporal-types.js.map +1 -1
- package/dist/src/util/async-iterator.d.ts +30 -0
- package/dist/src/util/async-iterator.d.ts.map +1 -0
- package/dist/src/util/async-iterator.js +101 -0
- package/dist/src/util/async-iterator.js.map +1 -0
- package/dist/src/util/coercion.d.ts +4 -5
- package/dist/src/util/coercion.d.ts.map +1 -1
- package/dist/src/util/coercion.js +10 -14
- package/dist/src/util/coercion.js.map +1 -1
- package/dist/src/util/comparison.d.ts +34 -21
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +77 -43
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/util/environment.d.ts +0 -8
- package/dist/src/util/environment.d.ts.map +1 -1
- package/dist/src/util/environment.js +0 -12
- package/dist/src/util/environment.js.map +1 -1
- package/dist/src/util/key-serializer.d.ts +33 -0
- package/dist/src/util/key-serializer.d.ts.map +1 -0
- package/dist/src/util/key-serializer.js +95 -0
- package/dist/src/util/key-serializer.js.map +1 -0
- package/dist/src/util/plugin-helper.d.ts.map +1 -1
- package/dist/src/util/plugin-helper.js +21 -45
- package/dist/src/util/plugin-helper.js.map +1 -1
- package/dist/src/util/serialization.d.ts +1 -0
- package/dist/src/util/serialization.d.ts.map +1 -1
- package/dist/src/util/serialization.js +8 -1
- package/dist/src/util/serialization.js.map +1 -1
- package/dist/src/util/working-table-iterable.d.ts +6 -5
- package/dist/src/util/working-table-iterable.d.ts.map +1 -1
- package/dist/src/util/working-table-iterable.js +8 -15
- package/dist/src/util/working-table-iterable.js.map +1 -1
- package/dist/src/vtab/best-access-plan.d.ts +12 -0
- package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
- package/dist/src/vtab/best-access-plan.js +22 -0
- package/dist/src/vtab/best-access-plan.js.map +1 -1
- package/dist/src/vtab/events.d.ts.map +1 -1
- package/dist/src/vtab/events.js +6 -3
- package/dist/src/vtab/events.js.map +1 -1
- package/dist/src/vtab/manifest.d.ts +3 -1
- package/dist/src/vtab/manifest.d.ts.map +1 -1
- package/dist/src/vtab/memory/index.d.ts +2 -2
- package/dist/src/vtab/memory/index.d.ts.map +1 -1
- package/dist/src/vtab/memory/index.js +4 -7
- package/dist/src/vtab/memory/index.js.map +1 -1
- package/dist/src/vtab/memory/layer/base-cursor.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base-cursor.js +37 -9
- package/dist/src/vtab/memory/layer/base-cursor.js.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +1 -1
- package/dist/src/vtab/memory/layer/base.js.map +1 -1
- package/dist/src/vtab/memory/layer/connection.d.ts +11 -7
- package/dist/src/vtab/memory/layer/connection.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/connection.js +32 -44
- package/dist/src/vtab/memory/layer/connection.js.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +15 -3
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +85 -37
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/dist/src/vtab/memory/layer/scan-plan.d.ts +2 -0
- package/dist/src/vtab/memory/layer/scan-plan.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-plan.js +153 -78
- package/dist/src/vtab/memory/layer/scan-plan.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction-cursor.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction-cursor.js +39 -9
- package/dist/src/vtab/memory/layer/transaction-cursor.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts +1 -0
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +6 -20
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +14 -24
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +88 -283
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/memory/table.d.ts +9 -0
- package/dist/src/vtab/memory/table.d.ts.map +1 -1
- package/dist/src/vtab/memory/table.js +121 -18
- package/dist/src/vtab/memory/table.js.map +1 -1
- package/dist/src/vtab/memory/types.d.ts +1 -0
- package/dist/src/vtab/memory/types.d.ts.map +1 -1
- package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
- package/dist/src/vtab/module.d.ts +13 -0
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/dist/src/vtab/table.d.ts +9 -0
- package/dist/src/vtab/table.d.ts.map +1 -1
- package/dist/src/vtab/table.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,461 +1,545 @@
|
|
|
1
|
-
import { createLogger } from '../../common/logger.js';
|
|
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');
|
|
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 };
|
|
13
|
-
//
|
|
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
|
|
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
|
-
|
|
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
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
150
|
-
|
|
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
|
-
|
|
153
|
-
|
|
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
|
|
156
|
-
|
|
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
|
|
160
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
case 'start of
|
|
191
|
-
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
let
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
245
|
-
|
|
246
|
-
startIndex = 1;
|
|
321
|
+
timeVal = args[0];
|
|
322
|
+
rawModifiers = args.slice(1);
|
|
247
323
|
}
|
|
248
|
-
|
|
249
|
-
let
|
|
250
|
-
const
|
|
251
|
-
for (const mod of
|
|
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
|
|
255
|
-
if (
|
|
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
|
-
|
|
259
|
-
targetTimeZoneId = 'UTC';
|
|
337
|
+
if (lower === 'utc') {
|
|
338
|
+
targetTimeZoneId = 'UTC';
|
|
339
|
+
continue;
|
|
260
340
|
}
|
|
261
|
-
|
|
262
|
-
|
|
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
|
-
|
|
266
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
360
|
+
}
|
|
361
|
+
function applyModifiers(dt, modifiers) {
|
|
362
|
+
let current = dt;
|
|
363
|
+
for (const modifier of modifiers) {
|
|
283
364
|
try {
|
|
284
|
-
|
|
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
|
|
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
|
|
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
|
|
298
|
-
|
|
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
|
|
306
|
-
|
|
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
|
|
314
|
-
|
|
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
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
|
|
330
|
-
|
|
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
|
|
335
|
-
if (!
|
|
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
|
-
|
|
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(
|
|
519
|
+
errorLog('Error during strftime formatting: %O', e);
|
|
419
520
|
return null;
|
|
420
521
|
}
|
|
421
522
|
});
|
|
422
|
-
//
|
|
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
|
-
|
|
430
|
-
|
|
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
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|