Untitled

 avatar
unknown
apex
a year ago
4.8 kB
7
Indexable
public abstract with sharing class halo_SObjectRollupsCalculator {
    public void recalculate(List<SObject> sObjects, TriggerContext triggerContext) {
        for (SObject sObj : sObjects) {
            SObjectType sObjType = sObj.getSObjectType();

            for (SObjectTypeCustomRollups rollups : this.getCustomRollups().get(sObjType)) {
                rollups.initialize(sObj, triggerContext);
            }
        }

        List<SObject> ancestorsToUpdate = new List<SObject>();

        for (SObjectTypeCustomRollups customRollups : this.getCustomRollups().values()) {
            rollups.recalculate();
            ancestorsToUpdate.addAll(rollups.getUpdatedRecords());
        }

        update ancestorsToUpdate;
    }

    protected abstract Map<SObjectType, SObjectTypeCustomRollups> getCustomRollups();

    protected abstract SObjectType getAncestorSObjectType();

    public abstract with sharing class SObjectTypeCustomRollups {
        private Map<Id, SObject> updatedRecords = new Map<Id, SObject>();

        public void initialize(SObject sObj, TriggerContext triggerContext) {
            for (CustomRollup rollup : this.getRollups()) {
                rollup.initialize(sObj, triggerContext);
            }
        }

        public void recalculate() {
            List<CustomRollup> rollupsToRecalculate = this.getRollupsToRecalculate();

            if (!rollupsToRecalculate.isEmpty()) {
                RollupSelector selector = new RollupSelector(rollupsToRecalculate, this.getRelationshipField(), this.getSObjectType());

                Map<Id, SObject> ancestors = selector.getAncestors();
                List<SObject> descendants = selector.getDescendants();

                for (CustomRollup rollup : rollupsToRecalculate) {
                    rollup.recalculate(ancestors, descendants);

                    for (Id recordId : rollup.getUpdatedRecordIds()) {
                        this.updatedRecords.put(recordId, ancestors.get(recordId));
                    }
                }
            }
        }

        public Set<SObject> getUpdatedRecords() {
            return this.updatedRecords;
        }

        protected abstract List<CustomRollup> getRollups();

        protected abstract SObjectType getSObjectType();

        protected abstract String getRelationshipField();

        private List<CustomRollup> getRollupsToRecalculate() {
            List<CustomRollup> customRollups = new List<CustomRollup>();

            for (CustomRollup rollup : this.getRollups()) {
                if (rollup.shouldRecalculate()) {
                    customRollups.add(rollup);
                }
            }

            return customRollups;
        }
    }

    public interface CustomRollup {
        void initialize(SObject sObj, TriggerContext triggerContext);
        void recalculate(Map<Id, SObject> ancestors, List<SObject> descendants);
        Boolean shouldRecalculate();
        Set<SObjectField> getDescendantQueryFields();
        Set<SObjectField> getAncestorQueryFields();
        Set<Id> getAncestorRecordIds();
        Set<Id> getUpdatedRecordIds();
    }

    private with sharing class RollupSelector() {
        private List<CustomRollup> customRollups;
        private String relationshipField;
        private SObjectType ancestorSObjectType;

        public RollupSelector(List<CustomRollup> customRollups, String relationshipField, SObjectType ancestorSObjectType) {
            this.customRollups = customRollups;
            this.relationshipField = relationshipField;
            this.ancestorSObjectType = ancestorSObjectType;
        }

        public Map<Id, SObject> getAncestors() {
            Set<SObjectField> fields = new Set<SObjectField>();
            Set<Id> recordIds = new Set<Id>();

            for (List<CustomRollup> rollups : this.customRollups) {
                for (CustomRollup rollup : rollups) {
                    fields.addAll(rollup.getAncestorQueryFields());
                    recordIds.addAll(rollup.getAncestorRecordIds());
                }
            }

            return Database.query(String.format('SELECT {0} FROM {1} WHERE {2}', new List<Object> { fields, this.ancestorSObjectType + '', 'Id IN :recordIds' }));
        }

        public List<SObject> getDescendants() {
            Set<SObjectField> fields = new Set<SObjectField>();
            Set<Id> ancestorRecordIds = new Set<Id>();

            for (CustomRollup rollup : this.customRollups) {
                fields.addAll(rollup.getDescendantQueryFields());
                ancestorRecordIds.addAll(rollup.getAncestorRecordIds());
            }

            return Database.query(String.format('SELECT {0} FROM {1} WHERE {2}', new List<Object> { fields, sObjType + '', this.relationshipField + ' IN :ancestorRecordIds' })));
        }
    }
}
Editor is loading...
Leave a Comment