@query-farm/vgi 0.21.0 → 0.22.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.
@@ -2935,7 +2935,8 @@ var BIND_REQUEST_SCHEMA = schema2([
2935
2935
  field2("transaction_opaque_data", binary2(), true),
2936
2936
  field2("resolved_secrets_provided", bool2(), false),
2937
2937
  field2("at_unit", utf82(), true),
2938
- field2("at_value", utf82(), true)
2938
+ field2("at_value", utf82(), true),
2939
+ field2("schema_name", utf82(), true)
2939
2940
  ]);
2940
2941
  var COPY_FROM_STRUCT_TYPE = struct2([
2941
2942
  field2("format", utf82(), false),
@@ -3003,6 +3004,7 @@ function deserializeBindRequest(params) {
3003
3004
  resolved_secrets_provided: params.resolved_secrets_provided ?? false,
3004
3005
  at_unit: params.at_unit ? String(params.at_unit) : null,
3005
3006
  at_value: params.at_value ? String(params.at_value) : null,
3007
+ schema_name: params.schema_name ? String(params.schema_name) : null,
3006
3008
  copy_from: parseCopyFromContext(params.copy_from),
3007
3009
  copy_to: parseCopyToContext(params.copy_to)
3008
3010
  };
@@ -3833,11 +3835,21 @@ function wrapResult(values, innerSchema) {
3833
3835
  const batch = batchFromColumns(Object.fromEntries(a.fields.map((f) => [f.name, [values[f.name] ?? null]])), a);
3834
3836
  return { result: serializeBatch(batch) };
3835
3837
  }
3836
- function overloadContext(req) {
3838
+ function overloadContext(req, catalogInterface) {
3839
+ let catalogName = null;
3840
+ if (catalogInterface && req.attach_opaque_data) {
3841
+ try {
3842
+ catalogName = catalogInterface.catalogNameForAttach(req.attach_opaque_data);
3843
+ } catch {
3844
+ catalogName = null;
3845
+ }
3846
+ }
3837
3847
  return {
3838
3848
  arguments: req.arguments,
3839
3849
  inputSchema: req.input_schema,
3840
- isScalar: String(req.function_type).toLowerCase() === "scalar"
3850
+ isScalar: String(req.function_type).toLowerCase() === "scalar",
3851
+ schemaName: req.schema_name ?? null,
3852
+ catalogName
3841
3853
  };
3842
3854
  }
3843
3855
  function recoverFinalizeState(request, recoverExchangeState) {
@@ -4852,7 +4864,7 @@ var columnOpParams = schema2([
4852
4864
 
4853
4865
  // src/protocol/handlers/function.ts
4854
4866
  function registerFunctionMethods(protocol, config) {
4855
- const { registry, signingKey } = config;
4867
+ const { registry, signingKey, catalogInterface } = config;
4856
4868
  async function stripAttach(attach, ctx) {
4857
4869
  if (attach == null)
4858
4870
  return null;
@@ -4861,6 +4873,15 @@ function registerFunctionMethods(protocol, config) {
4861
4873
  return env;
4862
4874
  return openAttach(env, ctx?.auth, signingKey);
4863
4875
  }
4876
+ async function strippedContext(bindCall, ctx) {
4877
+ let attach = null;
4878
+ try {
4879
+ attach = await stripAttach(bindCall.attach_opaque_data, ctx);
4880
+ } catch {
4881
+ attach = null;
4882
+ }
4883
+ return overloadContext({ ...bindCall, attach_opaque_data: attach }, catalogInterface);
4884
+ }
4864
4885
  const initHeaderSchema = schema2([
4865
4886
  field2("execution_id", binary2(), false),
4866
4887
  field2("opaque_data", binary2(), true),
@@ -4877,7 +4898,7 @@ function registerFunctionMethods(protocol, config) {
4877
4898
  const innerParams = unwrapRequest(params.request);
4878
4899
  const request = deserializeBindRequest(innerParams);
4879
4900
  request.attach_opaque_data = await stripAttach(request.attach_opaque_data, ctx);
4880
- const func = registry.get(request.function_name, overloadContext(request));
4901
+ const func = registry.get(request.function_name, overloadContext(request, catalogInterface));
4881
4902
  const response = await func.bind(request);
4882
4903
  const serialized = serializeBindResponse(response);
4883
4904
  return wrapResult(serialized, BindResultSchema);
@@ -4892,7 +4913,7 @@ function registerFunctionMethods(protocol, config) {
4892
4913
  const innerParams = unwrapRequest(params.request);
4893
4914
  const request = deserializeInitRequest(innerParams);
4894
4915
  request.bind_call.attach_opaque_data = await stripAttach(request.bind_call.attach_opaque_data, undefined);
4895
- const func = registry.get(request.bind_call.function_name, overloadContext(request.bind_call));
4916
+ const func = registry.get(request.bind_call.function_name, overloadContext(request.bind_call, catalogInterface));
4896
4917
  const initResponse = await func.globalInit(request);
4897
4918
  const accumulatedState = recoverFinalizeState(request, config.recoverExchangeState);
4898
4919
  const handlers = func.createStreamHandlers(request, initResponse, accumulatedState);
@@ -4932,7 +4953,7 @@ function registerFunctionMethods(protocol, config) {
4932
4953
  const initRequestBatch = deserializeBatch(state.initRequestIpc);
4933
4954
  const initRequestDict = batchToScalarDict(initRequestBatch);
4934
4955
  const request = deserializeInitRequest(initRequestDict);
4935
- const func = registry.get(state.functionName, overloadContext(request.bind_call));
4956
+ const func = registry.get(state.functionName, await strippedContext(request.bind_call));
4936
4957
  const executionId = state.executionId;
4937
4958
  const opaqueData = state.opaqueData ?? null;
4938
4959
  const initResponse = {
@@ -4980,7 +5001,7 @@ function registerFunctionMethods(protocol, config) {
4980
5001
  handler: async (params) => {
4981
5002
  const innerParams = unwrapRequest(params.request);
4982
5003
  const request = deserializeCardinalityRequest(innerParams);
4983
- const func = registry.get(request.bind_call.function_name, overloadContext(request.bind_call));
5004
+ const func = registry.get(request.bind_call.function_name, await strippedContext(request.bind_call));
4984
5005
  let cardResult;
4985
5006
  if (func.cardinality) {
4986
5007
  cardResult = serializeTableCardinality(await func.cardinality(request));
@@ -4993,10 +5014,10 @@ function registerFunctionMethods(protocol, config) {
4993
5014
  protocol.unary("table_function_statistics", {
4994
5015
  params: REQUEST_PARAMS_SCHEMA,
4995
5016
  result: RESULT_BINARY_NULLABLE_SCHEMA,
4996
- handler: (params) => {
5017
+ handler: async (params) => {
4997
5018
  const innerParams = unwrapRequest(params.request);
4998
5019
  const request = deserializeCardinalityRequest(innerParams);
4999
- const func = registry.get(request.bind_call.function_name, overloadContext(request.bind_call));
5020
+ const func = registry.get(request.bind_call.function_name, await strippedContext(request.bind_call));
5000
5021
  if (!func.statistics)
5001
5022
  return { result: null };
5002
5023
  const stats = func.statistics(request);
@@ -5016,7 +5037,7 @@ function registerFunctionMethods(protocol, config) {
5016
5037
  const bindCall = deserializeBindRequest(bindParams);
5017
5038
  const globalExecutionId = toUint8Array(innerParams.global_execution_id);
5018
5039
  const bindOpaqueData = innerParams.bind_opaque_data ? toUint8Array(innerParams.bind_opaque_data) : null;
5019
- const func = registry.get(bindCall.function_name, overloadContext(bindCall));
5040
+ const func = registry.get(bindCall.function_name, await strippedContext(bindCall));
5020
5041
  const map3 = func.dynamicToString ? await func.dynamicToString({ bindCall, bindOpaqueData, globalExecutionId }) : {};
5021
5042
  const keys = Object.keys(map3);
5022
5043
  const values = keys.map((k) => map3[k] ?? "");
@@ -6497,6 +6518,10 @@ function isPromise(v) {
6497
6518
  }
6498
6519
 
6499
6520
  class CatalogInterface {
6521
+ catalogNameForAttach(_attachOpaqueData) {
6522
+ const names = this.catalogs();
6523
+ return names.length === 1 ? names[0] : null;
6524
+ }
6500
6525
  create(name, onConflict, options) {
6501
6526
  throw new CatalogReadOnlyError("create");
6502
6527
  }
@@ -7231,7 +7256,8 @@ function buildVgiProtocol(config) {
7231
7256
  registerFunctionMethods(protocol, {
7232
7257
  registry: config.registry,
7233
7258
  recoverExchangeState: config.recoverExchangeState,
7234
- signingKey: config.signingKey
7259
+ signingKey: config.signingKey,
7260
+ catalogInterface: config.catalogInterface
7235
7261
  });
7236
7262
  registerAggregateMethods(protocol, config.registry);
7237
7263
  registerTableBufferingMethods(protocol, config.registry, config.signingKey);
@@ -7280,6 +7306,7 @@ var CACHE_STALE_WHILE_REVALIDATE_KEY = "vgi.cache.stale_while_revalidate";
7280
7306
  var CACHE_STALE_IF_ERROR_KEY = "vgi.cache.stale_if_error";
7281
7307
  var CACHE_NOT_MODIFIED_KEY = "vgi.cache.not_modified";
7282
7308
  var CACHE_PARTITION_SCOPE_KEY = "vgi.cache.partition_scope";
7309
+ var CACHE_PER_VALUE_KEY = "vgi.cache.per_value";
7283
7310
  var CACHE_IF_NONE_MATCH_KEY = "vgi.cache.if_none_match";
7284
7311
  var CACHE_IF_MODIFIED_SINCE_KEY = "vgi.cache.if_modified_since";
7285
7312
  var CACHE_SCOPE_CATALOG = "catalog";
@@ -7318,6 +7345,8 @@ function cacheControlMetadata(cc, extra) {
7318
7345
  md.set(CACHE_NOT_MODIFIED_KEY, "1");
7319
7346
  if (cc.partitionScope)
7320
7347
  md.set(CACHE_PARTITION_SCOPE_KEY, "1");
7348
+ if (cc.perValue)
7349
+ md.set(CACHE_PER_VALUE_KEY, "1");
7321
7350
  return md;
7322
7351
  }
7323
7352
 
@@ -8088,6 +8117,17 @@ class ReadOnlyCatalogInterface extends CatalogInterface {
8088
8117
  super();
8089
8118
  this._descriptor = descriptor;
8090
8119
  this._registry = registry;
8120
+ for (const sch of descriptor.schemas ?? []) {
8121
+ for (const fn of sch.functions ?? [])
8122
+ registry.registerInSchema(fn, sch.name, descriptor.name);
8123
+ for (const tbl of sch.tables ?? []) {
8124
+ for (const key of ["function", "insertFunction", "updateFunction", "deleteFunction"]) {
8125
+ const fn = tbl[key];
8126
+ if (fn)
8127
+ registry.registerInSchema(fn, sch.name, descriptor.name);
8128
+ }
8129
+ }
8130
+ }
8091
8131
  }
8092
8132
  catalogs() {
8093
8133
  return [this._descriptor.name];
@@ -8710,6 +8750,13 @@ class CompositeCatalogInterface extends CatalogInterface {
8710
8750
  }
8711
8751
  return route;
8712
8752
  }
8753
+ catalogNameForAttach(attachOpaqueData) {
8754
+ try {
8755
+ return this._route(attachOpaqueData).catalogNameForAttach(attachOpaqueData);
8756
+ } catch {
8757
+ return null;
8758
+ }
8759
+ }
8713
8760
  catalogs() {
8714
8761
  const all = [];
8715
8762
  for (const b of this._backends)
@@ -8938,9 +8985,17 @@ function filterByArgumentTypes(candidates, args, inputSchema, isScalar) {
8938
8985
  const maxScore = Math.max(...scored.map((s) => s.score));
8939
8986
  return scored.filter((s) => s.score === maxScore).map((s) => s.func);
8940
8987
  }
8988
+ function schemaKey(schemaName, functionName) {
8989
+ return `${schemaName.toLowerCase()}\x00${functionName}`;
8990
+ }
8991
+ function catalogKey(catalogName, schemaName, functionName) {
8992
+ return `${catalogName.toLowerCase()}\x00${schemaKey(schemaName, functionName)}`;
8993
+ }
8941
8994
 
8942
8995
  class FunctionRegistry {
8943
8996
  _functions = new Map;
8997
+ _bySchema = new Map;
8998
+ _byCatalog = new Map;
8944
8999
  register(func) {
8945
9000
  const name = func.meta.name;
8946
9001
  if (!this._functions.has(name)) {
@@ -8948,11 +9003,57 @@ class FunctionRegistry {
8948
9003
  }
8949
9004
  this._functions.get(name).push(func);
8950
9005
  }
9006
+ registerInSchema(func, schemaName, catalogName) {
9007
+ const add = (map3, key) => {
9008
+ const bucket = map3.get(key);
9009
+ if (!bucket) {
9010
+ map3.set(key, [func]);
9011
+ return;
9012
+ }
9013
+ if (!bucket.includes(func))
9014
+ bucket.push(func);
9015
+ };
9016
+ add(this._bySchema, schemaKey(schemaName, func.meta.name));
9017
+ if (catalogName) {
9018
+ add(this._byCatalog, catalogKey(catalogName, schemaName, func.meta.name));
9019
+ }
9020
+ }
9021
+ schemasFor(functionName) {
9022
+ const out = [];
9023
+ for (const key of this._bySchema.keys()) {
9024
+ const [schema3, name] = key.split("\x00");
9025
+ if (name === functionName)
9026
+ out.push(schema3);
9027
+ }
9028
+ return out.sort();
9029
+ }
8951
9030
  get(name, context) {
8952
- const candidates = this._functions.get(name);
9031
+ let candidates = this._functions.get(name);
9032
+ const catalogName = context?.catalogName;
9033
+ const schemaName = context?.schemaName;
9034
+ if (catalogName && schemaName) {
9035
+ const scoped = this._byCatalog.get(catalogKey(catalogName, schemaName, name));
9036
+ if (scoped && scoped.length > 0) {
9037
+ return this._disambiguate(name, scoped, context);
9038
+ }
9039
+ }
9040
+ if (schemaName) {
9041
+ const scoped = this._bySchema.get(schemaKey(schemaName, name));
9042
+ if (scoped && scoped.length > 0) {
9043
+ candidates = scoped;
9044
+ } else if (candidates && candidates.length > 0) {
9045
+ const schemas = this.schemasFor(name);
9046
+ if (schemas.length > 0) {
9047
+ throw new Error(`Function '${name}' is not registered in schema '${schemaName}'. ` + `It is available in: [${schemas.join(", ")}]`);
9048
+ }
9049
+ }
9050
+ }
8953
9051
  if (!candidates || candidates.length === 0) {
8954
9052
  throw new FunctionNotFoundError(name, this.names());
8955
9053
  }
9054
+ return this._disambiguate(name, candidates, context);
9055
+ }
9056
+ _disambiguate(name, candidates, context) {
8956
9057
  if (candidates.length === 1) {
8957
9058
  return candidates[0];
8958
9059
  }
@@ -9580,4 +9681,4 @@ export {
9580
9681
  Arguments
9581
9682
  };
9582
9683
 
9583
- //# debugId=702D54392090E98D64756E2164756E21
9684
+ //# debugId=0DAB6D0BDC711A3364756E2164756E21