Skip to content

Instantly share code, notes, and snippets.

@swapnilshrikhande
Last active August 24, 2017 09:08
Show Gist options
  • Save swapnilshrikhande/6ad3e92a924599d3d6830b06e8dcd404 to your computer and use it in GitHub Desktop.
Save swapnilshrikhande/6ad3e92a924599d3d6830b06e8dcd404 to your computer and use it in GitHub Desktop.
Generic SOQL Query Generator and other utility methods
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;
}
}
// 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