Skip to content

Instantly share code, notes, and snippets.

@meajinkya
Last active March 12, 2021 06:56
Show Gist options
  • Save meajinkya/42ced6572fb2c1613234fd20f405fed3 to your computer and use it in GitHub Desktop.
Save meajinkya/42ced6572fb2c1613234fd20f405fed3 to your computer and use it in GitHub Desktop.
QueryBuilder v2
/***************************************************************************************************
* 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