arboreal 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,73 @@
1
+ = Arboreal
2
+
3
+ Arboreal is yet another extension to ActiveRecord to support tree-shaped
4
+ data structures.
5
+
6
+ Arboreal surfaces relationships within the tree like +children+,
7
+ +ancestors+, +descendants+, and +siblings+ as scopes, so that additional
8
+ filtering/pagination can be performed.
9
+
10
+ == Getting started
11
+
12
+ First, install the "arboreal" gem, and add it to your Rails project's <tt>config/environment.rb</tt>.
13
+
14
+ Next, you'll need a migration to add an +ancestry_string+ column, and index thereupon:
15
+
16
+ class MakeThingsArboreal < ActiveRecord::Migration
17
+
18
+ def self.up
19
+ add_column "things", "ancestry_string", :string
20
+ add_index "things", ["ancestry_string"]
21
+ Thing.rebuild_ancestry
22
+ end
23
+
24
+ def self.down
25
+ remove_index "things", ["ancestry_string"]
26
+ remove_column "things", "ancestry_string"
27
+ end
28
+
29
+ end
30
+
31
+ This assumes that the table concerned already has a +parent_id+ column; if not, add that too (type +integer+, with a supporting index).
32
+
33
+ Finally, you can declare you model arboreal:
34
+
35
+ class Thing < ActiveRecord::Base
36
+
37
+ acts_arboreal
38
+
39
+ # .. etc etc ...
40
+
41
+ end
42
+
43
+ == Navigating the tree
44
+
45
+ Arboreal adds the relationships you'd expect:
46
+
47
+ * <tt>parent</tt>
48
+ * <tt>children</tt>
49
+
50
+ In addition, it provides the following handy methods on each tree-node:
51
+
52
+ * <tt>ancestors</tt>
53
+ * <tt>descendants</tt>
54
+ * <tt>subtree</tt> (the node itself, plus descendants)
55
+ * <tt>siblings</tt>
56
+ * <tt>root</tt> (the topmost ancestor)
57
+
58
+ The first four return scopes, to which additional filtering, ordering or limits may be applied.
59
+
60
+ At the class-level:
61
+
62
+ * <tt>roots</tt> is a named-scope returning all the nodes without parents
63
+ * <tt>rebuild_ancestry</tt> rebuilds the ancestry cache, as described below
64
+
65
+ == Rebuilding the ancestry cache
66
+
67
+ Internally, Arboreal uses the +ancestry_string+ column to cache the path down the tree to each node (or more correctly, it's parent. This technique - a variant of "path enumeration" or "materialized paths" - allows efficient retrieval of both ancestors and descendants.
68
+
69
+ It's conceivable that the computed ancestry-string values may get out of whack, particularly if changes are made directly to the database. If you suspect corruption, you can restore sanity using <tt>rebuild_ancestry</tt>, e.g
70
+
71
+ Thing.rebuild_ancestry
72
+
73
+ The ancestry rebuild is implemented in SQL to leverage the underlying DBMS, and so is pretty efficient, even on large trees.
@@ -1,17 +1,3 @@
1
- # Arboreal is yet another extension to ActiveRecord to support tree-shaped
2
- # data structures.
3
- #
4
- # Internally, Arboreal maintains a computed "ancestry_string" column, which
5
- # caches the path from the root of a tree to each node, allowing efficient
6
- # retrieval of both ancestors and descendants.
7
- #
8
- # Arboreal surfaces relationships within the tree like +children+,
9
- # +ancestors+, +descendants+, and +siblings+ as scopes, so that additional
10
- # filtering/pagination can be performed.
11
- #
12
- module Arboreal
13
- end
14
-
15
1
  require 'arboreal/active_record_extensions'
16
2
  require 'arboreal/class_methods'
17
3
  require 'arboreal/instance_methods'
@@ -1,6 +1,7 @@
1
1
  module Arboreal
2
2
  module ActiveRecordExtensions
3
3
 
4
+ # Declares that this ActiveRecord::Base model has a tree-like structure.
4
5
  def acts_arboreal
5
6
 
6
7
  belongs_to :parent, :class_name => self.name
@@ -36,6 +36,7 @@ module Arboreal
36
36
  JOIN _arboreals_ AS parent ON parent.id = child.parent_id
37
37
  SET child.ancestry_string = CONCAT(parent.ancestry_string, parent.id, '-')
38
38
  WHERE child.ancestry_string IS NULL
39
+ AND parent.ancestry_string IS NOT NULL
39
40
  SQL
40
41
  elsif connection.adapter_name == "JDBC" && connection.config[:url] =~ /sqlserver/
41
42
  <<-SQL
@@ -44,6 +45,7 @@ module Arboreal
44
45
  FROM _arboreals_ AS child
45
46
  JOIN _arboreals_ AS parent ON parent.id = child.parent_id
46
47
  WHERE child.ancestry_string IS NULL
48
+ AND parent.ancestry_string IS NOT NULL
47
49
  SQL
48
50
  else # SQLite, PostgreSQL, most others (SQL-92)
49
51
  <<-SQL
@@ -52,6 +54,7 @@ module Arboreal
52
54
  SELECT (parent.ancestry_string || _arboreals_.parent_id || '-')
53
55
  FROM _arboreals_ AS parent
54
56
  WHERE parent.id = _arboreals_.parent_id
57
+ AND parent.ancestry_string IS NOT NULL
55
58
  )
56
59
  WHERE ancestry_string IS NULL
57
60
  SQL
@@ -1,3 +1,3 @@
1
1
  module Arboreal
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arboreal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Williams
@@ -47,6 +47,7 @@ executables: []
47
47
  extensions: []
48
48
 
49
49
  extra_rdoc_files:
50
+ - README.rdoc
50
51
  - LICENSE
51
52
  files:
52
53
  - lib/arboreal/active_record_extensions.rb
@@ -57,6 +58,7 @@ files:
57
58
  - spec/arboreal_spec.rb
58
59
  - spec/spec_helper.rb
59
60
  - Rakefile
61
+ - README.rdoc
60
62
  - LICENSE
61
63
  has_rdoc: true
62
64
  homepage: http://github.com/mdub/arboreal
@@ -64,8 +66,10 @@ licenses: []
64
66
 
65
67
  post_install_message:
66
68
  rdoc_options:
67
- - --main
69
+ - --title
68
70
  - Arboreal
71
+ - --main
72
+ - README.rdoc
69
73
  require_paths:
70
74
  - lib
71
75
  required_ruby_version: !ruby/object:Gem::Requirement