From 274c93a5e2dffe8d2c8d51308fa4de6fe2daad90 Mon Sep 17 00:00:00 2001 From: nwcm <111259588+nwcm@users.noreply.github.com> Date: Fri, 19 Jun 2026 14:58:09 +1000 Subject: [PATCH 1/2] null Safe equals Filter method --- .../default/classes/standard-soql/SOQL.cls | 16 ++++++++++ website/docs/soql/api/soql-filter.md | 25 ++++++++++++++++ website/docs/soql/api/soql-having-filter.md | 29 +++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/force-app/main/default/classes/standard-soql/SOQL.cls b/force-app/main/default/classes/standard-soql/SOQL.cls index bdd415b3..f99f19f1 100644 --- a/force-app/main/default/classes/standard-soql/SOQL.cls +++ b/force-app/main/default/classes/standard-soql/SOQL.cls @@ -277,6 +277,7 @@ public virtual inherited sharing class SOQL implements Queryable { Filter isTrue(); Filter isFalse(); Filter equal(Object value); + Filter equalNullSafe(Object value); Filter notEqual(Object value); Filter lessThan(Object value); Filter lessOrEqual(Object value); @@ -348,6 +349,7 @@ public virtual inherited sharing class SOQL implements Queryable { HavingFilter isTrue(); HavingFilter isFalse(); HavingFilter equal(Object value); + HavingFilter equalNullSafe(Object value); HavingFilter notEqual(Object value); HavingFilter lessThan(Object value); HavingFilter lessOrEqual(Object value); @@ -2063,6 +2065,13 @@ public virtual inherited sharing class SOQL implements Queryable { return this.set('=', value); } + public Filter equalNullSafe(Object value) { + if(value == null) { + return this.isNull(); + } + return this.equal(value); + } + public Filter notEqual(Object value) { return this.set('!=', value); } @@ -2536,6 +2545,13 @@ public virtual inherited sharing class SOQL implements Queryable { return this.set('=', value); } + public HavingFilter equalNullSafe(Object value) { + if(value == null) { + return this.isNull(); + } + return this.equal(value); + } + public HavingFilter notEqual(Object value) { return this.set('!=', value); } diff --git a/website/docs/soql/api/soql-filter.md b/website/docs/soql/api/soql-filter.md index b89c29ec..b2435f4f 100644 --- a/website/docs/soql/api/soql-filter.md +++ b/website/docs/soql/api/soql-filter.md @@ -32,6 +32,7 @@ The following are methods for `Filter`. - [`isTrue()`](#istrue) - [`isFalse()`](#isfalse) - [`equal(Object value)`](#equal) +- [`equalNullSafe(Object value)`](#equalnullsafe) - [`notEqual(Object value)`](#notequal) - [`lessThan(Object value)`](#lessthan) - [`greaterThan(Object value)`](#greaterthan) @@ -334,6 +335,30 @@ SOQL.of(Account.SObjectType) .toList(); ``` +### equalNullSafe + +Safely call equals with a variable that can be null. Ensuring WHERE Field = null does not occur returning unrelated records. + +- `WHERE (Name = 'My Account' AND Name != NULL)` + +**Signature** + +```apex +Filter equalNullSafe(Object value) +``` + +**Example** + +```sql +SELECT Id FROM Account WHERE (Name = 'My Account' AND Name != NULL) +``` + +```apex +SOQL.of(Contact.SObjectType) + .whereAre(SOQL.Filter.name().equalNullSafe(variable)) + .toList(); +``` + ### notEqual - `WHERE Name != 'My Account'` diff --git a/website/docs/soql/api/soql-having-filter.md b/website/docs/soql/api/soql-having-filter.md index fb7dbf88..522beb0c 100644 --- a/website/docs/soql/api/soql-having-filter.md +++ b/website/docs/soql/api/soql-having-filter.md @@ -35,6 +35,7 @@ The following are methods for `HavingFilter`. - [`isTrue()`](#istrue) - [`isFalse()`](#isfalse) - [`equal(Object value)`](#equal) +- [`equalNullSafe(Object value)`](#equalnullsafe) - [`notEqual(Object value)`](#notequal) - [`lessThan(Object value)`](#lessthan) - [`greaterThan(Object value)`](#greaterthan) @@ -380,6 +381,34 @@ SOQL.of(Lead.SObjectType) .toAggregated(); ``` +### equalNullSafe + +- `HAVING (City = 'Los Angeles' AND City != NULL)` +- `HAVING SUM(AnnualRevenue) = 100000` + +**Signature** + +```apex +HavingFilter equalNullSafe(Object value) +``` + +**Example** + +```sql +SELECT COUNT(Name) +FROM Lead +GROUP BY LeadSource +HAVING (LeadSource = 'Web' AND LeadSource != NULL) +``` + +```apex +SOQL.of(Lead.SObjectType) + .count(Lead.Name) + .groupBy(Lead.LeadSource) + .have(SOQL.HavingFilter.with(Lead.LeadSource).equalNullSafe('Web')) + .toAggregated(); +``` + ### notEqual - `HAVING City != 'Los Angeles'` From ec45dd5824c60849fb554a676d2b4f35519767ec Mon Sep 17 00:00:00 2001 From: nwcm <111259588+nwcm@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:20:51 +1000 Subject: [PATCH 2/2] correct condition --- force-app/main/default/classes/standard-soql/SOQL.cls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/force-app/main/default/classes/standard-soql/SOQL.cls b/force-app/main/default/classes/standard-soql/SOQL.cls index f99f19f1..9db1d319 100644 --- a/force-app/main/default/classes/standard-soql/SOQL.cls +++ b/force-app/main/default/classes/standard-soql/SOQL.cls @@ -2067,7 +2067,7 @@ public virtual inherited sharing class SOQL implements Queryable { public Filter equalNullSafe(Object value) { if(value == null) { - return this.isNull(); + return this.isNotNull(); } return this.equal(value); } @@ -2547,7 +2547,7 @@ public virtual inherited sharing class SOQL implements Queryable { public HavingFilter equalNullSafe(Object value) { if(value == null) { - return this.isNull(); + return this.isNotNull(); } return this.equal(value); }