From 8ccb38cbb0db194f6baaefbf2c57a221ce6b2cc0 Mon Sep 17 00:00:00 2001 From: Andrew Fawcett Date: Sat, 18 Jun 2016 10:30:10 +0100 Subject: [PATCH] Added Row Limit feature https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/3 15 --- .../src/classes/CustomMetadataService.cls | 15 ++- rolluptool/src/classes/LREngine.cls | 24 +++- rolluptool/src/classes/RollupService.cls | 3 +- rolluptool/src/classes/RollupServiceTest.cls | 127 ++++++++++++++++++ rolluptool/src/classes/RollupSummaries.cls | 17 ++- .../src/classes/RollupSummariesSelector.cls | 6 +- .../src/classes/RollupSummariesTest.cls | 25 ++++ rolluptool/src/classes/RollupSummary.cls | 10 ++ rolluptool/src/classes/TestLREngine.cls | 23 ++++ ...2__mdt-Lookup Rollup Summary Layout.layout | 8 ++ ...ary__c-Lookup Rollup Summary Layout.layout | 8 ++ .../objects/LookupRollupSummary2__mdt.object | 13 +- .../src/objects/LookupRollupSummary__c.object | 12 ++ .../pages/managelookuprollupsummaries.page | 13 +- .../LookupRollupSummariesFull.permissionset | 5 + ...ookupRollupSummariesReadOnly.permissionset | 5 + 16 files changed, 299 insertions(+), 15 deletions(-) diff --git a/rolluptool/src/classes/CustomMetadataService.cls b/rolluptool/src/classes/CustomMetadataService.cls index 178c3fc7..d5ed14bd 100644 --- a/rolluptool/src/classes/CustomMetadataService.cls +++ b/rolluptool/src/classes/CustomMetadataService.cls @@ -89,11 +89,20 @@ public class CustomMetadataService { if(!dsr.isCustom()) continue; Object fieldValue = customMetadataRecord.get(sObjectField); - if(fieldValue == null) - continue; MetadataService.CustomMetadataValue cmdv = new MetadataService.CustomMetadataValue(); cmdv.field = dsr.getName(); - cmdv.value = fieldValue+''; // TODO: More work here, type conversion + if(dsr.getType() == Schema.DisplayType.Double) { + if(fieldValue!=null) { + Decimal fieldValueNumber = (Decimal) fieldValue; + // TODO: Bit of a hack, MDT Number fields seem to be populated with zeros when the VF bound field is emptied by the user?!? + if(fieldValueNumber != 0) { + fieldValueNumber = fieldValueNumber.setScale(dsr.getScale()); + cmdv.value = fieldValueNumber.format(); + } + } + } else { + cmdv.value = fieldValue + ''; // TODO: More work here, type conversion + } cm.values.add(cmdv); } return cm; diff --git a/rolluptool/src/classes/LREngine.cls b/rolluptool/src/classes/LREngine.cls index d0e1fff9..cd0d505a 100644 --- a/rolluptool/src/classes/LREngine.cls +++ b/rolluptool/src/classes/LREngine.cls @@ -278,7 +278,9 @@ public class LREngine { rsf.operation == RollupOperation.Concatenate_Distinct) { Concatenator concatenator = new Concatenator(rsf.operation == RollupOperation.Concatenate_Distinct, rsf.concatenateDelimiter); + Integer rowIdx = 0; for(SObject childDetailRecord : childDetailRecords) { + rowIdx++; String childFieldValue = String.valueOf(childDetailRecord.get(rsf.detail.getName())); if (childFieldValue != null) { if (rsf.detail.getType() == Schema.DisplayType.MultiPicklist) { @@ -289,6 +291,9 @@ public class LREngine { concatenator.add(childFieldValue); } } + if(rsf.RowLimit!=null && rsf.RowLimit>0 && rowIdx == rsf.RowLimit) { + break; + } } String concatenatedValues = concatenator.toString(); concatenatedValues = concatenatedValues.abbreviate(rsf.master.getLength()); @@ -297,8 +302,13 @@ public class LREngine { masterRecordsMap.get(masterId).put( rsf.master.getName(), childDetailRecords[0].get(rsf.detail.getName())); } else if(rsf.operation == RollupOperation.Last) { + Integer recordSetSize = childDetailRecords.size(); + Integer index = + rsf.RowLimit!=null && rsf.RowLimit>0 ? + (rsf.RowLimit < recordSetSize ? rsf.RowLimit-1 : recordSetSize - 1) : recordSetSize - 1; masterRecordsMap.get(masterId).put( - rsf.master.getName(), childDetailRecords[childDetailRecords.size()-1].get(rsf.detail.getName())); + rsf.master.getName(), + childDetailRecords[index].get(rsf.detail.getName())); } // Remove master Id record as its been processed masterIds.remove(masterId); @@ -380,6 +390,7 @@ public class LREngine { public Schema.Describefieldresult detail; public RollupOperation operation; public String concatenateDelimiter; + public Integer rowLimit; // derived fields, kept like this to save script lines later, by saving the same // computations over and over again @@ -402,10 +413,21 @@ public class LREngine { Schema.Describefieldresult d, RollupOperation op, String concatenateDelimiter) { + this(m, d, op, concatenateDelimiter, null); + } + + + public RollupSummaryField(Schema.Describefieldresult m, + Schema.Describefieldresult d, + RollupOperation op, + String concatenateDelimiter, + Integer rowLimit) { + this.master = m; this.detail = d; this.operation = op; this.concatenateDelimiter = concatenateDelimiter; + this.rowLimit = rowLimit; // caching these derived attrbutes for once // as their is no view state involved here // and this caching will lead to saving in script lines later on diff --git a/rolluptool/src/classes/RollupService.cls b/rolluptool/src/classes/RollupService.cls index e980350b..296d37de 100644 --- a/rolluptool/src/classes/RollupService.cls +++ b/rolluptool/src/classes/RollupService.cls @@ -1106,7 +1106,8 @@ global with sharing class RollupService aggregateResultField.getDescribe(), fieldToAggregate.getDescribe(), RollupSummaries.OPERATION_PICKLIST_TO_ENUMS.get(lookup.AggregateOperation), - lookup.ConcatenateDelimiter); + lookup.ConcatenateDelimiter, + Integer.valueOf(lookup.RowLimit)); LookupRollupSummaryWrapper wrapper = new LookupRollupSummaryWrapper(); wrapper.Lookup = lookup; diff --git a/rolluptool/src/classes/RollupServiceTest.cls b/rolluptool/src/classes/RollupServiceTest.cls index 9a164c5e..deb910de 100644 --- a/rolluptool/src/classes/RollupServiceTest.cls +++ b/rolluptool/src/classes/RollupServiceTest.cls @@ -1314,6 +1314,133 @@ private with sharing class RollupServiceTest System.assertEquals('Red;Yellow', (String) assertParents.get(parentC.id).get(aggregateResultField)); } + + private testmethod static void testPicklistRollupWithLimits() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField = LookupChild__c.Color__c.getDescribe().getName(); + String aggregateResultField = LookupParent__c.Colours__c.getDescribe().getName(); + + // Create a picklist rollup + LookupRollupSummary__c rollupSummary = new LookupRollupSummary__c(); + rollupSummary.Name = 'Test Rollup'; + rollupSummary.ParentObject__c = parentObjectName; + rollupSummary.ChildObject__c = childObjectName; + rollupSummary.RelationShipField__c = relationshipField; + rollupSummary.FieldToAggregate__c = aggregateField; + rollupSummary.AggregateOperation__c = RollupSummaries.AggregateOperation.Concatenate.name(); + rollupSummary.AggregateResultField__c = aggregateResultField; + rollupSummary.ConcatenateDelimiter__c = ';'; + rollupSummary.Active__c = true; + rollupSummary.CalculationMode__c = 'Realtime'; + rollupSummary.RowLimit__c = 2; + rollupSummary.AggregateAllRows__c = true; + insert rollupSummary; + + // Insert parents + 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 parents = new List { parentA, parentB, parentC }; + insert parents; + + // Insert children + List children = new List(); + for(SObject parent : parents) + { + String name = (String) parent.get('Name'); + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField, 'Red'); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField, 'Yellow'); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField, 'Blue'); + children.add(child3); + } + insert children; + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0} from {1}', new List{ aggregateResultField, parentObjectName }))); + System.assertEquals('Red;Yellow', (String) assertParents.get(parentA.id).get(aggregateResultField)); + System.assertEquals('Red;Yellow', (String) assertParents.get(parentB.id).get(aggregateResultField)); + System.assertEquals('Red;Yellow', (String) assertParents.get(parentC.id).get(aggregateResultField)); + } + + + private testmethod static void testLastRollupWithLimits() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField = LookupChild__c.Color__c.getDescribe().getName(); + String aggregateResultField = LookupParent__c.Colours__c.getDescribe().getName(); + + // Create a picklist rollup + LookupRollupSummary__c rollupSummary = new LookupRollupSummary__c(); + rollupSummary.Name = 'Test Rollup'; + rollupSummary.ParentObject__c = parentObjectName; + rollupSummary.ChildObject__c = childObjectName; + rollupSummary.RelationShipField__c = relationshipField; + rollupSummary.FieldToAggregate__c = aggregateField; + rollupSummary.AggregateOperation__c = RollupSummaries.AggregateOperation.Last.name(); + rollupSummary.AggregateResultField__c = aggregateResultField; + rollupSummary.FieldToOrderBy__c = aggregateField + ' DESC'; + rollupSummary.Active__c = true; + rollupSummary.CalculationMode__c = 'Realtime'; + rollupSummary.RowLimit__c = 2; + rollupSummary.AggregateAllRows__c = true; + insert rollupSummary; + + // Insert parents + SObject parent = parentType.newSObject(); + parent.put('Name', 'ParentA'); + List parents = new List { parent }; + insert parents; + + // Insert children + List children = new List(); + String name = (String) parent.get('Name'); + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField, '1'); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField, '2'); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField, '3'); + children.add(child3); + insert children; + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0} from {1}', new List{ aggregateResultField, parentObjectName }))); + System.assertEquals('2', (String) assertParents.get(parent.id).get(aggregateResultField)); + } + private testmethod static void testLimitsConsumedWithSingleChildChanged() { // Test supported? diff --git a/rolluptool/src/classes/RollupSummaries.cls b/rolluptool/src/classes/RollupSummaries.cls index d83ceb15..e4fad44a 100644 --- a/rolluptool/src/classes/RollupSummaries.cls +++ b/rolluptool/src/classes/RollupSummaries.cls @@ -291,7 +291,20 @@ public class RollupSummaries extends fflib_SObjectDomain lookupRollupSummary.Fields.RelationshipCriteriaFields.addError(error('Field ' + fieldsInError[0] + ' does not exist on the child object.', lookupRollupSummary.Record, LookupRollupSummary__c.RelationshipCriteriaFields__c)); else if(fieldsInError.size()>1) lookupRollupSummary.Fields.RelationshipCriteriaFields.addError(error('Fields ' + String.join(fieldsInError, ',') + ' do not exist on the child object.', lookupRollupSummary.Record, LookupRollupSummary__c.RelationshipCriteriaFields__c)); - } + } + // Row limit is only supported for certain operations + LREngine.RollupOperation operation = + OPERATION_PICKLIST_TO_ENUMS.get(lookupRollupSummary.AggregateOperation); + if(operation!=null && lookupRollupSummary.RowLimit!=null) { + Set operationsSupportingRowLimit + = new Set{ + LREngine.RollupOperation.Last, + LREngine.RollupOperation.Concatenate, + LREngine.RollupOperation.Concatenate_Distinct }; + if(!operationsSupportingRowLimit.contains(operation)) { + lookupRollupSummary.Fields.RowLimit.addError(error('Row Limit is only supported on Last and Concatentate operators.', lookupRollupSummary.Record, LookupRollupSummary__c.RowLimit__c )); + } + } try { // If all objects and fields valid... @@ -313,7 +326,7 @@ public class RollupSummaries extends fflib_SObjectDomain new LREngine.RollupSummaryField( aggregateResultField.getDescribe(), fieldToAggregate.getDescribe(), - OPERATION_PICKLIST_TO_ENUMS.get(lookupRollupSummary.AggregateOperation), + operation, lookupRollupSummary.ConcatenateDelimiter)); // Validate the SOQL if(lookupRollupSummary.RelationShipCriteria!=null && diff --git a/rolluptool/src/classes/RollupSummariesSelector.cls b/rolluptool/src/classes/RollupSummariesSelector.cls index 633daf52..3e515995 100644 --- a/rolluptool/src/classes/RollupSummariesSelector.cls +++ b/rolluptool/src/classes/RollupSummariesSelector.cls @@ -122,7 +122,8 @@ public class RollupSummariesSelector LookupRollupSummary__c.CalculationSharingMode__c, LookupRollupSummary__c.TestCode__c, LookupRollupSummary__c.TestCodeSeeAllData__c, - LookupRollupSummarY__c.AggregateAllRows__c + LookupRollupSummary__c.AggregateAllRows__c, + LookupRollupSummary__c.RowLimit__c }; } @@ -228,7 +229,8 @@ public class RollupSummariesSelector LookupRollupSummary2__mdt.TestCode__c, LookupRollupSummary2__mdt.TestCodeSeeAllData__c, LookupRollupSummary2__mdt.Description__c, - LookupRollupSummary2__mdt.AggregateAllRows__c + LookupRollupSummary2__mdt.AggregateAllRows__c, + LookupRollupSummary2__mdt.RowLimit__c }; } diff --git a/rolluptool/src/classes/RollupSummariesTest.cls b/rolluptool/src/classes/RollupSummariesTest.cls index 7fbcbff1..e73eafbb 100644 --- a/rolluptool/src/classes/RollupSummariesTest.cls +++ b/rolluptool/src/classes/RollupSummariesTest.cls @@ -517,4 +517,29 @@ private class RollupSummariesTest System.assertEquals(0, fflib_SObjectDomain.Errors.getAll().size()); } + + private testmethod static void testUseOfRowLimitOnSum() + { + // 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.AggregateOperation__c = 'Sum'; + rollupSummary.AggregateResultField__c = 'AnnualRevenue'; + rollupSummary.RowLimit__c = 10; + rollupSummary.Active__c = true; + rollupSummary.CalculationMode__c = 'Realtime'; + fflib_SObjectDomain.Test.Database.onInsert(new LookupRollupSummary__c[] { rollupSummary } ); + fflib_SObjectDomain.triggerHandler(RollupSummaries.class); + System.assertEquals(1, fflib_SObjectDomain.Errors.getAll().size()); + System.assertEquals('Row Limit is only supported on Last and Concatentate operators.', fflib_SObjectDomain.Errors.getAll()[0].message); + System.assertEquals(LookupRollupSummary__c.RowLimit__c, ((fflib_SObjectDomain.FieldError)fflib_SObjectDomain.Errors.getAll()[0]).field); + } } \ No newline at end of file diff --git a/rolluptool/src/classes/RollupSummary.cls b/rolluptool/src/classes/RollupSummary.cls index 11fd8659..34806662 100644 --- a/rolluptool/src/classes/RollupSummary.cls +++ b/rolluptool/src/classes/RollupSummary.cls @@ -156,6 +156,11 @@ public class RollupSummary { set { Record.put('AggregateAllRows__c', value); } } + public Decimal RowLimit { + get { return (Decimal) Record.get('RowLimit__c'); } + set { Record.put('RowLimit__c', value); } + } + public void addError(String errorMessage) { // Store the error message @@ -208,6 +213,7 @@ public class RollupSummary { public final FieldData TestCode = new FieldData(this); public final FieldData TestCodeSeeAllData = new FieldData(this); public final FieldData AggregateAllRows = new FieldData(this); + public final FieldData RowLimit = new FieldData(this); } /** @@ -261,6 +267,8 @@ public class RollupSummary { fieldLabelInError = LookupRollupSummary__c.TestCodeSeeAllData__c.getDescribe().getLabel(); } else if(this === RecordMetadata.AggregateAllRows) { fieldLabelInError = LookupRollupSummary__c.AggregateAllRows__c.getDescribe().getLabel(); + } else if(this === RecordMetadata.RowLimit) { + fieldLabelInError = LookupRollupSummary__c.RowLimit__c.getDescribe().getLabel(); } // Store error @@ -308,6 +316,8 @@ public class RollupSummary { customObjectRecord.TestCodeSeeAllData__c.addError(errorMessage); } else if(this === RecordMetadata.AggregateAllRows) { customObjectRecord.AggregateAllRows__c.addError(errorMessage); + } else if(this === RecordMetadata.RowLimit) { + customObjectRecord.RowLimit__c.addError(errorMessage); } } } diff --git a/rolluptool/src/classes/TestLREngine.cls b/rolluptool/src/classes/TestLREngine.cls index 8aa05024..30649e7f 100644 --- a/rolluptool/src/classes/TestLREngine.cls +++ b/rolluptool/src/classes/TestLREngine.cls @@ -800,6 +800,17 @@ private class TestLREngine { 'Lost,Won,Won'); } + static testMethod void testRollupConcatenateLimited() { + testRollup( + Schema.SObjectType.Opportunity.fields.StageName.getName(), + new LREngine.RollupSummaryField( + Schema.SObjectType.Account.fields.Description, + Schema.SObjectType.Opportunity.fields.StageName, + LREngine.RollupOperation.Concatenate, ',', 2), + 'test,test', + 'Lost,Won'); + } + static testMethod void testRollupConcatenateDeletedChildRows() { testRollup( Schema.SObjectType.Opportunity.fields.StageName.getName(), @@ -1054,6 +1065,17 @@ private class TestLREngine { 'Lost'); } + static testMethod void testRollupLastLimit() { + testRollup( + Schema.SObjectType.Opportunity.fields.Amount.getName(), + new LREngine.RollupSummaryField( + Schema.SObjectType.Account.fields.Description, + Schema.SObjectType.Opportunity.fields.StageName, + LREngine.RollupOperation.Last, null, 2), + 'test', + 'Won'); + } + static testMethod void testMultipleRollupsSameResultField() { prepareData(); @@ -1116,6 +1138,7 @@ private class TestLREngine { } static private void testRollup(String detailOrderByClause, LREngine.RollupSummaryField rollupField, String expected1, String expected2, boolean allRows) { + prepareData(); if(allRows) diff --git a/rolluptool/src/layouts/LookupRollupSummary2__mdt-Lookup Rollup Summary Layout.layout b/rolluptool/src/layouts/LookupRollupSummary2__mdt-Lookup Rollup Summary Layout.layout index 099fb806..4880b4f1 100644 --- a/rolluptool/src/layouts/LookupRollupSummary2__mdt-Lookup Rollup Summary Layout.layout +++ b/rolluptool/src/layouts/LookupRollupSummary2__mdt-Lookup Rollup Summary Layout.layout @@ -99,6 +99,14 @@ Required AggregateResultField__c + + Edit + AggregateAllRows__c + + + Edit + RowLimit__c + diff --git a/rolluptool/src/layouts/LookupRollupSummary__c-Lookup Rollup Summary Layout.layout b/rolluptool/src/layouts/LookupRollupSummary__c-Lookup Rollup Summary Layout.layout index 0efe9c14..0e6e2c1f 100644 --- a/rolluptool/src/layouts/LookupRollupSummary__c-Lookup Rollup Summary Layout.layout +++ b/rolluptool/src/layouts/LookupRollupSummary__c-Lookup Rollup Summary Layout.layout @@ -89,6 +89,14 @@ Required AggregateResultField__c + + Edit + AggregateAllRows__c + + + Edit + RowLimit__c + diff --git a/rolluptool/src/objects/LookupRollupSummary2__mdt.object b/rolluptool/src/objects/LookupRollupSummary2__mdt.object index c2e470fa..26b0f1b8 100644 --- a/rolluptool/src/objects/LookupRollupSummary2__mdt.object +++ b/rolluptool/src/objects/LookupRollupSummary2__mdt.object @@ -13,7 +13,7 @@ AggregateAllRows__c false false - Includes child records that have been archived by the system and/or placed in the recycle bin. + Includes child records that have been archived by the system and/or placed in the recycle bin. Checkbox @@ -159,6 +159,17 @@ Text false + + RowLimit__c + false + Limits the number of rows used in the rollup. Applies only to the Last and Concatenate operators. + + 5 + false + 0 + Number + false + TestCodeSeeAllData__c false diff --git a/rolluptool/src/objects/LookupRollupSummary__c.object b/rolluptool/src/objects/LookupRollupSummary__c.object index 7786e038..ec652cb6 100644 --- a/rolluptool/src/objects/LookupRollupSummary__c.object +++ b/rolluptool/src/objects/LookupRollupSummary__c.object @@ -305,6 +305,18 @@ Text false + + RowLimit__c + false + Limits the number of rows used in the rollup. Applies only to the Last and Concatenate operators. + + 5 + false + 0 + false + Number + false + TestCodeSeeAllData__c false diff --git a/rolluptool/src/pages/managelookuprollupsummaries.page b/rolluptool/src/pages/managelookuprollupsummaries.page index a7267e6d..9179f1f3 100644 --- a/rolluptool/src/pages/managelookuprollupsummaries.page +++ b/rolluptool/src/pages/managelookuprollupsummaries.page @@ -144,6 +144,11 @@ + + + + + @@ -158,12 +163,10 @@ - diff --git a/rolluptool/src/permissionsets/LookupRollupSummariesFull.permissionset b/rolluptool/src/permissionsets/LookupRollupSummariesFull.permissionset index 6faa6d02..e12cbf60 100644 --- a/rolluptool/src/permissionsets/LookupRollupSummariesFull.permissionset +++ b/rolluptool/src/permissionsets/LookupRollupSummariesFull.permissionset @@ -55,6 +55,11 @@ LookupRollupSummary__c.AggregateAllRows__c true + + true + LookupRollupSummary__c.RowLimit__c + true + true LookupRollupSummary__c.CalculationMode__c diff --git a/rolluptool/src/permissionsets/LookupRollupSummariesReadOnly.permissionset b/rolluptool/src/permissionsets/LookupRollupSummariesReadOnly.permissionset index a243e6e3..868d6cac 100644 --- a/rolluptool/src/permissionsets/LookupRollupSummariesReadOnly.permissionset +++ b/rolluptool/src/permissionsets/LookupRollupSummariesReadOnly.permissionset @@ -164,6 +164,11 @@ LookupRollupSummary__c.AggregateAllRows__c true + + false + LookupRollupSummary__c.RowLimit__c + true + false LookupRollupSummary__c.CalculationMode__c