diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts index 5220118c0f..21689593f9 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts @@ -96,15 +96,12 @@ const operators: Operators = { labelForFormat: "Not Contains", valueSources: ["value"], }, - /** - * Not supported with JSONLogic. Implement them and add these back -> https://github.com/jwadhams/json-logic-js/issues/81 - */ - // starts_with: { - // label: "Starts with", - // labelForFormat: "Starts with", - // jsonLogic: undefined, // not supported - // valueSources: ["value"], - // }, + starts_with: { + label: "Starts with", + labelForFormat: "Starts with", + jsonLogic: "starts_with", + valueSources: ["value"], + }, // ends_with: { // label: "Ends with", // labelForFormat: "Ends with", diff --git a/packages/lib/raqb/jsonLogic.test.ts b/packages/lib/raqb/jsonLogic.test.ts index d2a6dca1b8..72a0f80a62 100644 --- a/packages/lib/raqb/jsonLogic.test.ts +++ b/packages/lib/raqb/jsonLogic.test.ts @@ -225,4 +225,37 @@ describe("jsonLogic", () => { ).toBe(false); }); }); + + describe("starts_with operation", () => { + it("should return true if string starts with the given substring case-insensitively", () => { + expect(jsonLogic.apply({ starts_with: ["Hello World", "hello"] })).toBe(true); + expect(jsonLogic.apply({ starts_with: ["HELLO WORLD", "hello"] })).toBe(true); + expect(jsonLogic.apply({ starts_with: ["hello", "HELLO"] })).toBe(true); + }); + + it("should return false if string does not start with the given substring", () => { + expect(jsonLogic.apply({ starts_with: ["Hello World", "world"] })).toBe(false); + expect(jsonLogic.apply({ starts_with: ["Hello World", "hi"] })).toBe(false); + }); + + it("should return false if the second argument is falsy", () => { + expect(jsonLogic.apply({ starts_with: ["Hello World", ""] })).toBe(false); + expect(jsonLogic.apply({ starts_with: ["Hello World", null] })).toBe(false); + expect(jsonLogic.apply({ starts_with: ["Hello World", false] })).toBe(false); + }); + + it("should handle edge cases", () => { + expect(jsonLogic.apply({ starts_with: ["", "hello"] })).toBe(false); + expect(jsonLogic.apply({ starts_with: ["hello", "hello world"] })).toBe(false); + }); + + it("should handle non-string first argument (haystack) safely", () => { + expect(jsonLogic.apply({ starts_with: [null, "x"] })).toBe(false); + expect(jsonLogic.apply({ starts_with: [undefined, "x"] })).toBe(false); + expect(jsonLogic.apply({ starts_with: [123, "1"] })).toBe(false); + expect(jsonLogic.apply({ starts_with: [true, "t"] })).toBe(false); + expect(jsonLogic.apply({ starts_with: [[], ""] })).toBe(false); + expect(jsonLogic.apply({ starts_with: [{}, ""] })).toBe(false); + }); + }); }); diff --git a/packages/lib/raqb/jsonLogic.ts b/packages/lib/raqb/jsonLogic.ts index 5627a29df1..f3edbb0372 100644 --- a/packages/lib/raqb/jsonLogic.ts +++ b/packages/lib/raqb/jsonLogic.ts @@ -50,4 +50,18 @@ jsonLogic.add_operation("in", function (a: string, b: string | string[]) { return second.indexOf(first) !== -1; }); +/** + * Short Text/Long Text "starts with" uses it + */ +jsonLogic.add_operation("starts_with", function (a: unknown, b: unknown) { + if (typeof a !== "string" || typeof b !== "string") return false; + + const first = normalize(a); + const second = normalize(b); + + if (!second) return false; + + return first.startsWith(second); +}); + export default jsonLogic;