Created
June 20, 2017 22:01
-
-
Save rapsacnz/53e87c4ee90c8b9ced4eaa396661fe8c to your computer and use it in GitHub Desktop.
Apex Utilities
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
/** | |
* Created by caspar on 20/05/16. | |
*/ | |
public without sharing class Utilities { | |
public static Map<String, List<String>> fieldsForType = new Map<String, List<String>>(); | |
/** | |
* Retrieves a list of sObjects | |
* @param {String} Api name ie Account or Custom_Object__c | |
* @param {String} Name of the id to query on. | |
* @param {Set<Id>} Set of record ids to query | |
* @return {sObject[]} list of results. | |
*/ | |
public static SObject[] getRecordsByIdField(String objectAPIName, String idField, Set<Id> idSet) { | |
return getRecordsByIdField(objectAPIName,idField,idSet, new String[]{}); | |
} | |
public static SObject[] getRecordsByIdField(String objectAPIName, String idField, Set<Id> idSet, String[] fieldsOverride) { | |
//you may pass in an expression in the form of a concrete statement ie Id = \'0034B000002ULXf\' | |
//you can also pass in an expression that uses sObject list binding ie Id in :idSet | |
if (String.isEmpty(idField) || String.isEmpty(objectAPIName) || idSet.isEmpty() ) { | |
return new SObject[] {}; | |
} | |
String[] fields = new String[]{}; | |
fields.addAll(fieldsOverride); | |
if (fields.isEmpty()){ | |
fields = getAllFields(objectAPIName); | |
} | |
//if still empty, return empty object | |
if (fields.isEmpty()) { | |
return new SObject[] {}; | |
} | |
String conditionExpression = idField + ' IN :idSet'; | |
String soql = getSOQL(objectAPIName, fields, conditionExpression); | |
SObject[] records = new SObject[] {}; | |
try { | |
records = Database.query(soql); | |
} catch (Exception ex) { | |
System.debug('USR DEBUG QUERY EXCEPTION: ' + ex); | |
System.debug('USR DEBUG QUERY: ' + soql); | |
} | |
return records; | |
} | |
/** | |
* Retrieves a list of sObjects | |
* @param {String} Api name ie Account or Custom_Object__c | |
* @param {String} Name of the id to query on. | |
* @param {Set<String>} Set of record ids to query | |
* @return {sObject[]} list of results. | |
*/ | |
public static SObject[] getRecordsByIdField(String objectAPIName, String idField, Set<String> stringIds) { | |
return getRecordsByIdField(objectAPIName,idField,stringIds,new String[]{}); | |
} | |
public static SObject[] getRecordsByIdField(String objectAPIName, String idField, Set<String> stringIds, String[] fieldsOverride) { | |
Set<Id> idSet = new Set<Id>(); | |
stringIds.remove(null); | |
stringIds.remove(''); | |
try { | |
idSet = (Set<Id>)JSON.deserialize(JSON.serialize(stringIds), Set<Id>.class); | |
} catch (Exception e) { | |
return new SObject[] {}; | |
} | |
return getRecordsByIdField(objectAPIName, idField, idSet, fieldsOverride); | |
} | |
//return an sobject, with no sub-relationships | |
public static SObject getRecord(String objectAPIName, Id id) { | |
return getRecord(objectAPIName, id, new String[] {}); | |
} | |
//return an sobject with any listed relationships | |
public static SObject getRecord(String objectAPIName, Id id, List<String> relationships) { | |
String[] fields = getAllFields(objectAPIName); | |
if (null == fields || fields.isEmpty()) { | |
return null; | |
} | |
for (String relationshipName : relationships) { | |
fields.add(getSubquerySOQL(relationshipName, new List<String> {'Id'})); | |
} | |
String conditionExpression = 'Id = :id'; | |
SObject record = Database.query(getSOQL(objectAPIName, fields, conditionExpression)); | |
return record; | |
} | |
public static Set<Id> getChildRecordIds(SObject data, List<String> relationships) { | |
Set<Id> recordIds = new Set<Id>(); | |
for (String relationshipName : relationships) { | |
try { | |
Map<Id, SObject> childrenMap = new Map<Id, SObject>(data.getSObjects(relationshipName)); | |
recordIds.addAll(childrenMap.keySet()); | |
} catch (Exception e) { | |
// No Records Found For Given Relationship | |
} | |
} | |
return recordIds; | |
} | |
public static String getNameField(Schema.DescribeSObjectResult soDescribe) { | |
String fieldAPI = 'Name'; | |
Map<String, Schema.SObjectField> soFieldMap = soDescribe.fields.getMap(); | |
if (!soFieldMap.containsKey(fieldAPI)) { | |
for (Schema.SObjectField soField : soFieldMap.values()) { | |
Schema.DescribeFieldResult field = soField.getDescribe(); | |
if (field.isNameField()) { | |
fieldAPI = field.getName(); | |
break; | |
} | |
} | |
} | |
return fieldAPI; | |
} | |
public static String[] getAllFields(String type) { | |
//use cached version if possible. | |
if (fieldsForType.containsKey(type)) { | |
return fieldsForType.get(type); | |
} | |
SObjectType sObjType = getSObjectType(type); | |
if (sObjType == null) { | |
return new String[] {}; | |
} | |
Map<String, Schema.SObjectField> sObjectFields = sObjType.getDescribe().fields.getMap(); | |
String[] keys = new String[] {}; | |
keys.addAll(sObjectFields.keyset()); | |
addRelationshipFields(type, keys); | |
//add a cached version | |
fieldsForType.put(type, keys); | |
return keys; | |
} | |
private static void addRelationshipFields(String type, List<String> keys) | |
{ | |
if (type == 'Contact'){ | |
keys.add('Your relationship name'); | |
} | |
else if (type == 'Opportunity'){ | |
keys.addAll(new String[]{'Your relationship name' ,'Your relationship name'}); | |
} | |
else if (type == 'Case'){ | |
keys.addAll(new String[]{'Your relationship name'}); | |
} | |
else if (type == 'Note'){ | |
keys.addAll(new String[]{'Your relationship name'}); | |
} | |
} | |
public static List<String> sanitizeFields(String fieldList) { | |
return sanitizeFields(fieldList.split(',')); | |
} | |
public static List<String> sanitizeFields(List<String> fieldList) { | |
Set<String> fieldSet = new Set<String>(); | |
List<String> sanitizedFields = new List<String>(); | |
fieldSet.addAll(fieldList); | |
fieldSet.remove(null); | |
sanitizedFields.addAll(fieldSet); | |
return sanitizedFields; | |
} | |
public static SObjectType getSObjectType(String type) { | |
SObjectType objType = Schema.getGlobalDescribe().get(type); | |
if (objType == null) { | |
return null; | |
} | |
return objType; | |
} | |
public static String getSOQL(String objectType, List<String> fieldList, String conditionExpression) { | |
String soql = 'SELECT {fieldList} FROM {objectType} WHERE {conditionExpression}'; | |
soql = soql.replace('{fieldList}', String.join(fieldList, ',')); | |
soql = soql.replace('{objectType}', objectType); | |
soql = soql.replace('{conditionExpression}', conditionExpression); | |
return soql; | |
} | |
public static String getSubquerySOQL(String relationshipName, List<String> fieldList) { | |
String soql = '(SELECT {fieldList} FROM {relationshipName})'; | |
soql = soql.replace('{fieldList}', String.join(fieldList, ',')); | |
soql = soql.replace('{relationshipName}', relationshipName); | |
return soql; | |
} | |
public static Id[] slice (Id[] sourceList, Integer bugin, Integer endd) { | |
//we are casting to SObject | |
//so we can pass to the sobject slice method | |
if (sourceList.isEmpty()){ | |
return new Id[]{}; | |
} | |
Schema.SObjectType token = sourceList[0].getSObjectType(); | |
// Using the token, do a describe | |
Schema.DescribeSObjectResult dr = token.getDescribe(); | |
String objName = dr.getName(); | |
Schema.SObjectType objType = Schema.getGlobalDescribe().get(objName); | |
SObject[] objects = new SObject[]{}; | |
for (Id idx : sourceList){ | |
objects.add(objType.newSObject(idx)); | |
} | |
objects = slice(objects, bugin, endd); | |
Id[] resultIds = new Id[]{}; | |
for (SObject obj : objects){ | |
resultIds.add(obj.Id); | |
} | |
return resultIds; | |
} | |
public static SObject[] slice(SObject[] sourceList, Integer bugin, Integer endd) { | |
SObject[] resultList = new SObject[] {}; | |
System.debug(LoggingLevel.DEBUG, 'USR DEBUG SOURCE LIST SIZE: ' + sourceList.size()); | |
if (sourceList == null) { | |
return resultList; | |
} | |
Integer len = sourceList.size(); | |
// Handle negative value for "bugin" | |
Integer start = bugin; | |
start = (start >= 0) ? start : Math.max(0, len + start); | |
// Handle negative value for "endd" | |
Integer upTo = Math.min(endd, len); | |
if (endd < 0) { | |
upTo = len + endd; | |
} | |
// Actual expected size of the slice | |
Integer size = upTo - start; | |
System.debug(LoggingLevel.DEBUG, 'USR DEBUG UP TO: ' + upTo); | |
System.debug(LoggingLevel.DEBUG, 'USR DEBUG SIZE: ' + size); | |
if (size > 0) { | |
for (Integer i = 0; i < size; i++) { | |
SObject obj = sourceList[start + i]; | |
if (obj != null) { | |
resultList.add(obj); | |
} | |
} | |
} | |
return resultList; | |
} | |
public static set<Id> getIdSet (Set<String> stringIdSet){ | |
Set<Id> idSet = new Set<id>(); | |
for (String i : stringIdSet){ | |
if (UtilitUSR DEBUGsValidId(i)){ | |
idSet.add(i); | |
} | |
} | |
return idSet; | |
} | |
public static set<Id> getIdSet (String[] stringIdList){ | |
Set<Id> idSet = new Set<id>(); | |
for (String i : stringIdList){ | |
if (Utilities.isUSR DEBUGId(i)){ | |
idSet.add(i); | |
} | |
} | |
return idSet; | |
} | |
public static String debugAsJSON(String message, Object obj){ | |
String serializedObj = (obj == null ? '' : JSON.serialize(obj)); | |
String msg = String.isBlank(message) ? '' : message; | |
String debugMessage = 'USR DEBUG ' + msg + ': ' + serializedObj; | |
System.debug(debugMessage); | |
return debugMessage; | |
} | |
public static Boolean isValidId(String idString){ | |
try { | |
Id.valueOf(idString); | |
} | |
catch (Exception e){ | |
System.debug('USR DEBUG Non valid id: ' + idString); | |
return false; | |
} | |
return true; | |
} | |
//Create unique id value | |
public static String createUUID(){ | |
Blob aes = Crypto.generateAesKey(128); | |
String hex = EncodingUtil.convertToHex(aes); | |
return hex; | |
} | |
public static Boolean isBlank(Object val){ | |
if (val instanceof String){ | |
return String.isBlank((String)val); | |
} | |
if (val instanceof Integer){ | |
System.debug('USR DEBUG INTEGER: ' + val); | |
return ((Integer)val < 1 ? true : false); | |
} | |
if (val instanceof Double){ | |
System.debug('USR DEBUG DOUBLE: ' + val); | |
return ((Double)val == null ? true : false); | |
} | |
if (val instanceof Decimal){ | |
System.debug('USR DEBUG DECIMAL: ' + val); | |
return ((Decimal)val == null ? true : false); | |
} | |
if (val instanceof Date){ | |
return ((Date)val == null ? true : false); | |
} | |
if (val instanceof Datetime){ | |
return ((Datetime)val == null ? true : false); | |
} | |
else { | |
System.debug('USR DEBUG : ' + val); | |
return (val == null ? true : false); | |
} | |
} | |
public static String sanitizeQuerySet(Set<String> ids) { | |
if (ids == null || ids.isEmpty()) { | |
return ''; | |
} | |
ids.remove(null); | |
ids.remove(''); | |
String[] queryIds = new String[] {}; | |
queryIds.addAll(ids); | |
if (queryIds.isEmpty()) { | |
return ''; | |
} | |
String str = '(\''; | |
str += String.join(queryIds, '\',\''); | |
str += '\')'; | |
return str; | |
} | |
//this section is confined to working out dependent picklist values | |
// note it's not my code - reference http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/ | |
public static Map<String, List<String>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName) { | |
Map<String, List<String>> objResults = new Map<String, List<String>>(); | |
//get the string to sobject global map | |
Map<String, Schema.SObjectType> objGlobalMap = Schema.getGlobalDescribe(); | |
if (!Schema.getGlobalDescribe().containsKey(pObjName)) | |
return objResults; | |
//get the type being dealt with | |
Schema.SObjectType pType = Schema.getGlobalDescribe().get(pObjName); | |
return GetDependentOptionsImpl(pType, pControllingFieldName, pDependentFieldName); | |
} | |
public static Map<String, List<String>> GetDependentOptionsImpl(Schema.SObjectType pType, String pControllingFieldName, String pDependentFieldName) { | |
Map<String, List<String>> objResults = new Map<String, List<String>>(); | |
if (pType == null) | |
return objResults; | |
Bitset BitSetInstance = new Bitset(); | |
Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap(); | |
//verify field names | |
if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName)) | |
return objResults; | |
//get the control values | |
List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues(); | |
//get the dependent values | |
List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues(); | |
objFieldMap = null; | |
List<Integer> lstControllingIndexes = new List<Integer>(); | |
//iterate through the values and get the ones valid for the controlling field name | |
//set up the results | |
for (Integer pControllingIndex = 0; pControllingIndex < ctrl_ple.size(); pControllingIndex++) { | |
//get the pointer to the entry | |
Schema.PicklistEntry ctrl_entry = ctrl_ple[pControllingIndex]; | |
//get the label | |
String pControllingLabel = ctrl_entry.getLabel(); | |
//create the entry with the label | |
objResults.put(pControllingLabel, new List<String>()); | |
//keep track of the controlling indexes | |
lstControllingIndexes.add(pControllingIndex); | |
} | |
//DONT cater for null and empty | |
objResults.put('', new List<String>()); | |
objResults.put(null, new List<String>()); | |
// | |
//load all dep entries | |
List<Schema.PicklistEntry> objEntries = new List<Schema.PicklistEntry>(); | |
List<TPicklistEntry> objDS_Entries = new List<TPicklistEntry>(); | |
//add all entries | |
for (Integer pDependentIndex = 0; pDependentIndex < dep_ple.size(); pDependentIndex++) { | |
//get the pointer to the dependent index | |
Schema.PicklistEntry dep_entry = dep_ple[pDependentIndex]; | |
objEntries.add(dep_entry); | |
} | |
//serialize once | |
objDS_Entries = (List<TPicklistEntry>)JSON.deserialize(JSON.serialize(objEntries), List<TPicklistEntry>.class); | |
List<Integer> validIndexes; | |
for (TPicklistEntry objDepPLE : objDS_Entries) { | |
//if valid for is empty, skip | |
if (objDepPLE.validFor == null || objDepPLE.validFor == '') { | |
continue; | |
} | |
//get the test for the controlling indexes | |
validIndexes = BitSetInstance.testBits(objDepPLE.validFor, lstControllingIndexes); | |
for (Integer validIndex : validIndexes) { | |
//get the label | |
String pControllingLabel = ctrl_ple[validIndex].getLabel(); | |
objResults.get(pControllingLabel).add(objDepPLE.label); | |
} | |
} | |
objEntries = null; | |
objDS_Entries = null; | |
objResults.remove(null); | |
objResults.remove(''); | |
return objResults; | |
} | |
/* | |
* @Summary: Entity to represent a json version of a picklist entry | |
* so that the validFor property becomes exposed | |
*/ | |
public class TPicklistEntry { | |
public string active {get; set;} | |
public string defaultValue {get; set;} | |
public string label {get; set;} | |
public string value {get; set;} | |
public string validFor {get; set;} | |
public TPicklistEntry() { | |
} | |
} | |
public class Bitset { | |
public Map<String, Integer> AlphaNumCharCodes {get; set;} | |
public Map<String, Integer> Base64CharCodes { get; set; } | |
public Bitset() { | |
LoadCharCodes(); | |
} | |
/* | |
Effect: Method takes a validFor string and tests it against a set of controlling indexes | |
Postcondition: Returns a list of all controlling indexes for which the validFor string test True | |
*/ | |
public List<Integer> testBits(String pValidFor, List<Integer> nList) { | |
List<Integer> results = new List<Integer>(); | |
//the list of bytes (not derived from n) | |
List<Integer> pBytes = new List<Integer>(); | |
//multiply by 6 since base 64 uses 6 bits (not derived form n) | |
Integer bytesBeingUsed = (pValidFor.length() * 6) / 8; | |
//will be used to hold the full decimal value (not derived from n) | |
Integer pFullValue = 0; | |
//must be more than 1 byte | |
if (bytesBeingUsed <= 1) | |
return results; | |
//get the base64bytes | |
for (Integer i = 0; i < pValidFor.length(); i++) { | |
//get currenct character value | |
pBytes.Add((Base64CharCodes.get((pValidFor.Substring(i, i + 1))))); | |
} | |
//calculate the full decimal value | |
for (Integer i = 0; i < pBytes.size(); i++) { | |
Integer pShiftAmount = (pBytes.size() - (i + 1)) * 6; //used to shift by a factor 6 bits to get the value | |
pFullValue = pFullValue + (pBytes[i] << (pShiftAmount)); | |
} | |
//now we don't want to always be declaring memory, so let's set the initial | |
//variables | |
Integer bit; | |
Integer targetOctet; | |
Integer shiftBits; | |
Integer tBitVal; | |
Integer n; | |
Integer nListSize = nList.size(); | |
for (Integer i = 0; i < nListSize; i++) { | |
n = nList[i]; | |
//calculate the target bit for comparison | |
bit = 7 - (Math.mod(n, 8)); | |
//calculate the octet that has in the target bit | |
targetOctet = (bytesBeingUsed - 1) - (n >> bytesBeingUsed); | |
//the number of bits to shift by until we find the bit to compare for true or false | |
shiftBits = (targetOctet * 8) + bit; | |
//& is to set the same set of bits for testing | |
//shift to the bit which will dictate true or false | |
//Math.Pow(2, shiftBits) == 2 << (shiftBits+1) | |
tBitVal = ((Integer)(2 << (shiftBits - 1)) & pFullValue) >> shiftBits; | |
if (tBitVal == 1) | |
results.add(n); | |
} | |
return results; | |
} | |
//Method loads the char codes | |
private void LoadCharCodes() { | |
AlphaNumCharCodes = new Map <String, Integer> { | |
'!' => 33, '\"' => 34, '#' => 35, '$' => 36, '%' => 37, '&' => 38, '\'' => 39, '(' => 40, ')' => 41, '*' => 42, '+' => 43, ',' => 44, '-' => 45, | |
'.' => 46, '/' => 47, '0' => 48, '1' => 49, '2' => 50, '3' => 51, '4' => 52, '5' => 53, '6' => 54, '7' => 55, | |
'8' => 56, '9' => 57, ':' => 58, ';' => 59, '=' => 61, '>' => 62, '?' => 63, '@' => 64, | |
'A' => 65, 'B' => 66, 'C' => 67, 'D' => 68, 'E' => 69, 'F' => 70, 'G' => 71, 'H' => 72, 'I' => 73, 'J' => 74, | |
'K' => 75, 'L' => 76, 'M' => 77, 'N' => 78, 'O' => 79, 'P' => 80, 'Q' => 81, 'R' => 82, 'S' => 83, 'T' => 84, | |
'U' => 85, 'V' => 86, 'W' => 87, 'X' => 88, 'Y' => 89, 'Z' => 90 | |
}; | |
Base64CharCodes = new Map<String, Integer>(); | |
//lower case | |
Set<String> pUpperCase = AlphaNumCharCodes.keySet(); | |
for (String pKey : pUpperCase) { | |
//the difference between upper case and lower case is 32 | |
AlphaNumCharCodes.put(pKey.toLowerCase(), AlphaNumCharCodes.get(pKey) + 32); | |
//Base 64 alpha starts from 0 (The ascii charcodes started from 65) | |
Base64CharCodes.put(pKey, AlphaNumCharCodes.get(pKey) - 65); | |
Base64CharCodes.put(pKey.toLowerCase(), AlphaNumCharCodes.get(pKey) - (65) + 26); | |
} | |
//numerics | |
for (Integer i = 0; i <= 9; i++) { | |
AlphaNumCharCodes.put(string.valueOf(i), i + 48); | |
//base 64 numeric starts from 52 | |
Base64CharCodes.put(string.valueOf(i), i + 52); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment