@query-farm/vgi 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +134 -0
- package/README.md +494 -0
- package/dist/__dbg.test-d.d.ts +1 -0
- package/dist/arguments/argument-spec.d.ts +51 -0
- package/dist/arguments/arguments.d.ts +13 -0
- package/dist/arrow/codec/branded.d.ts +83 -0
- package/dist/arrow/codec/registry.d.ts +29 -0
- package/dist/arrow/codec/repr.d.ts +23 -0
- package/dist/arrow/codec/type-descriptors.d.ts +109 -0
- package/dist/arrow/impl-arrowjs/build.d.ts +19 -0
- package/dist/arrow/impl-arrowjs/canonical.d.ts +15 -0
- package/dist/arrow/impl-arrowjs/empty.d.ts +7 -0
- package/dist/arrow/impl-arrowjs/filter.d.ts +11 -0
- package/dist/arrow/impl-arrowjs/index.d.ts +11 -0
- package/dist/arrow/impl-arrowjs/ipc.d.ts +24 -0
- package/dist/arrow/impl-arrowjs/iterate.d.ts +39 -0
- package/dist/arrow/impl-arrowjs/project.d.ts +10 -0
- package/dist/arrow/impl-arrowjs/schema.d.ts +62 -0
- package/dist/arrow/impl-arrowjs/statistics.d.ts +13 -0
- package/dist/arrow/impl-flechette/build.d.ts +14 -0
- package/dist/arrow/impl-flechette/canonical.d.ts +18 -0
- package/dist/arrow/impl-flechette/empty.d.ts +9 -0
- package/dist/arrow/impl-flechette/filter.d.ts +10 -0
- package/dist/arrow/impl-flechette/index.d.ts +11 -0
- package/dist/arrow/impl-flechette/ipc.d.ts +33 -0
- package/dist/arrow/impl-flechette/iterate.d.ts +29 -0
- package/dist/arrow/impl-flechette/message-meta.d.ts +10 -0
- package/dist/arrow/impl-flechette/normalize-type.d.ts +11 -0
- package/dist/arrow/impl-flechette/project.d.ts +3 -0
- package/dist/arrow/impl-flechette/schema.d.ts +47 -0
- package/dist/arrow/impl-flechette/statistics.d.ts +13 -0
- package/dist/arrow/index.d.ts +11 -0
- package/dist/arrow/predicates.d.ts +47 -0
- package/dist/arrow/repr.test-d.d.ts +52 -0
- package/dist/arrow/schema-types.d.ts +71 -0
- package/dist/arrow/types.d.ts +57 -0
- package/dist/catalog/attach-option.d.ts +33 -0
- package/dist/catalog/attach-options.d.ts +30 -0
- package/dist/catalog/composite.d.ts +33 -0
- package/dist/catalog/descriptors.d.ts +154 -0
- package/dist/catalog/interface.d.ts +239 -0
- package/dist/catalog/read-only.d.ts +33 -0
- package/dist/client/client.d.ts +189 -0
- package/dist/client/errors.d.ts +26 -0
- package/dist/client/helpers.d.ts +12 -0
- package/dist/client/protocol.d.ts +16 -0
- package/dist/client/types.d.ts +125 -0
- package/dist/client-entry.d.ts +11 -0
- package/dist/client-entry.js +48 -0
- package/dist/client-entry.js.map +9 -0
- package/dist/codec/asd.d.ts +25 -0
- package/dist/crypto.d.ts +36 -0
- package/dist/errors.d.ts +24 -0
- package/dist/filter-pushdown/collector.d.ts +32 -0
- package/dist/filter-pushdown/deserialize.d.ts +16 -0
- package/dist/filter-pushdown/evaluate.d.ts +51 -0
- package/dist/filter-pushdown/index.d.ts +4 -0
- package/dist/filter-pushdown/types.d.ts +84 -0
- package/dist/functions/aggregate.d.ts +129 -0
- package/dist/functions/copy-from.d.ts +81 -0
- package/dist/functions/copy-to.d.ts +121 -0
- package/dist/functions/registry.d.ts +16 -0
- package/dist/functions/scalar.d.ts +98 -0
- package/dist/functions/storage-cf-do.d.ts +47 -0
- package/dist/functions/storage.d.ts +86 -0
- package/dist/functions/table-buffering.d.ts +99 -0
- package/dist/functions/table-in-out.d.ts +64 -0
- package/dist/functions/table.d.ts +118 -0
- package/dist/functions/types.d.ts +157 -0
- package/dist/generated/vgi-client.d.ts +466 -0
- package/dist/generated/vgi-protocol-schemas.d.ts +115 -0
- package/dist/index.core.d.ts +42 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +10888 -0
- package/dist/index.js.map +85 -0
- package/dist/metadata/resolve.d.ts +3 -0
- package/dist/metadata/serialize.d.ts +12 -0
- package/dist/metadata/types.d.ts +47 -0
- package/dist/protocol/dispatch.d.ts +23 -0
- package/dist/protocol/handlers/aggregate.d.ts +3 -0
- package/dist/protocol/handlers/catalog/admin.d.ts +3 -0
- package/dist/protocol/handlers/catalog/index.d.ts +3 -0
- package/dist/protocol/handlers/catalog/index_methods.d.ts +3 -0
- package/dist/protocol/handlers/catalog/macro.d.ts +3 -0
- package/dist/protocol/handlers/catalog/shared.d.ts +70 -0
- package/dist/protocol/handlers/catalog/table.d.ts +3 -0
- package/dist/protocol/handlers/catalog/view.d.ts +3 -0
- package/dist/protocol/handlers/function.d.ts +8 -0
- package/dist/protocol/handlers/shared.d.ts +31 -0
- package/dist/protocol/handlers/table-buffering.d.ts +3 -0
- package/dist/protocol/serialize.d.ts +4 -0
- package/dist/protocol/serializers/arguments.d.ts +3 -0
- package/dist/protocol/serializers/bind.d.ts +9 -0
- package/dist/protocol/serializers/cardinality.d.ts +7 -0
- package/dist/protocol/serializers/init.d.ts +9 -0
- package/dist/protocol/serializers/shared.d.ts +12 -0
- package/dist/protocol/state-serializer.d.ts +23 -0
- package/dist/protocol/types.d.ts +129 -0
- package/dist/secrets/helpers.d.ts +15 -0
- package/dist/types.d.ts +52 -0
- package/dist/util/arrow/index.d.ts +1 -0
- package/dist/util/bytes.d.ts +2 -0
- package/dist/util/statistics.d.ts +7 -0
- package/dist/worker-cf-entry.d.ts +30 -0
- package/dist/worker-cf-entry.js +8767 -0
- package/dist/worker-cf-entry.js.map +74 -0
- package/dist/worker.d.ts +36 -0
- package/package.json +96 -0
- package/src/arguments/argument-spec.ts +200 -0
- package/src/arguments/arguments.ts +81 -0
- package/src/arrow/codec/branded.ts +206 -0
- package/src/arrow/codec/registry.ts +674 -0
- package/src/arrow/codec/repr.ts +181 -0
- package/src/arrow/codec/type-descriptors.ts +137 -0
- package/src/arrow/impl-arrowjs/build.ts +88 -0
- package/src/arrow/impl-arrowjs/canonical.ts +509 -0
- package/src/arrow/impl-arrowjs/empty.ts +72 -0
- package/src/arrow/impl-arrowjs/filter.ts +53 -0
- package/src/arrow/impl-arrowjs/index.ts +54 -0
- package/src/arrow/impl-arrowjs/ipc.ts +67 -0
- package/src/arrow/impl-arrowjs/iterate.ts +159 -0
- package/src/arrow/impl-arrowjs/project.ts +73 -0
- package/src/arrow/impl-arrowjs/schema.ts +256 -0
- package/src/arrow/impl-arrowjs/statistics.ts +185 -0
- package/src/arrow/impl-flechette/build.ts +65 -0
- package/src/arrow/impl-flechette/canonical.ts +289 -0
- package/src/arrow/impl-flechette/empty.ts +20 -0
- package/src/arrow/impl-flechette/filter.ts +42 -0
- package/src/arrow/impl-flechette/index.ts +54 -0
- package/src/arrow/impl-flechette/ipc.ts +110 -0
- package/src/arrow/impl-flechette/iterate.ts +121 -0
- package/src/arrow/impl-flechette/message-meta.ts +175 -0
- package/src/arrow/impl-flechette/normalize-type.ts +99 -0
- package/src/arrow/impl-flechette/project.ts +64 -0
- package/src/arrow/impl-flechette/schema.ts +202 -0
- package/src/arrow/impl-flechette/statistics.ts +198 -0
- package/src/arrow/index.ts +129 -0
- package/src/arrow/predicates.ts +66 -0
- package/src/arrow/repr.test-d.ts +189 -0
- package/src/arrow/schema-types.ts +213 -0
- package/src/arrow/types.ts +74 -0
- package/src/catalog/attach-option.ts +107 -0
- package/src/catalog/attach-options.ts +79 -0
- package/src/catalog/composite.ts +180 -0
- package/src/catalog/descriptors.ts +164 -0
- package/src/catalog/interface.ts +721 -0
- package/src/catalog/read-only.ts +909 -0
- package/src/client/client.ts +1348 -0
- package/src/client/errors.ts +69 -0
- package/src/client/helpers.ts +56 -0
- package/src/client/protocol.ts +33 -0
- package/src/client/types.ts +140 -0
- package/src/client-entry.ts +112 -0
- package/src/codec/asd.ts +147 -0
- package/src/crypto.ts +143 -0
- package/src/errors.ts +61 -0
- package/src/filter-pushdown/collector.ts +147 -0
- package/src/filter-pushdown/deserialize.ts +253 -0
- package/src/filter-pushdown/evaluate.ts +591 -0
- package/src/filter-pushdown/index.ts +28 -0
- package/src/filter-pushdown/types.ts +91 -0
- package/src/functions/aggregate.ts +384 -0
- package/src/functions/copy-from.ts +282 -0
- package/src/functions/copy-to.ts +319 -0
- package/src/functions/registry.ts +258 -0
- package/src/functions/scalar.ts +356 -0
- package/src/functions/storage-cf-do.ts +303 -0
- package/src/functions/storage.ts +521 -0
- package/src/functions/table-buffering.ts +562 -0
- package/src/functions/table-in-out.ts +373 -0
- package/src/functions/table.ts +521 -0
- package/src/functions/types.ts +192 -0
- package/src/generated/vgi-client.ts +560 -0
- package/src/generated/vgi-protocol-schemas.ts +864 -0
- package/src/index.core.ts +267 -0
- package/src/index.ts +11 -0
- package/src/metadata/resolve.ts +109 -0
- package/src/metadata/serialize.ts +242 -0
- package/src/metadata/types.ts +60 -0
- package/src/protocol/dispatch.ts +52 -0
- package/src/protocol/handlers/aggregate.ts +355 -0
- package/src/protocol/handlers/catalog/admin.ts +368 -0
- package/src/protocol/handlers/catalog/index.ts +25 -0
- package/src/protocol/handlers/catalog/index_methods.ts +65 -0
- package/src/protocol/handlers/catalog/macro.ts +114 -0
- package/src/protocol/handlers/catalog/shared.ts +291 -0
- package/src/protocol/handlers/catalog/table.ts +401 -0
- package/src/protocol/handlers/catalog/view.ts +119 -0
- package/src/protocol/handlers/function.ts +302 -0
- package/src/protocol/handlers/shared.ts +80 -0
- package/src/protocol/handlers/table-buffering.ts +207 -0
- package/src/protocol/serialize.ts +23 -0
- package/src/protocol/serializers/arguments.ts +160 -0
- package/src/protocol/serializers/bind.ts +212 -0
- package/src/protocol/serializers/cardinality.ts +45 -0
- package/src/protocol/serializers/init.ts +247 -0
- package/src/protocol/serializers/shared.ts +46 -0
- package/src/protocol/state-serializer.ts +181 -0
- package/src/protocol/types.ts +153 -0
- package/src/secrets/helpers.ts +70 -0
- package/src/types.ts +71 -0
- package/src/util/arrow/index.ts +23 -0
- package/src/util/bytes.ts +14 -0
- package/src/util/statistics.ts +40 -0
- package/src/worker-cf-entry.ts +172 -0
- package/src/worker.ts +212 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Query Farm Source-Available License, Version 1.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, 2026 Query Farm LLC. All rights reserved.
|
|
4
|
+
|
|
5
|
+
## 1. Definitions
|
|
6
|
+
|
|
7
|
+
"Licensor" means Query Farm LLC (http://query.farm, hello@query.farm) and its
|
|
8
|
+
affiliates under common control.
|
|
9
|
+
|
|
10
|
+
"VGI" means the Vector Gateway Interface, the DuckDB extension technology developed
|
|
11
|
+
by the Licensor, also referred to by the Licensor as its "Hyperfederation" database
|
|
12
|
+
technology.
|
|
13
|
+
|
|
14
|
+
"Licensed Work" means VGI, including its source code, object code, and any
|
|
15
|
+
documentation distributed with it, in each version made available by the Licensor
|
|
16
|
+
under this License.
|
|
17
|
+
|
|
18
|
+
"You" (or "Your") means the individual or legal entity exercising rights under this
|
|
19
|
+
License, together with all affiliates under common control with that entity.
|
|
20
|
+
|
|
21
|
+
"Production Use" means any use of the Licensed Work other than for development,
|
|
22
|
+
testing, evaluation, experimentation, or other non-production purposes.
|
|
23
|
+
|
|
24
|
+
"Hyperfederation Services" means services relating to the federation, gateway,
|
|
25
|
+
integration, querying, or interoperation of data sources using VGI or
|
|
26
|
+
functionally equivalent technology, including services that expose, broker, or
|
|
27
|
+
provide access to such federated or gateway capabilities.
|
|
28
|
+
|
|
29
|
+
"Commercial Marketplace" means any platform, exchange, or intermediary service,
|
|
30
|
+
whether or not operated for a fee, that connects providers and consumers of
|
|
31
|
+
Hyperfederation Services, or that facilitates the offering, discovery, exchange,
|
|
32
|
+
sale, or licensing of Hyperfederation Services among third parties.
|
|
33
|
+
|
|
34
|
+
"Competing Offering" means a product or service that You make available to third
|
|
35
|
+
parties, on a paid basis (including through paid support, subscription, or hosting
|
|
36
|
+
arrangements), whose capabilities significantly overlap with those of the Licensor's
|
|
37
|
+
version(s) of the Licensed Work.
|
|
38
|
+
|
|
39
|
+
## 2. Grant of Rights
|
|
40
|
+
|
|
41
|
+
Subject to the terms and limitations of this License, the Licensor grants You a
|
|
42
|
+
worldwide, royalty-free, non-exclusive license to:
|
|
43
|
+
|
|
44
|
+
(a) use, copy, and run the Licensed Work for any non-production purpose;
|
|
45
|
+
|
|
46
|
+
(b) modify the Licensed Work and create derivative works of it;
|
|
47
|
+
|
|
48
|
+
(c) redistribute the Licensed Work and Your derivative works, provided You comply
|
|
49
|
+
with Section 5; and
|
|
50
|
+
|
|
51
|
+
(d) make Production Use of the Licensed Work, except where such use is restricted by
|
|
52
|
+
Section 3 or reserved to the Licensor by Section 4.
|
|
53
|
+
|
|
54
|
+
## 3. Production Use Conditions
|
|
55
|
+
|
|
56
|
+
The grant of Production Use in Section 2(d) does not extend to, and You may not
|
|
57
|
+
without a separate commercial license from the Licensor:
|
|
58
|
+
|
|
59
|
+
(a) provide a Competing Offering to third parties; or
|
|
60
|
+
|
|
61
|
+
(b) offer the Licensed Work, or any derivative work of it, to third parties on a
|
|
62
|
+
hosted, embedded, or as-a-service basis where doing so competes with the Licensor's
|
|
63
|
+
commercial interests in the Licensed Work.
|
|
64
|
+
|
|
65
|
+
"Embedded" includes incorporating the source or object code of the Licensed Work
|
|
66
|
+
into a Competing Offering, and packaging a Competing Offering such that the Licensed
|
|
67
|
+
Work must be accessed or downloaded for that offering to function.
|
|
68
|
+
|
|
69
|
+
Hosting or using the Licensed Work for Your own internal purposes is not a Competing
|
|
70
|
+
Offering and is permitted, including across Your affiliates under common control.
|
|
71
|
+
|
|
72
|
+
## 4. Reserved Rights
|
|
73
|
+
|
|
74
|
+
Notwithstanding any other provision of this License, the Licensor reserves to itself
|
|
75
|
+
the exclusive right to build, operate, offer, or authorize a Commercial Marketplace
|
|
76
|
+
that incorporates, integrates, is built upon, or otherwise uses the Licensed Work.
|
|
77
|
+
|
|
78
|
+
This License grants You no right to construct, operate, or enable a Commercial
|
|
79
|
+
Marketplace using the Licensed Work, whether on a commercial or non-commercial basis,
|
|
80
|
+
and any such use requires a separate written agreement with the Licensor.
|
|
81
|
+
|
|
82
|
+
## 5. Redistribution
|
|
83
|
+
|
|
84
|
+
If You redistribute the Licensed Work or any derivative work of it, in original or
|
|
85
|
+
modified form, You must:
|
|
86
|
+
|
|
87
|
+
(a) include a complete, unmodified copy of this License with each copy; and
|
|
88
|
+
|
|
89
|
+
(b) cause any recipient to receive the Licensed Work subject to the terms of this
|
|
90
|
+
License.
|
|
91
|
+
|
|
92
|
+
The conditions in Sections 3 and 4 apply to every recipient of the Licensed Work,
|
|
93
|
+
whether received directly from the Licensor or through a third party.
|
|
94
|
+
|
|
95
|
+
## 6. Conversion to Open Source
|
|
96
|
+
|
|
97
|
+
For each version of the Licensed Work, on the tenth anniversary of the date the
|
|
98
|
+
Licensor first made that version publicly available (the "Change Date" for that
|
|
99
|
+
version), the Licensor additionally grants You the right to use that version under
|
|
100
|
+
the terms of the Apache License, Version 2.0, and on and after that version's Change
|
|
101
|
+
Date the restrictions in Sections 3 and 4 no longer apply to that version.
|
|
102
|
+
|
|
103
|
+
This License applies separately to each version of the Licensed Work, and the Change
|
|
104
|
+
Date may differ between versions.
|
|
105
|
+
|
|
106
|
+
## 7. Commercial Licensing
|
|
107
|
+
|
|
108
|
+
If Your intended use is not permitted under this License, You may obtain a separate
|
|
109
|
+
commercial license from the Licensor by contacting hello@query.farm. Absent such a
|
|
110
|
+
license, You must refrain from the restricted use.
|
|
111
|
+
|
|
112
|
+
## 8. Trademarks
|
|
113
|
+
|
|
114
|
+
This License does not grant You any right to use the names, trademarks, service
|
|
115
|
+
marks, or logos of the Licensor, including "Vector Gateway Interface," "VGI," and
|
|
116
|
+
"Hyperfederation," except as required for reasonable and customary use in describing
|
|
117
|
+
the origin of the Licensed Work.
|
|
118
|
+
|
|
119
|
+
## 9. Termination
|
|
120
|
+
|
|
121
|
+
Any use of the Licensed Work in violation of this License automatically terminates
|
|
122
|
+
Your rights under this License for the current and all other versions of the Licensed
|
|
123
|
+
Work. Your rights may be reinstated only by a writing signed by the Licensor.
|
|
124
|
+
|
|
125
|
+
## 10. Disclaimer of Warranty and Limitation of Liability
|
|
126
|
+
|
|
127
|
+
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
128
|
+
AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED,
|
|
129
|
+
INCLUDING WITHOUT LIMITATION ANY WARRANTIES OR CONDITIONS OF MERCHANTABILITY, FITNESS
|
|
130
|
+
FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE.
|
|
131
|
+
|
|
132
|
+
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL THE LICENSOR BE
|
|
133
|
+
LIABLE TO YOU FOR ANY DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR THE USE
|
|
134
|
+
OF THE LICENSED WORK, WHETHER IN CONTRACT, TORT, OR OTHERWISE.
|
package/README.md
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
# @query-farm/vgi
|
|
2
|
+
|
|
3
|
+
TypeScript framework for extending [DuckDB](https://duckdb.org) with user-defined
|
|
4
|
+
functions written in TypeScript, served to DuckDB over the **Vector Gateway
|
|
5
|
+
Interface (VGI)** — an Apache Arrow IPC protocol.
|
|
6
|
+
|
|
7
|
+
You write scalar, table, aggregate, and table-in-out functions (plus catalogs) in
|
|
8
|
+
TypeScript; a *worker* exposes them; DuckDB attaches to the worker and calls them as
|
|
9
|
+
if they were native. It is wire-compatible with [`vgi-python`](https://query.farm),
|
|
10
|
+
so a worker written in either language is interchangeable.
|
|
11
|
+
|
|
12
|
+
```sql
|
|
13
|
+
LOAD vgi;
|
|
14
|
+
ATTACH 'demo' AS demo (TYPE vgi, LOCATION '/path/to/your-worker');
|
|
15
|
+
SELECT demo.upper_case(name) FROM users;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @query-farm/vgi
|
|
22
|
+
# or: bun add @query-farm/vgi
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Requires **Node.js ≥ 22.15** or **Bun**.
|
|
26
|
+
|
|
27
|
+
> **Peer dependencies (since 0.3.0).** `@query-farm/apache-arrow` (`^21.1.1`) and
|
|
28
|
+
> `@query-farm/vgi-rpc` (`^0.7.5`) are **peerDependencies** — install them directly
|
|
29
|
+
> alongside `@query-farm/vgi`:
|
|
30
|
+
>
|
|
31
|
+
> ```bash
|
|
32
|
+
> npm install @query-farm/vgi @query-farm/apache-arrow @query-farm/vgi-rpc
|
|
33
|
+
> ```
|
|
34
|
+
>
|
|
35
|
+
> The SDK bundles both as external, so a single shared instance avoids
|
|
36
|
+
> duplicate-type errors — notably the `vgi-rpc` `Protocol` clash you hit when you
|
|
37
|
+
> also import `createHttpHandler` (or any `vgi-rpc` type) directly and two copies
|
|
38
|
+
> get installed. See [`MIGRATION.md`](./MIGRATION.md#020--030--peer-dependencies).
|
|
39
|
+
|
|
40
|
+
Using VGI from DuckDB also requires the **`vgi` DuckDB extension**. The easiest way to
|
|
41
|
+
get it is via [**Haybarn**](https://haybarn.query.farm) — Query Farm's distribution of
|
|
42
|
+
DuckDB — which publishes the extension (and a DuckDB-Wasm engine) as prebuilt npm
|
|
43
|
+
packages, so there's no C++ toolchain or manual `INSTALL`/compile step:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# The vgi extension as prebuilt binaries, from npm:
|
|
47
|
+
npm install @haybarn/ext-vgi-h1-5-3 # built for Haybarn / DuckDB 1.5.3
|
|
48
|
+
|
|
49
|
+
# Haybarn's DuckDB-Wasm engine, for running VGI in the browser / Cloudflare Workers:
|
|
50
|
+
npm install @haybarn/haybarn-wasm
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The `@haybarn/ext-*` packages are meta-packages: npm pulls only the prebuilt binary
|
|
54
|
+
matching your platform (native leaves for linux/darwin/win, plus
|
|
55
|
+
`wasm-mvp`/`wasm-eh`/`wasm-threads` variants for DuckDB-Wasm). The Wasm engine is what
|
|
56
|
+
lets VGI run in the browser and on Cloudflare Workers — see
|
|
57
|
+
[Runtimes & entry points](#runtimes--entry-points).
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
60
|
+
|
|
61
|
+
### 1. Define a scalar function and run a worker
|
|
62
|
+
|
|
63
|
+
Types are plain aliases (`str`, `int`, `float`, `bool`, `bytes`, …) and the input
|
|
64
|
+
arrives as a columnar Arrow batch:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// worker.ts
|
|
68
|
+
import { Worker, defineScalarFunction, str, int } from "@query-farm/vgi";
|
|
69
|
+
|
|
70
|
+
const upperCase = defineScalarFunction({
|
|
71
|
+
name: "upper_case", // SQL name → demo.upper_case(...)
|
|
72
|
+
description: "Convert a string to uppercase",
|
|
73
|
+
|
|
74
|
+
// Declares the argument types *and order*. DuckDB calls scalar functions
|
|
75
|
+
// positionally, so the keys are just parameter names (for docs/metadata) —
|
|
76
|
+
// inside compute you read the input columns by position, not by this name.
|
|
77
|
+
// Type aliases: str, int, int32, float, float32, bool, bytes — or any Arrow
|
|
78
|
+
// DataType (e.g. `new Decimal(18, 2)`).
|
|
79
|
+
params: { value: str },
|
|
80
|
+
|
|
81
|
+
// Static output type. For a type that depends on the input, omit `returns`
|
|
82
|
+
// and use `outputType: (bind) => <DataType>` (may be async).
|
|
83
|
+
returns: str,
|
|
84
|
+
|
|
85
|
+
// compute runs once per input batch. Read each argument as a column by
|
|
86
|
+
// position (column 0 = first arg); return one output value per row (null ok).
|
|
87
|
+
// Full signature: compute(batch, consts, info) where
|
|
88
|
+
// consts → values of any `constParams` (literals folded at bind time)
|
|
89
|
+
// info → { settings, secrets, auth } — session settings, secrets, caller
|
|
90
|
+
compute: (batch) => {
|
|
91
|
+
const values = batch.getChildAt(0)!; // first positional argument
|
|
92
|
+
return Array.from(values, (v) =>
|
|
93
|
+
v == null ? null : String(v).toUpperCase(),
|
|
94
|
+
);
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
// Other optional fields: constParams, nullHandling, stability (volatility),
|
|
98
|
+
// examples, categories, tags, requiredSettings, requiredSecrets, maxWorkers.
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// A two-argument scalar — the args are positional, so column 0 is the first
|
|
102
|
+
// argument and column 1 is the second (the param keys are just names).
|
|
103
|
+
const multiply = defineScalarFunction({
|
|
104
|
+
name: "multiply",
|
|
105
|
+
description: "Multiply two numbers",
|
|
106
|
+
params: { a: int, b: int }, // two positional arguments
|
|
107
|
+
returns: int, // int = Int64 → values are bigint
|
|
108
|
+
compute: (batch) => {
|
|
109
|
+
const a = batch.getChildAt(0)!; // first argument
|
|
110
|
+
const b = batch.getChildAt(1)!; // second argument
|
|
111
|
+
return Array.from({ length: batch.numRows }, (_, i) => {
|
|
112
|
+
const x = a.get(i);
|
|
113
|
+
const y = b.get(i);
|
|
114
|
+
return x == null || y == null ? null : x * y; // NULL in → NULL out
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Functions are served through a catalog — that's what DuckDB ATTACHes to.
|
|
120
|
+
// `name` is the catalog DuckDB sees (matches the ATTACH target below).
|
|
121
|
+
new Worker({
|
|
122
|
+
catalog: { name: "demo", schemas: [{ name: "main", functions: [upperCase, multiply] }] },
|
|
123
|
+
}).run();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
A worker speaks Arrow IPC over stdin/stdout (or AF_UNIX / HTTP — see
|
|
127
|
+
[Transports](#transports)). It is **not** interactive; DuckDB drives it.
|
|
128
|
+
|
|
129
|
+
### 2. Stream rows from a table function
|
|
130
|
+
|
|
131
|
+
Table functions are incremental producers: build a schema with `toSchema`, keep your
|
|
132
|
+
own `state`, and `emit` batches until you `finish`. DuckDB pulls lazily, so this
|
|
133
|
+
streams without materializing everything up front:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import { Worker, defineTableFunction, batchFromColumns, toSchema, int } from "@query-farm/vgi";
|
|
137
|
+
|
|
138
|
+
const schema = toSchema({ n: int }); // output columns → n BIGINT
|
|
139
|
+
|
|
140
|
+
const sequence = defineTableFunction({
|
|
141
|
+
name: "sequence",
|
|
142
|
+
description: "Emit integers 0..n-1, streamed in batches of 1000",
|
|
143
|
+
|
|
144
|
+
// Positional args by name. Also available: argDefaults, varargs, argDocs.
|
|
145
|
+
args: { n: int },
|
|
146
|
+
|
|
147
|
+
// onBind runs once at plan time → declare the output schema. May be async,
|
|
148
|
+
// and may also return opaqueData / secret + scope lookups for the call.
|
|
149
|
+
onBind: () => ({ outputSchema: schema }),
|
|
150
|
+
|
|
151
|
+
// Per-execution mutable state, built from the bound args.
|
|
152
|
+
initialState: ({ args }) => ({ i: 0, n: Number(args.n) }),
|
|
153
|
+
|
|
154
|
+
// process is the pull loop. DuckDB calls it repeatedly and consumes lazily:
|
|
155
|
+
// emit zero or more batches per call, then finish() to signal end-of-stream.
|
|
156
|
+
// You never have to materialize the whole result. May be async.
|
|
157
|
+
process: (_params, state, out) => {
|
|
158
|
+
if (state.i >= state.n) return out.finish(); // end-of-stream
|
|
159
|
+
const end = Math.min(state.i + 1000, state.n);
|
|
160
|
+
const ns: bigint[] = [];
|
|
161
|
+
for (let k = state.i; k < end; k++) ns.push(BigInt(k));
|
|
162
|
+
out.emit(batchFromColumns({ n: ns }, schema)); // hand a batch to DuckDB
|
|
163
|
+
state.i = end;
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// Optional optimizer/runtime hooks — all omittable:
|
|
167
|
+
// cardinality: (bind) => ({ estimate, max }) row-count hints
|
|
168
|
+
// statistics: (bind) => ColumnStatistics[] min/max → filter folding
|
|
169
|
+
// projectionPushdown / filterPushdown / autoApplyFilters
|
|
170
|
+
// dynamicToString: (...) => Record<string,string> EXPLAIN ANALYZE counters
|
|
171
|
+
// onInit + shared storage for partitioned producers / work queues
|
|
172
|
+
// partitionKind, preservesOrder, lateMaterialization, samplingPushdown, …
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Serve every function from the same catalog.
|
|
176
|
+
new Worker({
|
|
177
|
+
catalog: { name: "demo", schemas: [{ name: "main", functions: [upperCase, multiply, sequence] }] },
|
|
178
|
+
}).run();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 3. Attach it from DuckDB
|
|
182
|
+
|
|
183
|
+
The `LOCATION` is a shell command DuckDB runs to spawn the worker. For Bun:
|
|
184
|
+
|
|
185
|
+
```sql
|
|
186
|
+
LOAD vgi;
|
|
187
|
+
ATTACH 'demo' AS demo (TYPE vgi, LOCATION 'bun run /abs/path/to/worker.ts');
|
|
188
|
+
|
|
189
|
+
SELECT demo.upper_case('hello'); -- HELLO
|
|
190
|
+
SELECT demo.multiply(6, 7); -- 42
|
|
191
|
+
SELECT * FROM demo.sequence(5); -- 0,1,2,3,4
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Function types
|
|
195
|
+
|
|
196
|
+
Five factories, each mapping to a DuckDB function shape with its own lifecycle:
|
|
197
|
+
|
|
198
|
+
- **`defineScalarFunction`** — row-in / row-out (`SELECT f(x)`). DuckDB hands you a
|
|
199
|
+
columnar batch; you return one output value per input row. For transforms,
|
|
200
|
+
parsing, formatting, crypto, encoding, per-row lookups.
|
|
201
|
+
- **`defineTableFunction`** — a set-returning producer (`SELECT * FROM f(...)`). You
|
|
202
|
+
keep your own `state` and `emit` batches until `finish`, and DuckDB pulls lazily.
|
|
203
|
+
The richest type: projection / filter / sampling pushdown, cardinality and
|
|
204
|
+
per-column statistics for the optimizer, Hive-style partitioning, late
|
|
205
|
+
materialization, and EXPLAIN ANALYZE counters.
|
|
206
|
+
- **`defineAggregate`** — aggregate / window function (`f(x) … GROUP BY`). Implement
|
|
207
|
+
`initialState` / `update` / `combine` / `finalize`; `combine` lets DuckDB
|
|
208
|
+
aggregate partitions in parallel and merge the results.
|
|
209
|
+
- **`defineTableInOutFunction`** — table-in / table-out
|
|
210
|
+
(`SELECT * FROM f(TABLE t, …)`). Per-partition `state`, a streaming `process` per
|
|
211
|
+
input batch, and a `finalize` that sees every worker's state — for windowing,
|
|
212
|
+
reshaping, enrichment, sessionization.
|
|
213
|
+
- **`defineTableBufferingFunction`** — table-in / table-out that must observe **all**
|
|
214
|
+
input before producing output (global sort, top-N, pivot). Sink (`process`) →
|
|
215
|
+
`combine` → source (`finalize`), with explicit sink/source ordering controls.
|
|
216
|
+
|
|
217
|
+
### Capability matrix
|
|
218
|
+
|
|
219
|
+
| Capability | Scalar | Table | Aggregate | Table-in-out | Buffering |
|
|
220
|
+
|---|:--:|:--:|:--:|:--:|:--:|
|
|
221
|
+
| Columnar input rows | ✓ | — | ✓ | ✓ | ✓ |
|
|
222
|
+
| Streaming output (`emit` / `finish`) | — | ✓ | — | ✓ | ✓ |
|
|
223
|
+
| Per-group / per-partition state | — | — | ✓ | ✓ | ✓ |
|
|
224
|
+
| Parallel merge (`combine`) | — | — | ✓ | — | ✓ |
|
|
225
|
+
| Bind-time dynamic output type | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
226
|
+
| Named args · defaults · varargs | ✓¹ | ✓ | ✓ | ✓ | ✓ |
|
|
227
|
+
| Constant (bind-folded) params | ✓ | ✓² | ✓ | ✓² | ✓² |
|
|
228
|
+
| Cardinality hints | — | ✓ | — | — | ✓ |
|
|
229
|
+
| Column statistics (optimizer) | — | ✓ | — | — | — |
|
|
230
|
+
| Projection pushdown | — | ✓ | — | ✓ | ✓ |
|
|
231
|
+
| Filter pushdown (+ auto-apply) | — | ✓ | — | ✓ | ✓ |
|
|
232
|
+
| Sampling pushdown | — | ✓ | — | — | — |
|
|
233
|
+
| Late materialization | — | ✓ | — | — | — |
|
|
234
|
+
| Hive-style partitioning | — | ✓ | — | — | — |
|
|
235
|
+
| Batch-index threading | — | ✓ | — | — | ✓ |
|
|
236
|
+
| Order preservation / dependence | — | ✓ | — | — | ✓³ |
|
|
237
|
+
| EXPLAIN ANALYZE diagnostics | — | ✓ | — | — | — |
|
|
238
|
+
| Shared storage (work queues, cross-worker state) | — | ✓ | — | ✓ | ✓ |
|
|
239
|
+
| Settings & secrets access | ✓ | ✓ | — | ✓ | ✓ |
|
|
240
|
+
| Volatility / stability hint | ✓ | ✓ | — | ✓ | ✓ |
|
|
241
|
+
| NULL-handling control | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
242
|
+
| Async lifecycle | bind⁴ | ✓ | bind⁴ | ✓ | ✓ |
|
|
243
|
+
|
|
244
|
+
¹ via the ordered `parameters` form. ² supplied as bind-time `args`.
|
|
245
|
+
³ via `sinkOrderDependent` / `sourceOrderDependent`. ⁴ `onBind` / `outputType`
|
|
246
|
+
may be async; `compute` / `update` / `finalize` run synchronously.
|
|
247
|
+
|
|
248
|
+
Workers can also expose a **catalog** (schemas, tables, views, macros, secrets) via
|
|
249
|
+
`ReadOnlyCatalogInterface` / `CompositeCatalogInterface`, so an `ATTACH`ed worker
|
|
250
|
+
presents browsable database objects, not just functions.
|
|
251
|
+
|
|
252
|
+
## Type representations
|
|
253
|
+
|
|
254
|
+
Every value DuckDB exchanges with a worker has an Arrow type, and each Arrow type
|
|
255
|
+
maps to exactly one JS value shape. A single **codec** layer is the only authority
|
|
256
|
+
for that mapping: it converts between the JS value you read/write and an internal
|
|
257
|
+
*canonical* pivot (the raw Arrow wire unit), identically across both Arrow backends.
|
|
258
|
+
|
|
259
|
+
There are two author-facing representations, selected per scalar function with
|
|
260
|
+
`repr`:
|
|
261
|
+
|
|
262
|
+
- **`rich`** (the default) — the ergonomic shape. Identical to the canonical wire
|
|
263
|
+
unit for every type **except** `date32` / `date64`, which surface as a JS `Date`.
|
|
264
|
+
Sub-second temporal types (`time`, `timestamp`, `duration`) stay numeric/`bigint`,
|
|
265
|
+
because `Date` cannot hold microsecond/nanosecond precision losslessly.
|
|
266
|
+
- **`raw`** (opt-in) — the canonical wire unit with a **branded** TypeScript type that
|
|
267
|
+
carries the unit (e.g. `TimestampMicros`, `Date32`, `UnscaledDecimal`). At runtime a
|
|
268
|
+
branded value *is* the underlying `number`/`bigint`; the brand exists only at compile
|
|
269
|
+
time so a wrong-unit mix-up is a type error.
|
|
270
|
+
|
|
271
|
+
### Per-type mapping
|
|
272
|
+
|
|
273
|
+
| Arrow type | `rich` JS value | `raw` branded type |
|
|
274
|
+
|---|---|---|
|
|
275
|
+
| `bool` | `boolean` | `boolean` |
|
|
276
|
+
| `int8` / `int16` / `int32` | `number` | `number` |
|
|
277
|
+
| `uint8` / `uint16` / `uint32` | `number` | `number` |
|
|
278
|
+
| `int64` | `bigint` | `Int64` |
|
|
279
|
+
| `uint64` | `bigint` | `Uint64` (exported as `Uint64Raw`) |
|
|
280
|
+
| `float16` / `float32` / `float64` | `number` | `number` |
|
|
281
|
+
| `utf8` / `largeUtf8` | `string` | `string` |
|
|
282
|
+
| `binary` / `largeBinary` / `fixedSizeBinary` | `Uint8Array` | `Uint8Array` |
|
|
283
|
+
| **`date32`** | **`Date`** | `Date32` (days since epoch, `number`) |
|
|
284
|
+
| **`date64`** | **`Date`** | `Date64Ms` (ms since epoch, `bigint`) |
|
|
285
|
+
| `time32[s]` / `time32[ms]` | `number` (raw unit) | `Time32S` / `Time32Ms` |
|
|
286
|
+
| `time64[us]` / `time64[ns]` | `bigint` (raw unit) | `Time64Us` / `Time64Ns` |
|
|
287
|
+
| `timestamp[s/ms/us/ns]` | `bigint` (raw unit) | `TimestampSeconds` / `TimestampMillis` / `TimestampMicros` / `TimestampNanos` |
|
|
288
|
+
| `duration[s/ms/us/ns]` | `bigint` (raw unit) | `DurationSeconds` / `DurationMillis` / `DurationMicros` / `DurationNanos` |
|
|
289
|
+
| `decimal128` / `decimal256` | `bigint` (UNSCALED integer) | `UnscaledDecimal` |
|
|
290
|
+
| `struct` | `{ field: richValue }` | `{ field: rawValue }` |
|
|
291
|
+
| `list` / `largeList` / `fixedSizeList` | `Array<richValue \| null>` | `Array<rawValue \| null>` |
|
|
292
|
+
| `map` | `Array<[richKey, richValue]>` | `Array<[rawKey, rawValue]>` |
|
|
293
|
+
| `dictionary` | the decoded value's `rich` | the decoded value's `raw` |
|
|
294
|
+
|
|
295
|
+
`date32` / `date64` are the **only** types where `rich` differs from the canonical
|
|
296
|
+
wire unit. Everywhere else, `rich` *is* the canonical value and `raw` is the same
|
|
297
|
+
value with a branded type. `null` / `undefined` pass through as `null` in every type.
|
|
298
|
+
|
|
299
|
+
Notes:
|
|
300
|
+
|
|
301
|
+
- **Discriminate Arrow types by `typeId` / predicates, never `constructor.name`.**
|
|
302
|
+
The factories return Arrow *type instances*, not classes named after the factory.
|
|
303
|
+
`dateDay()` returns an arrow-js `Date_` instance with `typeId === Type.Date` and
|
|
304
|
+
`unit === DateUnit.DAY` — there is **no** class named `DateDay`, so a check like
|
|
305
|
+
`type.constructor.name === "DateDay"` will always fail (and is brittle across the
|
|
306
|
+
two Arrow backends and minified builds). Use the exported `isDate(type)` predicate,
|
|
307
|
+
or compare `type.typeId` (to `Type.Date` / the backend-agnostic `TypeId.Date`) and
|
|
308
|
+
`type.unit` (to `DateUnit.DAY` / `DateUnit.MILLISECOND`) to distinguish day vs.
|
|
309
|
+
millisecond dates:
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import { dateDay, isDate, DateUnit, TypeId } from "@query-farm/vgi";
|
|
313
|
+
|
|
314
|
+
const t = dateDay();
|
|
315
|
+
isDate(t); // ✓ true — backend-agnostic predicate
|
|
316
|
+
t.typeId === TypeId.Date; // ✓ true
|
|
317
|
+
t.unit === DateUnit.DAY; // ✓ true — day-resolution date32
|
|
318
|
+
t.constructor.name === "DateDay" // ✗ NEVER — no such class; this is always false
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
- **Decimals are unscaled.** A `decimal128(18, 2)` value of `123.45` is the bigint
|
|
322
|
+
`12345n`; apply the scale yourself (`Number(v) / 100`). The declared
|
|
323
|
+
precision/scale travel with the column type, not the value.
|
|
324
|
+
- **Temporal units are lossless `bigint`.** A `timestamp[us]` round-trips as the
|
|
325
|
+
exact microsecond count — no `Date` narrowing, no precision loss.
|
|
326
|
+
|
|
327
|
+
### Symmetry, round-tripping, and validation
|
|
328
|
+
|
|
329
|
+
Reads and writes are symmetric: a value read from a column rebuilds into the same
|
|
330
|
+
column. `build(read(x))` round-trips, in either representation —
|
|
331
|
+
`iterRows(batch)` (and scalar inputs) return `rich` values, and a `rich` value fed
|
|
332
|
+
back through `batchFromColumns`/a scalar `compute` return rebuilds the original
|
|
333
|
+
column (pass `"raw"` / `repr: 'raw'` on both ends for the branded form).
|
|
334
|
+
|
|
335
|
+
The codec **validates and throws** on invalid or lossy input: a non-integer where an
|
|
336
|
+
integer is required, a `bigint` that overflows the declared width or the safe-integer
|
|
337
|
+
range when narrowing to `number`, an out-of-range `Date`, the wrong number of bytes
|
|
338
|
+
for a `fixedSizeBinary`, etc. You get a clear `codec[<type>]: …` `TypeError` at build
|
|
339
|
+
time rather than silently corrupt data on the wire.
|
|
340
|
+
|
|
341
|
+
### Typed author API
|
|
342
|
+
|
|
343
|
+
Declare `params` and `returns` (or `args`) with the typed factories and `compute` is
|
|
344
|
+
statically typed end to end — the input columns and the return value are checked
|
|
345
|
+
against the declared Arrow types and the chosen representation:
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
import { Worker, defineScalarFunction, timestampMicros, int64 } from "@query-farm/vgi";
|
|
349
|
+
|
|
350
|
+
// rich (default): timestamp values are plain bigint microsecond counts.
|
|
351
|
+
const addHour = defineScalarFunction({
|
|
352
|
+
name: "add_hour",
|
|
353
|
+
params: { ts: timestampMicros }, // input column: bigint (us)
|
|
354
|
+
returns: timestampMicros, // output: bigint (us)
|
|
355
|
+
compute: (batch) => {
|
|
356
|
+
const ts = batch.getChildAt(0)!;
|
|
357
|
+
return Array.from(ts, (v: bigint | null) =>
|
|
358
|
+
v == null ? null : v + 3_600_000_000n, // +1h in microseconds
|
|
359
|
+
); // returning a Date here is a COMPILE error
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
import {
|
|
366
|
+
Worker, defineScalarFunction, timestampMicros,
|
|
367
|
+
asTimestampMicros, type TimestampMicros,
|
|
368
|
+
} from "@query-farm/vgi";
|
|
369
|
+
|
|
370
|
+
// raw mode: outputs are branded units, constructed with `asTimestampMicros`.
|
|
371
|
+
const epoch = defineScalarFunction({
|
|
372
|
+
name: "epoch_us",
|
|
373
|
+
params: { ts: timestampMicros },
|
|
374
|
+
returns: timestampMicros,
|
|
375
|
+
repr: "raw", // opt in to branded raw units
|
|
376
|
+
compute: (batch) => {
|
|
377
|
+
const ts = batch.getChildAt(0)!;
|
|
378
|
+
return Array.from(ts, (v: TimestampMicros | null) =>
|
|
379
|
+
v == null ? null : asTimestampMicros(v + 1n), // branded in, branded out
|
|
380
|
+
);
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
For manual conversions outside a function, `codecFor(type)` returns the codec with
|
|
386
|
+
`richToCanonical` / `canonicalToRich` / `rawToCanonical` / `canonicalToRaw`.
|
|
387
|
+
|
|
388
|
+
### Factory name note
|
|
389
|
+
|
|
390
|
+
The typed Arrow type factories `int`, `int32`, `float32`, and `bool` are **not**
|
|
391
|
+
re-exported from the package root, because `@query-farm/vgi` already re-exports
|
|
392
|
+
vgi-rpc argument builders of the same names. Import those four from the arrow facade
|
|
393
|
+
(they ship as the typed factories there); the rest of the typed factory set
|
|
394
|
+
(`int8`/`int16`/`int64`, `uint*`, `float16`/`float64`, `decimal*`, `dateDay`,
|
|
395
|
+
`timestampMicros`, `struct`, `list`, `map`, …) is exported from the package root as
|
|
396
|
+
usual.
|
|
397
|
+
|
|
398
|
+
## Migration: the type-handling break
|
|
399
|
+
|
|
400
|
+
This is a pre-1.0 breaking change to how columnar values are represented in and out
|
|
401
|
+
of functions. The contract is now uniform across both Arrow backends and both
|
|
402
|
+
directions (read and write). For consumers upgrading:
|
|
403
|
+
|
|
404
|
+
- **`date32` / `date64` columns are now JS `Date` in *and* out by default.**
|
|
405
|
+
Previously dates were inconsistent — a day-number went *in* but a `Date` came back
|
|
406
|
+
*out*. Both directions are now `Date` under the default `rich` representation.
|
|
407
|
+
- **Reads return rich values.** `iterRows`, scalar inputs, and setting/secret reads
|
|
408
|
+
all surface the `rich` value for their type.
|
|
409
|
+
- **Non-date temporal types are lossless `bigint` raw units.** `time64`, `timestamp`,
|
|
410
|
+
and `duration` are the exact `bigint` count in their declared unit (us, ns, …) — no
|
|
411
|
+
`Date`, no precision loss.
|
|
412
|
+
- **Decimals are unscaled `bigint`.** A `decimal(18,2)` of `123.45` is `12345n`.
|
|
413
|
+
- **Opt into `repr: 'raw'`** for branded, unit-tagged raw units everywhere (including
|
|
414
|
+
`date32`/`date64` as plain day-number / ms-`bigint` rather than `Date`).
|
|
415
|
+
|
|
416
|
+
Before / after for the common date case:
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
// BEFORE (old, inconsistent): wrote a day-number, read back a Date.
|
|
420
|
+
returns: dateDay,
|
|
421
|
+
compute: () => [20000], // 20000 days since epoch
|
|
422
|
+
|
|
423
|
+
// AFTER (rich, default): write a Date, read a Date — symmetric.
|
|
424
|
+
returns: dateDay,
|
|
425
|
+
compute: () => [new Date("2024-10-19")],
|
|
426
|
+
|
|
427
|
+
// AFTER (raw): opt in to the branded day-number.
|
|
428
|
+
returns: dateDay,
|
|
429
|
+
repr: "raw",
|
|
430
|
+
compute: () => [asDate32(20000)], // branded number, not a Date
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Transports
|
|
434
|
+
|
|
435
|
+
A worker serves the same functions over any of:
|
|
436
|
+
|
|
437
|
+
- **stdin/stdout** — the default; how DuckDB subprocess-spawns a worker.
|
|
438
|
+
- **AF_UNIX** — a long-lived warm worker (`--unix <path>`), reused across calls.
|
|
439
|
+
- **HTTP** — stateless; all state round-trips in a self-contained token, so requests
|
|
440
|
+
can be load-balanced across hosts.
|
|
441
|
+
|
|
442
|
+
Transport handling lives in [`@query-farm/vgi-rpc`](https://www.npmjs.com/package/@query-farm/vgi-rpc).
|
|
443
|
+
|
|
444
|
+
## Runtimes & entry points
|
|
445
|
+
|
|
446
|
+
The package ships a backend-agnostic Arrow facade and selects an implementation at
|
|
447
|
+
build time per runtime, so the same source runs on servers, Cloudflare Workers, and
|
|
448
|
+
browsers:
|
|
449
|
+
|
|
450
|
+
| Runtime | Arrow backend |
|
|
451
|
+
| --- | --- |
|
|
452
|
+
| Node.js / Bun | [`@query-farm/apache-arrow`](https://www.npmjs.com/package/@query-farm/apache-arrow) (arrow-js) |
|
|
453
|
+
| Cloudflare Workers (`workerd`) / browser | [`@query-farm/flechette`](https://www.npmjs.com/package/@query-farm/flechette) |
|
|
454
|
+
|
|
455
|
+
Subpath exports:
|
|
456
|
+
|
|
457
|
+
- `@query-farm/vgi` — main API (define functions, `Worker`, `VgiClient`, catalogs).
|
|
458
|
+
- `@query-farm/vgi/client` — client-only entry (no server-side code).
|
|
459
|
+
- `@query-farm/vgi/worker-cf` — Cloudflare Workers entry (`workerd`/browser bundle).
|
|
460
|
+
|
|
461
|
+
## Relationship to other packages
|
|
462
|
+
|
|
463
|
+
- **[Haybarn](https://haybarn.query.farm)** — Query Farm's distribution of DuckDB,
|
|
464
|
+
with the `vgi` extension (and others) as prebuilt npm packages
|
|
465
|
+
([`@haybarn/haybarn-wasm`](https://www.npmjs.com/package/@haybarn/haybarn-wasm),
|
|
466
|
+
[`@haybarn/ext-vgi-h1-5-3`](https://www.npmjs.com/package/@haybarn/ext-vgi-h1-5-3)).
|
|
467
|
+
The host side: it runs the DuckDB engine that attaches to your worker.
|
|
468
|
+
- **[`@query-farm/vgi-rpc`](https://www.npmjs.com/package/@query-farm/vgi-rpc)** —
|
|
469
|
+
the RPC layer: protocol, server, transports, Arrow IPC framing. A runtime
|
|
470
|
+
dependency of this package.
|
|
471
|
+
- **`vgi-python`** — the reference implementation. This package is a wire-compatible
|
|
472
|
+
TypeScript port; workers from either side interoperate.
|
|
473
|
+
|
|
474
|
+
## Development
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
make install # bun install
|
|
478
|
+
make build # types + JS bundles
|
|
479
|
+
make test # integration tests (launcher transport)
|
|
480
|
+
make -j8 test-all # launcher + HTTP suites in parallel
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
See [`CLAUDE.md`](./CLAUDE.md) for the full build/test reference.
|
|
484
|
+
|
|
485
|
+
## License
|
|
486
|
+
|
|
487
|
+
Copyright © 2025, 2026 Query Farm LLC — https://query.farm
|
|
488
|
+
|
|
489
|
+
Distributed under the **Query Farm Source-Available License, Version 1.0**. Use,
|
|
490
|
+
modification, redistribution, and non-production use are permitted; some production
|
|
491
|
+
uses (notably competing offerings and commercial marketplaces) require a separate
|
|
492
|
+
commercial license. Each version converts to Apache-2.0 ten years after its release.
|
|
493
|
+
See [`LICENSE`](./LICENSE) for the full terms, or contact hello@query.farm for
|
|
494
|
+
commercial licensing.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type VgiSchema, type VgiDataType } from "../arrow/index.js";
|
|
2
|
+
export interface ArgumentSpec {
|
|
3
|
+
name: string;
|
|
4
|
+
position: number | string;
|
|
5
|
+
arrowType: VgiDataType;
|
|
6
|
+
isTableInput?: boolean;
|
|
7
|
+
isAnyType?: boolean;
|
|
8
|
+
isVarargs?: boolean;
|
|
9
|
+
isConst?: boolean;
|
|
10
|
+
doc?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Convert ArgumentSpecs to an Arrow Schema with VGI metadata keys.
|
|
14
|
+
* Positional arguments come first (in order), named arguments follow.
|
|
15
|
+
*/
|
|
16
|
+
export declare function argumentSpecsToSchema(specs: ArgumentSpec[]): VgiSchema;
|
|
17
|
+
/**
|
|
18
|
+
* Build a macro `arguments_schema` describing macro parameters.
|
|
19
|
+
*
|
|
20
|
+
* Mirrors the function `arguments_schema` mechanism: one Arrow field per macro
|
|
21
|
+
* parameter, in `parameters` order, each nullable. The per-parameter
|
|
22
|
+
* description is carried via the same `vgi_doc` field-metadata key functions use
|
|
23
|
+
* (UTF-8, presence-only — the key is omitted entirely when there is no doc). A
|
|
24
|
+
* parameter's field type is the type of its default value when one is known
|
|
25
|
+
* (decoded from `parameterDefaultValues`, a one-row RecordBatch serialized as
|
|
26
|
+
* IPC bytes), else `nullType()`.
|
|
27
|
+
*
|
|
28
|
+
* @param parameters Ordered list of macro parameter names.
|
|
29
|
+
* @param parameterDefaultValues Optional one-row RecordBatch (IPC bytes) whose
|
|
30
|
+
* columns are parameter names with typed default values; used to infer each
|
|
31
|
+
* parameter's field type.
|
|
32
|
+
* @param parameterDocs Optional mapping of parameter name to description. Empty
|
|
33
|
+
* or missing descriptions yield no `vgi_doc` metadata on the field.
|
|
34
|
+
* @returns Arrow schema with one nullable field per parameter, in order.
|
|
35
|
+
*/
|
|
36
|
+
export declare function macroArgumentsSchema(parameters: string[], parameterDefaultValues?: Uint8Array | null, parameterDocs?: Record<string, string>): VgiSchema;
|
|
37
|
+
/**
|
|
38
|
+
* Extract per-parameter descriptions from a macro `arguments_schema`.
|
|
39
|
+
*
|
|
40
|
+
* Inverse of {@link macroArgumentsSchema}'s `vgi_doc` handling: reads the
|
|
41
|
+
* `vgi_doc` field metadata (UTF-8) for each field. Fields without the key
|
|
42
|
+
* (undocumented) are omitted from the result.
|
|
43
|
+
*
|
|
44
|
+
* @param schema A macro `arguments_schema` (one field per parameter).
|
|
45
|
+
* @returns Mapping of parameter name to description, for documented parameters only.
|
|
46
|
+
*/
|
|
47
|
+
export declare function macroParameterDocsFromSchema(schema: VgiSchema): Record<string, string>;
|
|
48
|
+
/**
|
|
49
|
+
* Convert an Arrow Schema back to ArgumentSpecs.
|
|
50
|
+
*/
|
|
51
|
+
export declare function schemaToArgumentSpecs(schema: VgiSchema): ArgumentSpec[];
|