From ae8f20e9ddb32df54cd15742e50b850465ebf318 Mon Sep 17 00:00:00 2001 From: Piotr Gajek Date: Tue, 12 Sep 2023 11:53:56 +0200 Subject: [PATCH 01/15] GROUP BY CUBE + Exception (#82) * GROUP BY CUBE + Exception * Fix groupBy with default fields --- force-app/main/default/classes/SOQL.cls | 63 +++++++++++++++++--- force-app/main/default/classes/SOQL_Test.cls | 35 +++++++++++ website/docs/api/soql.md | 25 +++++++- website/docs/docs/design.md | 1 + 4 files changed, 116 insertions(+), 8 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 5dc1a585..f74ba61e 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -81,6 +81,7 @@ public virtual inherited sharing class SOQL implements Queryable { // GROUP BY Queryable groupBy(SObjectField field); Queryable groupByRollup(SObjectField field); + Queryable groupByCube(SObjectField field); // ORDER BY Queryable orderBy(String field); Queryable orderBy(String field, String direction); @@ -403,11 +404,19 @@ public virtual inherited sharing class SOQL implements Queryable { public SOQL groupBy(SObjectField field) { builder.groupBy.with(field); + builder.fields.addAsGroupedOrAggregated(field); return this; } public SOQL groupByRollup(SObjectField field) { builder.groupBy.rollup(field); + builder.fields.addAsGroupedOrAggregated(field); + return this; + } + + public SOQL groupByCube(SObjectField field) { + builder.groupBy.cube(field); + builder.fields.addAsGroupedOrAggregated(field); return this; } @@ -685,32 +694,41 @@ public virtual inherited sharing class SOQL implements Queryable { private class QFields implements QueryClause { private Set fields = new Set(); private Set counts = new Set(); + private Set groupedOrAggregated = new Set(); public void count() { // COUNT() must be the only element in the SELECT list. + clearAllFields(); count('COUNT()'); } public void count(SObjectField field) { + addAsGroupedOrAggregated(field); count('COUNT(' + field + ')'); } public void count(SObjectField field, String alias) { + addAsGroupedOrAggregated(field); count('COUNT(' + field + ') ' + alias); } - public void count(String countSoql) { - // Clear all default fields to avoid "Field must be grouped or aggregated" - clearAllFields(); + private void count(String countSoql) { counts.add(countSoql); } public void with(SObjectField field, String alias) { - // Only aggregate expressions use field aliasing. Clear all default fields to avoid "Field must be grouped or aggregated" - clearAllFields(); + addAsGroupedOrAggregated(field + ' ' + alias); fields.add(field + ' ' + alias); } + public void addAsGroupedOrAggregated(SObjectField field) { + addAsGroupedOrAggregated(field.getDescribe().getName()); + } + + public void addAsGroupedOrAggregated(String field) { + groupedOrAggregated.add(field); + } + public void with(String stringFields) { // To avoid field duplicates in query fields.addAll(stringFields.deleteWhitespace().split(',')); @@ -745,6 +763,8 @@ public virtual inherited sharing class SOQL implements Queryable { } public override String toString() { + clearNotGroupedOrAggregatedFields(); + if (fields.isEmpty() && counts.isEmpty()) { return 'SELECT Id'; } @@ -756,6 +776,18 @@ public virtual inherited sharing class SOQL implements Queryable { return 'SELECT ' + String.join(selectStatement, ', '); } + + public void clearNotGroupedOrAggregatedFields() { + if (groupedOrAggregated.isEmpty()) { + return; + } + // Clear not grouped or aggregated fields to avoid "Field must be grouped or aggregated" error + for (String field : fields) { + if (!groupedOrAggregated.contains(field)) { + fields.remove(field); + } + } + } } private class QSubQuery implements SubQuery { @@ -1274,17 +1306,34 @@ public virtual inherited sharing class SOQL implements Queryable { private class QGroupBy implements QueryClause { private Set groupByFields = new Set(); + private String groupByFunction = ''; public void with(SObjectField field) { + setGroupByFunction('{0}'); groupByFields.add(field.getDescribe().getName()); } public void rollup(SObjectField field) { - groupByFields.add('ROLLUP(' + field + ')'); + setGroupByFunction('ROLLUP({0})'); + groupByFields.add(field.getDescribe().getName()); + } + + public void cube(SObjectField field) { + setGroupByFunction('CUBE({0})'); + groupByFields.add(field.getDescribe().getName()); + } + + public void setGroupByFunction(String newGroupByFunction) { + if (String.isNotEmpty(groupByFunction) && groupByFunction != newGroupByFunction) { + QueryException e = new QueryException(); + e.setMessage('You cant combine GROUP BY, GROUP BY ROLLUP and GROUP BY CUBE syntax in the same statement.'); + throw e; + } + this.groupByFunction = newGroupByFunction; } public override String toString() { - return 'GROUP BY ' + String.join(groupByFields, ', '); + return 'GROUP BY ' + String.format(groupByFunction, new List { String.join(groupByFields, ', ') }); } } diff --git a/force-app/main/default/classes/SOQL_Test.cls b/force-app/main/default/classes/SOQL_Test.cls index 40d634bf..48b8d5a3 100644 --- a/force-app/main/default/classes/SOQL_Test.cls +++ b/force-app/main/default/classes/SOQL_Test.cls @@ -1297,6 +1297,41 @@ private class SOQL_Test { Assert.areEqual('SELECT COUNT(Name) cnt, LeadSource FROM Lead GROUP BY ROLLUP(LeadSource)', soql); } + @IsTest + static void groupByCube() { + // Test + String soql = SOQL.of(Account.SObjectType) + .with(Account.Type) + .groupByCube(Account.Type) + .toString(); + + // Verify + Assert.areEqual('SELECT Type FROM Account GROUP BY CUBE(Type)', soql); + } + + @IsTest + static void differentGroupByFunctionsException() { + // Setup + Exception queryException = null; + + // Test + try { + String soql = SOQL.of(Account.SObjectType) + .with(Account.Type) + .groupBy(Account.Type) + .groupByCube(Account.Type) + .toString(); + } catch(Exception e) { + queryException = e; + } + + // Verify + Assert.areEqual( + 'You cant combine GROUP BY, GROUP BY ROLLUP and GROUP BY CUBE syntax in the same statement.', + queryException.getMessage() + ); + } + @IsTest static void orderByString() { // Test diff --git a/website/docs/api/soql.md b/website/docs/api/soql.md index 78cbb19e..80b3fb72 100644 --- a/website/docs/api/soql.md +++ b/website/docs/api/soql.md @@ -62,6 +62,7 @@ The following are methods for `SOQL`. - [`groupBy(SObjectField field)`](#group-by) - [`groupByRollup(SObjectField field)`](#groupbyrollup) +- [`groupByCube(SObjectField field)`](#groupbycube) [**ORDER BY**](#order-by) @@ -726,13 +727,35 @@ FROM Lead GROUP BY ROLLUP(LeadSource) ``` ```apex -QS.of(Lead.SObjectType) +SOQL.of(Lead.SObjectType) .with(Lead.LeadSource) .count(Lead.Name, 'cnt') .groupByRollup(Lead.LeadSource) .toAggregated(); ``` +### groupByCube + +**Signature** + +```apex +SOQL groupByCube(SObjectField field) +``` + +**Example** + +```sql +SELECT Type +FROM Account +GROUP BY ROLLUP(Type) +``` +```apex +SOQL.of(Account.SObjectType) + .with(Account.Type) + .groupByCube(Account.Type) + .toAggregated(); +``` + ## ORDER BY [ORDER BY](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_orderby.htm) diff --git a/website/docs/docs/design.md b/website/docs/docs/design.md index ba47ccde..cdf991b5 100644 --- a/website/docs/docs/design.md +++ b/website/docs/docs/design.md @@ -81,6 +81,7 @@ public interface Queryable { Queryable groupBy(SObjectField field); Queryable groupByRollup(SObjectField field); + Queryable groupByCube(SObjectField field); Queryable orderBy(String field); // ASC, NULLS FIRST by default Queryable orderBy(String field, String direction); // dynamic order by, NULLS FIRST by default From e546fecd34c64e85afbbb2d90794af13a7566e2c Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 12 Sep 2023 12:09:17 +0200 Subject: [PATCH 02/15] Improve naming --- force-app/main/default/classes/SOQL.cls | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index f74ba61e..9baa9b82 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -404,19 +404,19 @@ public virtual inherited sharing class SOQL implements Queryable { public SOQL groupBy(SObjectField field) { builder.groupBy.with(field); - builder.fields.addAsGroupedOrAggregated(field); + builder.fields.withAggregatedField(field); return this; } public SOQL groupByRollup(SObjectField field) { builder.groupBy.rollup(field); - builder.fields.addAsGroupedOrAggregated(field); + builder.fields.withAggregatedField(field); return this; } public SOQL groupByCube(SObjectField field) { builder.groupBy.cube(field); - builder.fields.addAsGroupedOrAggregated(field); + builder.fields.withAggregatedField(field); return this; } @@ -694,7 +694,7 @@ public virtual inherited sharing class SOQL implements Queryable { private class QFields implements QueryClause { private Set fields = new Set(); private Set counts = new Set(); - private Set groupedOrAggregated = new Set(); + private Set aggregatedFields = new Set(); public void count() { // COUNT() must be the only element in the SELECT list. @@ -703,12 +703,12 @@ public virtual inherited sharing class SOQL implements Queryable { } public void count(SObjectField field) { - addAsGroupedOrAggregated(field); + withAggregatedField(field); count('COUNT(' + field + ')'); } public void count(SObjectField field, String alias) { - addAsGroupedOrAggregated(field); + withAggregatedField(field); count('COUNT(' + field + ') ' + alias); } @@ -717,16 +717,16 @@ public virtual inherited sharing class SOQL implements Queryable { } public void with(SObjectField field, String alias) { - addAsGroupedOrAggregated(field + ' ' + alias); + withAggregatedField(field + ' ' + alias); fields.add(field + ' ' + alias); } - public void addAsGroupedOrAggregated(SObjectField field) { - addAsGroupedOrAggregated(field.getDescribe().getName()); + public void withAggregatedField(SObjectField field) { + withAggregatedField(field.getDescribe().getName()); } - public void addAsGroupedOrAggregated(String field) { - groupedOrAggregated.add(field); + public void withAggregatedField(String field) { + aggregatedFields.add(field); } public void with(String stringFields) { @@ -763,7 +763,7 @@ public virtual inherited sharing class SOQL implements Queryable { } public override String toString() { - clearNotGroupedOrAggregatedFields(); + removeNotAggregatedFieldsFromAggregateSoql(); if (fields.isEmpty() && counts.isEmpty()) { return 'SELECT Id'; @@ -777,13 +777,13 @@ public virtual inherited sharing class SOQL implements Queryable { return 'SELECT ' + String.join(selectStatement, ', '); } - public void clearNotGroupedOrAggregatedFields() { - if (groupedOrAggregated.isEmpty()) { + public void removeNotAggregatedFieldsFromAggregateSoql() { + if (aggregatedFields.isEmpty()) { return; } // Clear not grouped or aggregated fields to avoid "Field must be grouped or aggregated" error for (String field : fields) { - if (!groupedOrAggregated.contains(field)) { + if (!aggregatedFields.contains(field)) { fields.remove(field); } } From 88029f85df0c67af545fc0fde183d963cbc8c33f Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Thu, 14 Sep 2023 19:51:20 +0200 Subject: [PATCH 03/15] formatting --- force-app/main/default/classes/SOQL.cls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 9baa9b82..d45a6400 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -1333,7 +1333,7 @@ public virtual inherited sharing class SOQL implements Queryable { } public override String toString() { - return 'GROUP BY ' + String.format(groupByFunction, new List { String.join(groupByFields, ', ') }); + return 'GROUP BY ' + String.format(groupByFunction, new List{ String.join(groupByFields, ', ') }); } } From 031b69d0508e51fa764869835d1ca2ae1143ab04 Mon Sep 17 00:00:00 2001 From: Piotr Gajek Date: Thu, 14 Sep 2023 20:38:35 +0200 Subject: [PATCH 04/15] grouping (#84) * grouping * refactoring --- force-app/main/default/classes/SOQL.cls | 40 +++++++++++--------- force-app/main/default/classes/SOQL_Test.cls | 16 ++++++++ website/docs/api/soql.md | 34 +++++++++++++++++ 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index d45a6400..ab8594b1 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -65,6 +65,8 @@ public virtual inherited sharing class SOQL implements Queryable { Queryable count(); Queryable count(SObjectField field); Queryable count(SObjectField field, String alias); + // GROUPING + Queryable grouping(SObjectField field, String alias); // USING SCOPE Queryable delegatedScope(); Queryable mineScope(); @@ -347,6 +349,11 @@ public virtual inherited sharing class SOQL implements Queryable { return this; } + public SOQL grouping(SObjectField field, String alias) { + builder.fields.grouping(field, alias); + return this; + } + public SOQL delegatedScope() { builder.scope.delegated(); return this; @@ -539,7 +546,7 @@ public virtual inherited sharing class SOQL implements Queryable { } public Integer toInteger() { - if (builder.fields.areCountsEmpty()) { + if (!builder.fields.hasCount()) { count(); } return executor.toInteger(builder.toString(), binder.getBindingMap()); @@ -693,27 +700,31 @@ public virtual inherited sharing class SOQL implements Queryable { private class QFields implements QueryClause { private Set fields = new Set(); - private Set counts = new Set(); private Set aggregatedFields = new Set(); + private Boolean hasCount = false; public void count() { - // COUNT() must be the only element in the SELECT list. - clearAllFields(); count('COUNT()'); } public void count(SObjectField field) { - withAggregatedField(field); count('COUNT(' + field + ')'); } public void count(SObjectField field, String alias) { - withAggregatedField(field); count('COUNT(' + field + ') ' + alias); + fields.add('COUNT(' + field + ') ' + alias); } - private void count(String countSoql) { - counts.add(countSoql); + private void count(String count) { + this.hasCount = true; + withAggregatedField(count); + fields.add(count); + } + + public void grouping(SObjectField field, String alias) { + withAggregatedField('GROUPING(' + field + ') ' + alias); + fields.add('GROUPING(' + field + ') ' + alias); } public void with(SObjectField field, String alias) { @@ -758,23 +769,18 @@ public virtual inherited sharing class SOQL implements Queryable { fields.clear(); } - public Boolean areCountsEmpty() { - return counts.isEmpty(); + public Boolean hasCount() { + return hasCount; } public override String toString() { removeNotAggregatedFieldsFromAggregateSoql(); - if (fields.isEmpty() && counts.isEmpty()) { + if (fields.isEmpty()) { return 'SELECT Id'; } - List selectStatement = new List(); - - selectStatement.addAll(counts); - selectStatement.addAll(fields); - - return 'SELECT ' + String.join(selectStatement, ', '); + return 'SELECT ' + String.join(fields, ', '); } public void removeNotAggregatedFieldsFromAggregateSoql() { diff --git a/force-app/main/default/classes/SOQL_Test.cls b/force-app/main/default/classes/SOQL_Test.cls index 48b8d5a3..41063914 100644 --- a/force-app/main/default/classes/SOQL_Test.cls +++ b/force-app/main/default/classes/SOQL_Test.cls @@ -62,6 +62,22 @@ private class SOQL_Test { Assert.areEqual('SELECT COUNT(Name) names FROM Account', soql); } + @IsTest + static void grouping() { + // Test + String soql = SOQL.of(Lead.SObjectType) + .with(Lead.LeadSource, Lead.Rating) + .grouping(Lead.LeadSource, 'grpLS') + .grouping(Lead.Rating, 'grpRating') + .count(Lead.Name, 'cnt') + .groupByRollup(Lead.LeadSource) + .groupByRollup(Lead.Rating) + .toString(); + + // Verify + Assert.areEqual('SELECT LeadSource, Rating, GROUPING(LeadSource) grpLS, GROUPING(Rating) grpRating, COUNT(Name) cnt FROM Lead GROUP BY ROLLUP(LeadSource, Rating)', soql); + } + @IsTest static void withField() { // Test diff --git a/website/docs/api/soql.md b/website/docs/api/soql.md index 80b3fb72..de38c5b9 100644 --- a/website/docs/api/soql.md +++ b/website/docs/api/soql.md @@ -38,6 +38,10 @@ The following are methods for `SOQL`. - [`count(SObjectField field)`](#count-field) - [`count(SObjectField field, String alias)`](#count-with-alias) +[**GROUPING**](#grouping) + +- [`grouping(SObjectField field, String alias)`](#grouping) + [**SUBQUERY**](#sub-query) - [`with(SubQuery subQuery)`](#with-subquery) @@ -437,6 +441,36 @@ SOQL.of(Account.SObjectType) .toAggregated(); ``` +## GROUPING + +### grouping + +**Signature** + +```apex +grouping(SObjectField field, String alias) +``` + +**Example** + +```sql +SELECT LeadSource, Rating, + GROUPING(LeadSource) grpLS, GROUPING(Rating) grpRating, + COUNT(Name) cnt +FROM Lead +GROUP BY ROLLUP(LeadSource, Rating) +``` +```apex +SOQL.of(Lead.SObjectType) + .with(Lead.LeadSource, Lead.Rating) + .grouping(Lead.LeadSource, 'grpLS') + .grouping(Lead.Rating, 'grpRating') + .count(Lead.Name, 'cnt') + .groupByRollup(Lead.LeadSource) + .groupByRollup(Lead.Rating) + .toAggregated(); +``` + ## USING SCOPE [USING SCOPE](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_using_scope.htm) From 020a5182091a69758eac7122525421d9acdbf228 Mon Sep 17 00:00:00 2001 From: Piotr Gajek Date: Sun, 24 Sep 2023 11:20:11 +0200 Subject: [PATCH 05/15] toMap with custom key (#85) * toMap with custom key * toMap with custom key and type * toAggregatedMap * refactoring * toMap and toAggregatedMap * refactoring * Fix toMap cast * documentation update --- force-app/main/default/classes/SOQL.cls | 39 +++++++++++++++- force-app/main/default/classes/SOQL_Test.cls | 47 +++++++++++++++++++- website/docs/api/soql.md | 30 +++++++++++++ 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index ab8594b1..d4b43ed4 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -126,6 +126,8 @@ public virtual inherited sharing class SOQL implements Queryable { List toList(); List toAggregated(); Map toMap(); + Map toMap(SObjectField keyField); + Map> toAggregatedMap(SObjectField keyField); Database.QueryLocator toQueryLocator(); } @@ -246,6 +248,8 @@ public virtual inherited sharing class SOQL implements Queryable { private QueryBuilder builder; private Executor executor; + private String ofObject; + public static SOQL of(SObjectType ofObject) { return new SOQL(ofObject); } @@ -259,6 +263,7 @@ public virtual inherited sharing class SOQL implements Queryable { } public SOQL(String ofObject) { + this.ofObject = ofObject; binder = new Binder(); executor = new Executor(); builder = new QueryBuilder(ofObject); @@ -565,7 +570,39 @@ public virtual inherited sharing class SOQL implements Queryable { } public Map toMap() { - return new Map(toList()); + Map idToSObject = (Map) Type.forName('Map').newInstance(); + idToSObject.putAll(toList()); + return idToSObject; + } + + public Map toMap(SObjectField keyField) { + with(keyField); + + Map cutomKeyToRecord = (Map) Type.forName('Map').newInstance(); + + for (SObject record : toList()) { + cutomKeyToRecord.put(record.get(keyField) + '', record); + } + + return cutomKeyToRecord; + } + + public Map> toAggregatedMap(SObjectField keyField) { + with(keyField); + + Map> cutomKeyToRecords = (Map>) Type.forName('Map>').newInstance(); + + for (SObject record : toList()) { + String customKey = record.get(keyField) + ''; + + if (!cutomKeyToRecords.containsKey(customKey)) { + cutomKeyToRecords.put(customKey, new List()); + } + + cutomKeyToRecords.get(customKey).add(record); + } + + return cutomKeyToRecords; } public Database.QueryLocator toQueryLocator() { diff --git a/force-app/main/default/classes/SOQL_Test.cls b/force-app/main/default/classes/SOQL_Test.cls index 41063914..45f8b5f3 100644 --- a/force-app/main/default/classes/SOQL_Test.cls +++ b/force-app/main/default/classes/SOQL_Test.cls @@ -1882,15 +1882,60 @@ private class SOQL_Test { List accounts = insertAccounts(); // Test - Map result = SOQL.of(Account.SObjectType).toMap(); + Map result = (Map) SOQL.of(Account.SObjectType).toMap(); // Verify Assert.areEqual(accounts.size(), result.size()); + for (Account acc : accounts) { Assert.isNotNull(result.get(acc.Id)); } } + @IsTest + static void toMapWithCustomKey() { + // Setup + List accounts = insertAccounts(); + + // Test + Map result = (Map) SOQL.of(Account.SObjectType).toMap(Account.Name); + + // Verify + Assert.areEqual(accounts.size(), result.size()); + + for (Account acc : accounts) { + Assert.isNotNull(result.get(acc.Name)); + } + } + + @IsTest + static void toAggregatedMapWithCustomKey() { + // Setup + List accounts = insertAccounts(); + + // Test + Map> result = SOQL.of(Account.SObjectType).toAggregatedMap(Account.Name); + + // Verify + Assert.areEqual(accounts.size(), result.size()); + + for (Account acc : accounts) { + Assert.isNotNull(result.get(acc.Name)); + } + } + + @IsTest + static void toAggregatedMapWithEmptyCustomKey() { + // Setup + List accounts = insertAccounts(); + + // Test + Map> result = SOQL.of(Account.SObjectType).toAggregatedMap(Account.Industry); + + // Verify + Assert.areEqual(1, result.size()); // grouped by empty Industry + } + @IsTest static void toQueryLocator() { // Test diff --git a/website/docs/api/soql.md b/website/docs/api/soql.md index de38c5b9..e1541c33 100644 --- a/website/docs/api/soql.md +++ b/website/docs/api/soql.md @@ -128,6 +128,8 @@ The following are methods for `SOQL`. - [`toList()`](#tolist) - [`toAggregated()`](#toaggregated) - [`toMap()`](#tomap) +- [`toMap(SObjectField keyField)`](#tomap-with-custom-key) +- [`toAggregatedMap(SObjectField keyField)`](#toaggregatedmap) - [`toQueryLocator()`](#toquerylocator) ## INIT @@ -1480,6 +1482,34 @@ Map toMap() SOQL.of(Account.SObjectType).toMap(); ``` +### toMap with custom key + +**Signature** + +```apex +Map toMap(SObjectField keyField) +``` + +**Example** + +```apex +Map nameToAccount = (Map) SOQL.of(Account.SObjectType).toMap(Account.Name); +``` + +### toAggregatedMap + +**Signature** + +```apex +Map> toAggregatedMap(SObjectField keyField) +``` + +**Example** + +```apex +Map industryToAccounts = SOQL.of(Account.SObjectType).toAggregatedMap(Account.Industry); +``` + ### toQueryLocator **Signature** From c1d68433216e631bac091a52eb6777f11805a5f4 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Sun, 24 Sep 2023 18:25:13 +0200 Subject: [PATCH 06/15] error message rename + formatting --- force-app/main/default/classes/SOQL.cls | 6 +++--- force-app/main/default/classes/SOQL_Test.cls | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index d4b43ed4..cb297321 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -1312,10 +1312,10 @@ public virtual inherited sharing class SOQL implements Queryable { public override String toString() { if (skipBinding) { - return String.format(wrapper, new List { field + ' ' + comperator + ' ' + value }); + return String.format(wrapper, new List{ field + ' ' + comperator + ' ' + value }); } - return String.format(wrapper, new List { field + ' ' + comperator + ' :' + binder.bind(value) }); + return String.format(wrapper, new List{ field + ' ' + comperator + ' :' + binder.bind(value) }); } } @@ -1369,7 +1369,7 @@ public virtual inherited sharing class SOQL implements Queryable { public void setGroupByFunction(String newGroupByFunction) { if (String.isNotEmpty(groupByFunction) && groupByFunction != newGroupByFunction) { QueryException e = new QueryException(); - e.setMessage('You cant combine GROUP BY, GROUP BY ROLLUP and GROUP BY CUBE syntax in the same statement.'); + e.setMessage('You cant use GROUP BY, GROUP BY ROLLUP and GROUP BY CUBE in the same query.'); throw e; } this.groupByFunction = newGroupByFunction; diff --git a/force-app/main/default/classes/SOQL_Test.cls b/force-app/main/default/classes/SOQL_Test.cls index 45f8b5f3..4f25d740 100644 --- a/force-app/main/default/classes/SOQL_Test.cls +++ b/force-app/main/default/classes/SOQL_Test.cls @@ -1343,7 +1343,7 @@ private class SOQL_Test { // Verify Assert.areEqual( - 'You cant combine GROUP BY, GROUP BY ROLLUP and GROUP BY CUBE syntax in the same statement.', + 'You cant use GROUP BY, GROUP BY ROLLUP and GROUP BY CUBE in the same query.', queryException.getMessage() ); } From 68ebda59a8fc868ffcb33b18f2f07691dd7c0244 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 26 Sep 2023 16:51:14 +0200 Subject: [PATCH 07/15] groupByWithDefaultFields --- force-app/main/default/classes/SOQL.cls | 1 + force-app/main/default/classes/SOQL_Test.cls | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index cb297321..0044e1e3 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -547,6 +547,7 @@ public virtual inherited sharing class SOQL implements Queryable { public Set toValuesOf(SObjectField fieldToExtract) { // https://salesforce.stackexchange.com/questions/393308/get-a-list-of-one-column-from-a-soql-result + builder.fields.clearAllFields(); // other fields not needed return new Map(with(fieldToExtract, 'Id').groupBy(fieldToExtract).toAggregated()).keySet(); } diff --git a/force-app/main/default/classes/SOQL_Test.cls b/force-app/main/default/classes/SOQL_Test.cls index 4f25d740..eff70234 100644 --- a/force-app/main/default/classes/SOQL_Test.cls +++ b/force-app/main/default/classes/SOQL_Test.cls @@ -1348,6 +1348,19 @@ private class SOQL_Test { ); } + @IsTest + static void groupByWithDefaultFields() { + // Test + String soql = SOQL.of(Lead.SObjectType) + .with(Lead.FirstName, Lead.LastName, Lead.Email) + .with(Lead.LeadSource) + .groupBy(Lead.LeadSource) + .toString(); + + // Verify + Assert.areEqual('SELECT LeadSource FROM Lead GROUP BY LeadSource', soql); + } + @IsTest static void orderByString() { // Test From d5ac02a930aafd7b9f86bfd365f7115ba8589e5e Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 26 Sep 2023 16:55:29 +0200 Subject: [PATCH 08/15] refactoring --- force-app/main/default/classes/SOQL.cls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 0044e1e3..64bb6d3e 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -582,7 +582,7 @@ public virtual inherited sharing class SOQL implements Queryable { Map cutomKeyToRecord = (Map) Type.forName('Map').newInstance(); for (SObject record : toList()) { - cutomKeyToRecord.put(record.get(keyField) + '', record); + cutomKeyToRecord.put(String.valueOf(record.get(keyField)), record); } return cutomKeyToRecord; @@ -594,7 +594,7 @@ public virtual inherited sharing class SOQL implements Queryable { Map> cutomKeyToRecords = (Map>) Type.forName('Map>').newInstance(); for (SObject record : toList()) { - String customKey = record.get(keyField) + ''; + String customKey = String.valueOf(record.get(keyField)); if (!cutomKeyToRecords.containsKey(customKey)) { cutomKeyToRecords.put(customKey, new List()); From fd7b31ef7a658b5f1faa37ee1b297e4dc01d12be Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Mon, 2 Oct 2023 10:03:14 +0200 Subject: [PATCH 09/15] Refactoring --- force-app/main/default/classes/SOQL_Test.cls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/force-app/main/default/classes/SOQL_Test.cls b/force-app/main/default/classes/SOQL_Test.cls index eff70234..1f4e8106 100644 --- a/force-app/main/default/classes/SOQL_Test.cls +++ b/force-app/main/default/classes/SOQL_Test.cls @@ -1940,7 +1940,7 @@ private class SOQL_Test { @IsTest static void toAggregatedMapWithEmptyCustomKey() { // Setup - List accounts = insertAccounts(); + insertAccounts(); // Test Map> result = SOQL.of(Account.SObjectType).toAggregatedMap(Account.Industry); From 6387c51bde84f2257e04d79f3e3e2e79606543fc Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Mon, 9 Oct 2023 17:26:33 +0200 Subject: [PATCH 10/15] toMap methods --- force-app/main/default/classes/SOQL.cls | 39 ++++++++++++++++++++ force-app/main/default/classes/SOQL_Test.cls | 34 ++++++++++++++++- website/docs/api/soql.md | 33 ++++++++++++++++- 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 64bb6d3e..4e86e88a 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -127,7 +127,9 @@ public virtual inherited sharing class SOQL implements Queryable { List toAggregated(); Map toMap(); Map toMap(SObjectField keyField); + Map toMap(SObjectField keyField, SObjectField valueField); Map> toAggregatedMap(SObjectField keyField); + Map> toAggregatedMap(SObjectField keyField, SObjectField valueField); Database.QueryLocator toQueryLocator(); } @@ -588,6 +590,23 @@ public virtual inherited sharing class SOQL implements Queryable { return cutomKeyToRecord; } + public Map toMap(SObjectField keyField, SObjectField valueField) { + builder.fields.clearAllFields(); // other fields not needed + + with(keyField, valueField); + + Map cutomKeyToCustomValue = new Map(); + + for (SObject record : toList()) { + cutomKeyToCustomValue.put( + String.valueOf(record.get(keyField)), + String.valueOf(record.get(valueField)) + ); + } + + return cutomKeyToCustomValue; + } + public Map> toAggregatedMap(SObjectField keyField) { with(keyField); @@ -606,6 +625,26 @@ public virtual inherited sharing class SOQL implements Queryable { return cutomKeyToRecords; } + public Map> toAggregatedMap(SObjectField keyField, SObjectField valueField) { + builder.fields.clearAllFields(); // other fields not needed + + with(keyField, valueField); + + Map> customKeyToValues = new Map>(); + + for (SObject record : toList()) { + String customKey = String.valueOf(record.get(keyField)); + + if (!customKeyToValues.containsKey(customKey)) { + customKeyToValues.put(customKey, new List()); + } + + customKeyToValues.get(customKey).add(String.valueOf(record.get(valueField))); + } + + return customKeyToValues; + } + public Database.QueryLocator toQueryLocator() { return executor.toQueryLocator(builder.toString(), binder.getBindingMap()); } diff --git a/force-app/main/default/classes/SOQL_Test.cls b/force-app/main/default/classes/SOQL_Test.cls index 1f4e8106..677f90f9 100644 --- a/force-app/main/default/classes/SOQL_Test.cls +++ b/force-app/main/default/classes/SOQL_Test.cls @@ -1921,6 +1921,22 @@ private class SOQL_Test { } } + @IsTest + static void toMapWithCustomKeyAndCustomValue() { + // Setup + List accounts = insertAccounts(); + + // Test + Map result = SOQL.of(Account.SObjectType).toMap(Account.Name, Account.Id); + + // Verify + Assert.areEqual(accounts.size(), result.size()); + + for (Account acc : accounts) { + Assert.isNotNull(result.get(acc.Name)); + } + } + @IsTest static void toAggregatedMapWithCustomKey() { // Setup @@ -1933,7 +1949,7 @@ private class SOQL_Test { Assert.areEqual(accounts.size(), result.size()); for (Account acc : accounts) { - Assert.isNotNull(result.get(acc.Name)); + Assert.isFalse(result.get(acc.Name).isEmpty()); } } @@ -1949,6 +1965,22 @@ private class SOQL_Test { Assert.areEqual(1, result.size()); // grouped by empty Industry } + @IsTest + static void toAggregatedMapWithCustomKeyAndCustomValue() { + // Setup + List accounts = insertAccounts(); + + // Test + Map> result = SOQL.of(Account.SObjectType).toAggregatedMap(Account.Name, Account.Id); + + // Verify + Assert.areEqual(accounts.size(), result.size()); + + for (Account acc : accounts) { + Assert.isFalse(result.get(acc.Name).isEmpty()); + } + } + @IsTest static void toQueryLocator() { // Test diff --git a/website/docs/api/soql.md b/website/docs/api/soql.md index e1541c33..f3fd609e 100644 --- a/website/docs/api/soql.md +++ b/website/docs/api/soql.md @@ -129,7 +129,9 @@ The following are methods for `SOQL`. - [`toAggregated()`](#toaggregated) - [`toMap()`](#tomap) - [`toMap(SObjectField keyField)`](#tomap-with-custom-key) +- [`toMap(SObjectField keyField, SObjectField valueField)`](#tomap-with-custom-key-and-value) - [`toAggregatedMap(SObjectField keyField)`](#toaggregatedmap) +- [`toAggregatedMap(SObjectField keyField, SObjectField valueField)`](#toaggregatedmap-with-custom-value) - [`toQueryLocator()`](#toquerylocator) ## INIT @@ -1479,7 +1481,7 @@ Map toMap() **Example** ```apex -SOQL.of(Account.SObjectType).toMap(); +Map idToAccount = (Map) SOQL.of(Account.SObjectType).toMap(); ``` ### toMap with custom key @@ -1496,6 +1498,21 @@ Map toMap(SObjectField keyField) Map nameToAccount = (Map) SOQL.of(Account.SObjectType).toMap(Account.Name); ``` +### toMap with custom key and value + +**Signature** + +```apex +Map toMap(SObjectField keyField, , SObjectField valueField) +``` + +**Example** + +```apex +Map nameToAccount = SOQL.of(Account.SObjectType).toMap(Account.Name, Account.Industry); +``` + + ### toAggregatedMap **Signature** @@ -1510,6 +1527,20 @@ Map> toAggregatedMap(SObjectField keyField) Map industryToAccounts = SOQL.of(Account.SObjectType).toAggregatedMap(Account.Industry); ``` +### toAggregatedMap with custom value + +**Signature** + +```apex +Map> toAggregatedMap(SObjectField keyField, SObjectField valueField) +``` + +**Example** + +```apex +Map> industryToAccounts = SOQL.of(Account.SObjectType).toAggregatedMap(Account.Industry, Account.Name); +``` + ### toQueryLocator **Signature** From 32d35e043c768efa5978f6461ab178d952032aa5 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 10 Oct 2023 10:48:40 +0200 Subject: [PATCH 11/15] Refactoring --- force-app/main/default/classes/SOQL.cls | 42 ++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 4e86e88a..df720b03 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -573,21 +573,21 @@ public virtual inherited sharing class SOQL implements Queryable { } public Map toMap() { - Map idToSObject = (Map) Type.forName('Map').newInstance(); - idToSObject.putAll(toList()); - return idToSObject; + Map recordPerId = (Map) Type.forName('Map').newInstance(); + recordPerId.putAll(toList()); + return recordPerId; } public Map toMap(SObjectField keyField) { with(keyField); - Map cutomKeyToRecord = (Map) Type.forName('Map').newInstance(); + Map recordPerCustomKey = (Map) Type.forName('Map').newInstance(); for (SObject record : toList()) { - cutomKeyToRecord.put(String.valueOf(record.get(keyField)), record); + recordPerCustomKey.put(String.valueOf(record.get(keyField)), record); } - return cutomKeyToRecord; + return recordPerCustomKey; } public Map toMap(SObjectField keyField, SObjectField valueField) { @@ -595,34 +595,34 @@ public virtual inherited sharing class SOQL implements Queryable { with(keyField, valueField); - Map cutomKeyToCustomValue = new Map(); + Map customValuePerCustomKey = new Map(); for (SObject record : toList()) { - cutomKeyToCustomValue.put( + customValuePerCustomKey.put( String.valueOf(record.get(keyField)), String.valueOf(record.get(valueField)) ); } - return cutomKeyToCustomValue; + return customValuePerCustomKey; } public Map> toAggregatedMap(SObjectField keyField) { with(keyField); - Map> cutomKeyToRecords = (Map>) Type.forName('Map>').newInstance(); + Map> recordsPerCustomKey = (Map>) Type.forName('Map>').newInstance(); for (SObject record : toList()) { - String customKey = String.valueOf(record.get(keyField)); + String key = String.valueOf(record.get(keyField)); - if (!cutomKeyToRecords.containsKey(customKey)) { - cutomKeyToRecords.put(customKey, new List()); + if (!recordsPerCustomKey.containsKey(key)) { + recordsPerCustomKey.put(key, new List()); } - cutomKeyToRecords.get(customKey).add(record); + recordsPerCustomKey.get(key).add(record); } - return cutomKeyToRecords; + return recordsPerCustomKey; } public Map> toAggregatedMap(SObjectField keyField, SObjectField valueField) { @@ -630,19 +630,19 @@ public virtual inherited sharing class SOQL implements Queryable { with(keyField, valueField); - Map> customKeyToValues = new Map>(); + Map> customValuesPerCustomKey = new Map>(); for (SObject record : toList()) { - String customKey = String.valueOf(record.get(keyField)); + String key = String.valueOf(record.get(keyField)); - if (!customKeyToValues.containsKey(customKey)) { - customKeyToValues.put(customKey, new List()); + if (!customValuesPerCustomKey.containsKey(key)) { + customValuesPerCustomKey.put(key, new List()); } - customKeyToValues.get(customKey).add(String.valueOf(record.get(valueField))); + customValuesPerCustomKey.get(key).add(String.valueOf(record.get(valueField))); } - return customKeyToValues; + return customValuesPerCustomKey; } public Database.QueryLocator toQueryLocator() { From 12f657af1a495573f74f6a8b3e09f370fcbbbedd Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 10 Oct 2023 12:12:59 +0200 Subject: [PATCH 12/15] refactoring --- force-app/main/default/classes/SOQL.cls | 155 +++++++++++++----------- 1 file changed, 86 insertions(+), 69 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index df720b03..3cb567b3 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -250,8 +250,6 @@ public virtual inherited sharing class SOQL implements Queryable { private QueryBuilder builder; private Executor executor; - private String ofObject; - public static SOQL of(SObjectType ofObject) { return new SOQL(ofObject); } @@ -265,10 +263,9 @@ public virtual inherited sharing class SOQL implements Queryable { } public SOQL(String ofObject) { - this.ofObject = ofObject; binder = new Binder(); - executor = new Executor(); builder = new QueryBuilder(ofObject); + executor = new Executor(ofObject, builder, binder); } public SOQL with(SObjectField field) { @@ -557,15 +554,15 @@ public virtual inherited sharing class SOQL implements Queryable { if (!builder.fields.hasCount()) { count(); } - return executor.toInteger(builder.toString(), binder.getBindingMap()); + return executor.toInteger(); } public SObject toObject() { - return executor.toObject(builder.toString(), binder.getBindingMap()); + return executor.toObject(); } public List toList() { - return executor.toList(builder.toString(), binder.getBindingMap()); + return executor.toList(); } public List toAggregated() { @@ -573,80 +570,33 @@ public virtual inherited sharing class SOQL implements Queryable { } public Map toMap() { - Map recordPerId = (Map) Type.forName('Map').newInstance(); - recordPerId.putAll(toList()); - return recordPerId; + return executor.toMap(); } public Map toMap(SObjectField keyField) { with(keyField); - - Map recordPerCustomKey = (Map) Type.forName('Map').newInstance(); - - for (SObject record : toList()) { - recordPerCustomKey.put(String.valueOf(record.get(keyField)), record); - } - - return recordPerCustomKey; + return executor.toMap(keyField); } public Map toMap(SObjectField keyField, SObjectField valueField) { builder.fields.clearAllFields(); // other fields not needed - with(keyField, valueField); - - Map customValuePerCustomKey = new Map(); - - for (SObject record : toList()) { - customValuePerCustomKey.put( - String.valueOf(record.get(keyField)), - String.valueOf(record.get(valueField)) - ); - } - - return customValuePerCustomKey; + return executor.toMap(keyField, valueField); } public Map> toAggregatedMap(SObjectField keyField) { with(keyField); - - Map> recordsPerCustomKey = (Map>) Type.forName('Map>').newInstance(); - - for (SObject record : toList()) { - String key = String.valueOf(record.get(keyField)); - - if (!recordsPerCustomKey.containsKey(key)) { - recordsPerCustomKey.put(key, new List()); - } - - recordsPerCustomKey.get(key).add(record); - } - - return recordsPerCustomKey; + return executor.toAggregatedMap(keyField); } public Map> toAggregatedMap(SObjectField keyField, SObjectField valueField) { builder.fields.clearAllFields(); // other fields not needed - with(keyField, valueField); - - Map> customValuesPerCustomKey = new Map>(); - - for (SObject record : toList()) { - String key = String.valueOf(record.get(keyField)); - - if (!customValuesPerCustomKey.containsKey(key)) { - customValuesPerCustomKey.put(key, new List()); - } - - customValuesPerCustomKey.get(key).add(String.valueOf(record.get(valueField))); - } - - return customValuesPerCustomKey; + return executor.toAggregatedMap(keyField, valueField); } public Database.QueryLocator toQueryLocator() { - return executor.toQueryLocator(builder.toString(), binder.getBindingMap()); + return executor.toQueryLocator(); } public SOQL byId(SObject record) { @@ -1577,6 +1527,15 @@ public virtual inherited sharing class SOQL implements Queryable { private DatabaseQuery sharingExecutor = new InheritedSharing(); private AccessType accessType; private String mockId; + private String ofObject; + private QueryBuilder builder; + private Binder binder; + + public Executor(String ofObject, QueryBuilder builder, Binder binder) { + this.ofObject = ofObject; + this.builder = builder; + this.binder = binder; + } public void withSharing() { sharingExecutor = new WithSharing(); @@ -1598,8 +1557,8 @@ public virtual inherited sharing class SOQL implements Queryable { mockId = id; } - public SObject toObject(String query, Map binding) { - List records = toList(query, binding); + public SObject toObject() { + List records = toList(); if (records.size() > 1) { QueryException e = new QueryException(); @@ -1614,31 +1573,89 @@ public virtual inherited sharing class SOQL implements Queryable { return records[0]; } - public List toList(String query, Map binding) { + public List toList() { if (mock.hasMock(mockId)) { return mock.getSObjectsMock(mockId); } if (accessType == null) { - return sharingExecutor.toSObjects(query, binding, accessMode); + return sharingExecutor.toSObjects(builder.toString(), binder.getBindingMap(), accessMode); } return Security.stripInaccessible( accessType, - sharingExecutor.toSObjects(query, binding, accessMode) + sharingExecutor.toSObjects(builder.toString(), binder.getBindingMap(), accessMode) ).getRecords(); } - public Integer toInteger(String query, Map binding) { + public Map toMap() { + Map recordPerId = (Map) Type.forName('Map').newInstance(); + recordPerId.putAll(toList()); + return recordPerId; + } + + public Map toMap(SObjectField keyField) { + Map recordPerCustomKey = (Map) Type.forName('Map').newInstance(); + + for (SObject record : toList()) { + recordPerCustomKey.put(String.valueOf(record.get(keyField)), record); + } + + return recordPerCustomKey; + } + + public Map toMap(SObjectField keyField, SObjectField valueField) { + Map customValuePerCustomKey = new Map(); + + for (SObject record : toList()) { + customValuePerCustomKey.put(String.valueOf(record.get(keyField)), String.valueOf(record.get(valueField))); + } + + return customValuePerCustomKey; + } + + public Map> toAggregatedMap(SObjectField keyField) { + Map> recordsPerCustomKey = (Map>) Type.forName('Map>').newInstance(); + + for (SObject record : toList()) { + String key = String.valueOf(record.get(keyField)); + + if (!recordsPerCustomKey.containsKey(key)) { + recordsPerCustomKey.put(key, new List()); + } + + recordsPerCustomKey.get(key).add(record); + } + + return recordsPerCustomKey; + } + + public Map> toAggregatedMap(SObjectField keyField, SObjectField valueField) { + Map> customValuesPerCustomKey = new Map>(); + + for (SObject record : toList()) { + String key = String.valueOf(record.get(keyField)); + + if (!customValuesPerCustomKey.containsKey(key)) { + customValuesPerCustomKey.put(key, new List()); + } + + customValuesPerCustomKey.get(key).add(String.valueOf(record.get(valueField))); + } + + return customValuesPerCustomKey; + } + + public Integer toInteger() { if (mock.hasCountMock(mockId)) { return mock.getCountMock(mockId); } - return sharingExecutor.toInteger(query, binding, accessMode); + return sharingExecutor.toInteger(builder.toString(), binder.getBindingMap(), accessMode); } - public Database.QueryLocator toQueryLocator(String query, Map binding) { - return Database.getQueryLocatorWithBinds(query, binding, accessMode); + public Database.QueryLocator toQueryLocator() { + return Database.getQueryLocatorWithBinds(builder.toString(), binder.getBindingMap(), accessMode); } } From 36c9ecb25ad62de399daa6c3efe1eaa5981fadfa Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 10 Oct 2023 15:01:10 +0200 Subject: [PATCH 13/15] Binder Fix --- force-app/main/default/classes/SOQL.cls | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 3cb567b3..6de22951 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -265,7 +265,7 @@ public virtual inherited sharing class SOQL implements Queryable { public SOQL(String ofObject) { binder = new Binder(); builder = new QueryBuilder(ofObject); - executor = new Executor(ofObject, builder, binder); + executor = new Executor(ofObject, builder); } public SOQL with(SObjectField field) { @@ -1529,12 +1529,10 @@ public virtual inherited sharing class SOQL implements Queryable { private String mockId; private String ofObject; private QueryBuilder builder; - private Binder binder; - public Executor(String ofObject, QueryBuilder builder, Binder binder) { + public Executor(String ofObject, QueryBuilder builder) { this.ofObject = ofObject; this.builder = builder; - this.binder = binder; } public void withSharing() { From b01c1cf9d5b4e615cc7d55ee303e1423992501c3 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 10 Oct 2023 15:36:52 +0200 Subject: [PATCH 14/15] Refactoring --- force-app/main/default/classes/SOQL.cls | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 6de22951..7f89b7e2 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -728,7 +728,6 @@ public virtual inherited sharing class SOQL implements Queryable { private class QFields implements QueryClause { private Set fields = new Set(); private Set aggregatedFields = new Set(); - private Boolean hasCount = false; public void count() { count('COUNT()'); @@ -744,7 +743,6 @@ public virtual inherited sharing class SOQL implements Queryable { } private void count(String count) { - this.hasCount = true; withAggregatedField(count); fields.add(count); } @@ -797,7 +795,7 @@ public virtual inherited sharing class SOQL implements Queryable { } public Boolean hasCount() { - return hasCount; + return !aggregatedFields.isEmpty(); } public override String toString() { From bebf3b0747907f27f97099d90b0525c659f7a121 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 10 Oct 2023 16:33:41 +0200 Subject: [PATCH 15/15] Refactoring --- force-app/main/default/classes/SOQL.cls | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 7f89b7e2..f270545e 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -220,9 +220,9 @@ public virtual inherited sharing class SOQL implements Queryable { public interface InnerJoin { InnerJoin of(SObjectType ofObject); - + // SELECT InnerJoin with(SObjectField field); - + // WHERE InnerJoin whereAre(FilterGroup filterGroup); InnerJoin whereAre(Filter filter); } @@ -1396,12 +1396,12 @@ public virtual inherited sharing class SOQL implements Queryable { private String sortingOrder = 'ASC'; private String nullsOrder = 'FIRST'; - public QOrderBy with(SObjectField field) { - return with(field.getDescribe().getName()); + public void with(SObjectField field) { + with(field.getDescribe().getName()); } - public QOrderBy with(String relationshipName, SObjectField field) { - return with(relationshipName + '.' + field); + public void with(String relationshipName, SObjectField field) { + with(relationshipName + '.' + field); } public QOrderBy with(String field) { @@ -1413,9 +1413,8 @@ public virtual inherited sharing class SOQL implements Queryable { sortingOrder('DESC'); } - public QOrderBy sortingOrder(String direction) { + public void sortingOrder(String direction) { sortingOrder = direction; - return this; } public void nullsLast() { @@ -1482,7 +1481,6 @@ public virtual inherited sharing class SOQL implements Queryable { public String bind(Object value) { bindIndex++; binding.put('v' + bindIndex, value); - return 'v' + bindIndex; }