Component treemanager


This component exposes methods for manipulating in-database trees based on the nested set model. All you need to do is ensure your table has a numeric primary key (the 'id' field), numeric left/right fields (the 'lpos' and 'rpos' fields, and a sortable field for ordering (the 'sort' field), if you want to use the sortChildren and/or sortSiblings methods. The names of the actual fields (along with the datasource and table name) are passed as arguments to the init method, and all are optional.

While the nested set model theoretically allows for multiple 'root' nodes, this implementation doesn't support that. There must be a single root node that all other nodes are descendants of. While parts of the code will work with multiple top-level nodes, many methods will fail, and none are indended to be used with a multi-root tree.

It must be mentioned that there is no guarentee that the left/right positions maintained by this object will remain fully compressed. It is entirely possible that spaces will develop.


Method Summary
public treemanager init(string dsn, string table, [string sortField="name"], [string lposField="lpos"], [string rposField="rpos"], [string idField="id"])
          I initialize this treemanager object, and return myself.
public string getChildIds(numeric id)
          I return a list of IDs for the child nodes of the specified node.
public struct getFirstChild(numeric id)
          I return a struct with id, lpos, and rpos of the specified node's first child.
public struct getNextSibling(numeric id)
          Returns a struct with the id, lpos, and rpos of the specified node's next sibling.
public struct getNode(numeric id)
          Returns a struct with the id, lpos, and rpos of the specified node
public query getNodeList([string columnList="*"])
          I return a recordset containing the full list of nodes, using the specified columnList, with the addition of a 'depth' column, which contains the depth of each node in the tree.
package struct getParent(numeric id)
          Returns a struct with the id, lpos, and rpos of the specified node's parent.
public struct getPreviousSibling(numeric id)
          Returns a struct with the id, lpos, and rpos of the specified node's previous sibling.
public void initializeHierarchy(numeric id)
          I initialize the tree hierarchy with the specified node as the root.
public void injectIntoHierarchy(numeric id, numeric parentID)
          I inject a node into the hierarchy. In terms of the database, I take a record that doesn't currently belong to the tree and add it into the tree, using the specified node as it's parent. Newly added nodes will always end up as the last child of the parent.
public void makeChildOfNode(numeric id, numeric parentId)
          I nest an node under another node. If the new parent node is a descendant of the node being moved, an exception is raised.
public void moveDown(numeric id)
          I move a node down one slot. In other words, swap it with it's next sibling. If the node doesn't have a next sibling, nothing happens.
private void moveSubtree(numeric id, numeric destPos)
          Thid moves the specified node to a new place in the tree.
public void moveToBottom(numeric id)
          I move a node to the bottom of the sibling list. If the node doesn't have siblings or is already at the bottom, nothing happens.
public void moveToTop(numeric id)
          I move a node to the top of the sibling list. If the node doesn't have siblings or is already at the top, nothing happens.
public void moveUp(numeric id)
          I move a node up one slot. In other words, swap it with it's previous sibling. If the node doesn't have a previous sibling, nothing happens.
public void nestObject(numeric id)
          I nest an object under it's previous sibling. If the node doesn't have a previous sibling, nothing happens.
public void removeFromHierarchy(numeric id)
          I remove the specified node from the tree hierarchy. Note that the record will continue to exist in the database, it just won't be linked into the hierarchy
private void shift(numeric startPos, numeric delta)
          I move all positions greater than a certain position a certain distance. This is typically used to make or close hole in the hierarchy when moving subtrees around.
private void shiftRange(numeric startPos, numeric endPos, numeric delta)
          I move a range of positions a certain distance. Usually used for moving a subtree into/out of a hole in the hierarchy created with the shift method.
public void sortChildren(numeric parentID, [boolean descending="false"])
          I sort the children of the specified node according to the configured sort field, using the id field as backup to ensure a stable sort. The sort method used will be most performant when the nodes are already close to sorted (under the assumption that if you want the nodes sorted, you'll resort them after every operation that might have disturbed their ordering, and so rarely have more than a node or two to reorder).
public void sortSiblings(numeric id, [boolean descending="false"])
          I sort the node and it's siblings according to the configured sort field, using the id field as backup to ensure a stable sort. This method is currently implemented as nothing more than a call to sortChildren passing the id of the specified node's parent. That means that you can't sort the root level of the hierarchy, which should be expected, since a tree never has more than one node at it's root.
public void unnestObject(numeric id)
          I unnest an object (make it a sibling of it's parent). If the node doesn't have a parent, nothing happens.
 

Method Detail

getChildIds

public string getChildIds(numeric id)
I return a list of IDs for the child nodes of the specified node.

Parameters:
numeric id - The node to find the children of.

getFirstChild

public struct getFirstChild(numeric id)
I return a struct with id, lpos, and rpos of the specified node's first child.

Parameters:
numeric id - The id of the node to find the first child of.

Throws:
IllegalStateException.NoChildrenException

getNextSibling

public struct getNextSibling(numeric id)
Returns a struct with the id, lpos, and rpos of the specified node's next sibling.

Parameters:
numeric id - The id of the node to find the next sibling of.

Throws:
IllegalStateException.NoNextSiblingException

getNode

public struct getNode(numeric id)
Returns a struct with the id, lpos, and rpos of the specified node

Parameters:
numeric id - The id of the node to get info about.

Throws:
IllegalStateException.NoSuchNodeException

getNodeList

public query getNodeList([string columnList="*"])
I return a recordset containing the full list of nodes, using the specified columnList, with the addition of a 'depth' column, which contains the depth of each node in the tree.

Parameters:
[string columnList="*"] - The list of columns to select for the recordset. This value will be injected directly into the SQL, so it must be sanitized before passing. Since the string is injected into the SELECT clause of the statement, you cannot perform joins, but you can use subqueries. The statement you're injecting into is a single table SELECT on the unaliased table name, and ordered by the lpos column.

getParent

package struct getParent(numeric id)
Returns a struct with the id, lpos, and rpos of the specified node's parent.

Parameters:
numeric id - The id of the node to find the parent of.

Throws:
IllegalStateException.NoParentException

getPreviousSibling

public struct getPreviousSibling(numeric id)
Returns a struct with the id, lpos, and rpos of the specified node's previous sibling.

Parameters:
numeric id - The id of the node to find the next previous of.

Throws:
IllegalStateException.NoPreviousSiblingException

init

public treemanager init(string dsn, string table, [string sortField="name"], [string lposField="lpos"], [string rposField="rpos"], [string idField="id"])
I initialize this treemanager object, and return myself.

Parameters:
string dsn - The datasource to access the database though.
string table - The database table that the tree objects are stored in.
[string sortField="name"] - The field that should control sorting operations. This field needn't be unique, it will always be backed up with the 'id' field to ensure a stable result.
[string lposField="lpos"] - The field that stores the left number of nodes.
[string rposField="rpos"] - The field that stores the right number of nodes.
[string idField="id"] - The field that stores the unique id of a node.

initializeHierarchy

public void initializeHierarchy(numeric id)
I initialize the tree hierarchy with the specified node as the root.

Parameters:
numeric id - The id of the node to start as the root of the hierarchy.

injectIntoHierarchy

public void injectIntoHierarchy(numeric id, numeric parentID)
I inject a node into the hierarchy. In terms of the database, I take a record that doesn't currently belong to the tree and add it into the tree, using the specified node as it's parent. Newly added nodes will always end up as the last child of the parent.

Parameters:
numeric id - The id of the record to inject.
numeric parentID - The id of the node the new node should be a child of.

makeChildOfNode

public void makeChildOfNode(numeric id, numeric parentId)
I nest an node under another node. If the new parent node is a descendant of the node being moved, an exception is raised.

Parameters:
numeric id - The node to nest.
numeric parentId - The node's new parent node.

Throws:
IllegalStateException.InvalidNestingRequest

moveDown

public void moveDown(numeric id)
I move a node down one slot. In other words, swap it with it's next sibling. If the node doesn't have a next sibling, nothing happens.

Parameters:
numeric id - The id of the node to move down.

moveSubtree

private void moveSubtree(numeric id, numeric destPos)
Thid moves the specified node to a new place in the tree.

Parameters:
numeric id - The node to move.
numeric destPos - The new lpos for the node. Note that this is not necessarily the lpos the node will keep, because after the move the nodes may be recompressed and the lpos shifted.

moveToBottom

public void moveToBottom(numeric id)
I move a node to the bottom of the sibling list. If the node doesn't have siblings or is already at the bottom, nothing happens.

Parameters:
numeric id - The id of the node to move to the bottom.

moveToTop

public void moveToTop(numeric id)
I move a node to the top of the sibling list. If the node doesn't have siblings or is already at the top, nothing happens.

Parameters:
numeric id - The id of the node to move to the top.

moveUp

public void moveUp(numeric id)
I move a node up one slot. In other words, swap it with it's previous sibling. If the node doesn't have a previous sibling, nothing happens.

Parameters:
numeric id - The id of the node to move up.

nestObject

public void nestObject(numeric id)
I nest an object under it's previous sibling. If the node doesn't have a previous sibling, nothing happens.

Parameters:
numeric id - The node to nest.

removeFromHierarchy

public void removeFromHierarchy(numeric id)
I remove the specified node from the tree hierarchy. Note that the record will continue to exist in the database, it just won't be linked into the hierarchy

Parameters:
numeric id - The id of the node to remove.

shift

private void shift(numeric startPos, numeric delta)
I move all positions greater than a certain position a certain distance. This is typically used to make or close hole in the hierarchy when moving subtrees around.

Parameters:
numeric startPos - The lowest position to move.
numeric delta - The distance to move (may be negative).

shiftRange

private void shiftRange(numeric startPos, numeric endPos, numeric delta)
I move a range of positions a certain distance. Usually used for moving a subtree into/out of a hole in the hierarchy created with the shift method.

Parameters:
numeric startPos - The starting position of the range.
numeric endPos - The ending position of the range.
numeric delta - The distance to move.

sortChildren

public void sortChildren(numeric parentID, [boolean descending="false"])
I sort the children of the specified node according to the configured sort field, using the id field as backup to ensure a stable sort. The sort method used will be most performant when the nodes are already close to sorted (under the assumption that if you want the nodes sorted, you'll resort them after every operation that might have disturbed their ordering, and so rarely have more than a node or two to reorder).

Parameters:
numeric parentID - The id of the node whose children need sorting
[boolean descending="false"] - Whether the sorting should be descending (reversed) order

sortSiblings

public void sortSiblings(numeric id, [boolean descending="false"])
I sort the node and it's siblings according to the configured sort field, using the id field as backup to ensure a stable sort. This method is currently implemented as nothing more than a call to sortChildren passing the id of the specified node's parent. That means that you can't sort the root level of the hierarchy, which should be expected, since a tree never has more than one node at it's root.

Parameters:
numeric id - The id of one of the sibling nodes that need sorting
[boolean descending="false"] - Whether the sorting should be descending (reversed) order

unnestObject

public void unnestObject(numeric id)
I unnest an object (make it a sibling of it's parent). If the node doesn't have a parent, nothing happens.

Parameters:
numeric id - The node to unnest.