@query-farm/vgi 0.7.0 → 0.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@query-farm/vgi",
3
- "version": "0.7.0",
3
+ "version": "0.8.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)",
@@ -2,6 +2,7 @@
2
2
  // Declarative catalog descriptor types.
3
3
 
4
4
  import type { VgiSchema, VgiDataType } from "../arrow/index.js";
5
+ import type { AttachCatalogInfo } from "./interface.js";
5
6
  import type { VgiFunction } from "../functions/types.js";
6
7
  import type { Arguments } from "../arguments/arguments.js";
7
8
  import type { ColumnStatistics } from "../util/statistics.js";
@@ -152,6 +153,11 @@ export interface CatalogDescriptor {
152
153
  schemas: SchemaDescriptor[];
153
154
  settings?: SettingDescriptor[];
154
155
  secretTypes?: SecretTypeDescriptor[];
156
+ /**
157
+ * Companion catalogs (lakehouse federation) the client should ATTACH when this
158
+ * VGI catalog attaches. Surfaced via `catalog_attach.attach_catalogs`.
159
+ */
160
+ attachCatalogs?: AttachCatalogInfo[];
155
161
  comment?: string;
156
162
  tags?: Record<string, string>;
157
163
  /**
@@ -74,7 +74,10 @@ export { encodeIndexInfo, decodeIndexInfo } from "../generated/vgi-client.js";
74
74
  // generic ASD codec with the generated schema. Mirrors vgi-python's
75
75
  // catalog_interface.CopyFromFormatInfo.
76
76
  import { encodeASD } from "../codec/asd.js";
77
- import { CopyFromFormatInfoSchema } from "../generated/vgi-protocol-schemas.js";
77
+ import {
78
+ AttachCatalogInfoSchema,
79
+ CopyFromFormatInfoSchema,
80
+ } from "../generated/vgi-protocol-schemas.js";
78
81
 
79
82
  export interface CopyFromFormatInfo {
80
83
  /** Free-text comment (CopyFromFunction's `copyFromComment`). */
@@ -117,6 +120,42 @@ export const encodeCopyFromFormatInfo = (v: CopyFromFormatInfo): Uint8Array =>
117
120
  ordered: v.ordered ?? false,
118
121
  });
119
122
 
123
+ /**
124
+ * A companion catalog the client should ATTACH when this VGI catalog attaches
125
+ * (lakehouse federation). Serialized into `CatalogAttachResult.attach_catalogs`;
126
+ * the C++ VGI extension attaches each at VGI-attach time so multi-branch
127
+ * catalog-table branches can resolve tables in a companion DuckLake / Iceberg /
128
+ * Postgres / DuckDB.
129
+ */
130
+ export interface AttachCatalogInfo {
131
+ /** ATTACH alias; also a catalog-table ScanBranch's `sourceCatalog`. */
132
+ alias: string;
133
+ /** ATTACH target — a path or DSN (e.g. `ducklake:sqlite:/data/meta.sqlite`). */
134
+ target: string;
135
+ /** DuckDB db type; empty => inferred from the target scheme prefix. */
136
+ db_type?: string;
137
+ /** Extra ATTACH options forwarded verbatim (e.g. DuckLake DATA_PATH). */
138
+ options?: Record<string, string>;
139
+ /** Attach hidden (excluded from duckdb_databases()); still resolvable. */
140
+ hidden?: boolean;
141
+ /** When true, attach failure fails the whole VGI ATTACH. */
142
+ required?: boolean;
143
+ /** Optional named secret to inject into the companion's ATTACH options. */
144
+ secret_ref?: string;
145
+ }
146
+
147
+ /** Encode an AttachCatalogInfo to Arrow IPC bytes (single-row batch). */
148
+ export const encodeAttachCatalogInfo = (v: AttachCatalogInfo): Uint8Array =>
149
+ encodeASD(AttachCatalogInfoSchema, {
150
+ alias: v.alias,
151
+ target: v.target,
152
+ db_type: v.db_type ?? "",
153
+ options: v.options ?? {},
154
+ hidden: v.hidden ?? false,
155
+ required: v.required ?? false,
156
+ secret_ref: v.secret_ref ?? "",
157
+ });
158
+
120
159
  // ============================================================================
121
160
  // ScanFunctionResult — typed result for catalog_table_scan_function_get.
122
161
  // Mirrors vgi-python's ScanFunctionResult (catalog_interface.py:380).
@@ -204,6 +243,9 @@ export function singleBranchResult(
204
243
  arguments: [toUint8Array(legacy.arguments)],
205
244
  branch_filter: [null],
206
245
  writable: [false],
246
+ source_catalog: [null],
247
+ source_schema: [null],
248
+ source_table: [null],
207
249
  },
208
250
  ScanBranchSchema as any,
209
251
  );
@@ -233,6 +275,15 @@ export interface ScanBranchInput {
233
275
  branchFilter?: string | null;
234
276
  /** Declares this branch as the INSERT target (at most one per table). */
235
277
  writable?: boolean;
278
+ /**
279
+ * Catalog-table branch (lakehouse federation): leave `functionName` empty and
280
+ * set these to scan the base table
281
+ * `sourceCatalog.sourceSchema.sourceTable` in a companion catalog instead of
282
+ * calling a table function.
283
+ */
284
+ sourceCatalog?: string | null;
285
+ sourceSchema?: string | null;
286
+ sourceTable?: string | null;
236
287
  }
237
288
 
238
289
  /**
@@ -284,6 +335,9 @@ export function buildScanBranchesResult(
284
335
  arguments: [serializeBranchArguments(branch)],
285
336
  branch_filter: [branch.branchFilter ?? null],
286
337
  writable: [branch.writable ?? false],
338
+ source_catalog: [branch.sourceCatalog ?? null],
339
+ source_schema: [branch.sourceSchema ?? null],
340
+ source_table: [branch.sourceTable ?? null],
287
341
  },
288
342
  ScanBranchSchema as any,
289
343
  );
@@ -16,6 +16,7 @@ import {
16
16
  type IndexInfo,
17
17
  type IndexConstraintType,
18
18
  type CopyFromFormatInfo,
19
+ encodeAttachCatalogInfo,
19
20
  } from "./interface.js";
20
21
  import type { CatalogDescriptor, SchemaDescriptor, TableDescriptor, ViewDescriptor, MacroDescriptor, SettingDescriptor, SecretTypeDescriptor, ForeignKeyDef, DefaultValue } from "./descriptors.js";
21
22
  import { serializeColumnStatistics } from "../util/statistics.js";
@@ -80,6 +81,10 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
80
81
  serializeSecretType(s)
81
82
  );
82
83
 
84
+ const attachCatalogs = (this._descriptor.attachCatalogs ?? []).map((c) =>
85
+ encodeAttachCatalogInfo(c)
86
+ );
87
+
83
88
  // Auto-derive supportsTimeTravel from table descriptors
84
89
  const hasTimeTravel = this._descriptor.schemas.some(
85
90
  (s) => s.tables?.some((t) => t.supportsTimeTravel) ?? false
@@ -95,6 +100,7 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
95
100
  default_schema: this._descriptor.defaultSchema ?? "main",
96
101
  settings,
97
102
  secret_types: secretTypes,
103
+ attach_catalogs: attachCatalogs,
98
104
  comment: this._descriptor.comment ?? null,
99
105
  tags: this._descriptor.tags ?? {},
100
106
  // Advertise true so DuckDB routes catalog_table_column_statistics_get
@@ -621,6 +621,9 @@ export class VgiClient {
621
621
  secret_types: inner.secret_types
622
622
  ? (Array.isArray(inner.secret_types) ? inner.secret_types : [...inner.secret_types]).map(toUint8Array)
623
623
  : [],
624
+ attach_catalogs: inner.attach_catalogs
625
+ ? (Array.isArray(inner.attach_catalogs) ? inner.attach_catalogs : [...inner.attach_catalogs]).map(toUint8Array)
626
+ : [],
624
627
  comment: inner.comment ?? null,
625
628
  tags: deserializeTags(inner.tags),
626
629
  supports_column_statistics: inner.supports_column_statistics ?? false,
@@ -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: 101207be9452
5
+ // Content hash: 5ddab596625f
6
6
  //
7
7
  // To regenerate:
8
8
  // uv run --project ~/Development/vgi-python vgi-gen-ts-client \
@@ -366,6 +366,7 @@ export interface CatalogAttachResult {
366
366
  default_schema: string;
367
367
  settings: Uint8Array[];
368
368
  secret_types: Uint8Array[];
369
+ attach_catalogs: Uint8Array[];
369
370
  comment?: string | null;
370
371
  tags: Record<string, string>;
371
372
  supports_column_statistics: boolean;
@@ -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: d028e7cb81cd
5
+ // Content hash: 673bfdc9573a
6
6
  //
7
7
  // To regenerate:
8
8
  // uv run --project ~/Development/vgi-python vgi-gen-ts-schemas \
@@ -175,6 +175,20 @@ export const ScanBranchSchema = schema([
175
175
  field("arguments", binary(), false),
176
176
  field("branch_filter", utf8(), true),
177
177
  field("writable", bool(), false),
178
+ field("source_catalog", utf8(), true),
179
+ field("source_schema", utf8(), true),
180
+ field("source_table", utf8(), true),
181
+ ]);
182
+
183
+ // Origin: AttachCatalogInfo
184
+ export const AttachCatalogInfoSchema = schema([
185
+ field("alias", utf8(), false),
186
+ field("target", utf8(), false),
187
+ field("db_type", utf8(), false),
188
+ field("options", map(field("key", utf8(), false), field("value", utf8(), true), false), false),
189
+ field("hidden", bool(), false),
190
+ field("required", bool(), false),
191
+ field("secret_ref", utf8(), false),
178
192
  ]);
179
193
 
180
194
  // Origin: method 'aggregate_bind' result
@@ -246,6 +260,7 @@ export const CatalogAttachResultSchema = schema([
246
260
  field("default_schema", utf8(), false),
247
261
  field("settings", list(field("item", binary(), true)), false),
248
262
  field("secret_types", list(field("item", binary(), true)), false),
263
+ field("attach_catalogs", list(field("item", binary(), true)), false),
249
264
  field("comment", utf8(), true),
250
265
  field("tags", map(field("key", utf8(), false), field("value", utf8(), true), false), false),
251
266
  field("supports_column_statistics", bool(), false),
@@ -100,6 +100,7 @@ export function registerCatalogAdminMethods(protocol: Protocol, getCatalog: GetC
100
100
  default_schema: result.default_schema ?? "main",
101
101
  settings: result.settings ?? [],
102
102
  secret_types: result.secret_types ?? [],
103
+ attach_catalogs: result.attach_catalogs ?? [],
103
104
  comment: result.comment ?? null,
104
105
  tags: result.tags ?? {},
105
106
  // True so DuckDB will route catalog_table_column_statistics_get RPCs