Skip to content

Instantly share code, notes, and snippets.

@ralphcallaway
Created October 25, 2013 17:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ralphcallaway/7158252 to your computer and use it in GitHub Desktop.
Save ralphcallaway/7158252 to your computer and use it in GitHub Desktop.
Sample code for working with account hierarchies
/*
Developer: Ralph Callaway <ralph@callawaycloudconsulting.com>
Description:
Representation of an account hierarchy.
*/
public class AccountHierarchy {
/* Variables */
private Boolean accountsLoaded = false;
private Boolean hierarchyLoaded = false;
private Id refId;
private Set<String> queryFields = new Set<String>();
private static Set<String> alwaysQueryFields = new Set<String>{ 'name', 'parentid' };
/* Properties */
private List<Account> accounts {
get {
if(!accountsLoaded) {
loadAccounts();
}
return accounts;
}
set;
}
public Integer limitAmt { get; set; }
public String whereClause {
get;
set {
if(whereClause != value) {
whereClause = value;
accountsLoaded = false;
hierarchyLoaded = false;
}
}
}
public Node root {
get {
if(whereClause != null) {
root = null;
} else if(!hierarchyLoaded) {
buildHierarchy();
}
return root;
}
private set;
}
/* Constructor */
public AccountHierarchy(Id refId) {
this.refId = refId;
}
/* Public Methods */
public void addQueryField(String field) {
if(field != null) {
Boolean newField = queryFields.add(field.toLowerCase());
if(newField) {
accountsLoaded = false;
hierarchyLoaded = false;
}
}
}
// returns by value
public Set<String> getQueryFields() {
return queryFields.clone();
}
public List<Account> toAccountList() {
return (root == null) ? accounts : root.toAccountList();
}
public List<Id> toIdList() {
List<Id> idList = new List<Id>();
if(root == null) {
Map<Id, Account> tempMap = new Map<Id, Account>(accounts);
idList.addAll(tempMap.keySet());
} else {
idList = root.toIdList();
}
return idList;
}
public List<Node> toList() {
return (root == null) ? new List<Node>() : root.toList();
}
// returns true if value present, false if value not found
public Boolean removeQueryField(String field) {
if(field != null) {
field = field.toLowerCase();
if(queryFields.contains(field)) {
queryFields.remove(field);
return true;
}
}
return false;
}
public void setRefToHQ() {
refId = getHQId(refId);
}
/* Static Public Methods */
public static Id getHQId(Id startId) {
Account account = [
select
parentId
, parent.parentId
, parent.parent.parentId
, parent.parent.parent.parentId
, parent.parent.parent.parent.parentId
, parent.parent.parent.parent.parent.parentId
from Account
where id = :startId
];
if(account.parent.parent.parent.parent.parent.parentId != null) {
return account.parent.parent.parent.parent.parent.parentId;
} else if(account.parent.parent.parent.parent.parentId != null) {
return account.parent.parent.parent.parent.parentId;
} else if(account.parent.parent.parent.parentId != null) {
return account.parent.parent.parent.parentId;
} else if(account.parent.parent.parentId != null) {
return account.parent.parent.parentId;
} else if(account.parent.parentId != null) {
return account.parent.parentId;
} else if(account.parentId != null) {
return account.parentId;
} else {
return account.id;
}
}
/* Support Methods */
private void buildHierarchy() {
hierarchyLoaded = true;
// bail if we don't have any accounts to build
if(accounts.isEmpty()) return;
// query all accounts down the hierarchy and organize by their parent
Map<Id, List<Node>> nodeByParent = new Map<Id, List<Node>>();
for(Account account : accounts) {
if(!nodeByParent.containsKey(account.parentId))
nodeByParent.put(account.parentId, new List<Node>());
Node accountNode = new Node(account);
if(account.id == refId)
root = accountNode;
nodeByParent.get(account.parentId).add(new Node(account));
}
// build the hierarchy one level at a time
root.depth = 1;
recursiveNodeBuild(root, nodeByParent);
}
private String buildQuery() {
String selectFields = '';
Set<String> allFields = new Set<String>();
allFields.addAll(alwaysQueryFields);
allFields.addAll(queryFields);
for(String field : allFields) {
selectFields += ', ' + field;
}
selectFields = selectFields.substring(2);
String innerWhereClause = ''
+ ' where (id = \'' + refId + '\''
+ ' or parentId = \'' + refId + '\''
+ ' or parent.parentId = \'' + refId + '\''
+ ' or parent.parent.parentId = \'' + refId + '\''
+ ' or parent.parent.parent.parentId = \'' + refId + '\''
+ ' or parent.parent.parent.parent.parentId = \'' + refId + '\''
+ ' or parent.parent.parent.parent.parent.parentId = \'' + refId + '\')';
String queryString = 'select ' + selectFields + ' from Account' + innerWhereClause;
if(whereClause != null) {
whereClause = whereClause.toLowerCase();
whereClause = whereClause.replace('where', '');
queryString += ' and (' + whereClause + ')';
}
queryString += ' order by name asc';
if(limitAmt != null) {
queryString += ' limit ' + limitAmt;
}
return queryString;
}
private void loadAccounts() {
accountsLoaded = true;
accounts = (List<Account>) Database.query(buildQuery());
}
private void recursiveNodeBuild(Node currentNode, Map<Id, List<Node>> nodesByParent) {
if(nodesByParent.containsKey(currentNode.id)) {
for(Node child : nodesByParent.get(currentNode.id)) {
child.depth = currentNode.depth + 1;
currentNode.children.add(child);
recursiveNodeBuild(child, nodesByParent);
}
}
}
/* Inner Classs */
public class Node {
// variables
public Integer depth { get; set; } // root node has depth of 1
public String name { get; private set; }
public String id { get; private set; }
public Account record { get; set; }
public List<Node> children { get; set; }
// constructor
public Node(Account record) {
this.record = record;
name = record.name;
id = record.id;
depth = -1; // -1 indicates depth has not been set
children = new List<Node>();
}
// methods
public List<Account> toAccountList() {
List<Account> accountList = new Account[] { record };
for(Node child : children) {
accountList.addAll(child.toAccountList());
}
return accountList;
}
public List<Id> toIdList() {
List<Id> toIdList = new Id[] { id };
for(Node child : children) {
toIdList.addAll(child.toIdList());
}
return toIdList;
}
public List<Node> toList() {
List<Node> nodeList = new Node[] { this };
for(Node child : children) {
nodeList.addAll(child.toList());
}
return nodeList;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment