Skip to content

Commit

Permalink
Add set and range filters to filter validation when using Wrangler CLI (
Browse files Browse the repository at this point in the history
  • Loading branch information
garrettgu10 authored Jan 10, 2025
1 parent c63f1b0 commit f613276
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 33 deletions.
5 changes: 5 additions & 0 deletions .changeset/lemon-years-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": minor
---

New filter validation logic supporting set and range queries in Vectorize CLI
4 changes: 2 additions & 2 deletions packages/wrangler/src/__tests__/vectorize/vectorize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -727,11 +727,11 @@ describe("vectorize commands", () => {
describe("vectorize query filter", () => {
it("should parse correctly", async () => {
let jsonString =
'{ "p1": "abc", "p2": { "$ne": true }, "p3": 10, "p4": false, "nested.p5": "abcd" }'; // Successful parse
'{ "p1": "abc", "p2": { "$ne": true }, "p3": 10, "p4": false, "nested.p5": "abcd", "p6": { "$in": ["a", 3, 4] }, "p7": {"$gt": 4, "$lte": "aaa"} }'; // Successful parse
expect(
JSON.stringify(validateQueryFilter(JSON.parse(jsonString)))
).toMatchInlineSnapshot(
`"{\\"p1\\":\\"abc\\",\\"p2\\":{\\"$ne\\":true},\\"p3\\":10,\\"p4\\":false,\\"nested.p5\\":\\"abcd\\"}"`
`"{\\"p1\\":\\"abc\\",\\"p2\\":{\\"$ne\\":true},\\"p3\\":10,\\"p4\\":false,\\"nested.p5\\":\\"abcd\\",\\"p6\\":{\\"$in\\":[\\"a\\",3,4]},\\"p7\\":{\\"$gt\\":4,\\"$lte\\":\\"aaa\\"}}"`
);

jsonString =
Expand Down
52 changes: 23 additions & 29 deletions packages/wrangler/src/vectorize/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ import type {
} from "../yargs-types";
import type {
VectorizeMatches,
VectorizeMetadataFilterInnerValue,
VectorizeMetadataFilterValue,
VectorizeMetadataRetrievalLevel,
VectorizeQueryOptions,
VectorizeVectorMetadataFilter,
VectorizeVectorMetadataFilterOp,
VectorizeVectorMetadataValue,
} from "./types";

export function options(yargs: CommonYargsArgv) {
Expand Down Expand Up @@ -155,6 +153,12 @@ export async function handler(
logger.log(JSON.stringify(res, null, 2));
}

function validateQueryFilterInnerValue(
innerValue: VectorizeMetadataFilterValue
) {
return ["string", "number", "boolean"].includes(typeof innerValue);
}

export function validateQueryFilter(
input: object
): VectorizeVectorMetadataFilter | null {
Expand All @@ -176,7 +180,7 @@ export function validateQueryFilter(
for (const field in parsedObj) {
if (Object.prototype.hasOwnProperty.call(parsedObj, field)) {
const value = (
parsedObj as Record<string, VectorizeMetadataFilterValue>
parsedObj as Record<string, VectorizeVectorMetadataFilter>
)[field];

if (Array.isArray(value)) {
Expand All @@ -186,38 +190,28 @@ export function validateQueryFilter(

if (typeof value === "object" && value !== null) {
// Handle nested objects
const innerObj: Partial<{
[Op in VectorizeVectorMetadataFilterOp]?: Exclude<
VectorizeVectorMetadataValue,
string[]
> | null;
}> = {};
const innerObj: VectorizeVectorMetadataFilter = {};
let validInnerObj = true;

for (const op in value) {
if (Object.prototype.hasOwnProperty.call(value, op)) {
if (!["$eq", "$ne"].includes(op)) {
// Skip objects with invalid operators
validInnerObj = false;
break;
}
const innerValue = (value as VectorizeMetadataFilterInnerValue)[
op as VectorizeVectorMetadataFilterOp
];
if (Array.isArray(innerValue)) {
// Skip arrays in nested objects
validInnerObj = false;
break;
}
if (
typeof innerValue === "object" &&
innerValue !== null &&
Object.keys(innerValue).length === 0
) {
// Skip empty objects in nested objects
const innerValue = value[op];
if (["$eq", "$ne", "$lt", "$lte", "$gt", "gte"].includes(op)) {
if (!validateQueryFilterInnerValue(innerValue)) {
validInnerObj = false;
}
} else if (["$in", "$nin"].includes(op)) {
if (!Array.isArray(innerValue)) {
validInnerObj = false;
} else {
if (!innerValue.every(validateQueryFilterInnerValue)) {
validInnerObj = false;
}
}
} else {
validInnerObj = false;
break;
}

innerObj[op as VectorizeVectorMetadataFilterOp] = innerValue;
}
}
Expand Down
12 changes: 10 additions & 2 deletions packages/wrangler/src/vectorize/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@ export type VectorFloatArray = Float32Array | Float64Array;
*
* This list is expected to grow as support for more operations are released.
*/
export type VectorizeVectorMetadataFilterOp = "$eq" | "$ne";
export type VectorizeMetadataFilterEqualityOp = "$eq" | "$ne";
export type VectorizeMetadataFilterSetOp = "$in" | "$nin";
export type VectorizeMetadataFilterRangeOp = "$lt" | "$lte" | "$gt" | "$gte";

export type VectorizeVectorMetadataFilterOp =
| VectorizeMetadataFilterEqualityOp
| VectorizeMetadataFilterSetOp
| VectorizeMetadataFilterRangeOp;

export type VectorizeMetadataFilterInnerValue = Record<
VectorizeVectorMetadataFilterOp,
Exclude<VectorizeVectorMetadataValue, string[]>
| Exclude<VectorizeVectorMetadataValue, string[]>
| Exclude<VectorizeVectorMetadataValue, string[]>[]
>;

export type VectorizeMetadataFilterValue =
Expand Down

0 comments on commit f613276

Please sign in to comment.