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)