Skip to content

Commit

Permalink
v1.7.2 - RollupCalcItemReplacer bugfix (#642)
Browse files Browse the repository at this point in the history
* Fixes issue reported with RollupCalcItemReplacer incorrectly detecting Type__r fields as polymorphic
  • Loading branch information
jamessimone authored Dec 11, 2024
1 parent d89e615 commit 588af42
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 19 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ As well, don't miss [the Wiki](../../wiki), which includes even more info for co

## Deployment & Setup

<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfWQAA0">
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfXTAA0">
<img alt="Deploy to Salesforce" src="./media/deploy-package-to-prod.png">
</a>

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfWQAA0">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfXTAA0">
<img alt="Deploy to Salesforce Sandbox" src="./media/deploy-package-to-sandbox.png">
</a>
<br/>
Expand Down
14 changes: 14 additions & 0 deletions extra-tests/classes/RollupCalcItemReplacerTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,18 @@ private class RollupCalcItemReplacerTests {

Assert.areEqual(0, records.size());
}

@IsTest
static void doesNotReplaceForCustomTypeFields() {
List<Account> accounts = [SELECT Id FROM Account];
RollupCalcItemReplacer replacer = new RollupCalcItemReplacer(
new RollupControl__mdt(IsRollupLoggingEnabled__c = true, ReplaceCalcItemsAsyncWhenOverCount__c = 3)
);
List<Rollup__mdt> metas = new List<Rollup__mdt>{ new Rollup__mdt(CalcItemWhereClause__c = 'Parent.Type__r = \'hello\'', CalcItem__c = 'Account') };

List<SObject> records = replacer.replace(accounts, metas);

Assert.areEqual(1, records.size());
Assert.isTrue(replacer.hasProcessedMetadata(metas, accounts));
}
}
58 changes: 58 additions & 0 deletions extra-tests/classes/RollupFlowBulkProcessorTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -639,4 +639,62 @@ private class RollupFlowBulkProcessorTests {
Individual updatedIndy = [SELECT Id, ConsumerCreditScore FROM Individual WHERE Id = :indy.Id];
System.assertEquals(secondChild.AnnualRevenue, updatedIndy.ConsumerCreditScore);
}

@IsTest
static void doesNotNoOpForSomeAllNoneRollups() {
Rollup.rollupMetadata = new List<Rollup__mdt>{
new Rollup__mdt(
RollupFieldOnCalcItem__c = 'Id',
LookupObject__c = 'Account',
LookupFieldOnCalcItem__c = 'AccountId',
LookupFieldOnLookupObject__c = 'Id',
RollupFieldOnLookupObject__c = 'AnnualRevenue',
RollupOperation__c = 'SOME',
CalcItem__c = 'Contact',
CalcItemWhereClause__c = 'FirstName != \'One\''
),
new Rollup__mdt(
RollupFieldOnCalcItem__c = 'Id',
LookupObject__c = 'Account',
LookupFieldOnCalcItem__c = 'AccountId',
LookupFieldOnLookupObject__c = 'Id',
RollupFieldOnLookupObject__c = 'Description',
RollupOperation__c = 'ALL',
CalcItem__c = 'Contact',
CalcItemWhereClause__c = 'FirstName != \'One\''
),
new Rollup__mdt(
RollupFieldOnCalcItem__c = 'Id',
LookupObject__c = 'Account',
LookupFieldOnCalcItem__c = 'AccountId',
LookupFieldOnLookupObject__c = 'Id',
RollupFieldOnLookupObject__c = 'NumberOfEmployees',
RollupOperation__c = 'NONE',
CalcItem__c = 'Contact',
CalcItemWhereClause__c = 'FirstName != \'One\''
)
};
Rollup.onlyUseMockMetadata = true;
Account acc = (Account) RollupTestUtils.queryRecord(Account.SObjectType, new List<Schema.SObjectField>());
acc.Description = 'true';
acc.AnnualRevenue = 1;
acc.NumberOfEmployees = 0;
RollupAsyncProcessor.stubParentRecords = new List<SObject>{ acc };

Rollup.records = new List<Contact>{ new Contact(FirstName = 'One', AccountId = acc.Id) };

RollupFlowBulkProcessor.FlowInput input = new RollupFlowBulkProcessor.FlowInput();
input.recordsToRollup = new List<Contact>{ new Contact(FirstName = 'One', AccountId = acc.Id, Id = RollupTestUtils.createId(Contact.SObjectType)) };
input.oldRecordsToRollup = new List<SObject>{ new Contact(Id = input.recordsToRollup[0].Id, FirstName = 'One', AccountId = acc.Id) };
input.rollupContext = 'UPDATE';
input.deferProcessing = false;

Test.startTest();
RollupFlowBulkProcessor.addRollup(new List<RollupFlowBulkProcessor.FlowInput>{ input });
Test.stopTest();

Assert.areEqual('false', acc.Description);
Assert.areEqual(0, acc.AnnualRevenue);
Assert.areEqual(1, acc.NumberOfEmployees);
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apex-rollup",
"version": "1.7.1",
"version": "1.7.2",
"description": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions rollup-namespaced/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ For more info, see the base `README`.

## Deployment & Setup

<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfWVAA0">
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfXYAA0">
<img alt="Deploy to Salesforce"
src="./media/deploy-package-to-prod.png">
</a>

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfWVAA0">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfXYAA0">
<img alt="Deploy to Salesforce Sandbox"
src="./media/deploy-package-to-sandbox.png">
</a>
7 changes: 4 additions & 3 deletions rollup-namespaced/sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"default": true,
"package": "apex-rollup-namespaced",
"path": "rollup-namespaced/source/rollup",
"versionName": "Scheduled Rollup updates, RollupDateLiteral updates",
"versionNumber": "1.2.1.0",
"versionName": "Fixes issue in RollupCalcItemReplacer where custom Type fields were incorrectly flagged as polymorphic",
"versionNumber": "1.2.2.0",
"versionDescription": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"releaseNotesUrl": "https://github.com/jamessimone/apex-rollup/releases/latest",
"unpackagedMetadata": {
Expand All @@ -26,6 +26,7 @@
"apex-rollup-namespaced@1.1.29": "04t6g000008OfMjAAK",
"apex-rollup-namespaced@1.1.30": "04t6g000008OfSJAA0",
"apex-rollup-namespaced@1.2.0": "04t6g000008OfU0AAK",
"apex-rollup-namespaced@1.2.1": "04t6g000008OfWVAA0"
"apex-rollup-namespaced@1.2.1": "04t6g000008OfWVAA0",
"apex-rollup-namespaced@1.2.2": "04t6g000008OfXYAA0"
}
}
2 changes: 1 addition & 1 deletion rollup/core/classes/Rollup.cls
Original file line number Diff line number Diff line change
Expand Up @@ -2850,7 +2850,7 @@ global without sharing virtual class Rollup implements RollupLogger.ToStringObje
/**
* - in order to accomodate CDC, we set the apexContext manually there
* since technically all CDC is done from an AFTER_INSERT context
* - an undelete behaviors _strictly_ the same as an insert
* - an undelete behaves _strictly_ the same as an insert
* because the underlying SObject can't be modified till afterwards
*/
private static Boolean shouldRunFromTrigger() {
Expand Down
12 changes: 6 additions & 6 deletions rollup/core/classes/RollupCalcItemReplacer.cls
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ public without sharing class RollupCalcItemReplacer {

private void processWhereClauseForDownstreamEvals(Schema.SObjectType sObjectType, Rollup__mdt metadata, RollupEvaluator.WhereFieldEvaluator whereEval) {
for (String whereClause : whereEval.getWhereClauses()) {
Boolean hasTypeField = whereClause.contains(TYPE_FIELD);
Boolean hasTypeField = whereClause.split(TYPE_FIELD + '(?!__r)').size() > 1;
Boolean hasOwnerField = whereClause.contains(OWNER);
if (hasTypeField == false && hasOwnerField == false) {
continue;
Expand Down Expand Up @@ -340,8 +340,8 @@ public without sharing class RollupCalcItemReplacer {
Map<String, SObjectField> fieldNameToFieldToken = calcItems[0].getSObjectType().getDescribe().fields.getMap();
for (Integer index = 0; index < calcItems.size(); index++) {
SObject calcItem = calcItems[index];
SObject calcItemWIthUpdatedParentField = idToCalcItemsWithParentFields.get(calcItem.Id);
Map<String, Object> updatedParentFields = calcItemWIthUpdatedParentField?.getPopulatedFieldsAsMap() ?? new Map<String, Object>();
SObject calcItemWithUpdatedParentField = idToCalcItemsWithParentFields.get(calcItem.Id);
Map<String, Object> updatedParentFields = calcItemWithUpdatedParentField?.getPopulatedFieldsAsMap() ?? new Map<String, Object>();
for (String fieldName : updatedParentFields.keySet()) {
Schema.DescribeFieldResult fieldToken = fieldNameToFieldToken.get(fieldName)?.getDescribe();
Boolean isSkippableField = fieldToken?.getReferenceTo().isEmpty() != false || fieldToken?.getName() == 'Id';
Expand All @@ -353,23 +353,23 @@ public without sharing class RollupCalcItemReplacer {
try {
SObject parent = calcItem.getSObject(fieldToken.getRelationshipName());
if (parent == null) {
calcItem.putSObject(fieldToken.getRelationshipName(), calcItemWIthUpdatedParentField.getSObject(fieldToken.getRelationshipName()));
calcItem.putSObject(fieldToken.getRelationshipName(), calcItemWithUpdatedParentField.getSObject(fieldToken.getRelationshipName()));
} else {
parent.put(fieldName, updatedParentFields.get(fieldName));
}
} catch (SObjectException ex) {
// avoids "System.SObjectException: Relationship { relationship name } is not editable"
if (updatedParentFields.containsKey(fieldToken.getRelationshipName())) {
String relationshipName = fieldToken.getRelationshipName();
calcItems.set(index, serializeReplace(calcItem, relationshipName, calcItemWIthUpdatedParentField.getSObject(relationshipName)));
calcItems.set(index, serializeReplace(calcItem, relationshipName, calcItemWithUpdatedParentField.getSObject(relationshipName)));
}
}
} else {
// polymorphic parent fields that are returned from SOQL can get retrieved via .getSObject,
// but can't be appended via .putSObject without reinitializing the parent object to its actual type
// this is because they are returned with type "Name", and avoids the dreaded:
// "System.SObjectException: Illegal assignment from Name to { the calcItem type }"
SObject parentFieldObject = calcItemWIthUpdatedParentField.getSObject(fieldToken.getRelationshipName());
SObject parentFieldObject = calcItemWithUpdatedParentField.getSObject(fieldToken.getRelationshipName());
SObject replacementObject = parentFieldObject.Id.getSObjectType().newSObject();
for (String populatedFieldName : parentFieldObject.getPopulatedFieldsAsMap().keySet()) {
replacementObject.put(populatedFieldName, parentFieldObject.get(populatedFieldName));
Expand Down
2 changes: 1 addition & 1 deletion rollup/core/classes/RollupLogger.cls
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
global without sharing virtual class RollupLogger implements ILogger {
@TestVisible
// this gets updated via the pipeline as the version number gets incremented
private static final String CURRENT_VERSION_NUMBER = 'v1.7.1';
private static final String CURRENT_VERSION_NUMBER = 'v1.7.2';
private static final System.LoggingLevel FALLBACK_LOGGING_LEVEL = System.LoggingLevel.DEBUG;
private static final RollupPlugin PLUGIN = new RollupPlugin();

Expand Down
7 changes: 4 additions & 3 deletions sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"package": "apex-rollup",
"path": "rollup",
"scopeProfiles": true,
"versionName": "Scheduled Rollup updates, RollupDateLiteral updates",
"versionNumber": "1.7.1.0",
"versionName": "Fixes issue in RollupCalcItemReplacer where custom Type fields were incorrectly flagged as polymorphic",
"versionNumber": "1.7.2.0",
"versionDescription": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"releaseNotesUrl": "https://github.com/jamessimone/apex-rollup/releases/latest",
"unpackagedMetadata": {
Expand Down Expand Up @@ -107,6 +107,7 @@
"apex-rollup@1.6.36": "04t6g000008OfMeAAK",
"apex-rollup@1.6.37": "04t6g000008OfSEAA0",
"apex-rollup@1.7.0": "04t6g000008OfTvAAK",
"apex-rollup@1.7.1": "04t6g000008OfWQAA0"
"apex-rollup@1.7.1": "04t6g000008OfWQAA0",
"apex-rollup@1.7.2": "04t6g000008OfXTAA0"
}
}

0 comments on commit 588af42

Please sign in to comment.