@query-farm/vgi 0.24.1 → 0.25.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/attach-option.d.ts +40 -0
- package/dist/catalog/read-only.d.ts +11 -0
- package/dist/client-entry.d.ts +2 -0
- package/dist/client-entry.js +76 -1
- package/dist/client-entry.js.map +5 -4
- package/dist/http/fetch.d.ts +5 -5
- package/dist/index.core.d.ts +2 -2
- package/dist/index.js +84 -442
- package/dist/index.js.map +6 -7
- package/dist/serve-entry.js +7 -446
- package/dist/serve-entry.js.map +5 -7
- package/dist/worker-cf-entry.d.ts +1 -2
- package/dist/worker-cf-entry.js +55 -440
- package/dist/worker-cf-entry.js.map +7 -8
- package/package.json +3 -3
- package/src/catalog/attach-option.ts +128 -0
- package/src/catalog/read-only.ts +20 -0
- package/src/client-entry.ts +11 -0
- package/src/http/fetch.ts +6 -6
- package/src/index.core.ts +6 -13
- package/src/serve-entry.ts +2 -7
- package/src/worker-cf-entry.ts +4 -4
- package/dist/http/describe-json.d.ts +0 -62
- package/src/http/describe-json.ts +0 -644
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@query-farm/vgi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.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)",
|
|
@@ -90,12 +90,12 @@
|
|
|
90
90
|
},
|
|
91
91
|
"peerDependencies": {
|
|
92
92
|
"@query-farm/apache-arrow": "^21.1.1",
|
|
93
|
-
"@query-farm/vgi-rpc": ">=0.
|
|
93
|
+
"@query-farm/vgi-rpc": ">=0.19.0 <0.20.0"
|
|
94
94
|
},
|
|
95
95
|
"devDependencies": {
|
|
96
96
|
"@duckdb/node-api": "^1.5.2-r.1",
|
|
97
97
|
"@query-farm/apache-arrow": "^21.1.1",
|
|
98
|
-
"@query-farm/vgi-rpc": "^0.
|
|
98
|
+
"@query-farm/vgi-rpc": "^0.19.0",
|
|
99
99
|
"@types/bun": "latest",
|
|
100
100
|
"typescript": "^6.0.3"
|
|
101
101
|
},
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
// default_value: Binary nullable -- serialized single-row RecordBatch with
|
|
18
18
|
// the default value under "value", or
|
|
19
19
|
// null when no default is declared
|
|
20
|
+
// required: Bool nullable -- the caller must supply this option at ATTACH
|
|
21
|
+
// time. Nullable and appended LAST so a peer
|
|
22
|
+
// that predates the column reads the batch by
|
|
23
|
+
// name and simply doesn't see it; absent and
|
|
24
|
+
// explicit-null both mean "not required".
|
|
20
25
|
//
|
|
21
26
|
// The extension reads the outer `attach_option_specs: list<binary>` column
|
|
22
27
|
// from CatalogInfo and validates user-supplied ATTACH options against the
|
|
@@ -28,10 +33,15 @@ import {
|
|
|
28
33
|
field,
|
|
29
34
|
utf8,
|
|
30
35
|
binary,
|
|
36
|
+
bool,
|
|
31
37
|
batchFromColumns,
|
|
38
|
+
iterRows,
|
|
32
39
|
serializeBatch,
|
|
40
|
+
deserializeBatch,
|
|
33
41
|
serializeSchema,
|
|
42
|
+
deserializeSchema,
|
|
34
43
|
} from "../arrow/index.js";
|
|
44
|
+
import { toUint8Array } from "../util/bytes.js";
|
|
35
45
|
|
|
36
46
|
/**
|
|
37
47
|
* Declarative spec for a single attach-time option.
|
|
@@ -55,6 +65,16 @@ export interface AttachOptionSpec {
|
|
|
55
65
|
* the options dict delivered to attach()).
|
|
56
66
|
*/
|
|
57
67
|
default?: unknown;
|
|
68
|
+
/**
|
|
69
|
+
* The caller must supply this option at ATTACH time. A catalog that cannot
|
|
70
|
+
* be attached without it advertises that fact at discovery, so a client can
|
|
71
|
+
* say so before attempting the attach rather than surfacing a failure that
|
|
72
|
+
* reads like an empty catalog.
|
|
73
|
+
*
|
|
74
|
+
* Mutually exclusive with `default` — an option that falls back to a value
|
|
75
|
+
* is by definition satisfiable without the caller.
|
|
76
|
+
*/
|
|
77
|
+
required?: boolean;
|
|
58
78
|
}
|
|
59
79
|
|
|
60
80
|
const SPEC_SCHEMA = makeSchema([
|
|
@@ -62,6 +82,7 @@ const SPEC_SCHEMA = makeSchema([
|
|
|
62
82
|
field("description", utf8(), false),
|
|
63
83
|
field("type", binary(), false),
|
|
64
84
|
field("default_value", binary(), true),
|
|
85
|
+
field("required", bool(), true),
|
|
65
86
|
]);
|
|
66
87
|
|
|
67
88
|
/**
|
|
@@ -69,6 +90,17 @@ const SPEC_SCHEMA = makeSchema([
|
|
|
69
90
|
* (one IPC-serialized RecordBatch with a single row).
|
|
70
91
|
*/
|
|
71
92
|
export function serializeAttachOptionSpec(spec: AttachOptionSpec): Uint8Array {
|
|
93
|
+
// Mirrors AttachOptionSpec.__post_init__ on the Python side: an option that
|
|
94
|
+
// falls back to a value is always satisfiable without the caller, so the
|
|
95
|
+
// combination is a declaration bug rather than a runtime condition.
|
|
96
|
+
if (spec.required && spec.default !== undefined && spec.default !== null) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Attach option '${spec.name}' is required but also declares a default ` +
|
|
99
|
+
`(${JSON.stringify(spec.default)}); an option with a default is always ` +
|
|
100
|
+
"satisfiable without the caller. Drop one.",
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
72
104
|
// `type` is encoded as a serialized Arrow Schema with one field named
|
|
73
105
|
// "value" of the option's DataType. This lets the extension peek at the
|
|
74
106
|
// logical type without a separate enum.
|
|
@@ -91,6 +123,9 @@ export function serializeAttachOptionSpec(spec: AttachOptionSpec): Uint8Array {
|
|
|
91
123
|
description: [spec.description],
|
|
92
124
|
type: [typeBytes],
|
|
93
125
|
default_value: [defaultBytes],
|
|
126
|
+
// Written explicitly rather than left null so a reader sees `false`, not
|
|
127
|
+
// NULL, for an option that simply isn't required.
|
|
128
|
+
required: [spec.required ?? false],
|
|
94
129
|
},
|
|
95
130
|
SPEC_SCHEMA,
|
|
96
131
|
);
|
|
@@ -105,3 +140,96 @@ export function serializeAttachOptionSpecs(
|
|
|
105
140
|
): Uint8Array[] {
|
|
106
141
|
return Array.from(specs, serializeAttachOptionSpec);
|
|
107
142
|
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Deserialize one AttachOptionSpec from the wire format above.
|
|
146
|
+
*
|
|
147
|
+
* Reads by column name, so a spec written by a peer that predates the
|
|
148
|
+
* `required` column deserializes with `required: false` rather than failing —
|
|
149
|
+
* the same tolerance the Python and C++ readers have.
|
|
150
|
+
*/
|
|
151
|
+
export function deserializeAttachOptionSpec(
|
|
152
|
+
bytes: Uint8Array,
|
|
153
|
+
): AttachOptionSpec {
|
|
154
|
+
const row = [...iterRows(deserializeBatch(bytes))][0] as
|
|
155
|
+
| Record<string, unknown>
|
|
156
|
+
| undefined;
|
|
157
|
+
if (row === undefined) {
|
|
158
|
+
throw new Error("Cannot deserialize AttachOptionSpec from an empty batch");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// `type` is a serialized Arrow Schema whose single "value" field carries the
|
|
162
|
+
// option's DataType.
|
|
163
|
+
const typeSchema = deserializeSchema(toUint8Array(row.type as Uint8Array));
|
|
164
|
+
const type = typeSchema.fields[0]!.type;
|
|
165
|
+
|
|
166
|
+
let value: unknown;
|
|
167
|
+
const defaultBytes = row.default_value;
|
|
168
|
+
if (defaultBytes != null) {
|
|
169
|
+
const asBytes = toUint8Array(defaultBytes as Uint8Array);
|
|
170
|
+
if (asBytes.length > 0) {
|
|
171
|
+
const defaultRow = [...iterRows(deserializeBatch(asBytes))][0] as
|
|
172
|
+
| Record<string, unknown>
|
|
173
|
+
| undefined;
|
|
174
|
+
value = defaultRow?.value;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
name: String(row.name),
|
|
180
|
+
description: String(row.description ?? ""),
|
|
181
|
+
type,
|
|
182
|
+
...(value === undefined || value === null ? {} : { default: value }),
|
|
183
|
+
required: row.required === true,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Deserialize many specs — the shape `CatalogInfo.attach_option_specs` holds. */
|
|
188
|
+
export function deserializeAttachOptionSpecs(
|
|
189
|
+
specs: Iterable<Uint8Array>,
|
|
190
|
+
): AttachOptionSpec[] {
|
|
191
|
+
return Array.from(specs, deserializeAttachOptionSpec);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Raised when `attach` omits options declared `required`.
|
|
196
|
+
*
|
|
197
|
+
* Carries the option names in `missing` so a caller can act on them without
|
|
198
|
+
* parsing the message. Mirrors `MissingAttachOptionsError` on the Python side,
|
|
199
|
+
* message included — the extension's integration suite matches on its text.
|
|
200
|
+
*/
|
|
201
|
+
export class MissingAttachOptionsError extends Error {
|
|
202
|
+
readonly missing: string[];
|
|
203
|
+
|
|
204
|
+
constructor(catalogName: string, missing: string[]) {
|
|
205
|
+
const joined = missing.map((name) => `'${name}'`).join(", ");
|
|
206
|
+
super(
|
|
207
|
+
`Catalog '${catalogName}' cannot be attached without the required ` +
|
|
208
|
+
`option${missing.length > 1 ? "s" : ""} ${joined}.`,
|
|
209
|
+
);
|
|
210
|
+
this.name = "MissingAttachOptionsError";
|
|
211
|
+
this.missing = missing;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Throw if any `required` spec has no corresponding entry in `options`.
|
|
217
|
+
*
|
|
218
|
+
* Option names are matched case-insensitively, mirroring DuckDB's handling of
|
|
219
|
+
* ATTACH option keys.
|
|
220
|
+
*
|
|
221
|
+
* @throws {MissingAttachOptionsError} If a required option was not supplied.
|
|
222
|
+
*/
|
|
223
|
+
export function validateRequiredAttachOptions(
|
|
224
|
+
catalogName: string,
|
|
225
|
+
specs: Iterable<AttachOptionSpec>,
|
|
226
|
+
options: Record<string, unknown>,
|
|
227
|
+
): void {
|
|
228
|
+
const supplied = new Set(Object.keys(options).map((key) => key.toLowerCase()));
|
|
229
|
+
const missing = Array.from(specs)
|
|
230
|
+
.filter((spec) => spec.required && !supplied.has(spec.name.toLowerCase()))
|
|
231
|
+
.map((spec) => spec.name);
|
|
232
|
+
if (missing.length > 0) {
|
|
233
|
+
throw new MissingAttachOptionsError(catalogName, missing);
|
|
234
|
+
}
|
|
235
|
+
}
|
package/src/catalog/read-only.ts
CHANGED
|
@@ -26,6 +26,7 @@ import type { FunctionRegistry } from "../functions/registry.js";
|
|
|
26
26
|
import { argumentSpecsToSchema, macroArgumentsSchema } from "../arguments/argument-spec.js";
|
|
27
27
|
import { serializeSchema, serializeBatch, emptyBatch, batchFromColumns } from "../util/arrow/index.js";
|
|
28
28
|
import { resolveMetadata } from "../metadata/resolve.js";
|
|
29
|
+
import { type AttachOptionSpec, validateRequiredAttachOptions } from "./attach-option.js";
|
|
29
30
|
import { FunctionStability, NullHandling, OrderPreservation, DEFAULT_MAX_WORKERS } from "../types.js";
|
|
30
31
|
import { Arguments } from "../arguments/arguments.js";
|
|
31
32
|
|
|
@@ -58,6 +59,19 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
58
59
|
return [this._descriptor.name];
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Attach-time options this catalog declares, for the named catalog.
|
|
64
|
+
*
|
|
65
|
+
* Empty by default — the declarative descriptor path carries no attach
|
|
66
|
+
* options. A subclass that advertises specs in `catalogsInfo()` should
|
|
67
|
+
* return the same specs here so `attach()` enforces the `required` ones it
|
|
68
|
+
* advertised. Takes the catalog name because one interface may serve
|
|
69
|
+
* several catalogs with different option sets.
|
|
70
|
+
*/
|
|
71
|
+
attachOptionSpecs(_name: string): AttachOptionSpec[] {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
|
|
61
75
|
// Advertise the catalog's discovery record. The declarative path carries no
|
|
62
76
|
// version metadata or attach option specs, but it does surface the optional
|
|
63
77
|
// `source_url` from the descriptor so it flows through `catalog_catalogs`
|
|
@@ -82,6 +96,12 @@ export class ReadOnlyCatalogInterface extends CatalogInterface {
|
|
|
82
96
|
if (!this.catalogs().includes(name)) {
|
|
83
97
|
throw new Error(`No worker handles catalog '${name}'`);
|
|
84
98
|
}
|
|
99
|
+
// Refuse an attach that omits a declared-required option, so the caller
|
|
100
|
+
// gets the option name rather than a catalog that looks mysteriously
|
|
101
|
+
// empty. A subclass that overrides `attach` outright bypasses this and
|
|
102
|
+
// should call `validateRequiredAttachOptions` itself — mirrors
|
|
103
|
+
// CatalogInterface.catalog_attach on the Python side.
|
|
104
|
+
validateRequiredAttachOptions(name, this.attachOptionSpecs(name), options ?? {});
|
|
85
105
|
|
|
86
106
|
const attachOpaqueData = new Uint8Array(16);
|
|
87
107
|
crypto.getRandomValues(attachOpaqueData);
|
package/src/client-entry.ts
CHANGED
|
@@ -103,6 +103,17 @@ export {
|
|
|
103
103
|
deserializeBatch,
|
|
104
104
|
} from "./util/arrow/index.js";
|
|
105
105
|
|
|
106
|
+
// Arrow type identification — lets a consumer render a DataType for display
|
|
107
|
+
// without reaching into the backend implementation.
|
|
108
|
+
export { TypeId, typeSignature } from "./arrow/predicates.js";
|
|
109
|
+
|
|
110
|
+
// Attach options — the page-facing decoder for CatalogInfo.attach_option_specs.
|
|
111
|
+
export {
|
|
112
|
+
type AttachOptionSpec,
|
|
113
|
+
deserializeAttachOptionSpec,
|
|
114
|
+
deserializeAttachOptionSpecs,
|
|
115
|
+
} from "./catalog/attach-option.js";
|
|
116
|
+
|
|
106
117
|
// Byte utilities
|
|
107
118
|
export { toUint8Array } from "./util/bytes.js";
|
|
108
119
|
|
package/src/http/fetch.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { createHttpHandler, unpackStateToken, type Protocol } from "@query-farm/vgi-rpc";
|
|
14
14
|
import { arrowStateSerializer } from "../protocol/state-serializer.js";
|
|
15
15
|
import { buildVgiProtocol, type ProtocolConfig } from "../protocol/dispatch.js";
|
|
16
|
-
import type {
|
|
16
|
+
import type { LandingInfo } from "@query-farm/vgi-rpc";
|
|
17
17
|
|
|
18
18
|
export interface VgiFetchOptions {
|
|
19
19
|
/** Wire-protocol config (registry + catalogInterface). */
|
|
@@ -36,10 +36,10 @@ export interface VgiFetchOptions {
|
|
|
36
36
|
/** Public source-repository URL, surfaced on the landing page. */
|
|
37
37
|
repositoryUrl?: string;
|
|
38
38
|
/** Enables the standardized VGI landing surface: `GET /` serves the shared
|
|
39
|
-
* landing.html
|
|
40
|
-
* `GET /
|
|
41
|
-
*
|
|
42
|
-
|
|
39
|
+
* landing.html plus a JSON status document carrying this identity, and
|
|
40
|
+
* `GET /vgi-client.js` serves the browser client build the page reads the
|
|
41
|
+
* catalog with. */
|
|
42
|
+
landingInfo?: LandingInfo;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -74,7 +74,7 @@ export function createVgiFetch(opts: VgiFetchOptions): (req: Request) => Promise
|
|
|
74
74
|
stateSerializer: arrowStateSerializer,
|
|
75
75
|
corsOrigins: opts.corsOrigins,
|
|
76
76
|
repositoryUrl: opts.repositoryUrl,
|
|
77
|
-
|
|
77
|
+
landingInfo: opts.landingInfo,
|
|
78
78
|
});
|
|
79
79
|
return async (req: Request) => handler(req);
|
|
80
80
|
}
|
package/src/index.core.ts
CHANGED
|
@@ -153,25 +153,18 @@ export { arrowStateSerializer, EXCHANGE_STATE_SCHEMA, serializeUserState, deseri
|
|
|
153
153
|
// Protocol assembly (for embedding the worker dispatcher in a custom HTTP server).
|
|
154
154
|
export { buildVgiProtocol, type ProtocolConfig } from "./protocol/dispatch.js";
|
|
155
155
|
|
|
156
|
-
// VGI HTTP landing surface
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
buildDescribeJson,
|
|
162
|
-
createLandingDescribe,
|
|
163
|
-
CUPOLA_BASE,
|
|
164
|
-
LANDING_SCHEMA_VERSION,
|
|
165
|
-
type LandingDescribeProvider,
|
|
166
|
-
type WorkerDescribeInfo,
|
|
167
|
-
} from "./http/describe-json.js";
|
|
156
|
+
// VGI HTTP landing surface. The shared landing.html reads catalog metadata by
|
|
157
|
+
// speaking the protocol through the client bundle the worker serves beside it,
|
|
158
|
+
// so a worker supplies only its own identity via `createHttpHandler`'s
|
|
159
|
+
// `landingInfo` option.
|
|
160
|
+
export type { LandingInfo } from "@query-farm/vgi-rpc";
|
|
168
161
|
|
|
169
162
|
// Wire schemas — needed by workers that synthesize TableInfo.bind_result /
|
|
170
163
|
// TableInfo.scan_function bytes to short-circuit per-scan RPCs.
|
|
171
164
|
export { BindResultSchema, ScanFunctionResultSchema } from "./generated/vgi-protocol-schemas.js";
|
|
172
165
|
|
|
173
166
|
// Attach-option specs (for catalogs that advertise typed ATTACH options).
|
|
174
|
-
export { type AttachOptionSpec, serializeAttachOptionSpec, serializeAttachOptionSpecs } from "./catalog/attach-option.js";
|
|
167
|
+
export { type AttachOptionSpec, serializeAttachOptionSpec, serializeAttachOptionSpecs, deserializeAttachOptionSpec, deserializeAttachOptionSpecs } from "./catalog/attach-option.js";
|
|
175
168
|
|
|
176
169
|
// Column statistics (for inlining on TableInfo.column_statistics).
|
|
177
170
|
export { type ColumnStatistics, serializeColumnStatistics } from "./util/statistics.js";
|
package/src/serve-entry.ts
CHANGED
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
|
|
24
24
|
import type { CatalogInterface } from "./catalog/interface.js";
|
|
25
25
|
import type { FunctionRegistry } from "./functions/registry.js";
|
|
26
|
-
import { createLandingDescribe } from "./http/describe-json.js";
|
|
27
26
|
import { createVgiFetch } from "./http/fetch.js";
|
|
28
27
|
|
|
29
28
|
/** Environment variables `serveVgiWorker` reads. Injectable for testing. */
|
|
@@ -192,11 +191,7 @@ export function createVgiWorkerFetch(
|
|
|
192
191
|
serverId: opts.serverId ?? opts.name,
|
|
193
192
|
corsOrigins,
|
|
194
193
|
repositoryUrl: opts.repositoryUrl,
|
|
195
|
-
|
|
196
|
-
name: opts.name,
|
|
197
|
-
doc: opts.doc,
|
|
198
|
-
version: opts.version,
|
|
199
|
-
}),
|
|
194
|
+
landingInfo: { name: opts.name, doc: opts.doc, version: opts.version },
|
|
200
195
|
});
|
|
201
196
|
}
|
|
202
197
|
|
|
@@ -225,7 +220,7 @@ export function serveVgiWorker(opts: ServeVgiWorkerOptions): VgiHttpServer {
|
|
|
225
220
|
const base = `http://localhost:${server.port}`;
|
|
226
221
|
console.log(`${opts.name} VGI HTTP worker listening on ${base}`);
|
|
227
222
|
console.log(` landing page ${base}/`);
|
|
228
|
-
console.log(`
|
|
223
|
+
console.log(` client bundle ${base}/vgi-client.js`);
|
|
229
224
|
console.log(` health ${base}/health`);
|
|
230
225
|
console.log(` attach ATTACH '${opts.name}' AS ${opts.name} (TYPE vgi, LOCATION '${base}');`);
|
|
231
226
|
}
|
package/src/worker-cf-entry.ts
CHANGED
|
@@ -53,10 +53,10 @@ export type {
|
|
|
53
53
|
|
|
54
54
|
export type { ProtocolConfig } from "./protocol/dispatch.js";
|
|
55
55
|
|
|
56
|
-
// Landing surface. CF workers pass
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
export type {
|
|
56
|
+
// Landing surface. CF workers pass their identity as `landingInfo` so `GET /`
|
|
57
|
+
// serves the standardized VGI landing page, and `GET /vgi-client.js` the
|
|
58
|
+
// browser client build it reads the catalog with.
|
|
59
|
+
export type { LandingInfo } from "@query-farm/vgi-rpc";
|
|
60
60
|
|
|
61
61
|
// Backend-agnostic Arrow facade. Same source resolves to arrow-js on
|
|
62
62
|
// Node/Bun and flechette under workerd/worker/browser via the package's
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { CatalogInterface } from "../catalog/interface.js";
|
|
2
|
-
export declare const LANDING_SCHEMA_VERSION = 1;
|
|
3
|
-
export declare const CUPOLA_BASE = "https://cupola.query-farm.services";
|
|
4
|
-
/**
|
|
5
|
-
* Producer for the VGI landing surface, passed to `createHttpHandler`'s
|
|
6
|
-
* `landingDescribe` option. Declared locally (structurally identical to
|
|
7
|
-
* `@query-farm/vgi-rpc`'s `LandingDescribeProvider`) so this package does not
|
|
8
|
-
* hard-couple to a specific vgi-rpc version.
|
|
9
|
-
*/
|
|
10
|
-
export interface LandingDescribeProvider {
|
|
11
|
-
describe(ctx: {
|
|
12
|
-
serverId: string;
|
|
13
|
-
oauth: boolean;
|
|
14
|
-
}): unknown | Promise<unknown>;
|
|
15
|
-
columns(catalog: string, schema: string, table: string): unknown | null | Promise<unknown | null>;
|
|
16
|
-
}
|
|
17
|
-
/** Identity of the worker software surfaced in `describe.json` → `worker`. */
|
|
18
|
-
export interface WorkerDescribeInfo {
|
|
19
|
-
/** Worker name (e.g. class or catalog name). */
|
|
20
|
-
name: string;
|
|
21
|
-
/** One-line worker description. */
|
|
22
|
-
doc?: string;
|
|
23
|
-
/** Worker software version. */
|
|
24
|
-
version?: string;
|
|
25
|
-
}
|
|
26
|
-
interface ColumnJson {
|
|
27
|
-
name: string;
|
|
28
|
-
type: string;
|
|
29
|
-
comment?: string;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Build the full `describe.json` document for a worker's catalog interface.
|
|
33
|
-
*
|
|
34
|
-
* `oauth` and `serverId` are supplied by the HTTP server (they depend on runtime
|
|
35
|
-
* config, not the catalog).
|
|
36
|
-
*/
|
|
37
|
-
export declare function buildDescribeJson(iface: CatalogInterface, worker: WorkerDescribeInfo, opts?: {
|
|
38
|
-
oauth?: boolean;
|
|
39
|
-
serverId?: string;
|
|
40
|
-
cupolaBase?: string;
|
|
41
|
-
}): Promise<Record<string, unknown>>;
|
|
42
|
-
/**
|
|
43
|
-
* Build the lazy per-object column payload for one table or view.
|
|
44
|
-
*
|
|
45
|
-
* Returns `{ columns: [{ name, type, comment? }] }`, or `null` when the object
|
|
46
|
-
* can't be found. Tables deserialize their Arrow column schema; views expose
|
|
47
|
-
* their declared column comments (types are only known after binding the SQL,
|
|
48
|
-
* which the worker does not do here).
|
|
49
|
-
*/
|
|
50
|
-
export declare function buildColumnsJson(iface: CatalogInterface, catalog: string, schema: string, table: string): Promise<{
|
|
51
|
-
columns: ColumnJson[];
|
|
52
|
-
} | null>;
|
|
53
|
-
/**
|
|
54
|
-
* Build a {@link LandingDescribeProvider} to pass to `createHttpHandler` from
|
|
55
|
-
* `@query-farm/vgi-rpc`. Wires the worker's catalog interface into the
|
|
56
|
-
* standardized landing surface (`GET {prefix}/describe.json` and the lazy
|
|
57
|
-
* per-object column endpoint).
|
|
58
|
-
*/
|
|
59
|
-
export declare function createLandingDescribe(iface: CatalogInterface, worker: WorkerDescribeInfo, opts?: {
|
|
60
|
-
cupolaBase?: string;
|
|
61
|
-
}): LandingDescribeProvider;
|
|
62
|
-
export {};
|