Skip to content

Instantly share code, notes, and snippets.

@rapsacnz
Created June 20, 2017 22:01
Show Gist options
  • Save rapsacnz/53e87c4ee90c8b9ced4eaa396661fe8c to your computer and use it in GitHub Desktop.
Save rapsacnz/53e87c4ee90c8b9ced4eaa396661fe8c to your computer and use it in GitHub Desktop.
Apex Utilities
/**
* 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