Skip to content

Added ability to auto-generate bind variable keys and specify filter logic #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
00d196d
Bumped API versions to 60.0 (Spring '24)
superkensington Apr 29, 2024
82c6d68
Added support for using System.AccessLevel (#36)
superkensington Apr 29, 2024
100d090
Added support for using bind variables with new Database query method…
superkensington May 7, 2024
f183a76
Update project API version to 60.0 (Spring '24)
superkensington May 7, 2024
158db75
Rename method parameter names for consistency
superkensington Jun 24, 2024
f497090
Set SOSL access level in base class
superkensington Jun 24, 2024
9a3f1c7
Bumped API versions to 61.0 (Summer '24)
superkensington Jun 24, 2024
b719a2c
Adds base properties and methods for auto-generating bind variable keys
superkensington Jun 24, 2024
e25b734
Updates havingAggregate method to auto-generate bind variable key
superkensington Jun 24, 2024
5fefc20
Updates doFilterWhere and doOrFilterWhere methods to auto-generate bi…
superkensington Jun 24, 2024
8d7db9e
Updates QueryFilter inner class to generate formattedValue and string…
superkensington Jun 24, 2024
12ee75b
Initial tests
superkensington Jun 24, 2024
b94879b
Retain complete "WHERE" QueryFilter instances instead of strings, gen…
superkensington Jun 29, 2024
b4556d0
Fix removal of bind keys
superkensington Jun 29, 2024
bb43208
Update tests to account for "WHERE" filters no longer being sorted, u…
superkensington Jun 29, 2024
249c971
Additional test
superkensington Jun 29, 2024
169fb52
Made SOQL.QueryFilter virtual and extended with new AggregateQuery.Ag…
superkensington Jun 30, 2024
ee03def
Updated AggregateQuery to handle HAVING filters with AggregateQueryFi…
superkensington Jun 30, 2024
7045be0
Refactored HAVING and WHERE clause stringification into single common…
superkensington Jun 30, 2024
fccae96
Rename variables and methods for clarity and consistency
superkensington Jun 30, 2024
39a9dd4
Refactored OR filter methods into single common method
superkensington Jun 30, 2024
e7fa0b2
Updated "setHasChanged" methods to invoke corresponding base method
superkensington Jun 30, 2024
198fd42
Fix OR filter methods refactor
superkensington Jul 1, 2024
bb0c8f2
Add methods to set custom HAVING and WHERE clause logic
superkensington Jul 1, 2024
d565b32
Tests for custom HAVING and WHERE clause logic
superkensington Jul 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 119 additions & 13 deletions nebula-query-and-search/main/classes/AggregateQuery.cls
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@
global class AggregateQuery extends SOQL {
private SOQL.GroupingDimension groupingDimension;
private List<AggregateField> aggregateFields;
private List<String> havingConditions;
private List<AggregateQueryFilter> havingClauseFilters;
protected String havingClauseFilterLogic;
private String countQuery;

global AggregateQuery(Schema.SObjectType sobjectType) {
super(sobjectType, false);

this.aggregateFields = new List<AggregateField>();
this.havingConditions = new List<String>();
this.havingClauseFilters = new List<AggregateQueryFilter>();
this.havingClauseFilterLogic = '';
}

global AggregateQuery groupByField(Schema.SObjectField field) {
Expand Down Expand Up @@ -79,19 +82,48 @@ global class AggregateQuery extends SOQL {
return this.havingAggregate(aggregateFunction, new SOQL.QueryField(field), operator, value);
}

global AggregateQuery havingAggregate(SOQL.Aggregate aggregateFunction, Schema.SObjectField field, SOQL.Operator operator, Object value, String bindWithKey) {
return this.havingAggregate(aggregateFunction, new SOQL.QueryField(field), operator, value, bindWithKey);
}

global AggregateQuery havingAggregate(SOQL.Aggregate aggregateFunction, SOQL.QueryField queryField, SOQL.Operator operator, Object value) {
this.havingConditions.add(aggregateFunction.name() + '(' + queryField + ') ' + SOQL.getOperatorValue(operator) + ' ' + value);
return this.havingAggregate(aggregateFunction, queryField, operator, value, this.generateNextBindVariableKey());
}

global AggregateQuery havingAggregate(SOQL.Aggregate aggregateFunction, SOQL.QueryField queryField, SOQL.Operator operator, Object value, String bindWithKey) {
this.havingClauseFilters.add(
new AggregateQueryFilter(aggregateFunction, queryField, operator, value, bindWithKey)
);
this.havingClauseFilterLogic += (this.havingClauseFilters.size() == 1 ? '1' : ' AND ' + this.havingClauseFilters.size());
return this.setHasChanged();
}

global AggregateQuery orHavingAggregate(List<AggregateQueryFilter> filters) {
this.havingClauseFilterLogic = this.doOrFilter(filters, this.havingClauseFilters, this.havingClauseFilterLogic);
return this.setHasChanged();
}

global AggregateQuery setHavingFilterLogic(String filterLogic) {
this.havingClauseFilterLogic = filterLogic;
return this.setHasChanged();
}

global AggregateQuery filterWhere(Schema.SObjectField field, SOQL.Operator operator, Object value) {
return this.filterWhere(new SOQL.QueryField(field), operator, value);
}

global AggregateQuery filterWhere(Schema.SObjectField field, SOQL.Operator operator, Object value, String bindWithKey) {
return this.filterWhere(new SOQL.QueryField(field), operator, value, bindWithKey);
}

global AggregateQuery filterWhere(SOQL.QueryField queryField, SOQL.Operator operator, Object value) {
return this.filterWhere(new SOQL.QueryFilter(queryField, operator, value));
}

global AggregateQuery filterWhere(SOQL.QueryField queryField, SOQL.Operator operator, Object value, String bindWithKey) {
return this.filterWhere(new SOQL.QueryFilter(queryField, operator, value, bindWithKey));
}

global AggregateQuery filterWhere(SOQL.QueryFilter filter) {
return this.filterWhere(new List<SOQL.QueryFilter>{ filter });
}
Expand All @@ -106,6 +138,16 @@ global class AggregateQuery extends SOQL {
return this.setHasChanged();
}

global AggregateQuery setWhereFilterLogic(String filterLogic) {
super.doSetWhereFilterLogic(filterLogic);
return this.setHasChanged();
}

global AggregateQuery withAccessLevel(System.AccessLevel accessLevel) {
super.doWithAccessLevel(accessLevel);
return this.setHasChanged();
}

global AggregateQuery orderByField(Schema.SObjectField field) {
return this.orderByField(field, null);
}
Expand Down Expand Up @@ -166,6 +208,31 @@ global class AggregateQuery extends SOQL {
return this.setHasChanged();
}

global AggregateQuery setBind(String key, Object value) {
super.doSetBind(key, value);
return this.setHasChanged();
}

global AggregateQuery setBinds(Map<String, Object> binds) {
super.doSetBinds(binds);
return this.setHasChanged();
}

global AggregateQuery removeBind(String key) {
super.doRemoveBind(key);
return this.setHasChanged();
}

global AggregateQuery clearBinds() {
super.doClearBinds();
return this.setHasChanged();
}

global AggregateQuery generateBindVariableKeys() {
super.doGenerateBindVariableKeys();
return this;
}

// TODO decide if this should be global
public AggregateQuery cacheResults() {
super.doCacheResults();
Expand Down Expand Up @@ -197,7 +264,7 @@ global class AggregateQuery extends SOQL {
super.doGetUsingScopeString() +
super.doGetWhereClauseString() +
this.getGroupByString() +
this.getHavingString() +
this.getHavingClauseString() +
super.doGetOrderByString() +
super.doGetLimitCountString() +
super.doGetOffetString();
Expand All @@ -206,21 +273,35 @@ global class AggregateQuery extends SOQL {
return this.query;
}

// TODO consider renaming to getCountResult()
@SuppressWarnings('PMD.ApexSOQLInjection')
global Integer getResultCount() {
String countQuery =
global String getCountQuery() {
if (this.countQuery != null && !this.hasChanged) {
return this.countQuery;
}

this.countQuery =
'SELECT COUNT()' +
' FROM ' +
this.sobjectType +
super.doGetUsingScopeString() +
super.doGetWhereClauseString() +
this.getGroupByString() +
this.getHavingString() +
this.getHavingClauseString() +
super.doGetOrderByString() +
super.doGetLimitCountString() +
super.doGetOffetString();
return Database.countQuery(countQuery);

System.debug(System.LoggingLevel.FINEST, this.countQuery);
return this.countQuery;
}

// TODO consider renaming to getCountResult()
@SuppressWarnings('PMD.ApexSOQLInjection')
global Integer getResultCount() {
return Database.countQueryWithBinds(
this.getCountQuery(),
this.doGetBindsMap(),
this.doGetAccessLevel()
);
}

global AggregateResult getFirstResult() {
Expand All @@ -232,7 +313,7 @@ global class AggregateQuery extends SOQL {
}

private AggregateQuery setHasChanged() {
this.hasChanged = true;
this.doSetHasChanged();
return this;
}

Expand Down Expand Up @@ -262,8 +343,8 @@ global class AggregateQuery extends SOQL {
return String.isEmpty(queryFieldString) ? '' : groupByTextString + queryFieldString + groupingDimensionClosingString;
}

private String getHavingString() {
return this.havingConditions.isEmpty() ? '' : ' HAVING ' + String.join(this.havingConditions, ', ');
private String getHavingClauseString() {
return this.doGetFilterableClauseString('HAVING', this.havingClauseFilters, this.havingClauseFilterLogic);
}

private class AggregateField {
Expand All @@ -287,4 +368,29 @@ global class AggregateQuery extends SOQL {
return aggregateFunction.name() + '(' + fieldApiName + ') ' + fieldAlias;
}
}

global class AggregateQueryFilter extends SOQL.QueryFilter {
private SOQL.Aggregate aggregateFunction;

public AggregateQueryFilter(SOQL.Aggregate aggregateFunction, SOQL.QueryField queryField, SOQL.Operator operator, Object value, String bindKey)
{
super(queryField, operator, value, bindKey);
this.aggregateFunction = aggregateFunction;
}

public override String toString()
{
return String.format(
'{0}({1}) {2} {3}',
new List<String> {
this.aggregateFunction.name(),
this.queryField.toString(),
SOQL.getOperatorValue(this.operator),
(String.isNotBlank(this.bindKey) ? ':' + this.bindKey : new QueryArgument(this.value).toString())
}
);
}

}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<apiVersion>61.0</apiVersion>
<status>Active</status>
</ApexClass>
45 changes: 44 additions & 1 deletion nebula-query-and-search/main/classes/Query.cls
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,18 @@ global class Query extends SOQL {
return this.filterWhere(new SOQL.QueryField(field), operator, value);
}

global Query filterWhere(Schema.SObjectField field, SOQL.Operator operator, Object value, String bindWithKey) {
return this.filterWhere(new SOQL.QueryField(field), operator, value, bindWithKey);
}

global Query filterWhere(SOQL.QueryField queryField, SOQL.Operator operator, Object value) {
return this.filterWhere(new SOQL.QueryFilter(queryField, operator, value));
}

global Query filterWhere(SOQL.QueryField queryField, SOQL.Operator operator, Object value, String bindWithKey) {
return this.filterWhere(new SOQL.QueryFilter(queryField, operator, value, bindWithKey));
}

global Query filterWhere(SOQL.QueryFilter filter) {
return this.filterWhere(new List<SOQL.QueryFilter>{ filter });
}
Expand All @@ -217,6 +225,11 @@ global class Query extends SOQL {
return this.setHasChanged();
}

global Query setWhereFilterLogic(String filterLogic) {
super.doSetWhereFilterLogic(filterLogic);
return this.setHasChanged();
}

//global Query filterWhereInSubquery(Schema.SObjectType childSObjectType, Schema.SObjectField lookupFieldOnChildSObject) {
//this.whereFilters.add('Id IN (SELECT ' + lookupFieldOnChildSObject + ' FROM ' + childSObjectType + ')');
//return this.setHasChanged();
Expand All @@ -239,6 +252,11 @@ global class Query extends SOQL {
//return this.setHasChanged();
//}

global Query withAccessLevel(System.AccessLevel accessLevel) {
super.doWithAccessLevel(accessLevel);
return this.setHasChanged();
}

global Query orderByField(Schema.SObjectField field) {
return this.orderByField(new SOQL.QueryField(field));
}
Expand Down Expand Up @@ -289,6 +307,31 @@ global class Query extends SOQL {
return this.setHasChanged();
}

global Query setBind(String key, Object value) {
super.doSetBind(key, value);
return this.setHasChanged();
}

global Query setBinds(Map<String, Object> binds) {
super.doSetBinds(binds);
return this.setHasChanged();
}

global Query removeBind(String key) {
super.doRemoveBind(key);
return this.setHasChanged();
}

global Query clearBinds() {
super.doClearBinds();
return this.setHasChanged();
}

global Query generateBindVariableKeys() {
super.doGenerateBindVariableKeys();
return this;
}

// TODO decide if this should be global
public Query cacheResults() {
super.doCacheResults();
Expand Down Expand Up @@ -412,7 +455,7 @@ global class Query extends SOQL {
}

private Query setHasChanged() {
this.hasChanged = true;
this.doSetHasChanged();
return this;
}

Expand Down
2 changes: 1 addition & 1 deletion nebula-query-and-search/main/classes/Query.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<apiVersion>61.0</apiVersion>
<status>Active</status>
</ApexClass>
5 changes: 5 additions & 0 deletions nebula-query-and-search/main/classes/RecordSearch.cls
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ global class RecordSearch extends SOSL {
return this.setHasChanged();
}

global RecordSearch withAccessLevel(System.AccessLevel accessLevel) {
super.doWithAccessLevel(accessLevel);
return this.setHasChanged();
}

global RecordSearch updateArticleReporting(SOSL.ArticleReporting articleReporting) {
this.articleReporting = articleReporting;
return this.setHasChanged();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<apiVersion>61.0</apiVersion>
<status>Active</status>
</ApexClass>
Loading