@query-farm/vgi 0.17.0 → 0.18.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 +13 -7
- package/dist/client-entry.js +2 -2
- package/dist/client-entry.js.map +4 -4
- package/dist/generated/vgi-client.d.ts +1 -1
- package/dist/index.js +16 -11
- package/dist/index.js.map +5 -5
- package/dist/serve-entry.js +2 -2
- package/dist/serve-entry.js.map +4 -4
- package/dist/worker-cf-entry.js +16 -11
- package/dist/worker-cf-entry.js.map +5 -5
- package/package.json +1 -1
- package/src/catalog/descriptors.ts +13 -7
- package/src/catalog/read-only.ts +22 -14
- package/src/generated/vgi-client.ts +2 -2
- package/src/generated/vgi-protocol-schemas.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@query-farm/vgi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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)",
|
|
@@ -60,18 +60,24 @@ export interface TableDescriptor {
|
|
|
60
60
|
*/
|
|
61
61
|
statisticsCacheMaxAgeSeconds?: number | null;
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
63
|
+
* Required WHERE-filter groups in conjunctive normal form — an AND (outer
|
|
64
|
+
* list) of OR-groups (inner lists) of dotted-path column references that MUST
|
|
65
|
+
* appear in a WHERE expression for any scan of this table. A group is
|
|
66
|
+
* satisfied when any one of its paths has a filter; every group must be
|
|
67
|
+
* satisfied. So `[["accession_number"], ["ticker", "cik"]]` means
|
|
68
|
+
* "accession_number AND one of (ticker, cik)"; a single-path group
|
|
69
|
+
* `[["country"]]` is a plain mandatory filter. Paths are top-level names
|
|
70
|
+
* (`"country"`) or struct subfields (`"bbox.xmin"`, `"nested.outer.inner"`).
|
|
71
|
+
* Empty/undefined (default) means no enforcement — the zero-cost fast path
|
|
72
|
+
* for every existing table.
|
|
67
73
|
*
|
|
68
74
|
* Satisfaction is prefix-based: a present filter on a shorter path satisfies
|
|
69
75
|
* any required path it is a prefix of. So a whole-struct filter on `bbox`
|
|
70
76
|
* satisfies all of `bbox.xmin` / `.xmax` / `.ymin` / `.ymax`. The VGI DuckDB
|
|
71
|
-
* extension's optimizer pass consults this
|
|
72
|
-
* `BinderException` listing any unsatisfied
|
|
77
|
+
* extension's optimizer pass consults this at bind time and throws a
|
|
78
|
+
* `BinderException` listing any unsatisfied groups.
|
|
73
79
|
*/
|
|
74
|
-
|
|
80
|
+
requiredFilters?: string[][];
|
|
75
81
|
supportsTimeTravel?: boolean;
|
|
76
82
|
/**
|
|
77
83
|
* Inline cardinality estimate/max surfaced through TableInfo. When set,
|
package/src/catalog/read-only.ts
CHANGED
|
@@ -235,26 +235,34 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
235
235
|
const pkIndices = resolveIndexGroups(colSchema, t.primaryKey);
|
|
236
236
|
const fkBytes = serializeForeignKeys(t.foreignKey, name);
|
|
237
237
|
|
|
238
|
-
// Validate
|
|
239
|
-
//
|
|
238
|
+
// Validate required_filters: an AND (outer list) of OR-groups (inner
|
|
239
|
+
// lists). Each OR-group must be non-empty, and the leading dotted segment
|
|
240
|
+
// of each path must be a real column on this table. Struct subfield
|
|
240
241
|
// validity is not checked here — DuckDB's binder catches typos at scan
|
|
241
242
|
// time, and the descriptor doesn't unpack STRUCT subfields. (Mirrors
|
|
242
243
|
// vgi-python's Table descriptor validation.)
|
|
243
|
-
const
|
|
244
|
-
if (
|
|
244
|
+
const requiredFilters = t.requiredFilters ?? [];
|
|
245
|
+
if (requiredFilters.length > 0) {
|
|
245
246
|
const columnNames = new Set(colSchema.fields.map((f) => f.name));
|
|
246
|
-
for (const
|
|
247
|
-
if (!
|
|
247
|
+
for (const group of requiredFilters) {
|
|
248
|
+
if (!group || group.length === 0) {
|
|
248
249
|
throw new Error(
|
|
249
|
-
`Table '${t.name}':
|
|
250
|
+
`Table '${t.name}': requiredFilters must not contain empty groups`
|
|
250
251
|
);
|
|
251
252
|
}
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
253
|
+
for (const path of group) {
|
|
254
|
+
if (!path) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
`Table '${t.name}': requiredFilters must not contain empty strings`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
const head = path.split(".", 1)[0];
|
|
260
|
+
if (!columnNames.has(head)) {
|
|
261
|
+
throw new Error(
|
|
262
|
+
`Table '${t.name}': requiredFilters path '${path}' references ` +
|
|
263
|
+
`unknown column '${head}'. Available columns: ${[...columnNames].sort().join(", ")}`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
258
266
|
}
|
|
259
267
|
}
|
|
260
268
|
}
|
|
@@ -292,7 +300,7 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
292
300
|
cardinality_max: t.inlinedCardinality
|
|
293
301
|
? Number(t.inlinedCardinality.max)
|
|
294
302
|
: null,
|
|
295
|
-
|
|
303
|
+
required_filters: requiredFilters,
|
|
296
304
|
};
|
|
297
305
|
}));
|
|
298
306
|
}
|
|
@@ -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: f3ac87321a0c
|
|
6
6
|
//
|
|
7
7
|
// To regenerate:
|
|
8
8
|
// uv run --project ~/Development/vgi-python vgi-gen-ts-client \
|
|
@@ -84,7 +84,7 @@ export interface TableInfo {
|
|
|
84
84
|
cardinality_max?: number | null;
|
|
85
85
|
column_statistics?: Uint8Array | null;
|
|
86
86
|
bind_result?: Uint8Array | null;
|
|
87
|
-
|
|
87
|
+
required_filters: string[][];
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export interface ViewInfo {
|
|
@@ -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: b3c99cc5fac8
|
|
6
6
|
//
|
|
7
7
|
// To regenerate:
|
|
8
8
|
// uv run --project ~/Development/vgi-python vgi-gen-ts-schemas \
|
|
@@ -70,7 +70,7 @@ export const TableInfoSchema = schema([
|
|
|
70
70
|
field("cardinality_max", int64(), false),
|
|
71
71
|
field("column_statistics", binary(), false),
|
|
72
72
|
field("bind_result", binary(), false),
|
|
73
|
-
field("
|
|
73
|
+
field("required_filters", list(field("item", list(field("item", utf8(), true)), true)), false),
|
|
74
74
|
]);
|
|
75
75
|
|
|
76
76
|
// Origin: ViewInfo
|