Skip to content

Commit ac25ba2

Browse files
release/v3.2.3 (#115)
* implement group by related object field support and introduce new tests (#113) * add new scratch org and illuminated cloud symbol table definitions to .gitignore * add new scratch org and illuminated cloud symbol table definitions to .gitignore * update sfdx-project.json `sourceApiVersion` to 60 * implement group by related object field support and introduce new tests * enable group by functionality for related object fields (#1) * add new scratch org and illuminated cloud symbol table definitions to .gitignore * add new scratch org and illuminated cloud symbol table definitions to .gitignore * update sfdx-project.json `sourceApiVersion` to 60 * implement group by related object field support and introduce new tests * update tests to match existing conventions and remove redundant calls to `.getDescribe().getName()` * groupBy Related documentation Signed-off-by: Piotr PG Gajek <[email protected]> * Typo fix Signed-off-by: Piotr PG Gajek <[email protected]> * code refactoring Signed-off-by: Piotr PG Gajek <[email protected]> * Refactoring Signed-off-by: Piotr PG Gajek <[email protected]> * groupByRollup related and groupByCube related Signed-off-by: Piotr PG Gajek <[email protected]> --------- Signed-off-by: Piotr PG Gajek <[email protected]> Co-authored-by: Jesse Wheeler <[email protected]>
1 parent 2a01f75 commit ac25ba2

File tree

5 files changed

+222
-21
lines changed

5 files changed

+222
-21
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,9 @@ $RECYCLE.BIN/
5555

5656
#Private keys
5757
*.key
58+
59+
# Additional scratch org definitions
60+
/config/*
61+
62+
# Illuminated Cloud Symbol Tables
63+
/IlluminatedCloud/*

force-app/main/default/classes/SOQL.cls

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,11 @@ public virtual inherited sharing class SOQL implements Queryable {
110110
Queryable anyConditionMatching();
111111
// GROUP BY
112112
Queryable groupBy(SObjectField field);
113+
Queryable groupBy(String relationshipName, SObjectField field);
113114
Queryable groupByRollup(SObjectField field);
115+
Queryable groupByRollup(String relationshipName, SObjectField field);
114116
Queryable groupByCube(SObjectField field);
117+
Queryable groupByCube(String relationshipName, SObjectField field);
115118
// ORDER BY
116119
Queryable orderBy(String field);
117120
Queryable orderBy(String field, String direction);
@@ -170,7 +173,7 @@ public virtual inherited sharing class SOQL implements Queryable {
170173
SubQuery with(SObjectField field1, SObjectField field2, SObjectField field3);
171174
SubQuery with(SObjectField field1, SObjectField field2, SObjectField field3, SObjectField field4);
172175
SubQuery with(SObjectField field1, SObjectField field2, SObjectField field3, SObjectField field4, SObjectField field5);
173-
SubQuery with(List<SObjectField> fields);
176+
SubQuery with(Iterable<SObjectField> fields);
174177
SubQuery with(String relationshipName, Iterable<SObjectField> fields);
175178
SubQuery with(SubQuery subQuery);
176179
// WHERE
@@ -223,7 +226,7 @@ public virtual inherited sharing class SOQL implements Queryable {
223226
Filter greaterThan(Object value);
224227
Filter lessOrEqual(Object value);
225228
Filter greaterOrEqual(Object value);
226-
Filter containsSome(List<String> values);
229+
Filter containsSome(Iterable<String> values);
227230
Filter contains(String value);
228231
Filter notContains(String value);
229232
Filter endsWith(String value);
@@ -568,18 +571,36 @@ public virtual inherited sharing class SOQL implements Queryable {
568571
return this;
569572
}
570573

574+
public SOQL groupBy(String relationshipName, SObjectField field) {
575+
builder.groupBy.with(relationshipName, field);
576+
builder.fields.withGroupedField(relationshipName, field);
577+
return this;
578+
}
579+
571580
public SOQL groupByRollup(SObjectField field) {
572581
builder.groupBy.rollup(field);
573582
builder.fields.withGroupedField(field);
574583
return this;
575584
}
576585

586+
public SOQL groupByRollup(String relationshipName, SObjectField field) {
587+
builder.groupBy.rollup(relationshipName, field);
588+
builder.fields.withGroupedField(relationshipName, field);
589+
return this;
590+
}
591+
577592
public SOQL groupByCube(SObjectField field) {
578593
builder.groupBy.cube(field);
579594
builder.fields.withGroupedField(field);
580595
return this;
581596
}
582597

598+
public SOQL groupByCube(String relationshipName, SObjectField field) {
599+
builder.groupBy.cube(relationshipName, field);
600+
builder.fields.withGroupedField(relationshipName, field);
601+
return this;
602+
}
603+
583604
public SOQL orderBy(String field) {
584605
builder.orderBys.newOrderBy().with(field);
585606
return this;
@@ -962,6 +983,10 @@ public virtual inherited sharing class SOQL implements Queryable {
962983
groupedFields.add(field.getDescribe().getName());
963984
}
964985

986+
public void withGroupedField(String relationshipName, SObjectField field) {
987+
groupedFields.add(relationshipName + '.' + field);
988+
}
989+
965990
public void with(String commaSeparatedFields) {
966991
// Added to Set to avoid field duplicates in query
967992
for (String splittedField : commaSeparatedFields.split(',')) {
@@ -979,7 +1004,7 @@ public virtual inherited sharing class SOQL implements Queryable {
9791004
return field.contains('(') && field.contains(')') || field.contains(' ');
9801005
}
9811006

982-
public void with(List<SObjectField> fields) {
1007+
public void with(Iterable<SObjectField> fields) {
9831008
for (SObjectField field : fields) {
9841009
with(field);
9851010
}
@@ -1088,7 +1113,7 @@ public virtual inherited sharing class SOQL implements Queryable {
10881113
return with(field1, field2, field3, field4).with(field5);
10891114
}
10901115

1091-
public SubQuery with(List<SObjectField> fields) {
1116+
public SubQuery with(Iterable<SObjectField> fields) {
10921117
builder.fields.with(fields);
10931118
return this;
10941119
}
@@ -1432,7 +1457,7 @@ public virtual inherited sharing class SOQL implements Queryable {
14321457
return set('>=', value);
14331458
}
14341459

1435-
public Filter containsSome(List<String> values) {
1460+
public Filter containsSome(Iterable<String> values) {
14361461
return set('LIKE', values);
14371462
}
14381463

@@ -1496,27 +1521,25 @@ public virtual inherited sharing class SOQL implements Queryable {
14961521
}
14971522

14981523
public Filter includesAll(Iterable<String> iterable) {
1499-
// Bind expressions can't be used with other clauses, such as INCLUDES.
1500-
skipBinding = true;
1501-
return set('INCLUDES', '(\'' + String.join(iterable, ';') + '\')');
1524+
return setMultipicklistFilter('INCLUDES', iterable, ';');
15021525
}
15031526

15041527
public Filter includesSome(Iterable<String> iterable) {
1505-
// Bind expressions can't be used with other clauses, such as INCLUDES.
1506-
skipBinding = true;
1507-
return set('INCLUDES', '(\'' + String.join(iterable, '\', \'') + '\')');
1528+
return setMultipicklistFilter('INCLUDES', iterable, '\', \'');
15081529
}
15091530

15101531
public Filter excludesAll(Iterable<String> iterable) {
1511-
// Bind expressions can't be used with other clauses, such as EXCLUDES.
1512-
skipBinding = true;
1513-
return set('EXCLUDES', '(\'' + String.join(iterable, '\', \'') + '\')');
1532+
return setMultipicklistFilter('EXCLUDES', iterable, '\', \'');
15141533
}
15151534

15161535
public Filter excludesSome(Iterable<String> iterable) {
1517-
// Bind expressions can't be used with other clauses, such as EXCLUDES.
1518-
skipBinding = true;
1519-
return set('EXCLUDES', '(\'' + String.join(iterable, ';') + '\')');
1536+
return setMultipicklistFilter('EXCLUDES', iterable, ';');
1537+
}
1538+
1539+
public Filter setMultipicklistFilter(String operator, Iterable<String> iterable, String separator) {
1540+
// Bind expressions can't be used with other clauses, such as INCLUDES, EXCLUDES
1541+
skipBinding = true;
1542+
return set(operator, '(\'' + String.join(iterable, separator) + '\')');
15201543
}
15211544

15221545
private Filter set(String comperator, Object value) {
@@ -1585,18 +1608,42 @@ public virtual inherited sharing class SOQL implements Queryable {
15851608
private String groupByFunction = '';
15861609

15871610
public void with(SObjectField field) {
1611+
with(field.getDescribe().getName());
1612+
}
1613+
1614+
public void with(String relationshipName, SObjectField field) {
1615+
with(relationshipName + '.' + field);
1616+
}
1617+
1618+
private void with(String field) {
15881619
setGroupByFunction('{0}');
1589-
groupByFields.add(field.getDescribe().getName());
1620+
groupByFields.add(field.trim());
15901621
}
15911622

15921623
public void rollup(SObjectField field) {
1624+
rollup(field.getDescribe().getName());
1625+
}
1626+
1627+
public void rollup(String relationshipName, SObjectField field) {
1628+
rollup(relationshipName + '.' + field);
1629+
}
1630+
1631+
private void rollup(String field) {
15931632
setGroupByFunction('ROLLUP({0})');
1594-
groupByFields.add(field.getDescribe().getName());
1633+
groupByFields.add(field.trim());
15951634
}
15961635

15971636
public void cube(SObjectField field) {
1637+
cube(field.getDescribe().getName());
1638+
}
1639+
1640+
public void cube(String relationshipName, SObjectField field) {
1641+
cube(relationshipName + '.' + field);
1642+
}
1643+
1644+
private void cube(String field) {
15981645
setGroupByFunction('CUBE({0})');
1599-
groupByFields.add(field.getDescribe().getName());
1646+
groupByFields.add(field.trim());
16001647
}
16011648

16021649
public void setGroupByFunction(String newGroupByFunction) {

force-app/main/default/classes/SOQL_Test.cls

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,6 +1702,33 @@ private class SOQL_Test {
17021702
Assert.areEqual('SELECT LeadSource FROM Lead GROUP BY LeadSource', soql);
17031703
}
17041704

1705+
@IsTest
1706+
static void groupByRelated() {
1707+
// Test
1708+
String soql = SOQL.of(OpportunityLineItem.SObjectType)
1709+
.count(OpportunityLineItem.Name, 'count')
1710+
.groupBy('OpportunityLineItem.Opportunity.Account', Account.Id)
1711+
.toString();
1712+
1713+
// Verify
1714+
Assert.areEqual('SELECT COUNT(Name) count FROM OpportunityLineItem GROUP BY OpportunityLineItem.Opportunity.Account.Id', soql);
1715+
}
1716+
1717+
@IsTest
1718+
static void groupByRelatedToAggregated() {
1719+
// Setup
1720+
List<Account> accounts = insertAccounts();
1721+
1722+
// Test
1723+
List<AggregateResult> results = SOQL.of(Account.SObjectType)
1724+
.count(Account.Name, 'names')
1725+
.groupBy('Account.CreatedBy', User.Id)
1726+
.toAggregated();
1727+
1728+
// Verify
1729+
Assert.areEqual(1, results.size());
1730+
}
1731+
17051732
@IsTest
17061733
static void groupByRollup() {
17071734
// Test
@@ -1715,6 +1742,32 @@ private class SOQL_Test {
17151742
Assert.areEqual('SELECT LeadSource, COUNT(Name) cnt FROM Lead GROUP BY ROLLUP(LeadSource)', soql);
17161743
}
17171744

1745+
@IsTest
1746+
static void groupByRollupManyFields() {
1747+
// Test
1748+
String soql = SOQL.of(Lead.SObjectType)
1749+
.count(Lead.Name, 'cnt')
1750+
.with(Lead.Status, Lead.LeadSource)
1751+
.groupByRollup(Lead.Status)
1752+
.groupByRollup(Lead.LeadSource)
1753+
.toString();
1754+
1755+
// Verify
1756+
Assert.areEqual('SELECT Status, LeadSource, COUNT(Name) cnt FROM Lead GROUP BY ROLLUP(Status, LeadSource)', soql);
1757+
}
1758+
1759+
@IsTest
1760+
static void groupByRollupRelated() {
1761+
// Test
1762+
String soql = SOQL.of(Lead.SObjectType)
1763+
.count(Lead.Name, 'cnt')
1764+
.groupByRollup('ConvertedOpportunity', Opportunity.StageName)
1765+
.toString();
1766+
1767+
// Verify
1768+
Assert.areEqual('SELECT COUNT(Name) cnt FROM Lead GROUP BY ROLLUP(ConvertedOpportunity.StageName)', soql);
1769+
}
1770+
17181771
@IsTest
17191772
static void groupByCube() {
17201773
// Test
@@ -1727,6 +1780,31 @@ private class SOQL_Test {
17271780
Assert.areEqual('SELECT Type FROM Account GROUP BY CUBE(Type)', soql);
17281781
}
17291782

1783+
@IsTest
1784+
static void groupByCubeManyFields() {
1785+
// Test
1786+
String soql = SOQL.of(Account.SObjectType)
1787+
.with(Account.Type, Account.BillingCountry)
1788+
.groupByCube(Account.Type)
1789+
.groupByCube(Account.BillingCountry)
1790+
.toString();
1791+
1792+
// Verify
1793+
Assert.areEqual('SELECT Type, BillingCountry FROM Account GROUP BY CUBE(Type, BillingCountry)', soql);
1794+
}
1795+
1796+
@IsTest
1797+
static void groupByCubeRelated() {
1798+
// Test
1799+
String soql = SOQL.of(Lead.SObjectType)
1800+
.count(Lead.Name, 'cnt')
1801+
.groupByCube('ConvertedOpportunity', Opportunity.StageName)
1802+
.toString();
1803+
1804+
// Verify
1805+
Assert.areEqual('SELECT COUNT(Name) cnt FROM Lead GROUP BY CUBE(ConvertedOpportunity.StageName)', soql);
1806+
}
1807+
17301808
@IsTest
17311809
static void differentGroupByFunctionsException() {
17321810
// Setup

sfdx-project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
"name": "BeyondTheCloud",
99
"namespace": "",
1010
"sfdcLoginUrl": "https://login.salesforce.com",
11-
"sourceApiVersion": "54.0"
11+
"sourceApiVersion": "60.0"
1212
}

0 commit comments

Comments
 (0)