|
1 | | -public virtual class Soql implements Comparable { |
| 1 | +public class Soql implements Comparable { |
2 | 2 |
|
3 | 3 | 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 } |
5 | 5 | public enum Scope { EVERYTHING, DELEGATED, TEAM, MINE, MY_TERRITORY, MY_TEAM_TERRITORY } |
6 | 6 | public enum SortOrder { ASCENDING, DESCENDING } |
7 | 7 |
|
@@ -146,8 +146,15 @@ public virtual class Soql implements Comparable { |
146 | 146 | } |
147 | 147 |
|
148 | 148 | 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()); |
151 | 158 | return this.setHasChanged(); |
152 | 159 | } |
153 | 160 |
|
@@ -326,60 +333,8 @@ public virtual class Soql implements Comparable { |
326 | 333 | return 'format(' + fieldApiName + ') ' + fieldApiName.replace('.', '_') + '__Formatted'; |
327 | 334 | } |
328 | 335 |
|
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 | | - |
380 | 336 | private List<String> getFieldsToQuery(QueryField queryField, FieldCategory fieldCat) { |
381 | 337 | List<String> fieldsToReturn = new List<String>(); |
382 | | - //Schema.SobjectField field = this.sobjectDescribe.fields.getMap().get(fieldApiName); |
383 | 338 |
|
384 | 339 | if(fieldCat == null) return fieldsToReturn; |
385 | 340 | else if(fieldCat == FieldCategory.ACCESSIBLE && !queryField.getDescribe().isAccessible()) return fieldsToReturn; |
@@ -545,6 +500,71 @@ public virtual class Soql implements Comparable { |
545 | 500 |
|
546 | 501 | } |
547 | 502 |
|
| 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 | + |
548 | 568 | public class QueryField { |
549 | 569 |
|
550 | 570 | private final String queryField; |
@@ -614,4 +634,29 @@ public virtual class Soql implements Comparable { |
614 | 634 |
|
615 | 635 | } |
616 | 636 |
|
| 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 | + |
617 | 662 | } |
0 commit comments