From 7b8faaee7bd425c52fcfeb31a5056301cb870cc7 Mon Sep 17 00:00:00 2001 From: Sonarly Claude Code Date: Sun, 3 May 2026 08:05:17 +0000 Subject: [PATCH] fix: handle IS_NOT_NULL operand in evaluateUuidFilter for workflow filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://sonarly.com/issue/33687?type=bug The `evaluateUuidFilter` function in the workflow filter step only handles `IS` and `IS_NOT` operands, throwing an unhandled error when a UUID-type filter uses the valid `IS_NOT_NULL` operand. This causes the entire workflow run to fail. Fix: Added `IS_NOT_NULL`, `IS_NOT_EMPTY`, and `IS_EMPTY` operand handling to `evaluateUuidFilter` in `evaluate-filter-conditions.util.ts`. **The problem:** `evaluateUuidFilter` only handled `IS` and `IS_NOT` operands. When a workflow Filter step used a UUID-typed field with the `IS_NOT_NULL` operand (a valid `ViewFilterOperand` enum member), the function hit the `default` branch and threw `Error: Operand IS_NOT_NULL not supported for uuid filter`, crashing the workflow run. **The fix:** Added three new cases to the switch statement, following the exact same pattern used in `evaluateRelationFilter` (same file, same semantics): - `IS_EMPTY`: returns `!isNonEmptyString(filter.leftOperand)` — true when the UUID is empty/missing - `IS_NOT_NULL` (falls through to `IS_NOT_EMPTY`): returns `isNonEmptyString(filter.leftOperand)` — true when the UUID has a value - `IS_NOT_EMPTY`: returns `isNonEmptyString(filter.leftOperand)` — same as IS_NOT_NULL **Tests added:** 6 new test cases in the existing `UUID filter operands` describe block: - IS_NOT_NULL with non-empty UUID → true - IS_NOT_NULL with empty string → false - IS_NOT_EMPTY with non-empty UUID → true - IS_NOT_EMPTY with empty string → false - IS_EMPTY with empty string → true - IS_EMPTY with non-empty UUID → false --- .../evaluate-filter-conditions.util.spec.ts | 72 +++++++++++++++++++ .../utils/evaluate-filter-conditions.util.ts | 5 ++ 2 files changed, 77 insertions(+) diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/__tests__/evaluate-filter-conditions.util.spec.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/__tests__/evaluate-filter-conditions.util.spec.ts index 7fbb7efcedb..083d4e2cf47 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/__tests__/evaluate-filter-conditions.util.spec.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/__tests__/evaluate-filter-conditions.util.spec.ts @@ -298,6 +298,78 @@ describe('evaluateFilterConditions', () => { expect(evaluateFilterConditions({ filters: [filter2] })).toBe(false); }); + it('should return true when left operand is non-empty (IS_NOT_NULL UUID)', () => { + const filter = createFilter( + ViewFilterOperand.IS_NOT_NULL, + uuid1, + '', + 'UUID', + ); + const result = evaluateFilterConditions({ filters: [filter] }); + + expect(result).toBe(true); + }); + + it('should return false when left operand is empty (IS_NOT_NULL UUID)', () => { + const filter = createFilter( + ViewFilterOperand.IS_NOT_NULL, + '', + '', + 'UUID', + ); + const result = evaluateFilterConditions({ filters: [filter] }); + + expect(result).toBe(false); + }); + + it('should return true when left operand is non-empty (IS_NOT_EMPTY UUID)', () => { + const filter = createFilter( + ViewFilterOperand.IS_NOT_EMPTY, + uuid1, + '', + 'UUID', + ); + const result = evaluateFilterConditions({ filters: [filter] }); + + expect(result).toBe(true); + }); + + it('should return false when left operand is empty (IS_NOT_EMPTY UUID)', () => { + const filter = createFilter( + ViewFilterOperand.IS_NOT_EMPTY, + '', + '', + 'UUID', + ); + const result = evaluateFilterConditions({ filters: [filter] }); + + expect(result).toBe(false); + }); + + it('should return true when left operand is empty (IS_EMPTY UUID)', () => { + const filter = createFilter( + ViewFilterOperand.IS_EMPTY, + '', + '', + 'UUID', + ); + const result = evaluateFilterConditions({ filters: [filter] }); + + expect(result).toBe(true); + }); + + it('should return false when left operand is non-empty (IS_EMPTY UUID)', () => { + const filter = createFilter( + ViewFilterOperand.IS_EMPTY, + uuid1, + '', + 'UUID', + ); + const result = evaluateFilterConditions({ filters: [filter] }); + + expect(result).toBe(false); + }); + it('should throw error for unsupported UUID filter operand', () => { const filter = createFilter( ViewFilterOperand.CONTAINS, diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/evaluate-filter-conditions.util.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/evaluate-filter-conditions.util.ts index 1ba0308573d..78e39b1a8c2 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/evaluate-filter-conditions.util.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/evaluate-filter-conditions.util.ts @@ -268,6 +268,11 @@ function evaluateUuidFilter(filter: ResolvedFilter): boolean { return filter.leftOperand === filter.rightOperand; case ViewFilterOperand.IS_NOT: return filter.leftOperand !== filter.rightOperand; + case ViewFilterOperand.IS_EMPTY: + return !isNonEmptyString(filter.leftOperand); + case ViewFilterOperand.IS_NOT_NULL: + case ViewFilterOperand.IS_NOT_EMPTY: + return isNonEmptyString(filter.leftOperand); default: throw new Error( `Operand ${filter.operand} not supported for uuid filter`,