Nested set plugin for Grails¶
What is Nested set?¶
A nested set model is a way of organising hierarchical data in a relational database, see Wikipedia.
Installation instructions¶
Download the grails-nested-set-0.3.zip and run
1 grails install-plugin /path/to/the/plugin.zip
Essentials¶
The NestedSet plugin injects the functionality of a nested set to any domain class. It is as simple as declaring a static variable.
1 class Employee {
2 String firstName
3 String lastName
4
5 static nestedSet = true
6 }
Moreover, it does not interfere with the domain at all. The whole structure is stored in a domain class named NestedSet, in a separate table.
It is possible to create a Nested set from any of your domain classes. Nevertheless, the tree structures can contain only classes with common ancestor. This ancestor have to be marked as a nested set.
The following example will create 2 tree structures: Employee and Location.
1 class Employee {
2 String firstName
3 String lastName
4
5 static nestedSet = true
6 }
7
8 class Location{
9 String name
10 static nestedSet = true
11 }
12
13 class Continent extends Location{}
14
15 class State extends Location{}
16
17 class City extends Location{}
The Location tree structure can contain any of the descendants - Continent, State, City.
The methods of the NestedSet are described in the following example.
Example¶
1 class Employee {
2 String firstName
3 String lastName
4
5 static nestedSet = true
6
7 /**
8 * Returns the direct manager of the employee
9 **/
10 def manager() {
11 nestedSetGetParent()
12 }
13
14 /**
15 * Returns all managers of the employee
16 **/
17 def managers() {
18 nestedSetGetAncestors()
19 }
20
21 /**
22 * Returns direct subordinates of the employee
23 **/
24 def directSubordinates() {
25 nestedSetGetChildren()
26 }
27
28 /**
29 * Returns direct subordinates of the employee and their subordinates
30 **/
31 def allSubordinates() {
32 nestedSetGetDescendants()
33 }
34
35 /**
36 * Returns the top managers (having no manager)
37 **/
38 static def topManagers() {
39 nestedSetGetRoots()
40 }
41
42 /**
43 * Promote employee to be the top manager
44 **/
45 def makeTopManager() {
46 nestedSetMakeRoot()
47 }
48
49 /**
50 * Remove the employee and all subordinates from hierarchy
51 **/
52 def outsourceDepartment() {
53 nestedSetRemove()
54 }
55
56 /**
57 * Adds a new subordinate
58 **/
59 def addSubordinate(so) {
60 nestedSetAddChild(so)
61 }
62
63 /**
64 * Move the whole department under different manager
65 **/
66 def reorganize(newManager){
67 nestedSetMoveTo(newManager)
68 }
69
70 String toString() {
71 "$firstName $lastName"
72 }
73 }
74 }
Limitations¶
- If DB set to update, it does not create the appropriate indexes.... Human:Hibernate 0:1
- It works well for "slowly changing" (static) hierarchical structures. The dynamic ones should be stored using different structure.