@query-farm/vgi 0.23.0 → 0.24.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/dist/catalog/descriptors.d.ts +18 -0
- package/dist/catalog/read-only.d.ts +20 -0
- package/dist/client-entry.js +5 -1
- package/dist/client-entry.js.map +5 -5
- package/dist/generated/vgi-client.d.ts +2 -0
- package/dist/index.js +79 -51
- package/dist/index.js.map +7 -7
- package/dist/serve-entry.js +5 -1
- package/dist/serve-entry.js.map +5 -5
- package/dist/worker-cf-entry.js +77 -52
- package/dist/worker-cf-entry.js.map +6 -6
- package/package.json +3 -3
- package/src/catalog/descriptors.ts +18 -0
- package/src/catalog/read-only.ts +51 -2
- package/src/client/client.ts +4 -0
- package/src/generated/vgi-client.ts +3 -1
- package/src/generated/vgi-protocol-schemas.ts +3 -1
- package/src/protocol/handlers/catalog/admin.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@query-farm/vgi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "TypeScript framework for extending DuckDB with user-defined functions via the Vector Gateway Interface (VGI) over Arrow IPC.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Query Farm LLC (https://query.farm)",
|
|
@@ -87,12 +87,12 @@
|
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"@query-farm/apache-arrow": "^21.1.1",
|
|
90
|
-
"@query-farm/vgi-rpc": "^0.
|
|
90
|
+
"@query-farm/vgi-rpc": "^0.17.0"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@duckdb/node-api": "^1.5.2-r.1",
|
|
94
94
|
"@query-farm/apache-arrow": "^21.1.1",
|
|
95
|
-
"@query-farm/vgi-rpc": "^0.
|
|
95
|
+
"@query-farm/vgi-rpc": "^0.17.0",
|
|
96
96
|
"@types/bun": "latest",
|
|
97
97
|
"typescript": "^6.0.3"
|
|
98
98
|
},
|
|
@@ -173,4 +173,22 @@ export interface CatalogDescriptor {
|
|
|
173
173
|
* advertises a null `source_url`.
|
|
174
174
|
*/
|
|
175
175
|
sourceUrl?: string;
|
|
176
|
+
/**
|
|
177
|
+
* Functions this catalog asks the client to *additionally* publish into its
|
|
178
|
+
* global (DuckDB `system.main`) function namespace, on top of the normal
|
|
179
|
+
* schema-qualified registration. Surfaced as IPC-serialized `FunctionInfo`
|
|
180
|
+
* records on `catalog_attach.global_functions`.
|
|
181
|
+
*
|
|
182
|
+
* Every entry must also be declared in exactly one of this catalog's
|
|
183
|
+
* schemas — the `FunctionInfo.schema_name` it carries is the bind-dispatch
|
|
184
|
+
* key, not a sentinel. Mirrors vgi-python's `Catalog.global_functions`.
|
|
185
|
+
*/
|
|
186
|
+
globalFunctions?: VgiFunction[];
|
|
187
|
+
/**
|
|
188
|
+
* Prefix applied client-side to every `globalFunctions` entry's name when it
|
|
189
|
+
* is published globally (e.g. prefix `vgi_example` + `global_scalar` →
|
|
190
|
+
* `vgi_example_global_scalar`). The advertised `FunctionInfo.name` stays
|
|
191
|
+
* unprefixed. Surfaced as `catalog_attach.global_function_prefix`.
|
|
192
|
+
*/
|
|
193
|
+
globalFunctionPrefix?: string;
|
|
176
194
|
}
|
package/src/catalog/read-only.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type IndexConstraintType,
|
|
18
18
|
type CopyFromFormatInfo,
|
|
19
19
|
encodeAttachCatalogInfo,
|
|
20
|
+
encodeFunctionInfo,
|
|
20
21
|
} from "./interface.js";
|
|
21
22
|
import type { CatalogDescriptor, SchemaDescriptor, TableDescriptor, ViewDescriptor, MacroDescriptor, SettingDescriptor, SecretTypeDescriptor, ForeignKeyDef, DefaultValue } from "./descriptors.js";
|
|
22
23
|
import { serializeColumnStatistics } from "../util/statistics.js";
|
|
@@ -119,6 +120,11 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
119
120
|
// Advertise true so DuckDB routes catalog_table_column_statistics_get
|
|
120
121
|
// for tables whose TableInfo.supports_column_statistics is also true.
|
|
121
122
|
supports_column_statistics: true,
|
|
123
|
+
// Functions the client should ALSO publish into its global (system.main)
|
|
124
|
+
// namespace, under `global_function_prefix` + "_" + name. Empty unless
|
|
125
|
+
// the descriptor opts in via `globalFunctions`.
|
|
126
|
+
global_functions: this._globalFunctionInfos().map(encodeFunctionInfo),
|
|
127
|
+
global_function_prefix: this._descriptor.globalFunctionPrefix ?? "",
|
|
122
128
|
resolved_data_version: null,
|
|
123
129
|
resolved_implementation_version: null,
|
|
124
130
|
};
|
|
@@ -374,7 +380,18 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
374
380
|
if (t === "AGGREGATE_FUNCTION") return (f.kind as string) === "aggregate";
|
|
375
381
|
return true;
|
|
376
382
|
})
|
|
377
|
-
.map((f) =>
|
|
383
|
+
.map((f) => this._functionToInfo(f, name));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Build the wire `FunctionInfo` for one declared function.
|
|
388
|
+
*
|
|
389
|
+
* `schemaName` is the schema the function actually lives in — it is the
|
|
390
|
+
* bind-dispatch key, so a function advertised through more than one route
|
|
391
|
+
* (schema contents *and* `global_functions`) must carry the same value in
|
|
392
|
+
* both. Shared by `schemaContentsFunctions` and `_globalFunctionInfos`.
|
|
393
|
+
*/
|
|
394
|
+
private _functionToInfo(f: VgiFunction, name: string): FunctionInfo {
|
|
378
395
|
const meta = resolveMetadata(f);
|
|
379
396
|
const argSchema = argumentSpecsToSchema(f.argumentSpecs);
|
|
380
397
|
const argBytes = serializeSchema(argSchema);
|
|
@@ -474,7 +491,39 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
474
491
|
secret_name: s.secret_name,
|
|
475
492
|
})),
|
|
476
493
|
};
|
|
477
|
-
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Build `FunctionInfo` records for `CatalogDescriptor.globalFunctions`.
|
|
498
|
+
*
|
|
499
|
+
* Each entry's `schema_name` is the schema it actually lives in — the
|
|
500
|
+
* globally visible name is derived client-side from
|
|
501
|
+
* `global_function_prefix`, so `name` stays unprefixed here. An entry not
|
|
502
|
+
* declared in any schema is a descriptor bug, so it throws rather than
|
|
503
|
+
* advertising a function no bind can resolve. Mirrors vgi-python's
|
|
504
|
+
* `_global_function_infos`.
|
|
505
|
+
*/
|
|
506
|
+
private _globalFunctionInfos(): FunctionInfo[] {
|
|
507
|
+
const globals = this._descriptor.globalFunctions ?? [];
|
|
508
|
+
if (globals.length === 0) return [];
|
|
509
|
+
|
|
510
|
+
const schemaOf = new Map<VgiFunction, string>();
|
|
511
|
+
for (const sch of this._descriptor.schemas) {
|
|
512
|
+
for (const fn of sch.functions ?? []) {
|
|
513
|
+
if (!schemaOf.has(fn)) schemaOf.set(fn, sch.name);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return globals.map((fn) => {
|
|
518
|
+
const schemaName = schemaOf.get(fn);
|
|
519
|
+
if (schemaName === undefined) {
|
|
520
|
+
throw new Error(
|
|
521
|
+
`Catalog '${this._descriptor.name}': '${fn.meta.name}' is listed in ` +
|
|
522
|
+
`globalFunctions but is not declared in any schema.`,
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
return this._functionToInfo(fn, schemaName);
|
|
526
|
+
});
|
|
478
527
|
}
|
|
479
528
|
|
|
480
529
|
override schemaContentsMacros(
|
package/src/client/client.ts
CHANGED
|
@@ -628,6 +628,10 @@ export class VgiClient {
|
|
|
628
628
|
comment: inner.comment ?? null,
|
|
629
629
|
tags: deserializeTags(inner.tags),
|
|
630
630
|
supports_column_statistics: inner.supports_column_statistics ?? false,
|
|
631
|
+
global_functions: inner.global_functions
|
|
632
|
+
? (Array.isArray(inner.global_functions) ? inner.global_functions : [...inner.global_functions]).map(toUint8Array)
|
|
633
|
+
: [],
|
|
634
|
+
global_function_prefix: inner.global_function_prefix ?? "",
|
|
631
635
|
resolved_data_version: inner.resolved_data_version ?? null,
|
|
632
636
|
resolved_implementation_version: inner.resolved_implementation_version ?? null,
|
|
633
637
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// GENERATED by vgi.codegen.ts_client. DO NOT EDIT BY HAND.
|
|
3
3
|
//
|
|
4
4
|
// Generator: vgi-gen-ts-client v1
|
|
5
|
-
// Content hash:
|
|
5
|
+
// Content hash: e0862da99312
|
|
6
6
|
//
|
|
7
7
|
// To regenerate:
|
|
8
8
|
// uv run --project ~/Development/vgi-python vgi-gen-ts-client \
|
|
@@ -384,6 +384,8 @@ export interface CatalogAttachResult {
|
|
|
384
384
|
comment?: string | null;
|
|
385
385
|
tags: Record<string, string>;
|
|
386
386
|
supports_column_statistics: boolean;
|
|
387
|
+
global_functions: Uint8Array[];
|
|
388
|
+
global_function_prefix: string;
|
|
387
389
|
resolved_data_version?: string | null;
|
|
388
390
|
resolved_implementation_version?: string | null;
|
|
389
391
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// GENERATED by vgi.codegen.ts_schemas. DO NOT EDIT BY HAND.
|
|
3
3
|
//
|
|
4
4
|
// Generator: vgi-gen-ts-schemas v2
|
|
5
|
-
// Content hash:
|
|
5
|
+
// Content hash: ae533ce2196c
|
|
6
6
|
//
|
|
7
7
|
// To regenerate:
|
|
8
8
|
// uv run --project ~/Development/vgi-python vgi-gen-ts-schemas \
|
|
@@ -265,6 +265,8 @@ export const CatalogAttachResultSchema = schema([
|
|
|
265
265
|
field("comment", utf8(), true),
|
|
266
266
|
field("tags", map(field("key", utf8(), false), field("value", utf8(), true), false), false),
|
|
267
267
|
field("supports_column_statistics", bool(), false),
|
|
268
|
+
field("global_functions", list(field("item", binary(), true)), false),
|
|
269
|
+
field("global_function_prefix", utf8(), false),
|
|
268
270
|
field("resolved_data_version", utf8(), true),
|
|
269
271
|
field("resolved_implementation_version", utf8(), true),
|
|
270
272
|
]);
|
|
@@ -108,6 +108,12 @@ export function registerCatalogAdminMethods(protocol: Protocol, getCatalog: GetC
|
|
|
108
108
|
// is also true. Catalogs that never serve column stats can override
|
|
109
109
|
// this in attach() via CatalogAttachResult.supports_column_statistics.
|
|
110
110
|
supports_column_statistics: result.supports_column_statistics ?? true,
|
|
111
|
+
// Protocol 1.3.0: functions the worker asks the client to publish into
|
|
112
|
+
// its global namespace. Empty unless the catalog advertises them —
|
|
113
|
+
// but the columns must still be present, since the extension pins the
|
|
114
|
+
// full CatalogAttachResult field list on the response schema.
|
|
115
|
+
global_functions: result.global_functions ?? [],
|
|
116
|
+
global_function_prefix: result.global_function_prefix ?? "",
|
|
111
117
|
resolved_data_version: result.resolved_data_version ?? null,
|
|
112
118
|
resolved_implementation_version: result.resolved_implementation_version ?? null,
|
|
113
119
|
}, CatalogAttachResultSchema);
|