Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.6.32 - Adds Rollup.runFromApex overload #613

Merged
merged 2 commits into from
Aug 6, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Adds overload for Rollup.runFromApex(List<SObject> children, Map<Id, …
…SObject> oldChildrenMap, System.TriggerOperation rollupContext)
  • Loading branch information
jamessimone committed Aug 6, 2024
commit e4fa83a73e7e865348574d827f3063ae3851be9e
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -453,12 +453,15 @@ global static void runFromCDCTrigger()

// imperatively from Apex, relying on CMDT for additional rollup info
// if you are actually using this from WITHIN a trigger, the second argument should
// ALWAYS be the "Trigger.operationType" static variable
global static void runFromApex(List<SObject> calcItems, TriggerOperation rollupContext)
// ALWAYS be the "Trigger.operationType" static variable (unless you're unit testing)
global static void runFromApex(List<SObject> children, TriggerOperation rollupContext)

// overload of the above, with support for the Trigger.oldMap variable (or your unit-tested approximation thereof)
global static void runFromApex(List<SObject> children, Map<Id, SObject> oldChildrenMap, TriggerOperation rollupContext)

// for more info on how this method differs from the one above it, check out the "Parent Level Merges" section!
// for anything OTHER than merge situations use of this method is an anti-pattern
global static Rollup runFromApex(List<Rollup__mdt> rollupMetadata, Evaluator eval, List<SObject> calcItems, Map<Id, SObject> oldCalcItems)
global static Rollup runFromApex(List<Rollup__mdt> rollupMetadata, Evaluator eval, List<SObject> children, Map<Id, SObject> oldChildrenMap)

// imperatively from Apex with arguments taking the place of values previously supplied by CMDT
// can be used in conjunction with "batch" to group rollup operations (as seen in the example preceding this section)
37 changes: 36 additions & 1 deletion extra-tests/classes/RollupIntegrationTests.cls
Original file line number Diff line number Diff line change
@@ -1625,7 +1625,6 @@ private class RollupIntegrationTests {
new ContactPointAddress(Id = RollupTestUtils.createId(ContactPointAddress.SObjectType), ParentId = acc.Id, PreferenceRank = 10)
};

Rollup.records = cpas;
Rollup.rollupMetadata = new List<Rollup__mdt>{
new Rollup__mdt(
RollupFieldOnCalcItem__c = 'PreferenceRank',
@@ -1646,6 +1645,42 @@ private class RollupIntegrationTests {
System.assertEquals(15, acc.AnnualRevenue);
}

@IsTest
static void shouldRunWithOldRecordsDirectlyFromApex() {
Account acc = [SELECT Id FROM Account];

List<ContactPointAddress> cpas = new List<ContactPointAddress>{
new ContactPointAddress(Id = RollupTestUtils.createId(ContactPointAddress.SObjectType), ParentId = acc.Id, PreferenceRank = 5),
new ContactPointAddress(Id = RollupTestUtils.createId(ContactPointAddress.SObjectType), ParentId = acc.Id, PreferenceRank = 10)
};

Rollup.rollupMetadata = new List<Rollup__mdt>{
new Rollup__mdt(
RollupFieldOnCalcItem__c = 'PreferenceRank',
LookupObject__c = 'Account',
LookupFieldOnCalcItem__c = 'ParentId',
LookupFieldOnLookupObject__c = 'Id',
RollupFieldOnLookupObject__c = 'AnnualRevenue',
RollupOperation__c = 'SUM',
CalcItem__c = 'ContactPointAddress'
)
};

Test.startTest();
Rollup.runFromApex(
cpas,
new Map<Id, SObject>{
cpas[0].Id => new ContactPointAddress(Id = cpas[0].Id, ParentId = acc.Id, PreferenceRank = 0),
cpas[1].Id => new ContactPointAddress(Id = cpas[1].Id, ParentId = acc.Id, PreferenceRank = 0)
},
TriggerOperation.AFTER_UPDATE
);
Test.stopTest();

acc = [SELECT AnnualRevenue FROM Account];
System.assertEquals(15, acc.AnnualRevenue);
}

@IsTest
static void shouldDeferUpdateWhenMaxParentRowsLessThanCurrentUpdateRows() {
Account acc = [SELECT Id FROM Account];
17 changes: 10 additions & 7 deletions rollup/core/classes/Rollup.cls
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ global without sharing virtual class Rollup implements RollupLogger.ToStringObje
* but this keeps things much simpler
*/
@TestVisible
private static Boolean shouldRun = false;
private static Boolean shouldRun;
@TestVisible
private static TriggerOperation apexContext;
@TestVisible
@@ -1699,12 +1699,9 @@ global without sharing virtual class Rollup implements RollupLogger.ToStringObje
* - TriggerOperation.BEFORE_DELETE
* - TriggerOperation.AFTER_UNDELETE
*
* Note that while it's an anti-pattern to call this from directly within a Trigger,
* because `runFromTrigger()` coupled with CMDT is the better option,
* you should pass: `Trigger.operationType` for the second argument if you do.
*/
global static void runFromApex(List<SObject> calcItems, TriggerOperation rollupContext) {
shouldRun = true;
global static void runFromApex(List<SObject> calcItems, System.TriggerOperation rollupContext) {
shouldRun = shouldRun ?? true;
records = calcItems;
apexContext = rollupContext;

@@ -1715,6 +1712,12 @@ global without sharing virtual class Rollup implements RollupLogger.ToStringObje
apexContext = null;
}

global static void runFromApex(List<SObject> children, Map<Id, SObject> oldChildrenMap, System.TriggerOperation rollupContext) {
oldChildrenMap = oldChildrenMap;
runFromApex(children, rollupContext);
oldChildrenMap = null;
}

global static Rollup runFromApex(List<Rollup__mdt> localMetas, Evaluator eval, List<SObject> calcItems, Map<Id, SObject> oldCalcItems) {
Rollup rollupConductor = RollupAsyncProcessor.getConductor(InvocationPoint.FROM_APEX, calcItems, oldCalcItems);
if (shouldRunFromTrigger() == false || localMetas.isEmpty()) {
@@ -2828,7 +2831,7 @@ global without sharing virtual class Rollup implements RollupLogger.ToStringObje
* because the underlying SObject can't be modified till afterwards
*/
private static Boolean shouldRunFromTrigger() {
shouldRun = shouldRun || Trigger.isExecuting;
shouldRun = Trigger.isExecuting || (shouldRun ?? false);
if (Trigger.operationType != null && isCDC == false) {
apexContext = Trigger.operationType;
}
5 changes: 2 additions & 3 deletions sfdx-project.json
Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@
"package": "apex-rollup",
"path": "rollup",
"scopeProfiles": true,
"versionName": "Fixes issue where sync rollups with lowercase field names in where clauses would not start up properly",
"versionNumber": "1.6.31.0",
"versionName": "Adds imperative Apex method Rollup.runFromApex for new and old record code paths",
"versionNumber": "1.6.32.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": {
@@ -101,7 +101,6 @@
"Apex Rollup - Rollup Callback@0.0.3-0": "04t6g000008Sis0AAC",
"Nebula Logger - Core@4.8.0-NEXT-ignore-origin-method": "04t5Y0000015lslQAA",
"apex-rollup": "0Ho6g000000TNcOCAW",
"apex-rollup@1.6.27": "04t6g000008ObL7AAK",
"apex-rollup@1.6.28": "04t6g000008ObN8AAK",
"apex-rollup@1.6.29": "04t6g000008ObNNAA0",
"apex-rollup@1.6.30": "04t6g000008ObVhAAK",
Loading