@query-farm/vgi 0.9.0 → 0.11.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/arguments/argument-spec.d.ts +7 -0
- package/dist/functions/aggregate.d.ts +8 -0
- package/dist/functions/table.d.ts +8 -0
- package/dist/index.js +78 -6
- package/dist/index.js.map +7 -7
- package/dist/worker-cf-entry.js +217 -138
- package/dist/worker-cf-entry.js.map +8 -8
- package/package.json +1 -1
- package/src/arguments/argument-spec.ts +68 -0
- package/src/functions/aggregate.ts +13 -1
- package/src/functions/scalar.ts +31 -2
- package/src/functions/table.ts +17 -1
- package/src/protocol/handlers/aggregate.ts +12 -2
|
@@ -58,6 +58,13 @@ export declare function formatRange(ge?: number, le?: number, gt?: number, lt?:
|
|
|
58
58
|
* no field). Mirrors Python's `_constraint_kwargs`.
|
|
59
59
|
*/
|
|
60
60
|
export declare function constraintSpecFields(constraints: ArgumentConstraints | undefined): Pick<ArgumentSpec, "defaultJson" | "choicesJson" | "rangeNotation" | "pattern">;
|
|
61
|
+
/**
|
|
62
|
+
* Enforce a bind-time const value against its declared {@link ArgumentConstraints},
|
|
63
|
+
* throwing {@link ArgumentValidationError} on violation. Mirrors the Python SDK's
|
|
64
|
+
* `Arg._validate`: numeric range (`ge`/`le`/`gt`/`lt`), closed choice set, and
|
|
65
|
+
* regex `pattern`. A `null`/`undefined` value skips its value constraints.
|
|
66
|
+
*/
|
|
67
|
+
export declare function validateConstConstraints(name: string, constraints: ArgumentConstraints, value: unknown): void;
|
|
61
68
|
/**
|
|
62
69
|
* Convert ArgumentSpecs to an Arrow Schema with VGI metadata keys.
|
|
63
70
|
* Positional arguments come first (in order), named arguments follow.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type VgiSchema, type VgiBatch, type VgiDataType } from "../arrow/index.js";
|
|
2
2
|
import type { Arguments } from "../arguments/arguments.js";
|
|
3
|
+
import { type ArgumentConstraints } from "../arguments/argument-spec.js";
|
|
3
4
|
import type { VgiFunction } from "./types.js";
|
|
4
5
|
import type { FunctionExample } from "./types.js";
|
|
5
6
|
export declare const GROUP_COLUMN_NAME = "__vgi_group_id";
|
|
@@ -70,6 +71,13 @@ export interface AggregateFunctionConfig<TArgs = Record<string, any>, TState = a
|
|
|
70
71
|
onBind?: (params: AggregateBindParams<TArgs>) => VgiDataType | Promise<VgiDataType>;
|
|
71
72
|
/** Optional per-arg default values (positional only here). */
|
|
72
73
|
argDefaults?: Record<string, any>;
|
|
74
|
+
/**
|
|
75
|
+
* Per-argument discovery constraints (choices / ge / le / gt / lt / pattern),
|
|
76
|
+
* keyed by argument name. Surfaced via `vgi_function_arguments()` and enforced
|
|
77
|
+
* at aggregate_bind for const params: a value violating a declared constraint
|
|
78
|
+
* fails the bind with an ArgumentValidationError.
|
|
79
|
+
*/
|
|
80
|
+
argConstraints?: Record<string, ArgumentConstraints>;
|
|
73
81
|
initialState: (params: AggregateBindParams<TArgs>) => TState;
|
|
74
82
|
/**
|
|
75
83
|
* Fold a batch of input rows into the provided per-group state map.
|
|
@@ -2,6 +2,7 @@ import { type VgiSchema, type VgiDataType } from "../arrow/index.js";
|
|
|
2
2
|
import type { OutputCollector } from "@query-farm/vgi-rpc";
|
|
3
3
|
import type { BindRequest, InitRequest, GlobalInitResponse, TableCardinality } from "../protocol/types.js";
|
|
4
4
|
import type { VgiFunction, FunctionExample } from "./types.js";
|
|
5
|
+
import { type ArgumentConstraints } from "../arguments/argument-spec.js";
|
|
5
6
|
import { type PushdownFilters } from "../filter-pushdown/index.js";
|
|
6
7
|
import type { ColumnStatistics } from "../util/statistics.js";
|
|
7
8
|
import { FunctionStability, type NullHandling, type OrderPreservation, type OrderDependence, type DistinctDependence } from "../types.js";
|
|
@@ -41,6 +42,13 @@ export interface TableFunctionConfig<TArgs = Record<string, any>, TState = null>
|
|
|
41
42
|
argDocs?: Record<string, string>;
|
|
42
43
|
/** Argument defaults */
|
|
43
44
|
argDefaults?: Record<string, any>;
|
|
45
|
+
/**
|
|
46
|
+
* Per-argument discovery constraints (choices / ge / le / gt / lt / pattern),
|
|
47
|
+
* keyed by argument name. Surfaced via `vgi_function_arguments()` for agent
|
|
48
|
+
* discovery AND enforced at bind: a value violating a declared constraint
|
|
49
|
+
* fails the bind with an ArgumentValidationError.
|
|
50
|
+
*/
|
|
51
|
+
argConstraints?: Record<string, ArgumentConstraints>;
|
|
44
52
|
/** Names of args that accept variable number of arguments */
|
|
45
53
|
varargs?: string[];
|
|
46
54
|
/** Bind: return output schema. May be async — handlers `await` the result. */
|
package/dist/index.js
CHANGED
|
@@ -2717,6 +2717,55 @@ function constraintSpecFields(constraints) {
|
|
|
2717
2717
|
}
|
|
2718
2718
|
return fields;
|
|
2719
2719
|
}
|
|
2720
|
+
function toNumber(value) {
|
|
2721
|
+
if (typeof value === "number")
|
|
2722
|
+
return value;
|
|
2723
|
+
if (typeof value === "bigint")
|
|
2724
|
+
return Number(value);
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2727
|
+
function choiceEquals(choice, value) {
|
|
2728
|
+
const cn = toNumber(choice);
|
|
2729
|
+
const vn = toNumber(value);
|
|
2730
|
+
if (cn !== undefined && vn !== undefined)
|
|
2731
|
+
return cn === vn;
|
|
2732
|
+
return choice === value;
|
|
2733
|
+
}
|
|
2734
|
+
function validateConstConstraints(name, constraints, value) {
|
|
2735
|
+
if (value === null || value === undefined)
|
|
2736
|
+
return;
|
|
2737
|
+
const num = toNumber(value);
|
|
2738
|
+
if (num !== undefined) {
|
|
2739
|
+
if (constraints.ge !== undefined && num < constraints.ge) {
|
|
2740
|
+
throw new ArgumentValidationError(`argument '${name}' must be >= ${constraints.ge}`);
|
|
2741
|
+
}
|
|
2742
|
+
if (constraints.le !== undefined && num > constraints.le) {
|
|
2743
|
+
throw new ArgumentValidationError(`argument '${name}' must be <= ${constraints.le}`);
|
|
2744
|
+
}
|
|
2745
|
+
if (constraints.gt !== undefined && num <= constraints.gt) {
|
|
2746
|
+
throw new ArgumentValidationError(`argument '${name}' must be > ${constraints.gt}`);
|
|
2747
|
+
}
|
|
2748
|
+
if (constraints.lt !== undefined && num >= constraints.lt) {
|
|
2749
|
+
throw new ArgumentValidationError(`argument '${name}' must be < ${constraints.lt}`);
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
if (constraints.choices !== undefined && constraints.choices.length > 0) {
|
|
2753
|
+
if (!constraints.choices.some((c) => choiceEquals(c, value))) {
|
|
2754
|
+
throw new ArgumentValidationError(`argument '${name}' must be one of ${JSON.stringify([...constraints.choices])}`);
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
if (constraints.pattern !== undefined && typeof value === "string") {
|
|
2758
|
+
let re;
|
|
2759
|
+
try {
|
|
2760
|
+
re = new RegExp(constraints.pattern);
|
|
2761
|
+
} catch {
|
|
2762
|
+
re = undefined;
|
|
2763
|
+
}
|
|
2764
|
+
if (re !== undefined && !re.test(value)) {
|
|
2765
|
+
throw new ArgumentValidationError(`argument '${name}' must match pattern ${JSON.stringify(constraints.pattern)}`);
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2720
2769
|
function argumentSpecSortKey(spec) {
|
|
2721
2770
|
if (typeof spec.position === "number") {
|
|
2722
2771
|
return [0, spec.position];
|
|
@@ -2884,6 +2933,14 @@ function defineScalarFunction(config) {
|
|
|
2884
2933
|
}
|
|
2885
2934
|
}
|
|
2886
2935
|
}
|
|
2936
|
+
const constConstraints = new Map;
|
|
2937
|
+
if (config.parameters) {
|
|
2938
|
+
for (const p of config.parameters) {
|
|
2939
|
+
if (p.const && (p.choices !== undefined || p.ge !== undefined || p.le !== undefined || p.gt !== undefined || p.lt !== undefined || p.pattern !== undefined)) {
|
|
2940
|
+
constConstraints.set(p.name, p);
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2887
2944
|
const meta = {
|
|
2888
2945
|
name: config.name,
|
|
2889
2946
|
description: config.description,
|
|
@@ -2910,7 +2967,11 @@ function defineScalarFunction(config) {
|
|
|
2910
2967
|
let constIdx = 0;
|
|
2911
2968
|
for (const spec of specs) {
|
|
2912
2969
|
if (spec.isConst) {
|
|
2913
|
-
|
|
2970
|
+
const value = request.arguments.get(constIdx, undefined);
|
|
2971
|
+
constArgs[spec.name] = value;
|
|
2972
|
+
const constraints = constConstraints.get(spec.name);
|
|
2973
|
+
if (constraints)
|
|
2974
|
+
validateConstConstraints(spec.name, constraints, value);
|
|
2914
2975
|
constIdx++;
|
|
2915
2976
|
}
|
|
2916
2977
|
}
|
|
@@ -3803,7 +3864,8 @@ function defineTableFunction(config) {
|
|
|
3803
3864
|
arrowType: isAny ? nullType2() : type,
|
|
3804
3865
|
isAnyType: isAny,
|
|
3805
3866
|
isVarargs: varargsSet.has(name),
|
|
3806
|
-
doc: config.argDocs?.[name]
|
|
3867
|
+
doc: config.argDocs?.[name],
|
|
3868
|
+
...constraintSpecFields(config.argConstraints?.[name])
|
|
3807
3869
|
});
|
|
3808
3870
|
}
|
|
3809
3871
|
}
|
|
@@ -3842,6 +3904,9 @@ function defineTableFunction(config) {
|
|
|
3842
3904
|
}
|
|
3843
3905
|
if (typeof val === "bigint")
|
|
3844
3906
|
val = safeNumber(val);
|
|
3907
|
+
const constraints = config.argConstraints?.[spec.name];
|
|
3908
|
+
if (constraints)
|
|
3909
|
+
validateConstConstraints(spec.name, constraints, val);
|
|
3845
3910
|
args[spec.name] = val;
|
|
3846
3911
|
}
|
|
3847
3912
|
return args;
|
|
@@ -4117,7 +4182,8 @@ function defineAggregate(config) {
|
|
|
4117
4182
|
arrowType: isAnyType2 ? nullType2() : type,
|
|
4118
4183
|
isAnyType: isAnyType2,
|
|
4119
4184
|
isVarargs: varargsSet.has(name),
|
|
4120
|
-
isConst
|
|
4185
|
+
isConst,
|
|
4186
|
+
...constraintSpecFields(config.argConstraints?.[name])
|
|
4121
4187
|
});
|
|
4122
4188
|
}
|
|
4123
4189
|
}
|
|
@@ -9079,8 +9145,9 @@ function extractArgMap(cfg, args) {
|
|
|
9079
9145
|
}
|
|
9080
9146
|
}
|
|
9081
9147
|
for (let i = 0;i < constNames.length; i++) {
|
|
9148
|
+
let v;
|
|
9082
9149
|
try {
|
|
9083
|
-
|
|
9150
|
+
v = args.get(i);
|
|
9084
9151
|
const field3 = args.argumentsSchema?.fields.find((f) => f.name === `positional_${i}`);
|
|
9085
9152
|
if (field3 && isDecimal(field3.type)) {
|
|
9086
9153
|
const scale = field3.type.scale;
|
|
@@ -9091,12 +9158,17 @@ function extractArgMap(cfg, args) {
|
|
|
9091
9158
|
} else if (typeof v === "bigint") {
|
|
9092
9159
|
v = Number(v);
|
|
9093
9160
|
}
|
|
9094
|
-
out[constNames[i]] = v;
|
|
9095
9161
|
} catch {
|
|
9096
9162
|
const def = cfg.argDefaults?.[constNames[i]];
|
|
9097
9163
|
if (def !== undefined)
|
|
9098
9164
|
out[constNames[i]] = def;
|
|
9165
|
+
continue;
|
|
9166
|
+
}
|
|
9167
|
+
const constraints = cfg.argConstraints?.[constNames[i]];
|
|
9168
|
+
if (constraints !== undefined) {
|
|
9169
|
+
validateConstConstraints(constNames[i], constraints, v);
|
|
9099
9170
|
}
|
|
9171
|
+
out[constNames[i]] = v;
|
|
9100
9172
|
}
|
|
9101
9173
|
if (cfg.argDefaults) {
|
|
9102
9174
|
for (const [name, def] of Object.entries(cfg.argDefaults)) {
|
|
@@ -10996,4 +11068,4 @@ export {
|
|
|
10996
11068
|
ArgumentValidationError
|
|
10997
11069
|
};
|
|
10998
11070
|
|
|
10999
|
-
//# debugId=
|
|
11071
|
+
//# debugId=606DBE277F7C8D1D64756E2164756E21
|