Last active
August 24, 2017 09:08
-
-
Save swapnilshrikhande/6ad3e92a924599d3d6830b06e8dcd404 to your computer and use it in GitHub Desktop.
Generic SOQL Query Generator and other utility methods
This file contains hidden or 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
public class OpportunityClone { | |
//get recordtypeids for all opportunity records | |
static final Map<String, Id> opportunityRecordTypeMap = Utils.getRecordTypeMapForObjectGeneric(Opportunity.SObjectType); | |
static final Map<String,Map<String,String>> opportunityRelationshipDetailMap = Utils.getRelationshipDetails(Opportunity.SObjectType); | |
public static final String FILTER_CLAUSE = ' WHERE ID IN :recordIdList'; | |
public static CloneConfig config; | |
public class CloneConfig { | |
//clone config | |
public Boolean preserveId; | |
public Boolean isDeepClone; | |
public Boolean preserveReadonlyTimestamps; | |
public Boolean preserveAutonumber; | |
//default values | |
public CloneConfig(){ | |
this.preserveId = false; | |
this.isDeepClone = false; | |
this.preserveReadonlyTimestamps = false; | |
this.preserveAutonumber = false; | |
} | |
} | |
//clone opportunity base on source record id and fieldset | |
public static Opportunity cloneOpportunity( Id recordId | |
, Schema.FieldSet fieldSet | |
, Set<String> relationshipNameSet){ | |
Map<Id,Opportunity> clonedOpportunityMap = cloneOpportunityList(new Id[]{recordId} ,fieldSet,relationshipNameSet); | |
return clonedOpportunityMap.get(recordId); | |
} | |
public static Map<Id,Opportunity> cloneOpportunityList( List<Id> recordIdList | |
, Schema.FieldSet fieldSet | |
, Set<String> relationshipNameSet){ | |
//sanity checks, allow injecting config variable from external context | |
config = config==null ? new CloneConfig() : config; | |
//source id verses cloned opportunity map | |
Map<Id,Opportunity> clonedOpportunityMap = new Map<Id,Opportunity>(); | |
//generate select for the opportunity and passed fieldset | |
String query = Utils.generateQuery( Opportunity.sObjectType | |
, fieldSet | |
, relationshipNameSet | |
, FILTER_CLAUSE | |
); | |
Map<Id,Opportunity> sourceOpportunityMap = new Map<Id,Opportunity>( (List<Opportunity>)Database.query(query) ) ; | |
for ( Opportunity opportunityRecord : sourceOpportunityMap.values() ){ | |
clonedOpportunityMap.put( opportunityRecord.Id, | |
opportunityRecord.clone( config.preserveId | |
, config.isDeepClone | |
, config.preserveReadonlyTimestamps | |
, config.preserveAutonumber) | |
); | |
} | |
for(Opportunity clonedOpportunity : clonedOpportunityMap.values()){ | |
clonedOpportunity.Name = '<Patient Name> IOP '+Datetime.now(); | |
clonedOpportunity.StageName = 'Pending IOP Assessment'; | |
clonedOpportunity.CloseDate = Date.today(); | |
clonedOpportunity.RecordTypeId = opportunityRecordTypeMap.get('Outpatient_Treatment'); | |
} | |
if( false == clonedOpportunityMap.isEmpty() ){ | |
insert clonedOpportunityMap.values(); | |
} | |
List<SObject> dataToInsert = new List<SObject>(); | |
//clone related records | |
Opportunity sourceOpportunity; | |
Opportunity clonedOpportunity; | |
List<SObject> clonedRelatedRecordList; | |
String fieldName; | |
for(Id parentId : recordIdList ){ | |
sourceOpportunity = sourceOpportunityMap.get(parentId); | |
clonedOpportunity = clonedOpportunityMap.get(parentId); | |
for( String relationName : relationshipNameSet ){ | |
clonedRelatedRecordList = sourceOpportunity.getsObjects(relationName); | |
if( null != clonedRelatedRecordList ){ | |
for(SObject clonedRecord : clonedRelatedRecordList.deepClone() ){ | |
fieldName = opportunityRelationshipDetailMap.get(relationName).get('RELATIONSHIP_FIELD'); | |
clonedRecord.put(fieldName,clonedOpportunity.Id); | |
dataToInsert.add(clonedRecord); | |
} | |
} | |
} | |
} | |
if( false == dataToInsert.isEmpty() ){ | |
insert dataToInsert; | |
} | |
return clonedOpportunityMap; | |
} | |
} |
This file contains hidden or 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
// Class which contains useful utility methods required across classes | |
public class Utils { | |
public static final String OBJECTNAME = 'RELATIONSHIP_OBJECT'; | |
public static final String FIELDNAME = 'RELATIONSHIP_FIELD'; | |
public static final String QUERY_TEMPLATE = 'SELECT {0} FROM {1} {2}'; | |
public static final String NESTED_QUERY = '({0})'; | |
public static final String COMMA_SEPARATOR = ', '; | |
public static final String FIELD_ID = 'Id'; | |
//cache holders | |
public static Map<String, Schema.SObjectType> GLOBALDESCRIBE; | |
//Sobject wise relationships details | |
public static Map<String, Map<String,Map<String,String>> > objectWiseRelationshipMap; | |
//cache methods | |
public static Schema.SObjectType getSObjectType(String objectName){ | |
//lazy load | |
if(null == GLOBALDESCRIBE){ | |
GLOBALDESCRIBE = Schema.getGlobalDescribe(); | |
} | |
return GLOBALDESCRIBE.get(objectName); | |
} | |
//static initializers | |
static { | |
objectWiseRelationshipMap = new Map<String, Map<String,Map<String,String>> >(); | |
} | |
//Util methods start | |
//Gerate query for all fields in the fieldset and all fields from the related objects | |
//relatedRelationshipNames is a map of | |
// Relationshipname => Related ObjectName | |
public static String generateQuery( Schema.sObjectType fromObject | |
, Schema.FieldSet fieldSet | |
, Set<String> relationshipNameSet | |
, String whereClause | |
){ | |
List<String> queryFieldList; | |
if( fieldSet != null ){ | |
queryFieldList = getFieldListFor(fieldSet); | |
} else { | |
queryFieldList = getFieldListFor(fromObject); | |
} | |
//generate nestedQueryClauses | |
if( null != relationshipNameSet ){ | |
queryFieldList.addAll( getInnerQueryList(fromObject,relationshipNameSet) ); | |
} | |
String query = generateQuery(''+fromObject, queryFieldList, whereClause); | |
return query; | |
} | |
public static List<String> getInnerQueryList(Schema.sObjectType fromObject,Set<String> relationshipNameSet){ | |
List<String> queryFieldList = new List<String>(); | |
String objectName; | |
List<String> relatedFieldList; | |
String relatedQuery; | |
Map<String,Map<String,String>> relationDetailsMap = getRelationshipDetails(fromObject); | |
for( String relationshipName : relationshipNameSet ){ | |
objectName = relationDetailsMap.get(relationshipName).get(OBJECTNAME); | |
relatedFieldList = getFieldListFor(getSObjectType(objectName)); | |
relatedQuery = generateQuery( relationshipName | |
, relatedFieldList | |
, ''); | |
relatedQuery = String.format(NESTED_QUERY,new String[]{relatedQuery}); | |
queryFieldList.add(relatedQuery); | |
} | |
return queryFieldList; | |
} | |
//generate query for fields within a field set | |
public static String generateQuery( Schema.sObjectType fromObject | |
, Schema.FieldSet fieldSet | |
, String whereClause){ | |
return generateQuery(''+fromObject, getFieldListFor(fieldSet), whereClause); | |
} | |
//generate query for fieldnames passed in | |
public static String generateQuery( String fromObject | |
, List<String> fieldNameSet | |
, String whereClause){ | |
//sanity check | |
whereClause = whereClause == null ? '' : whereClause; | |
//local variables | |
String queryFieldsClause = ''; | |
for(String fieldName : fieldNameSet) { | |
//if not first time here, add a , | |
if(false == String.isBlank(queryFieldsClause)){ | |
queryFieldsClause += COMMA_SEPARATOR; | |
} | |
queryFieldsClause += fieldName; | |
} | |
//Corner cases if no fields in the field set field set | |
//1 | |
if( true == String.isBlank(queryFieldsClause) ){ | |
queryFieldsClause += FIELD_ID; | |
} | |
String query = String.format(QUERY_TEMPLATE, new String[]{ | |
queryFieldsClause | |
, ''+fromObject | |
, whereClause | |
}); | |
return query; | |
} | |
//Supporting methods | |
public static List<String> getFieldListFor(Schema.FieldSet fieldSet){ | |
List<String> fieldNameSet = new List<String>(); | |
for(Schema.FieldSetMember fieldSetMember : fieldSet.getFields()) { | |
fieldNameSet.add(fieldSetMember.getFieldPath()); | |
} | |
return fieldNameSet; | |
} | |
public static List<String> getFieldListFor(Schema.sObjectType fromObject){ | |
List<String> fieldNameSet = new List<String>(); | |
Schema.DescribeFieldResult dfr; | |
for(Schema.SObjectField fieldInstance : fromObject.getDescribe().fields.getMap().values()) { | |
dfr = fieldInstance.getDescribe(); | |
//@TODO TO remove as all fields should be cloned | |
if( dfr.isAccessible() ){ | |
fieldNameSet.add( dfr.getname() ); | |
} | |
} | |
return fieldNameSet; | |
} | |
public static Boolean startsWith(String sourceString, String character){ | |
//sanity | |
if( sourceString == null ){ | |
return false; | |
} | |
return sourceString.trim().startsWith(character); | |
} | |
public static Map<String,Map<String,String>> getRelationshipDetails(Schema.SObjectType parentSobjectType){ | |
Map<String,Map<String,String>> relationDetailsMap = objectWiseRelationshipMap.get(''+parentSobjectType); | |
//if in cache return immediately | |
if( null != relationDetailsMap ){ | |
return relationDetailsMap; | |
} else { | |
relationDetailsMap = new Map<String,Map<String,String>>(); | |
} | |
Schema.DescribeSObjectResult describeResult = parentSobjectType.getDescribe(); | |
String fieldName; | |
Map<String,String> detailsMap; | |
for(Schema.ChildRelationship childRelationship : describeResult.getChildRelationships()){ | |
//objectname | |
detailsMap = new Map<String,String>(); | |
detailsMap.put(Utils.OBJECTNAME, ''+childRelationship.getChildSObject()); | |
//field | |
fieldName = childRelationship.getField().getDescribe().getName(); | |
detailsMap.put(Utils.FIELDNAME, fieldName); | |
relationDetailsMap.put( childRelationship.getRelationshipName(), detailsMap ); | |
} | |
objectWiseRelationshipMap.put(''+parentSobjectType,relationDetailsMap); | |
return relationDetailsMap; | |
} | |
//record type info utility methods | |
//Record types cache | |
private static Map<Schema.SObjectType,Map<String,Id>> rtypesCache; | |
private static List<sObject> results; | |
static { | |
rtypesCache = new Map<Schema.SObjectType,Map<String,Id>>();//convenient map, formatted from results. | |
results = new List<sObject>();//contains all recordtypes retrieved via SOQL | |
} | |
// Returns a map of active, user-available RecordType IDs for a given SObjectType, | |
// keyed by each RecordType's unique, unchanging DeveloperName | |
private static Map<String, Id> getRecordTypeMapForObjectGeneric(Schema.SObjectType token) { | |
// Do we already have a result? | |
Map<String, Id> mapRecordTypes = rtypesCache.get(token); | |
// If not, build a map of RecordTypeIds keyed by DeveloperName | |
if (mapRecordTypes == null) { | |
mapRecordTypes = new Map<String, Id>(); | |
rtypesCache.put(token,mapRecordTypes); | |
} else { | |
// If we do, return our cached result immediately! | |
return mapRecordTypes; | |
} | |
// Get the Describe Result | |
Schema.DescribeSObjectResult obj = token.getDescribe(); | |
//Check if we already queried all recordtypes. | |
if (results == null || results.isEmpty()) { | |
// Obtain ALL Active Record Types | |
// (We will filter out the Record Types that are unavailable | |
// to the Running User using Schema information) | |
String soql = 'SELECT Id, Name, DeveloperName, sObjectType FROM RecordType WHERE IsActive = TRUE'; | |
try { | |
results = Database.query(soql); | |
} catch (Exception ex) { | |
results = new List<SObject>(); | |
} | |
} | |
// Obtain the RecordTypeInfos for this SObjectType token | |
Map<Id,Schema.RecordTypeInfo> recordTypeInfos = obj.getRecordTypeInfosByID(); | |
// Loop through all of the Record Types we found, | |
// and weed out those that are unavailable to the Running User | |
for (SObject rt : results) { | |
if (recordTypeInfos.get(rt.Id) != null) { | |
if (recordTypeInfos.get(rt.Id).isAvailable()) { | |
// This RecordType IS available to the running user, | |
// so add it to our map of RecordTypeIds by DeveloperName | |
mapRecordTypes.put(String.valueOf(rt.get('DeveloperName')),rt.Id); | |
} | |
else { | |
System.debug('The record type ' + rt.get('DeveloperName') + ' for object ' + rt.get('sObjectType') + ' is not availiable for the user.'); | |
} | |
} | |
} | |
return mapRecordTypes; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment