Last active
March 12, 2021 06:56
-
-
Save meajinkya/42ced6572fb2c1613234fd20f405fed3 to your computer and use it in GitHub Desktop.
QueryBuilder v2
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
/*************************************************************************************************** | |
* Copyright (c), FinancialForce.com, inc | |
* All rights reserved. | |
* | |
* Generic Query Builder class to handle generation of SOQL queries and query exection | |
* based on fflib QueryFactory | |
***************************************************************************************************/ | |
public class QueryBuilder { | |
public enum SortOrder {ASCENDING, DESCENDING} | |
public Schema.SObjectType table {get; private set;} | |
private Set<String> fields; | |
private String conditionExpression; | |
private Integer limitCount; | |
private Integer offsetCount; | |
private List<Ordering> order; | |
private Boolean sortSelectFields = true; | |
public QueryBuilder(String table) { | |
this.table = Schema.getGlobalDescribe().get(table); | |
fields = new Set<String>(); | |
order = new List<Ordering>(); | |
} | |
/** | |
* Methods for query fields | |
*/ | |
public QueryBuilder selectFields(Set<String> fields) { | |
for (String fieldApiName : fields){ | |
this.fields.add(fieldApiName); | |
} | |
return this; | |
} | |
public Set<String> getSelectedFields() { | |
return this.fields; | |
} | |
/** | |
* Methods for query conditions | |
*/ | |
public QueryBuilder setCondition(String conditionExpression) { | |
if(this.conditionExpression == NULL) { | |
this.conditionExpression = conditionExpression; | |
} | |
else { | |
this.conditionExpression += ' AND ' + conditionExpression; | |
} | |
return this; | |
} | |
public QueryBuilder setCondition(List<String> conditions) { | |
if (!conditions.isEmpty()) { | |
for(String condition : conditions) { | |
setCondition(condition); | |
} | |
} | |
return this; | |
} | |
public QueryBuilder setConditions(Map<String, String> queryFilters) { | |
String[] conditions = new String[]{}; | |
for(String filter : queryFilters.keySet()) { | |
conditions.add( filter + ' = ' + '\'' + queryFilters.get(filter) + '\'' ); | |
} | |
for(String condition : conditions) { | |
this.setCondition(condition); | |
} | |
return this; | |
} | |
public String getCondition() { | |
return this.conditionExpression; | |
} | |
/** | |
* Methods for query limit | |
*/ | |
public QueryBuilder setLimit(Integer limitCount) { | |
this.limitCount = limitCount; | |
return this; | |
} | |
public Integer getLimit() { | |
return this.limitCount; | |
} | |
/** | |
* Methods for query offset | |
*/ | |
public QueryBuilder setOffset(Integer offsetCount) { | |
this.offsetCount = offsetCount; | |
return this; | |
} | |
public Integer getOffset() { | |
return this.offsetCount; | |
} | |
/** | |
* Methods for query ordering | |
*/ | |
public QueryBuilder addOrdering(Ordering o) { | |
this.order.add(o); | |
return this; | |
} | |
public QueryBuilder addOrdering(String fieldName, SortOrder direction){ | |
order.add( | |
new Ordering(getFieldPath(fieldName), direction) | |
); | |
return this; | |
} | |
public QueryBuilder setOrdering(Ordering o) { | |
this.order = new List<Ordering>{ o }; | |
return this; | |
} | |
public QueryBuilder setOrdering(String fieldName, SortOrder direction){ | |
Ordering order = new Ordering(getFieldPath(fieldName), direction); | |
return setOrdering(order); | |
} | |
public List<Ordering> getOrderings() { | |
return this.order; | |
} | |
/** | |
* Method to generate SOQL query from set parameters | |
*/ | |
public String toSOQL() { | |
String result = 'SELECT '; | |
if (fields.size() == 0) { | |
result += 'Id'; | |
} | |
else { | |
List<String> fieldsToQuery = new List<String>(fields); | |
if (sortSelectFields) { | |
fieldsToQuery.sort(); | |
} | |
result += String.join(fieldsToQuery,', '); | |
} | |
result += ' FROM ' + table.getDescribe().getName(); | |
if (conditionExpression != null) { | |
result += ' WHERE ' + conditionExpression; | |
} | |
if (order.size() > 0) { | |
result += ' ORDER BY '; | |
for(Ordering o : order) { | |
result += o.toSOQL() + ', '; | |
} | |
result = result.substring(0, result.length() - 2); | |
} | |
if (limitCount != null) { | |
result += ' LIMIT ' + limitCount; | |
} | |
if (offsetCount != null) { | |
result += ' OFFSET ' + offsetCount; | |
} | |
return result; | |
} | |
/** | |
* Method to get field path | |
*/ | |
private String getFieldPath(String fieldName) { | |
String tokenName; | |
if(!fieldName.contains('.')) { //single field | |
Schema.SObjectField token = table.getDescribe().fields.getMap().get(fieldName); | |
if(token == null) { | |
throw new InvalidFieldException(fieldName,this.table); | |
} | |
tokenName = token.getDescribe().getName(); | |
} | |
return tokenName; | |
} | |
/** | |
* Wrapper class for Ordering | |
*/ | |
public class Ordering { | |
private SortOrder direction; | |
private boolean nullsLast; | |
private String field; | |
public Ordering(String fieldApiName, SortOrder direction){ | |
this.direction = direction; | |
this.field = fieldApiName; | |
this.nullsLast = true; | |
} | |
public String getField(){ | |
return this.field; | |
} | |
public SortOrder getDirection(){ | |
return direction; | |
} | |
public boolean isNullsLast(){ | |
return nullsLast; | |
} | |
public String toSOQL(){ | |
return field | |
+ ' ' | |
+ (direction == SortOrder.ASCENDING ? 'ASC' : 'DESC') | |
+ (nullsLast ? ' NULLS LAST ' : ' NULLS FIRST '); | |
} | |
} | |
/** | |
* Custom exception for invalid field names | |
*/ | |
public class InvalidFieldException extends Exception { | |
private String fieldName; | |
private Schema.SObjectType objectType; | |
public InvalidFieldException(String fieldname, Schema.SObjectType objectType){ | |
this.objectType = objectType; | |
this.fieldName = fieldName; | |
this.setMessage( 'Invalid field \'' + fieldName + '\' for object \'' + objectType + '\'' ); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment