This repository has been archived by the owner on Jun 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
QueryBuilder.cls split into 3 new query builder classes - SObjectQueryBuilder (standard SOQL queries, AggregateResultQueryBuilder (aggregate SOQL queries) and SearchQueryBuilder (SOSL queries) * QueryBuilder.cls is now an abstract class, used by the 3 types of query builders for shared logic * Added QueryField.cls - parses an SObjectField or list of SObjectFields into the SOQL/SOSL string version. This can be used as a field in your 'SELECT' statement, as a field for QueryFilter, and in the 'ORDER BY' statement * Added QueryDate.cls - this represents date functions for date & datetime fields, like 'CALENDAR_MONTH(CreatedDate)'. QueryDates can be used in QueryFilter, as an aggregate result field, and in the 'ORDER BY' statement - DML methods now return a list of corresponding database result types - Began adding ApexDoc to classes
- Loading branch information
Showing
80 changed files
with
2,283 additions
and
744 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
cwd: '{PROJECT_PATH}' | ||
cmd: java -jar .\tools\apexdoc\apexdoc.jar -s .\src\classes -t . -p public;protected -g https://github.com/jongpie/NebulaFramework/blob/master/src/classes/ -a header.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
/************************************************************************************************* | ||
* This file is part of the Nebula Framework project, released under the MIT License. * | ||
* See LICENSE file or go to https://github.com/jongpie/NebulaFramework for full license details. * | ||
*************************************************************************************************/ | ||
|
||
/** | ||
* | ||
* @group Query Builder | ||
* | ||
* @description A builder class that generates dynamic queries & returns a list of AggregateResult | ||
* | ||
*/ | ||
public class AggregateResultQueryBuilder extends QueryBuilder implements IAggregateResultQueryBuilder { | ||
|
||
private Schema.SObjectType sobjectType; | ||
private List<String> groupByList; | ||
private List<String> aggregateFunctionList; | ||
|
||
public AggregateResultQueryBuilder(Schema.SObjectType sobjectType) { | ||
this.sobjectType = sobjectType; | ||
|
||
this.aggregateFunctionList = new List<String>(); | ||
this.groupByList = new List<String>(); | ||
} | ||
|
||
public IAggregateResultQueryBuilder groupBy(IQueryField groupByQueryField) { | ||
return this.groupBy(new List<IQueryField>{groupByQueryField}); | ||
} | ||
|
||
public IAggregateResultQueryBuilder groupBy(List<IQueryField> groupByQueryFields) { | ||
for(IQueryField groupByQueryField : groupByQueryFields) this.groupByList.add(groupByQueryField.getValue()); | ||
return this; | ||
} | ||
|
||
public IAggregateResultQueryBuilder groupBy(Schema.FieldSet fieldSet) { | ||
for(Schema.FieldSetMember field : fieldSet.getFields()) this.groupByList.add(field.getFieldPath()); | ||
return this; | ||
} | ||
|
||
public IAggregateResultQueryBuilder groupBy(QueryDate groupByQueryDate) { | ||
this.groupByList.add(groupByQueryDate.getValue()); | ||
return this; | ||
} | ||
|
||
/** | ||
* @description Adds the average value of the numeric field to the dynamically generated aggregate query | ||
* @param numericQueryField The field to use for calculating the average | ||
* @return The instance of IAggregateResultQueryBuilder, to allow chaining methods | ||
*/ | ||
public IAggregateResultQueryBuilder avg(IQueryField numericQueryField) { | ||
return this.avg(numericQueryField, null); | ||
} | ||
|
||
public IAggregateResultQueryBuilder avg(IQueryField numericQueryField, String fieldAlias) { | ||
return buildAggregateFunction('AVG', numericQueryField, fieldAlias); | ||
} | ||
|
||
public IAggregateResultQueryBuilder count(IQueryField queryField) { | ||
return this.count(queryField, null); | ||
} | ||
|
||
public IAggregateResultQueryBuilder count(IQueryField queryField, String fieldAlias) { | ||
return buildAggregateFunction('COUNT', queryField, fieldAlias); | ||
} | ||
|
||
public IAggregateResultQueryBuilder countDistinct(IQueryField queryField) { | ||
return this.countDistinct(queryField, null); | ||
} | ||
|
||
public IAggregateResultQueryBuilder countDistinct(IQueryField queryField, String fieldAlias) { | ||
return buildAggregateFunction('COUNT_DISTINCT', queryField, fieldAlias); | ||
} | ||
|
||
/** | ||
* @description Adds the maximum value of the field to the dynamically generated aggregate query | ||
* @param queryField The field to use for calculating the maximum | ||
* @return The instance of IAggregateResultQueryBuilder, to allow chaining methods | ||
*/ | ||
public IAggregateResultQueryBuilder max(IQueryField queryField) { | ||
return this.max(queryField, null); | ||
} | ||
|
||
public IAggregateResultQueryBuilder max(IQueryField queryField, String fieldAlias) { | ||
return buildAggregateFunction('MAX', queryField, fieldAlias); | ||
} | ||
|
||
/** | ||
* @description Adds the minimum value of the field to the dynamically generated aggregate query | ||
* @param queryField The field to use for calculating the minimum | ||
* @return The instance of IAggregateResultQueryBuilder, to allow chaining methods | ||
*/ | ||
public IAggregateResultQueryBuilder min(IQueryField queryField) { | ||
return this.min(queryField, null); | ||
} | ||
|
||
public IAggregateResultQueryBuilder min(IQueryField queryField, String fieldAlias) { | ||
return buildAggregateFunction('MIN', queryField, fieldAlias); | ||
} | ||
|
||
/** | ||
* @description Sums the values of the supplied numeric field to the dynamically generated aggregate query | ||
* @param numericQueryField The field to use for calculating the minimum | ||
* @return The instance of IAggregateResultQueryBuilder, to allow chaining methods | ||
*/ | ||
public IAggregateResultQueryBuilder sum(IQueryField numericQueryField) { | ||
return this.sum(numericQueryField, null); | ||
} | ||
|
||
public IAggregateResultQueryBuilder sum(IQueryField numericQueryField, String fieldAlias) { | ||
return buildAggregateFunction('SUM', numericQueryField, fieldAlias); | ||
} | ||
|
||
public IAggregateResultQueryBuilder filterBy(IQueryFilter queryFilter) { | ||
super.doFilterBy(queryFilter); | ||
return this; | ||
} | ||
|
||
public IAggregateResultQueryBuilder filterBy(List<IQueryFilter> queryFilters) { | ||
super.doFilterBy(queryFilters); | ||
return this; | ||
} | ||
|
||
public IAggregateResultQueryBuilder orderBy(IQueryField orderByQueryField) { | ||
super.doOrderBy(orderByQueryField); | ||
return this; | ||
} | ||
|
||
public IAggregateResultQueryBuilder orderBy(IQueryField orderByQueryField, QuerySortOrder sortOrder) { | ||
super.doOrderBy(orderByQueryField, sortOrder); | ||
return this; | ||
} | ||
|
||
public IAggregateResultQueryBuilder orderBy(IQueryField orderByQueryField, QuerySortOrder sortOrder, QueryNullSortOrder nullsSortOrder) { | ||
super.doOrderBy(orderByQueryField, sortOrder, nullsSortOrder); | ||
return this; | ||
} | ||
|
||
public IAggregateResultQueryBuilder limitCount(Integer limitCount) { | ||
super.doLimitCount(limitCount); | ||
return this; | ||
} | ||
|
||
public String getQuery() { | ||
String queryString = 'SELECT ' + this.getGroupByFieldString(false) + this.getAggregateFunctionString() | ||
+ '\nFROM ' + this.sobjectType.getDescribe().getName() | ||
+ super.doGetWhereClauseString() | ||
+ this.getGroupByFieldString(true) | ||
+ super.doGetOrderByString() | ||
+ super.doGetLimitCountString(); | ||
|
||
return queryString; | ||
} | ||
|
||
public AggregateResult getFirstQueryResult() { | ||
return this.getQueryResults()[0]; | ||
} | ||
|
||
public List<AggregateResult> getQueryResults() { | ||
return super.doGetQueryResults(this.getQuery()); | ||
} | ||
|
||
private String getGroupByFieldString(Boolean appendGroupByString) { | ||
String prefix = appendGroupByString && !this.groupByList.isEmpty() ? '\nGROUP BY ' : ''; | ||
return prefix + String.join(this.groupByList, ', '); | ||
} | ||
|
||
private String getAggregateFunctionString() { | ||
if(this.groupByList.isEmpty() && this.aggregateFunctionList.isEmpty()) return 'COUNT(Id) COUNT__Id'; | ||
|
||
this.aggregateFunctionList.sort(); | ||
// The extra delimiter adds a comma when needed for grouping by fields & aggregate functions | ||
// Example: 'Type, COUNT_DISTINCT(OwnerId)' | ||
String extraDelimiter = getGroupByFieldString(false) == null ? '' : ',\n'; | ||
return extraDelimiter + String.join(this.aggregateFunctionList, ', '); | ||
} | ||
|
||
private IAggregateResultQueryBuilder buildAggregateFunction(String functionName, IQueryField queryField) { | ||
return this.buildAggregateFunction(functionName, queryField, null); | ||
} | ||
|
||
private IAggregateResultQueryBuilder buildAggregateFunction(String functionName, IQueryField queryField, String fieldAlias) { | ||
if(fieldAlias == null) fieldAlias = functionName + '__' + queryField.getValue(); | ||
// Alias: MIN(Schema.Lead.MyField__c) is auto-aliased to MIN_MyField__c | ||
this.aggregateFunctionList.add(functionName + '(' + queryField.getValue() + ') ' + fieldAlias); | ||
return this; | ||
} | ||
|
||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/************************************************************************************************* | ||
* This file is part of the Nebula Framework project, released under the MIT License. * | ||
* See LICENSE file or go to https://github.com/jongpie/NebulaFramework for full license details. * | ||
*************************************************************************************************/ | ||
@isTest | ||
private class AggregateResultQueryBuilder_Tests { | ||
|
||
@isTest | ||
static void it_should_build_a_ridiculous_query_string() { | ||
String expectedString = 'SELECT Type,\nAVG(Amount) AVG__Amount, COUNT(AccountId) COUNT__AccountId, ' | ||
+ 'COUNT_DISTINCT(OwnerId) COUNT_DISTINCT__OwnerId, MAX(CreatedDate) MAX__CreatedDate, MIN(CreatedDate) MIN__CreatedDate' | ||
+ '\nFROM Opportunity' | ||
+ '\nGROUP BY Type'; | ||
|
||
IAggregateResultQueryBuilder aggregateResultQueryBuilder = new AggregateResultQueryBuilder(Schema.Opportunity.SObjectType) | ||
.max(new QueryField(Schema.Opportunity.CreatedDate)) | ||
.avg(new QueryField(Schema.Opportunity.Amount)) | ||
.countDistinct(new QueryField(Schema.Opportunity.OwnerId)) | ||
.min(new QueryField(Schema.Opportunity.CreatedDate)) | ||
.groupBy(new QueryField(Schema.Opportunity.Type)) | ||
.count(new QueryField(Schema.Opportunity.AccountId)); | ||
String returnedQueryString = aggregateResultQueryBuilder.getQuery(); | ||
|
||
System.assertEquals(expectedString, returnedQueryString); | ||
|
||
// Verify that the query can be executed | ||
Database.query(returnedQueryString); | ||
} | ||
|
||
|
||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.