Skip to content

Commit f9d0249

Browse files
committed
Soql.cls Enhancements
* Added new enum value, `Soql.FieldCategory.IGNORE_FLS`. This can be used to add a field to a query, regardless of the field-level security (FLS) * Added 2 new overloaded versions of filterWhere method * `public Soql filterWhere(QueryFilter filter)` * `public Soql filterWhere(List<QueryFilter> filters)` * Created 2 new subclasses * `Soql.QueryArgument` - takes an Object and formats it to use in a query * `Soql.QueryFilter` - represents a single where clause filter
1 parent f556043 commit f9d0249

File tree

1 file changed

+101
-56
lines changed

1 file changed

+101
-56
lines changed

src/classes/Soql.cls

Lines changed: 101 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
public virtual class Soql implements Comparable {
1+
public class Soql implements Comparable {
22

33
public enum Aggregate { AVG, COUNT, COUNT_DISTINCT, MAX, MIN, SUM }
4-
public enum FieldCategory { ACCESSIBLE, UPDATEABLE, STANDARD, CUSTOM }
4+
public enum FieldCategory { ACCESSIBLE, UPDATEABLE, STANDARD, CUSTOM, IGNORE_FLS }
55
public enum Scope { EVERYTHING, DELEGATED, TEAM, MINE, MY_TERRITORY, MY_TEAM_TERRITORY }
66
public enum SortOrder { ASCENDING, DESCENDING }
77

@@ -146,8 +146,15 @@ public virtual class Soql implements Comparable {
146146
}
147147

148148
public Soql filterWhere(Soql.QueryField queryField, String operator, Object value) {
149-
String whereFilter = queryField + ' ' + String.escapeSingleQuotes(operator) + ' ' + this.formatObjectForQueryString(value);
150-
this.whereFilters.add(whereFilter);
149+
return this.filterWhere(new QueryFilter(queryField, operator, value));
150+
}
151+
152+
public Soql filterWhere(QueryFilter filter) {
153+
return this.filterWhere(new List<QueryFilter>{filter});
154+
}
155+
156+
public Soql filterWhere(List<QueryFilter> filters) {
157+
for(QueryFilter filter : filters) this.whereFilters.add(filter.toString());
151158
return this.setHasChanged();
152159
}
153160

@@ -326,60 +333,8 @@ public virtual class Soql implements Comparable {
326333
return 'format(' + fieldApiName + ') ' + fieldApiName.replace('.', '_') + '__Formatted';
327334
}
328335

329-
private String formatObjectForQueryString(Object valueToFormat) {
330-
if(valueToFormat == null) return null;
331-
else if(valueToFormat instanceOf List<Object>) return this.convertListToQueryString((List<Object>)valueToFormat);
332-
else if(valueToFormat instanceOf Set<Object>) return this.convertSetToQueryString(valueToFormat);
333-
else if(valueToFormat instanceOf Map<Object, Object>) return this.convertMapToQueryString(valueToFormat);
334-
else if(valueToFormat instanceOf Date) return String.valueOf((Date)valueToFormat).left(10);
335-
else if(valueToFormat instanceOf Datetime) {
336-
Datetime datetimeValue = (Datetime)valueToFormat;
337-
return datetimeValue.format('yyyy-MM-dd\'T\'HH:mm:ss\'Z\'', 'Greenwich Mean Time');
338-
}
339-
else if(valueToFormat instanceOf Sobject) {
340-
Sobject record = (Sobject)valueToFormat;
341-
return this.wrapInSingleQuotes(((Sobject)valueToFormat).Id);
342-
}
343-
else if(valueToFormat instanceOf String) {
344-
// Escape single quotes to prevent SOQL/SOSL injection
345-
String stringArgument = String.escapeSingleQuotes((String)valueToFormat);
346-
return this.wrapInSingleQuotes(stringArgument);
347-
}
348-
else return String.valueOf(valueToFormat);
349-
}
350-
351-
private String wrapInSingleQuotes(String input) {
352-
input = input.trim();
353-
if(input.left(1) != '\'') input = '\'' + input;
354-
if(input.right(1) != '\'') input = input + '\'';
355-
return input;
356-
}
357-
358-
private String convertListToQueryString(List<Object> valueList) {
359-
List<String> parsedValueList = new List<String>();
360-
for(Object value : valueList) {
361-
parsedValueList.add(this.formatObjectForQueryString(value));
362-
}
363-
return '(' + String.join(parsedValueList, ', ') + ')';
364-
}
365-
366-
private String convertSetToQueryString(Object valueSet) {
367-
String unformattedString = String.valueOf(valueSet).replace('{', '').replace('}', '');
368-
List<String> parsedValueList = new List<String>();
369-
for(String collectionItem : unformattedString.split(',')) {
370-
parsedValueList.add(this.formatObjectForQueryString(collectionItem));
371-
}
372-
return '(' + String.join(parsedValueList, ', ') + ')';
373-
}
374-
375-
private String convertMapToQueryString(Object valueMap) {
376-
Map<String, Object> m = (Map<String, Object>)JSON.deserializeUntyped(JSON.serialize(valueMap));
377-
return this.convertSetToQueryString(m.keySet());
378-
}
379-
380336
private List<String> getFieldsToQuery(QueryField queryField, FieldCategory fieldCat) {
381337
List<String> fieldsToReturn = new List<String>();
382-
//Schema.SobjectField field = this.sobjectDescribe.fields.getMap().get(fieldApiName);
383338

384339
if(fieldCat == null) return fieldsToReturn;
385340
else if(fieldCat == FieldCategory.ACCESSIBLE && !queryField.getDescribe().isAccessible()) return fieldsToReturn;
@@ -545,6 +500,71 @@ public virtual class Soql implements Comparable {
545500

546501
}
547502

503+
public virtual class QueryArgument {
504+
505+
private String value;
506+
507+
public QueryArgument(Object valueToFormat) {
508+
this.value = this.formatObjectForQueryString(valueToFormat);
509+
}
510+
511+
public override String toString() {
512+
return this.value;
513+
}
514+
515+
private String formatObjectForQueryString(Object valueToFormat) {
516+
if(valueToFormat == null) return null;
517+
else if(valueToFormat instanceOf List<Object>) return this.convertListToQueryString((List<Object>)valueToFormat);
518+
else if(valueToFormat instanceOf Set<Object>) return this.convertSetToQueryString(valueToFormat);
519+
else if(valueToFormat instanceOf Map<Object, Object>) return this.convertMapToQueryString(valueToFormat);
520+
else if(valueToFormat instanceOf Date) return String.valueOf((Date)valueToFormat).left(10);
521+
else if(valueToFormat instanceOf Datetime) {
522+
Datetime datetimeValue = (Datetime)valueToFormat;
523+
return datetimeValue.format('yyyy-MM-dd\'T\'HH:mm:ss\'Z\'', 'Greenwich Mean Time');
524+
}
525+
else if(valueToFormat instanceOf Sobject) {
526+
Sobject record = (Sobject)valueToFormat;
527+
return this.wrapInSingleQuotes(((Sobject)valueToFormat).Id);
528+
}
529+
else if(valueToFormat instanceOf String) {
530+
// Escape single quotes to prevent SOQL/SOSL injection
531+
String stringArgument = String.escapeSingleQuotes((String)valueToFormat);
532+
return this.wrapInSingleQuotes(stringArgument);
533+
}
534+
else return String.valueOf(valueToFormat);
535+
}
536+
537+
private String wrapInSingleQuotes(String input) {
538+
input = input.trim();
539+
if(input.left(1) != '\'') input = '\'' + input;
540+
if(input.right(1) != '\'') input = input + '\'';
541+
return input;
542+
}
543+
544+
private String convertListToQueryString(List<Object> valueList) {
545+
List<String> parsedValueList = new List<String>();
546+
for(Object value : valueList) {
547+
parsedValueList.add(this.formatObjectForQueryString(value));
548+
}
549+
return '(' + String.join(parsedValueList, ', ') + ')';
550+
}
551+
552+
private String convertSetToQueryString(Object valueSet) {
553+
String unformattedString = String.valueOf(valueSet).replace('{', '').replace('}', '');
554+
List<String> parsedValueList = new List<String>();
555+
for(String collectionItem : unformattedString.split(',')) {
556+
parsedValueList.add(this.formatObjectForQueryString(collectionItem));
557+
}
558+
return '(' + String.join(parsedValueList, ', ') + ')';
559+
}
560+
561+
private String convertMapToQueryString(Object valueMap) {
562+
Map<String, Object> m = (Map<String, Object>)JSON.deserializeUntyped(JSON.serialize(valueMap));
563+
return this.convertSetToQueryString(m.keySet());
564+
}
565+
566+
}
567+
548568
public class QueryField {
549569

550570
private final String queryField;
@@ -614,4 +634,29 @@ public virtual class Soql implements Comparable {
614634

615635
}
616636

637+
public class QueryFilter implements Comparable {
638+
639+
private String value;
640+
641+
public QueryFilter(Schema.SobjectField field, String operator, Object value) {
642+
this(new QueryField(field), operator, value);
643+
}
644+
645+
public QueryFilter(QueryField queryField, String operator, Object value) {
646+
this.value = queryField + ' ' + operator + ' ' + new QueryArgument(value);
647+
}
648+
649+
public Integer compareTo(Object compareTo) {
650+
QueryFilter compareToQueryFilter = (QueryFilter)compareTo;
651+
if(this.toString() == compareToQueryFilter.toString()) return 0;
652+
else if(this.toString() > compareToQueryFilter.toString()) return 1;
653+
else return -1;
654+
}
655+
656+
public override String toString() {
657+
return this.value;
658+
}
659+
660+
}
661+
617662
}

0 commit comments

Comments
 (0)