EventFilter now supports more complex condition filters #271
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/core": patch
|
||||
---
|
||||
|
||||
EventFilter now supports more complex condition filters #271
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EventDispatcher, EventRecord } from "@trigger.dev/database";
|
||||
import type { EventFilter } from "@trigger.dev/core";
|
||||
import { EventFilterSchema } from "@trigger.dev/core";
|
||||
import { EventFilterSchema, eventFilterMatches } from "@trigger.dev/core";
|
||||
import { $transaction, PrismaClientOrTransaction, prisma } from "~/db.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { workerQueue } from "../worker.server";
|
||||
@@ -124,29 +124,6 @@ export class EventMatcher {
|
||||
}
|
||||
|
||||
public matches(filter: EventFilter) {
|
||||
return patternMatches(this.event, filter);
|
||||
return eventFilterMatches(this.event, filter);
|
||||
}
|
||||
}
|
||||
|
||||
function patternMatches(payload: any, pattern: any): boolean {
|
||||
for (const [patternKey, patternValue] of Object.entries(pattern)) {
|
||||
const payloadValue = payload[patternKey];
|
||||
|
||||
if (Array.isArray(patternValue)) {
|
||||
if (patternValue.length > 0 && !patternValue.includes(payloadValue)) {
|
||||
return false;
|
||||
}
|
||||
} else if (typeof patternValue === "object") {
|
||||
if (Array.isArray(payloadValue)) {
|
||||
if (!payloadValue.some((item) => patternMatches(item, patternValue))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!patternMatches(payloadValue, patternValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: ["ts", "tsx", "js"],
|
||||
transform: {
|
||||
"^.+\\.(ts|tsx)$": "ts-jest",
|
||||
},
|
||||
testMatch: ["<rootDir>/test/**/*.ts?(x)", "<rootDir>/test/**/?(*.)+(spec|test).ts?(x)"],
|
||||
testEnvironment: "node",
|
||||
};
|
||||
@@ -22,7 +22,8 @@
|
||||
"clean": "rimraf dist",
|
||||
"build": "npm run clean && npm run build:tsup",
|
||||
"build:tsup": "tsup --dts-resolve",
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"ulid": "^2.3.0",
|
||||
@@ -31,12 +32,15 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trigger.dev/tsconfig": "workspace:*",
|
||||
"@types/jest": "^29.5.3",
|
||||
"@types/node": "16",
|
||||
"jest": "^29.6.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-jest": "^29.1.1",
|
||||
"tsup": "^7.1.0",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.8.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
import { EventFilter } from "./schemas/eventFilter";
|
||||
|
||||
// EventFilter is a recursive type, where the keys are strings and the values are an array of strings, numbers, booleans, or objects.
|
||||
// If the values of the array are strings, numbers, or booleans, than we are matching against the value of the payload.
|
||||
// If the values of the array are objects, then we are doing content filtering
|
||||
// An example would be [{ $endsWith: ".png" }, { $startsWith: "images/" } ]
|
||||
export function eventFilterMatches(payload: any, filter: EventFilter): boolean {
|
||||
for (const [patternKey, patternValue] of Object.entries(filter)) {
|
||||
const payloadValue = payload[patternKey];
|
||||
|
||||
if (Array.isArray(patternValue)) {
|
||||
if (patternValue.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if all the items in the array are a string
|
||||
if ((patternValue as unknown[]).every((item) => typeof item === "string")) {
|
||||
if ((patternValue as string[]).includes(payloadValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if all the items in the array are a number
|
||||
if ((patternValue as unknown[]).every((item) => typeof item === "number")) {
|
||||
if ((patternValue as number[]).includes(payloadValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if all the items in the array are a boolean
|
||||
if ((patternValue as unknown[]).every((item) => typeof item === "boolean")) {
|
||||
if ((patternValue as boolean[]).includes(payloadValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we know that all the items in the array are objects
|
||||
const objectArray = patternValue as Exclude<
|
||||
typeof patternValue,
|
||||
number[] | string[] | boolean[]
|
||||
>;
|
||||
|
||||
if (!contentFiltersMatches(payloadValue, objectArray)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if (typeof patternValue === "object") {
|
||||
if (Array.isArray(payloadValue)) {
|
||||
if (!payloadValue.some((item) => eventFilterMatches(item, patternValue))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!eventFilterMatches(payloadValue, patternValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
type ContentFilters = Exclude<EventFilter[string], EventFilter | string[] | number[] | boolean[]>;
|
||||
|
||||
function contentFiltersMatches(actualValue: any, contentFilters: ContentFilters): boolean {
|
||||
for (const contentFilter of contentFilters) {
|
||||
if (typeof contentFilter === "object") {
|
||||
const [key, value] = Object.entries(contentFilter)[0];
|
||||
|
||||
if (!contentFilterMatches(actualValue, contentFilter)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function contentFilterMatches(actualValue: any, contentFilter: ContentFilters[number]): boolean {
|
||||
if ("$endsWith" in contentFilter) {
|
||||
if (typeof actualValue !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return actualValue.endsWith(contentFilter.$endsWith);
|
||||
}
|
||||
|
||||
if ("$startsWith" in contentFilter) {
|
||||
if (typeof actualValue !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return actualValue.startsWith(contentFilter.$startsWith);
|
||||
}
|
||||
|
||||
if ("$anythingBut" in contentFilter) {
|
||||
if (Array.isArray(contentFilter.$anythingBut)) {
|
||||
if ((contentFilter.$anythingBut as any[]).includes(actualValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (contentFilter.$anythingBut === actualValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ("$exists" in contentFilter) {
|
||||
if (contentFilter.$exists) {
|
||||
return actualValue !== undefined;
|
||||
}
|
||||
|
||||
return actualValue === undefined;
|
||||
}
|
||||
|
||||
if ("$gt" in contentFilter) {
|
||||
if (typeof actualValue !== "number") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return actualValue > contentFilter.$gt;
|
||||
}
|
||||
|
||||
if ("$lt" in contentFilter) {
|
||||
if (typeof actualValue !== "number") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return actualValue < contentFilter.$lt;
|
||||
}
|
||||
|
||||
if ("$gte" in contentFilter) {
|
||||
if (typeof actualValue !== "number") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return actualValue >= contentFilter.$gte;
|
||||
}
|
||||
|
||||
if ("$lte" in contentFilter) {
|
||||
if (typeof actualValue !== "number") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return actualValue <= contentFilter.$lte;
|
||||
}
|
||||
|
||||
if ("$between" in contentFilter) {
|
||||
if (typeof actualValue !== "number") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return actualValue >= contentFilter.$between[0] && actualValue <= contentFilter.$between[1];
|
||||
}
|
||||
|
||||
if ("$includes" in contentFilter) {
|
||||
if (Array.isArray(actualValue)) {
|
||||
return actualValue.includes(contentFilter.$includes);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use localCompare
|
||||
if ("$ignoreCaseEquals" in contentFilter) {
|
||||
if (typeof actualValue !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
actualValue.localeCompare(contentFilter.$ignoreCaseEquals, undefined, {
|
||||
sensitivity: "accent",
|
||||
}) === 0
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -5,3 +5,4 @@ export * from "./utils";
|
||||
export * from "./retry";
|
||||
export * from "./replacements";
|
||||
export * from "./searchParams";
|
||||
export * from "./eventFilterMatches";
|
||||
|
||||
@@ -7,6 +7,46 @@ const EventMatcherSchema = z.union([
|
||||
z.array(z.number()),
|
||||
/** Match against a boolean */
|
||||
z.array(z.boolean()),
|
||||
z.array(
|
||||
z.union([
|
||||
z.object({
|
||||
$endsWith: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
$startsWith: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
$exists: z.boolean(),
|
||||
}),
|
||||
z.object({
|
||||
$anythingBut: z.union([z.string(), z.number(), z.boolean()]),
|
||||
}),
|
||||
z.object({
|
||||
$anythingBut: z.union([z.array(z.string()), z.array(z.number()), z.array(z.boolean())]),
|
||||
}),
|
||||
z.object({
|
||||
$gt: z.number(),
|
||||
}),
|
||||
z.object({
|
||||
$lt: z.number(),
|
||||
}),
|
||||
z.object({
|
||||
$gte: z.number(),
|
||||
}),
|
||||
z.object({
|
||||
$lte: z.number(),
|
||||
}),
|
||||
z.object({
|
||||
$between: z.tuple([z.number(), z.number()]),
|
||||
}),
|
||||
z.object({
|
||||
$includes: z.union([z.string(), z.number(), z.boolean()]),
|
||||
}),
|
||||
z.object({
|
||||
$ignoreCaseEquals: z.string(),
|
||||
}),
|
||||
])
|
||||
),
|
||||
]);
|
||||
|
||||
type EventMatcher = z.infer<typeof EventMatcherSchema>;
|
||||
|
||||
@@ -0,0 +1,522 @@
|
||||
import { EventFilter } from "../src";
|
||||
import { eventFilterMatches } from "../src/eventFilterMatches";
|
||||
|
||||
describe("eventFilterMatches", () => {
|
||||
it("should return true when payload matches string filter", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: ["John"],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload matches boolean filter", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
isAdmin: [false],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload matches number filter", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
age: [30],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload matches $startsWith content filter", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $startsWith: "Jo" }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload matches $endsWith content filter", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $endsWith: "hn" }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload matches $startsWith and $endsWith content filters", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $startsWith: "Jo" }, { $endsWith: "hn" }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload does not match $anythingBut filter", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $anythingBut: "Jane" }],
|
||||
address: {
|
||||
street: [{ $anythingBut: "456 Elm St" }],
|
||||
},
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload does not match $anythingBut filter with an array", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $anythingBut: ["Jane", "Joe"] }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload does have a key that $exists = true", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $exists: true }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload does NOT have a key that $exists = false", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
foo: [{ $exists: false }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload does match numeric condition", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
score: 100,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
age: [{ $gt: 20 }, { $lt: 40 }],
|
||||
score: [{ $between: [90, 110] }],
|
||||
};
|
||||
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload matches an includes condition", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
score: 100,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
hobbies: [{ $includes: "reading" }],
|
||||
};
|
||||
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when payload matches an ignoreCaseEquals condition", () => {
|
||||
const payload = {
|
||||
name: "John",
|
||||
age: 30,
|
||||
score: 100,
|
||||
isAdmin: false,
|
||||
hobbies: ["reading", "swimming"],
|
||||
address: {
|
||||
street: "123 Main St",
|
||||
city: "Anytown",
|
||||
state: "CA",
|
||||
zip: "12345",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $ignoreCaseEquals: "john" }],
|
||||
};
|
||||
|
||||
expect(eventFilterMatches(payload, filter)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when payload does not match string filter", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: ["John"],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does not match string filter because it's the wrong type", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
age: ["John"],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does not match boolean filter", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
isAdmin: [false],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does not match number filter", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
age: [30],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does not match $startsWith content filter", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $startsWith: "Jo" }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does not match $endsWith content filter", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $startsWith: "Ja" }, { $endsWith: "hn" }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does match $anythingBut content filters", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $anythingBut: "Jane" }],
|
||||
address: {
|
||||
street: [{ $anythingBut: "456 Elm St" }],
|
||||
},
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does match $anythingBut content filters with an array", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $anythingBut: ["Jane", "John"] }],
|
||||
address: {
|
||||
street: [{ $anythingBut: "456 Elm St" }],
|
||||
},
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does not have a key that $exists = true", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
foo: [{ $exists: true }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when payload does have a key that $exists = false", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
score: 100,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $exists: false }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when the payload does not match the numeric filters", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
score: 100,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "Othertown",
|
||||
state: "NY",
|
||||
zip: "67890",
|
||||
latitude: 37.7749,
|
||||
longitude: 122.4194,
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
age: [{ $gt: 30 }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("Should return false when the payload does not match an includes filter", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
score: 100,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "San Francisco",
|
||||
state: "CA",
|
||||
zip: "67890",
|
||||
latitude: 37.7749,
|
||||
longitude: 122.4194,
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
hobbies: [{ $includes: "swimming" }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
|
||||
it("Should return false when the payload does not match any ignoreCaseEquals condition", () => {
|
||||
const payload = {
|
||||
name: "Jane",
|
||||
age: 25,
|
||||
score: 100,
|
||||
isAdmin: true,
|
||||
hobbies: ["running", "yoga"],
|
||||
address: {
|
||||
street: "456 Elm St",
|
||||
city: "San Francisco",
|
||||
state: "CA",
|
||||
zip: "67890",
|
||||
latitude: 37.7749,
|
||||
longitude: 122.4194,
|
||||
},
|
||||
};
|
||||
const filter: EventFilter = {
|
||||
name: [{ $ignoreCaseEquals: "john" }],
|
||||
};
|
||||
expect(eventFilterMatches(payload, filter)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "@trigger.dev/tsconfig/node18.json",
|
||||
"include": ["src/globals.d.ts", "./src/**/*.ts", "tsup.config.ts"],
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"declaration": false,
|
||||
"declarationMap": false
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"extends": "@trigger.dev/tsconfig/node18.json",
|
||||
"include": ["src/globals.d.ts", "./src/**/*.ts", "tsup.config.ts"],
|
||||
"include": ["src/globals.d.ts", "./src/**/*.ts", "tsup.config.ts", "./test/**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"declaration": false,
|
||||
"declarationMap": false
|
||||
"declarationMap": false,
|
||||
"types": ["jest"]
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { defineConfig } from "tsup";
|
||||
export default defineConfig([
|
||||
{
|
||||
name: "main",
|
||||
config: "tsconfig.build.json",
|
||||
entry: ["./src/index.ts"],
|
||||
outDir: "./dist",
|
||||
platform: "neutral",
|
||||
|
||||
Generated
+946
-4
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user