Skip to content

Commit

Permalink
Add support for Concatenate, Last and First operations
Browse files Browse the repository at this point in the history
See for more info

#7
6

#7
9
  • Loading branch information
afawcettffdc committed Feb 15, 2015
1 parent e9a322e commit 9526865
Show file tree
Hide file tree
Showing 7 changed files with 672 additions and 56 deletions.
273 changes: 232 additions & 41 deletions rolluptool/src/classes/LREngine.cls

Large diffs are not rendered by default.

25 changes: 16 additions & 9 deletions rolluptool/src/classes/RollupService.cls
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ global with sharing class RollupService
global static Id runJobToCalculate(Id lookupId)
{
// Is another calculate job running for this lookup?
List<LookupRollupSummary__c> lookups = new RollupSummariesSelector().selectById(new Set<Id> { lookupId });
List<LookupRollupSummary__c> lookups = new RollupSummariesSelector().selectById(new Set<Id> { lookupId });
if(lookups.size()==0)
throw RollupServiceException.rollupNotFound(lookupId);
LookupRollupSummary__c lookup = lookups[0];
Expand Down Expand Up @@ -559,30 +559,37 @@ global with sharing class RollupService
if(childFields==null)
gdFields.put(childObjectType, ((childFields = childObjectType.getDescribe().fields.getMap())));
SObjectField fieldToAggregate = childFields.get(lookup.FieldToAggregate__c);
SObjectField fieldToOrderBy = lookup.FieldToOrderBy__c!=null ? childFields.get(lookup.FieldToOrderBy__c) : null;
SObjectField relationshipField = childFields.get(lookup.RelationshipField__c);
SObjectField aggregateResultField = parentFields.get(lookup.AggregateResultField__c);
if(fieldToAggregate==null || relationshipField==null || aggregateResultField==null)
throw RollupServiceException.invalidRollup(lookup);

// Determine if an LREngine Context has been created for this parent child relationship and filter combination?
String contextKey = lookup.ParentObject__c + '#' + lookup.RelationshipField__c + '#' + lookup.RelationShipCriteria__c;
// Summary field definition used by LREngine
LREngine.RollupSummaryField rsf =
new LREngine.RollupSummaryField(
aggregateResultField.getDescribe(),
fieldToAggregate.getDescribe(),
fieldToOrderBy !=null ? fieldToOrderBy.getDescribe() : null, // field to order by on child
RollupSummaries.OPERATION_PICKLIST_TO_ENUMS.get(lookup.AggregateOperation__c),
lookup.ConcatenateDelimiter__c);

// Determine if an LREngine Context has been created for this parent child relationship, filter combination or underlying query type?
String rsfType = rsf.isAggregateBasedRollup() ? 'aggregate' : 'query';
String contextKey = lookup.ParentObject__c + '#' + lookup.RelationshipField__c + '#' + lookup.RelationShipCriteria__c + '#' + rsfType;
LREngine.Context lreContext = engineCtxByParentRelationship.get(contextKey);
if(lreContext==null)
{
// Construct LREngine.Context
lreContext = new LREngine.Context(
parentObjectType, // parent object
childObjectType, // child object
childObjectType, // child object
relationshipField.getDescribe(), // relationship field name
lookup.RelationShipCriteria__c);
engineCtxByParentRelationship.put(contextKey, lreContext);
}
// Add the lookup
lreContext.add(
new LREngine.RollupSummaryField(
aggregateResultField.getDescribe(),
fieldToAggregate.getDescribe(),
RollupSummaries.OPERATION_PICKLIST_TO_ENUMS.get(lookup.AggregateOperation__c)));
lreContext.add(rsf);
}
return engineCtxByParentRelationship;
}
Expand Down
136 changes: 136 additions & 0 deletions rolluptool/src/classes/RollupServiceTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -954,4 +954,140 @@ private with sharing class RollupServiceTest
// Assert rollup
System.assertEquals(expectedResult, [select AnnualRevenue from Account where Id = :account.Id].AnnualRevenue);
}

private testmethod static void testMultiRollupOfDifferentTypes()
{
// Test supported?
if(!TestContext.isSupported())
return;

// Test data
List<Decimal> rollups = new List<Decimal> { 250, 250, 50, 50 };

// Test data for rollup A
Decimal expectedResultA = 600;
RollupSummaries.AggregateOperation operationA = RollupSummaries.AggregateOperation.Sum;
String conditionA = null;

// Test data for rollup B
String expectedResultB = 'Open,Open,Open,Open';
RollupSummaries.AggregateOperation operationB = RollupSummaries.AggregateOperation.Concatenate;
String conditionB = null;

// Configure rollup A
LookupRollupSummary__c rollupSummaryA = new LookupRollupSummary__c();
rollupSummaryA.Name = 'Total Opportunities into Annual Revenue on Account';
rollupSummaryA.ParentObject__c = 'Account';
rollupSummaryA.ChildObject__c = 'Opportunity';
rollupSummaryA.RelationShipField__c = 'AccountId';
rollupSummaryA.RelationShipCriteria__c = conditionA;
rollupSummaryA.FieldToAggregate__c = 'Amount';
rollupSummaryA.AggregateOperation__c = operationA.name();
rollupSummaryA.AggregateResultField__c = 'AnnualRevenue';
rollupSummaryA.Active__c = true;
rollupSummaryA.CalculationMode__c = 'Realtime';

// Configure rollup B
LookupRollupSummary__c rollupSummaryB = new LookupRollupSummary__c();
rollupSummaryB.Name = 'Concatenate Opportunities Stage Name into Description on Account';
rollupSummaryB.ParentObject__c = 'Account';
rollupSummaryB.ChildObject__c = 'Opportunity';
rollupSummaryB.RelationShipField__c = 'AccountId';
rollupSummaryB.RelationShipCriteria__c = conditionB;
rollupSummaryB.FieldToAggregate__c = 'StageName';
rollupSummaryB.AggregateOperation__c = operationB.name();
rollupSummaryB.AggregateResultField__c = 'Description';
rollupSummaryB.ConcatenateDelimiter__c = ',';
rollupSummaryB.Active__c = true;
rollupSummaryB.CalculationMode__c = 'Realtime';

// Insert rollup definitions
insert new List<LookupRollupSummary__c> { rollupSummaryA, rollupSummaryB };

// Test data
Account account = new Account();
account.Name = 'Test Account';
account.AnnualRevenue = 0;
insert account;
List<Opportunity> opps = new List<Opportunity>();
for(Decimal rollupValue : rollups)
{
Opportunity opp = new Opportunity();
opp.Name = 'Test Opportunity';
opp.StageName = 'Open';
opp.CloseDate = System.today();
opp.AccountId = account.Id;
opp.Amount = rollupValue;
opps.add(opp);
}
insert opps;

// Assert rollup
Id accountId = account.Id;
Account accountResult = Database.query('select AnnualRevenue, Description from Account where Id = :accountId');
System.assertEquals(expectedResultA, accountResult.AnnualRevenue);
System.assertEquals(expectedResultB, accountResult.Description);
}

private testmethod static void testPicklistRollup()
{
// Test supported?
if(!TestContext.isSupported())
return;

// Create a picklist rollup
LookupRollupSummary__c rollupSummary = new LookupRollupSummary__c();
rollupSummary.Name = 'Test Rollup';
rollupSummary.ParentObject__c = 'dlrs__LookupParent__c';
rollupSummary.ChildObject__c = 'dlrs__LookupChild__c';
rollupSummary.RelationShipField__c = 'dlrs__LookupParent__c';
rollupSummary.FieldToAggregate__c = 'dlrs__Color__c';
rollupSummary.AggregateOperation__c = RollupSummaries.AggregateOperation.Concatenate.name();
rollupSummary.AggregateResultField__c = 'dlrs__Colours__c';
rollupSummary.ConcatenateDelimiter__c = ';';
rollupSummary.Active__c = true;
rollupSummary.CalculationMode__c = 'Realtime';
insert rollupSummary;

// Insert parents
Schema.SObjectType parentType = Schema.getGlobalDescribe().get('dlrs__LookupParent__c');
SObject parentA = parentType.newSObject();
parentA.put('Name', 'ParentA');
SObject parentB = parentType.newSObject();
parentB.put('Name', 'ParentB');
SObject parentC = parentType.newSObject();
parentC.put('Name', 'ParentC');
List<SObject> parents = new List<SObject> { parentA, parentB, parentC };
insert parents;

// Insert children
Schema.SObjectType childType = Schema.getGlobalDescribe().get('dlrs__LookupChild__c');
List<SObject> children = new List<SObject>();
for(SObject parent : parents)
{
String name = (String) parent.get('Name');
SObject child1 = childType.newSObject();
child1.put('dlrs__LookupParent__c', parent.Id);
child1.put('dlrs__Color__c', 'Red');
children.add(child1);
SObject child2 = childType.newSObject();
child2.put('dlrs__LookupParent__c', parent.Id);
child2.put('dlrs__Color__c', 'Yellow');
children.add(child2);
if(name.equals('ParentA') || name.equals('ParentB'))
{
SObject child3 = childType.newSObject();
child3.put('dlrs__LookupParent__c', parent.Id);
child3.put('dlrs__Color__c', 'Blue');
children.add(child3);
}
}
insert children;

// Assert rollups
Map<Id, SObject> assertParents = new Map<Id, SObject>(Database.query('select id, dlrs__Colours__c from dlrs__LookupParent__c'));
System.assertEquals('Red;Yellow;Blue', (String) assertParents.get(parentA.id).get('dlrs__Colours__c'));
System.assertEquals('Red;Yellow;Blue', (String) assertParents.get(parentB.id).get('dlrs__Colours__c'));
System.assertEquals('Red;Yellow', (String) assertParents.get(parentC.id).get('dlrs__Colours__c'));
}
}
23 changes: 20 additions & 3 deletions rolluptool/src/classes/RollupSummaries.cls
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ public with sharing class RollupSummaries extends SObjectDomain
AggregateOperation.Min.name() => LREngine.RollupOperation.Min,
AggregateOperation.Avg.name() => LREngine.RollupOperation.Avg,
AggregateOperation.Count.name() => LREngine.RollupOperation.Count,
AggregateOperation.Count_Distinct.name().replace('_', ' ') => LREngine.RollupOperation.Count_Distinct
AggregateOperation.Count_Distinct.name().replace('_', ' ') => LREngine.RollupOperation.Count_Distinct,
AggregateOperation.Concatenate.name() => LREngine.RollupOperation.Concatenate,
AggregateOperation.Concatenate_Distinct.name().replace('_', ' ') => LREngine.RollupOperation.Concatenate_Distinct,
AggregateOperation.First.name() => LREngine.RollupOperation.First,
AggregateOperation.Last.name() => LREngine.RollupOperation.Last
};

/**
Expand All @@ -66,7 +70,11 @@ public with sharing class RollupSummaries extends SObjectDomain
Min,
Avg,
Count,
Count_Distinct
Count_Distinct,
Concatenate,
Concatenate_Distinct,
First,
Last
}

public RollupSummaries(List<LookupRollupSummary__c> records)
Expand Down Expand Up @@ -112,6 +120,7 @@ public with sharing class RollupSummaries extends SObjectDomain
// Child Object fields valid?
SObjectField relationshipField = null;
SObjectField fieldToAggregate = null;
SObjectField fieldToOrderBy = null;
Map<String, Schema.SObjectField> childObjectFields = gdFields.get(childObjectType);
if(childObjectFields!=null)
{
Expand All @@ -123,6 +132,12 @@ public with sharing class RollupSummaries extends SObjectDomain
fieldToAggregate = childObjectFields.get(lookupRollupSummary.FieldToAggregate__c);
if(fieldToAggregate==null)
lookupRollupSummary.FieldToAggregate__c.addError(error('Field does not exist.', lookupRollupSummary, LookupRollupSummary__c.FieldToAggregate__c));
// Field to Order By valid?
if(lookupRollupSummary.FieldToOrderBy__c!=null) {
fieldToOrderBy = childObjectFields.get(lookupRollupSummary.FieldToOrderBy__c);
if(fieldToOrderBy==null)
lookupRollupSummary.FieldToOrderBy__c.addError(error('Field does not exist.', lookupRollupSummary, LookupRollupSummary__c.FieldToOrderBy__c));
}
// TODO: Validate relationship field is a lookup to the parent
// ...
}
Expand Down Expand Up @@ -178,7 +193,9 @@ public with sharing class RollupSummaries extends SObjectDomain
new LREngine.RollupSummaryField(
aggregateResultField.getDescribe(),
fieldToAggregate.getDescribe(),
OPERATION_PICKLIST_TO_ENUMS.get(lookupRollupSummary.AggregateOperation__c)));
fieldToOrderBy!=null ? fieldToOrderBy.getDescribe() : null, // optional field to order by
OPERATION_PICKLIST_TO_ENUMS.get(lookupRollupSummary.AggregateOperation__c),
lookupRollupSummary.ConcatenateDelimiter__c));
// Validate the SOQL
if(lookupRollupSummary.RelationShipCriteria__c!=null &&
lookupRollupSummary.RelationShipCriteria__c.length()>0)
Expand Down
2 changes: 2 additions & 0 deletions rolluptool/src/classes/RollupSummariesSelector.cls
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ public with sharing class RollupSummariesSelector extends SObjectSelector
LookupRollupSummary__c.AggregateResultField__c,
LookupRollupSummary__c.CalculationMode__c,
LookupRollupSummary__c.ChildObject__c,
LookupRollupSummary__c.ConcatenateDelimiter__c,
LookupRollupSummary__c.FieldToAggregate__c,
LookupRollupSummary__c.FieldToOrderBy__c,
LookupRollupSummary__c.ParentObject__c,
LookupRollupSummary__c.RelationshipCriteria__c,
LookupRollupSummary__c.RelationshipCriteriaFields__c,
Expand Down
25 changes: 25 additions & 0 deletions rolluptool/src/classes/RollupSummariesTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,31 @@ private with sharing class RollupSummariesTest
System.assertEquals('Field does not exist.', SObjectDomain.Errors.getAll()[0].message);
System.assertEquals(LookupRollupSummary__c.FieldToAggregate__c, ((SObjectDomain.FieldError)SObjectDomain.Errors.getAll()[0]).field);
}

private testmethod static void testInsertFieldToOrderByValidation()
{
// Test supported?
if(!TestContext.isSupported())
return;

LookupRollupSummary__c rollupSummary = new LookupRollupSummary__c();
rollupSummary.Name = 'Total Opportunities into Annual Revenue on Account';
rollupSummary.ParentObject__c = 'Account';
rollupSummary.ChildObject__c = 'Opportunity';
rollupSummary.RelationShipField__c = 'AccountId';
rollupSummary.RelationShipCriteria__c = null;
rollupSummary.FieldToAggregate__c = 'Amount';
rollupSummary.FieldToOrderBy__c = 'AmountX';
rollupSummary.AggregateOperation__c = 'Sum';
rollupSummary.AggregateResultField__c = 'AnnualRevenue';
rollupSummary.Active__c = true;
rollupSummary.CalculationMode__c = 'Realtime';
SObjectDomain.Test.Database.onInsert(new LookupRollupSummary__c[] { rollupSummary } );
SObjectDomain.triggerHandler(RollupSummaries.class);
System.assertEquals(1, SObjectDomain.Errors.getAll().size());
System.assertEquals('Field does not exist.', SObjectDomain.Errors.getAll()[0].message);
System.assertEquals(LookupRollupSummary__c.FieldToOrderBy__c, ((SObjectDomain.FieldError)SObjectDomain.Errors.getAll()[0]).field);
}

private testmethod static void testInsertAggregateResultFieldValidation()
{
Expand Down
Loading

0 comments on commit 9526865

Please sign in to comment.