Skip to content

Commit

Permalink
v1.5.38 - Parent Recalc Button bugfix (#396)
Browse files Browse the repository at this point in the history
* Initial commit with updated version and some notes on advanced dated currency edge cases

* Adding in a bit more feedback on full recalc page for when CMDT is loading AND immediate feedback on when the start rollup button is clicked

* Consolidated some enums to prevent unnecessary duplication. rollup processors now track apex context

* Fixing an issue reported by Stephen Stanley where the parent recalc button was failing when Rollup Order By metadata was in use

* Adding Rollup.FlowOutput variables for RollupFlowFullRecalcDispatcher

* Heap size reductions on full recalc path - started clearing some stateful variables that otherwise for many rollups and parent objects would have built up in excess of the total heap size
  • Loading branch information
jamessimone authored Dec 16, 2022
1 parent e9a3147 commit 021d4bc
Show file tree
Hide file tree
Showing 18 changed files with 84 additions and 68 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ As well, don't miss [the Wiki](../../wiki), which includes more advanced informa

## Deployment & Setup

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

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000007zMCdAAM">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008fjOcAAI">
<img alt="Deploy to Salesforce Sandbox"
src="./media/deploy-package-to-sandbox.png">
</a>
Expand Down
23 changes: 0 additions & 23 deletions extra-tests/classes/RollupCalculatorTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -721,29 +721,6 @@ private class RollupCalculatorTests {
System.assertEquals(opp.CloseDate, calc.getReturnValue());
}

@IsTest
static void updateMostWorks() {
RollupCalculator calc = getCalculator(
null,
Rollup.Op.UPDATE_MOST,
Opportunity.CloseDate,
Account.AnnualRevenue,
new Rollup__mdt(CalcItem__c = 'Opportunity'),
'0011g00003VDGbF002',
Opportunity.AccountId
);

Opportunity opp = new Opportunity(CloseDate = System.today(), Id = RollupTestUtils.createId(Opportunity.SObjectType));
calc.performRollup(new List<SObject>{ opp }, new Map<Id, SObject>());

System.assertEquals(opp.CloseDate, calc.getReturnValue());

opp.CloseDate = opp.CloseDate.addDays(-1);
calc.performRollup(new List<SObject>{ opp }, new Map<Id, SObject>());

System.assertEquals(opp.CloseDate, calc.getReturnValue());
}

// SUM tests

@IsTest
Expand Down
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.5.37",
"version": "1.5.38",
"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=04t6g000007zMCiAAM">
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008fjOhAAI">
<img alt="Deploy to Salesforce"
src="./media/deploy-package-to-prod.png">
</a>

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000007zMCiAAM">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008fjOhAAI">
<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": "Adding support for dated conversion rates multi-currency orgs",
"versionNumber": "1.0.10.0",
"versionName": "Fixed a bug on the parent recalc button when used in conjunction with RollupOrderBy__mdt records. Added FlowOutput to Full Recalc CMDT-driven Invocable invocable",
"versionNumber": "1.0.11.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 @@ -31,6 +31,7 @@
"apex-rollup-namespaced@1.0.7-0": "04t6g000007zLxLAAU",
"apex-rollup-namespaced@1.0.8-0": "04t6g000007zM2gAAE",
"apex-rollup-namespaced@1.0.9-0": "04t6g000007zM7DAAU",
"apex-rollup-namespaced@1.0.10-0": "04t6g000007zMCiAAM"
"apex-rollup-namespaced@1.0.10-0": "04t6g000007zMCiAAM",
"apex-rollup-namespaced@1.0.11-0": "04t6g000008fjOhAAI"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ describe('recalc parent rollup from flexipage tests', () => {
// once recalc has finished ...
// we need to validate that what was sent includes our custom rollup invocation point
matchingMetadata[0].CalcItemWhereClause__c = " ||| AccountId = '" + FAKE_RECORD_ID + "'";
matchingMetadata[0].RollupOrderBys__r = { totalSize: 0, done: true, records: [] };
expect(parentRecalcEl.shadowRoot.querySelector('lightning-spinner')).toBeFalsy();
expect(performSerializedBulkFullRecalc.mock.calls[0][0]).toEqual({
serializedMetadata: JSON.stringify(matchingMetadata),
Expand Down Expand Up @@ -183,6 +184,7 @@ describe('recalc parent rollup from flexipage tests', () => {
await flushPromises();

matchingMetadata[0].CalcItemWhereClause__c = " ||| RollupParent__r.RollupGrandparent__r.Id = '" + FAKE_RECORD_ID + "'";
matchingMetadata[0].RollupOrderBys__r = { totalSize: 0, done: true, records: [] };
expect(parentRecalcEl.shadowRoot.querySelector('lightning-spinner')).toBeFalsy();
expect(performSerializedBulkFullRecalc.mock.calls[0][0]).toEqual({
serializedMetadata: JSON.stringify(matchingMetadata),
Expand Down Expand Up @@ -219,6 +221,7 @@ describe('recalc parent rollup from flexipage tests', () => {
await flushPromises('wait for click event to call controller');

matchingMetadata[0].please__CalcItemWhereClause__c = " ||| AccountId = '" + FAKE_RECORD_ID + "'";
matchingMetadata[0].please__RollupOrderBys__r = { totalSize: 0, done: true, records: [] };
expect(parentRecalcEl.shadowRoot.querySelector('lightning-spinner')).toBeFalsy();
expect(performSerializedBulkFullRecalc.mock.calls[0][0]).toEqual({
serializedMetadata: JSON.stringify(matchingMetadata),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { api, LightningElement } from 'lwc';
import performSerializedBulkFullRecalc from '@salesforce/apex/Rollup.performSerializedBulkFullRecalc';
import getNamespaceInfo from '@salesforce/apex/Rollup.getNamespaceInfo';

import { getRollupMetadata } from 'c/rollupUtils';
import { getRollupMetadata, transformToSerializableChildren } from 'c/rollupUtils';

const DELIMITER = ' ||| ';

Expand Down Expand Up @@ -73,6 +73,10 @@ export default class RecalculateParentRollupFlexipage extends LightningElement {
} else {
metadata[calcItemWhereClause] = DELIMITER + equalsParent;
}
const orderByFieldName = this._getNamespaceSafeFieldName('RollupOrderBys__r');
const children = metadata[orderByFieldName];
transformToSerializableChildren(metadata, orderByFieldName, children);

this._matchingMetas.push(metadata);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
Alternatively, you can select a single Child Object based off of your CMDT rollup records and have the recalculation run for all CMDT associated with
that SObject type:
</div>
<template if:true={isLoadingCustomMetadata}>
<div class="slds-is-relative slds-is-fixed-left">
Checking if there's custom metadata ...
<lightning-spinner alternative-text="Please wait while CMDT is retrieved" title="Checking if there's custom metadata ...."></lightning-spinner>
</div>
</template>
<template if:true={canDisplayCmdtToggle}>
<lightning-input class="slds-m-bottom_small" data-id="cmdt-toggle" label="Run off of CMDT?" onchange={handleToggle} type="toggle"></lightning-input>
</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import performSerializedFullRecalculation from '@salesforce/apex/Rollup.performS
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { getObjectInfo, getPicklistValues } from 'lightning/uiObjectInfoApi';

import { getRollupMetadata } from 'c/rollupUtils';
import { getRollupMetadata, transformToSerializableChildren } from 'c/rollupUtils';

const MAX_ROW_SELECTION = 200;

Expand Down Expand Up @@ -123,7 +123,9 @@ export default class RollupForceRecalculation extends LightningElement {
}

async _fetchAvailableCMDT() {
this.isLoadingCustomMetadata = true;
this._localMetadata = await getRollupMetadata();
this.isLoadingCustomMetadata = false;

Object.keys(this._localMetadata).forEach(localMeta => {
if (!this.canDisplayCmdtToggle) {
Expand Down Expand Up @@ -156,11 +158,12 @@ export default class RollupForceRecalculation extends LightningElement {
this._displayErrorToast('Select a valid option', 'Child Object(s) must be selected!');
return;
}

this.isRollingUp = true;
const localMetas = [...this.selectedRows];
this._getMetadataWithChildrenRecords(localMetas);
jobId = await performSerializedBulkFullRecalc({ serializedMetadata: JSON.stringify(localMetas), invokePointName: 'FROM_FULL_RECALC_LWC' });
} else {
this.isRollingUp = true;
this._getMetadataWithChildrenRecords([this._metadata]);
jobId = await performSerializedFullRecalculation({
metadata: JSON.stringify(this._metadata)
Expand All @@ -179,7 +182,6 @@ export default class RollupForceRecalculation extends LightningElement {
this.rollupStatus = 'Job failed to enqueue, check logs for more info';
return Promise.resolve();
}
this.isRollingUp = true;

this.jobIdToDisplay = jobId;
this.rollupStatus = await getBatchRollupStatus({ jobId });
Expand Down Expand Up @@ -221,9 +223,7 @@ export default class RollupForceRecalculation extends LightningElement {
children = possibleOrderByComponent.orderBys;
}
}
if (children && !children.totalSize) {
_metadata[rollupOrderByFieldName] = { totalSize: children?.length, done: true, records: children };
}
transformToSerializableChildren(_metadata, rollupOrderByFieldName, children);
}
}

Expand Down
8 changes: 7 additions & 1 deletion rollup/app/lwc/rollupUtils/rollupUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ const getRollupMetadata = async () => {
return cleanedMetaByCalcItem;
};

export { getRollupMetadata };
const transformToSerializableChildren = (record, key, children) => {
if (children && !children.totalSize) {
record[key] = { totalSize: children?.length ?? 0, done: true, records: children ?? [] };
}
};

export { getRollupMetadata, transformToSerializableChildren };
26 changes: 11 additions & 15 deletions rollup/core/classes/Rollup.cls
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ global without sharing virtual class Rollup {
protected Boolean isCDCUpdate = false;
protected Integer queryCount;
protected RollupCalcItemReplacer calcItemReplacer;
protected TriggerOperation triggerContext;

// Lazy-load section. Lots of additional lines, but with the benefit that we keep the heap size down for instances of Rollup
// that never reference these variables
Expand Down Expand Up @@ -169,7 +170,6 @@ global without sharing virtual class Rollup {
CONCAT,
COUNT_DISTINCT,
COUNT,
DELETE_ALL,
DELETE_AVERAGE,
DELETE_CONCAT_DISTINCT,
DELETE_CONCAT,
Expand All @@ -179,10 +179,7 @@ global without sharing virtual class Rollup {
DELETE_LAST,
DELETE_MAX,
DELETE_MIN,
DELETE_MOST,
DELETE_NONE,
DELETE_SUM,
DELETE_SOME,
FIRST,
LAST,
MAX,
Expand All @@ -191,7 +188,6 @@ global without sharing virtual class Rollup {
NONE,
SOME,
SUM,
UPDATE_ALL,
UPDATE_AVERAGE,
UPDATE_CONCAT_DISTINCT,
UPDATE_CONCAT,
Expand All @@ -201,10 +197,7 @@ global without sharing virtual class Rollup {
UPDATE_LAST,
UPDATE_MAX,
UPDATE_MIN,
UPDATE_MOST,
UPDATE_NONE,
UPDATE_SUM,
UPDATE_SOME
UPDATE_SUM
}

public class FilterResults {
Expand Down Expand Up @@ -660,7 +653,7 @@ global without sharing virtual class Rollup {
global class FlowOutput {
@InvocableVariable(label='Is Success' description='Was rollup enqueued successfully?')
global Boolean isSuccess;
@InvocableVariable(label='Status Message' description='"SUCCESS" when isSuccess is true, otherwise the encountered error message')
@InvocableVariable(label='Status Message' description='"SUCCESS" (or more info) when isSuccess is true, otherwise the encountered error message')
global String message;
global FlowOutput() {
this.isSuccess = true;
Expand Down Expand Up @@ -1982,11 +1975,12 @@ global without sharing virtual class Rollup {
} else {
// if the same items get run through different rollup operations in the same transaction (rare, but not impossible ...)
// we need to reset the CMDT to the correct base operation prior to appending the new context
meta.RollupOperation__c =
rollupContext +
(meta.RollupOperation__c.contains('UPDATE_') || meta.RollupOperation__c.contains('DELETE_')
? meta.RollupOperation__c.substringAfter('_')
: meta.RollupOperation__c);
meta.RollupOperation__c = (meta.RollupOperation__c.contains('UPDATE_') || meta.RollupOperation__c.contains('DELETE_')
? meta.RollupOperation__c.substringAfter('_')
: meta.RollupOperation__c);
if (OP_NAME_TO_OP.containsKey(rollupContext + meta.RollupOperation__c)) {
meta.RollupOperation__c = rollupContext + meta.RollupOperation__c;
}
}
}

Expand Down Expand Up @@ -2481,6 +2475,7 @@ global without sharing virtual class Rollup {
matchingOperation = TriggerOperation.BEFORE_DELETE;
}
}
apexContext = matchingOperation;
populateCachedApexOperations(sObjectType, matchingOperation);

return flowContext == 'INSERT' ? '' : flowContext + '_';
Expand Down Expand Up @@ -2847,6 +2842,7 @@ global without sharing virtual class Rollup {
rollupControl,
rollupMetadata
);
processor.triggerContext = apexContext;
return addRollup(rollupConductor, processor);
}

Expand Down
19 changes: 17 additions & 2 deletions rollup/core/classes/RollupAsyncProcessor.cls
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ global virtual without sharing class RollupAsyncProcessor extends Rollup impleme
// calling clear in a loop here might look interesting - and it would be a massive problem if not for the
// bag only responding to the very first clear() invocation. everything after that is a no-op (so, any rollup with more
// than one rollup operation going at a time)
if (rollup.op.name().contains('DELETE')) {
if (rollup.triggerContext == System.TriggerOperation.BEFORE_DELETE) {
bag.clear();
}
}
Expand Down Expand Up @@ -663,6 +663,12 @@ global virtual without sharing class RollupAsyncProcessor extends Rollup impleme
return this.metadata?.ShouldRunWithoutCustomSettingEnabled__c == true;
}

private void clearPreviouslyResetParents(RollupAsyncProcessor processor, SObject parent) {
String key = this.getParentResetKey(String.valueOf(processor.opFieldOnLookupObject), parent);
this.previouslyResetParents.remove(key);
this.fullRecalcProcessor?.previouslyResetParents.remove(key);
}

private Boolean hasParentRollupFieldBeenReset(String rollupFieldName, SObject parent) {
String resetKey = this.getParentResetKey(rollupFieldName, parent);
Boolean hasParentRollupFieldBeenReset = this.previouslyResetParents.contains(resetKey);
Expand Down Expand Up @@ -942,7 +948,7 @@ global virtual without sharing class RollupAsyncProcessor extends Rollup impleme
private Boolean isEmptyReparentingSet(Op operation) {
switch on operation {
// reparenting is handled already for these operations
when ALL, DELETE_ALL, DELETE_MOST, DELETE_NONE, DELETE_SOME, MOST, NONE, SOME, UPDATE_ALL, UPDATE_MOST, UPDATE_NONE, UPDATE_SOME {
when ALL, MOST, NONE, SOME {
return true;
}
when else {
Expand Down Expand Up @@ -1079,6 +1085,7 @@ global virtual without sharing class RollupAsyncProcessor extends Rollup impleme
Map<String, SObject> unprocessedCalcItems = new Map<String, SObject>();
RollupSObjectUpdater updater = new RollupSObjectUpdater(roll.opFieldOnLookupObject);
RollupCalculator calc;
String priorKey;
for (Integer index = lookupItems.size() - 1; index >= 0; index--) {
SObject lookupRecord = lookupItems[index];
if (lookupRecord.getSObjectType() != roll.lookupObj) {
Expand Down Expand Up @@ -1114,6 +1121,14 @@ global virtual without sharing class RollupAsyncProcessor extends Rollup impleme
calc = this.getCalculator(calc, roll, localCalcItems, lookupRecord, priorValToUse, key, roll.lookupFieldOnCalcItem);
this.conditionallyPerformUpdate(priorVal, calc, lookupRecord, roll, recordsToUpdate, updater, 'lookup', localCalcItems);
}
if (priorKey != null && key != priorKey) {
// once we've fully processed a parent (in separate batches)
// it's safe to clear the stateful map
this.clearPreviouslyResetParents(roll, lookupRecord);
priorKey = key;
} else if (priorKey == null) {
priorKey = key;
}
}
}

Expand Down
10 changes: 5 additions & 5 deletions rollup/core/classes/RollupCalculator.cls
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public without sharing abstract class RollupCalculator {
) {
RollupCalculator calc;
switch on op {
when ALL, DELETE_ALL, DELETE_NONE, DELETE_SOME, NONE, SOME, UPDATE_ALL, UPDATE_NONE, UPDATE_SOME {
when ALL, NONE, SOME {
calc = new ConditionalCalculator(op, opFieldOnCalcItem, opFieldOnLookupObject, metadata, lookupKeyField);
}
when AVERAGE, UPDATE_AVERAGE, DELETE_AVERAGE {
Expand All @@ -61,7 +61,7 @@ public without sharing abstract class RollupCalculator {
when FIRST, UPDATE_FIRST, DELETE_FIRST, LAST, UPDATE_LAST, DELETE_LAST {
calc = new FirstLastRollupCalculator(op, opFieldOnCalcItem, opFieldOnLookupObject, metadata, lookupKeyField);
}
when MOST, DELETE_MOST, UPDATE_MOST {
when MOST {
calc = new MostRollupCalculator(op, opFieldOnCalcItem, opFieldOnLookupObject, metadata, lookupKeyField);
}
when else {
Expand Down Expand Up @@ -304,7 +304,7 @@ public without sharing abstract class RollupCalculator {
}
if (currentItemMatches) {
items.add(this.getTransformedCalcItem(item));
if (this.op == Rollup.Op.SOME || this.op == Rollup.Op.UPDATE_SOME) {
if (this.op == Rollup.Op.SOME) {
break;
}
}
Expand Down Expand Up @@ -1228,10 +1228,10 @@ public without sharing abstract class RollupCalculator {
List<SObject> filteredItems = this.winnowItems(new List<SObject>(calcItems), oldCalcItems);
Boolean matches = false;
switch on this.op {
when ALL, DELETE_ALL, UPDATE_ALL {
when ALL {
matches = calcItems.size() == filteredItems.size();
}
when NONE, DELETE_NONE, DELETE_SOME, SOME, UPDATE_NONE, UPDATE_SOME {
when NONE, SOME {
matches = filteredItems.isEmpty() == this.op.name().contains(Rollup.Op.SOME.name()) == false;
}
}
Expand Down
Loading

0 comments on commit 021d4bc

Please sign in to comment.