mongoid-ancestry-fixes 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +0,0 @@
1
- module Mongoid
2
- module Ancestry
3
- class Error < RuntimeError; end
4
- class IntegrityError < RuntimeError; end
5
- end
6
- end
@@ -1,248 +0,0 @@
1
- module Mongoid
2
- module Ancestry
3
-
4
- # Validate that the ancestors don't include itself
5
- def ancestry_exclude_self
6
- if ancestor_ids.include? id
7
- errors.add(:base, "#{self.class.name.humanize} cannot be a descendant of itself.")
8
- end
9
- end
10
-
11
- # Update descendants with new ancestry
12
- def update_descendants_with_new_ancestry
13
- # Skip this if callbacks are disabled
14
- unless ancestry_callbacks_disabled?
15
- # If node is valid, not a new record and ancestry was updated ...
16
- if changed.include?(self.base_class.ancestry_field.to_s) && !new_record? && valid?
17
- # ... for each descendant ...
18
- descendants.each do |descendant|
19
- # ... replace old ancestry with new ancestry
20
- descendant.without_ancestry_callbacks do
21
- for_replace = \
22
- if read_attribute(self.class.ancestry_field).blank?
23
- id.to_s
24
- else
25
- "#{read_attribute self.class.ancestry_field}/#{id}"
26
- end
27
- new_ancestry = descendant.read_attribute(descendant.class.ancestry_field).gsub(/^#{self.child_ancestry}/, for_replace)
28
- descendant.update_attribute(self.base_class.ancestry_field, new_ancestry)
29
- end
30
- end
31
- end
32
- end
33
- end
34
-
35
- # Apply orphan strategy
36
- def apply_orphan_strategy
37
- # Skip this if callbacks are disabled
38
- unless ancestry_callbacks_disabled?
39
- # If this isn't a new record ...
40
- unless new_record?
41
- # ... make al children root if orphan strategy is rootify
42
- if self.base_class.orphan_strategy == :rootify
43
- descendants.each do |descendant|
44
- descendant.without_ancestry_callbacks do
45
- val = \
46
- unless descendant.ancestry == child_ancestry
47
- descendant.read_attribute(descendant.class.ancestry_field).gsub(/^#{child_ancestry}\//, '')
48
- end
49
- descendant.update_attribute descendant.class.ancestry_field, val
50
- end
51
- end
52
- # ... destroy all descendants if orphan strategy is destroy
53
- elsif self.base_class.orphan_strategy == :destroy
54
- descendants.all.each do |descendant|
55
- descendant.without_ancestry_callbacks { descendant.destroy }
56
- end
57
- # ... throw an exception if it has children and orphan strategy is restrict
58
- elsif self.base_class.orphan_strategy == :restrict
59
- raise Error.new('Cannot delete record because it has descendants.') unless is_childless?
60
- end
61
- end
62
- end
63
- end
64
-
65
- # The ancestry value for this record's children
66
- def child_ancestry
67
- # New records cannot have children
68
- raise Error.new('No child ancestry for new record. Save record before performing tree operations.') if new_record?
69
-
70
- if self.send("#{self.base_class.ancestry_field}_was").blank?
71
- id.to_s
72
- else
73
- "#{self.send "#{self.base_class.ancestry_field}_was"}/#{id}"
74
- end
75
- end
76
-
77
- # Scope
78
- def current_search_scope
79
- self.embedded? ? self._parent.send(self.base_class.to_s.tableize) : self.base_class
80
- end
81
-
82
- # Ancestors
83
- def ancestor_ids
84
- read_attribute(self.base_class.ancestry_field).to_s.split('/').map { |id| cast_primary_key(id) }
85
- end
86
-
87
- def ancestor_conditions
88
- { :_id.in => ancestor_ids }
89
- end
90
-
91
- def ancestors depth_options = {}
92
- self.base_class.scope_depth(depth_options, depth).where(ancestor_conditions)
93
- end
94
-
95
- def path_ids
96
- ancestor_ids + [id]
97
- end
98
-
99
- def path_conditions
100
- { :_id.in => path_ids }
101
- end
102
-
103
- def path depth_options = {}
104
- self.base_class.scope_depth(depth_options, depth).where(path_conditions)
105
- end
106
-
107
- def depth
108
- ancestor_ids.size
109
- end
110
-
111
- def cache_depth
112
- write_attribute self.base_class.depth_cache_field, depth
113
- end
114
-
115
- # Parent
116
- def parent= parent
117
- write_attribute(self.base_class.ancestry_field, parent.blank? ? nil : parent.child_ancestry)
118
- end
119
-
120
- def parent_id= parent_id
121
- self.parent = parent_id.blank? ? nil : current_search_scope.find(parent_id)
122
- end
123
-
124
- def parent_id
125
- ancestor_ids.empty? ? nil : ancestor_ids.last
126
- end
127
-
128
- def parent
129
- parent_id.blank? ? nil : current_search_scope.find(parent_id)
130
- end
131
-
132
- # Root
133
- def root_id
134
- (root_id == id) ? self : current_search.find(root_id)
135
- end
136
-
137
- def root
138
- (root_id == id) ? self : current_search_scope.find(root_id)
139
- end
140
-
141
- def is_root?
142
- read_attribute(self.base_class.ancestry_field).blank?
143
- end
144
-
145
- # Children
146
- def child_conditions
147
- {self.base_class.ancestry_field => child_ancestry}
148
- end
149
-
150
- def children
151
- current_search_scope.where(child_conditions)
152
- end
153
-
154
- def child_ids
155
- children.only(:_id).map(&:id)
156
- end
157
-
158
- def has_children?
159
- self.children.present?
160
- end
161
-
162
- def is_childless?
163
- !has_children?
164
- end
165
-
166
- # Siblings
167
- def sibling_conditions
168
- {self.base_class.ancestry_field => read_attribute(self.base_class.ancestry_field)}
169
- end
170
-
171
- def siblings
172
- self.base_class.where sibling_conditions
173
- end
174
-
175
- def sibling_ids
176
- siblings.only(:_id).map(&:id)
177
- end
178
-
179
- def has_siblings?
180
- self.siblings.count > 1
181
- end
182
-
183
- def is_only_child?
184
- !has_siblings?
185
- end
186
-
187
- # Descendants
188
- def descendant_conditions
189
- [
190
- { self.base_class.ancestry_field => /^#{child_ancestry}\// },
191
- { self.base_class.ancestry_field => child_ancestry }
192
- ]
193
- end
194
-
195
- def descendants depth_options = {}
196
- self.base_class.scope_depth(depth_options, depth).any_of(descendant_conditions)
197
- end
198
-
199
- def descendant_ids depth_options = {}
200
- descendants(depth_options).only(:_id).map(&:id)
201
- end
202
-
203
- # Subtree
204
- def subtree_conditions
205
- [
206
- { :_id => id },
207
- { self.base_class.ancestry_field => /^#{child_ancestry}\// },
208
- { self.base_class.ancestry_field => child_ancestry }
209
- ]
210
- end
211
-
212
- def subtree depth_options = {}
213
- self.base_class.scope_depth(depth_options, depth).any_of(subtree_conditions)
214
- end
215
-
216
- def subtree_ids depth_options = {}
217
- subtree(depth_options).only(:_id).map(&:id)
218
- end
219
-
220
- # Callback disabling
221
- def without_ancestry_callbacks
222
- @disable_ancestry_callbacks = true
223
- yield
224
- @disable_ancestry_callbacks = false
225
- end
226
-
227
- def ancestry_callbacks_disabled?
228
- !!@disable_ancestry_callbacks
229
- end
230
-
231
- private
232
-
233
- def cast_primary_key(key)
234
- if primary_key_type == Integer
235
- key.to_i
236
- elsif primary_key_type == BSON::ObjectId && key =~ /[a-z0-9]{24}/
237
- BSON::ObjectId.convert(self, key)
238
- else
239
- key
240
- end
241
- end
242
-
243
- def primary_key_type
244
- @primary_key_type ||= self.base_class.fields['_id'].options[:type]
245
- end
246
- end
247
-
248
- end
@@ -1,5 +0,0 @@
1
- module Mongoid
2
- module Ancestry
3
- VERSION = '0.2.3'
4
- end
5
- end
data/log/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- # Ignore everything in this directory
2
- *
3
- # Except this file
4
- !.gitignore
@@ -1,29 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "mongoid-ancestry/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = 'mongoid-ancestry-fixes'
7
- s.version = '0.0.1'
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ["Stefan Kroes", "Anton Orel"]
10
- s.email = ["eagle.anton@gmail.com"]
11
- s.description = %q{Organise Mongoid model into a tree structure}
12
- s.homepage = "http://github.com/skyeagle/mongoid-ancestry"
13
- s.summary = %q{Ancestry allows the records of a Mongoid model to be organised in a tree structure, using a single, intuitively formatted database field. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single query. Additional features are named_scopes, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.}
14
- s.licenses = ["MIT"]
15
-
16
- s.rubyforge_project = "mongoid-ancestry-fixes"
17
-
18
- s.files = `git ls-files`.split("\n")
19
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
- s.require_paths = ["lib"]
22
- s.extra_rdoc_files = [
23
- "README.md"
24
- ]
25
-
26
- s.add_dependency('mongoid', ">= 2.0")
27
- s.add_dependency('bson_ext', ">= 1.3")
28
- end
29
-
@@ -1,110 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'mongoid-ancestry/exceptions'
4
-
5
-
6
- describe MongoidAncestry do
7
-
8
- subject { MongoidAncestry }
9
-
10
- it "should have ancestry fields" do
11
- subject.with_model do |model|
12
- model.fields['ancestry'].options[:type].should eql(String)
13
- end
14
- end
15
-
16
- it "should have non default ancestry field" do
17
- subject.with_model :ancestry_field => :alternative_ancestry do |model|
18
- model.ancestry_field.should eql(:alternative_ancestry)
19
- end
20
- end
21
-
22
- it "should set ancestry field" do
23
- subject.with_model do |model|
24
- model.ancestry_field = :ancestors
25
- model.ancestry_field.should eql(:ancestors)
26
- model.ancestry_field = :ancestry
27
- model.ancestry_field.should eql(:ancestry)
28
- end
29
- end
30
-
31
- it "should have default orphan strategy" do
32
- subject.with_model do |model|
33
- model.orphan_strategy.should eql(:destroy)
34
- end
35
- end
36
-
37
- it "should have non default orphan strategy" do
38
- subject.with_model :orphan_strategy => :rootify do |model|
39
- model.orphan_strategy.should eql(:rootify)
40
- end
41
- end
42
-
43
- it "should set orphan strategy" do
44
- subject.with_model do |model|
45
- model.orphan_strategy = :rootify
46
- model.orphan_strategy.should eql(:rootify)
47
- model.orphan_strategy = :destroy
48
- model.orphan_strategy.should eql(:destroy)
49
- end
50
- end
51
-
52
- it "should not set invalid orphan strategy" do
53
- subject.with_model do |model|
54
- expect {
55
- model.orphan_strategy = :non_existent_orphan_strategy
56
- }.to raise_error Mongoid::Ancestry::Error
57
- end
58
- end
59
-
60
- it "should setup test nodes" do
61
- subject.with_model :depth => 3, :width => 3 do |model, roots|
62
- roots.class.should eql(Array)
63
- roots.length.should eql(3)
64
- roots.each do |node, children|
65
- node.class.should eql(model)
66
- children.class.should eql(Array)
67
- children.length.should eql(3)
68
- children.each do |node, children|
69
- node.class.should eql(model)
70
- children.class.should eql(Array)
71
- children.length.should eql(3)
72
- children.each do |node, children|
73
- node.class.should eql(model)
74
- children.class.should eql(Array)
75
- children.length.should eql(0)
76
- end
77
- end
78
- end
79
- end
80
- end
81
-
82
- it "should have STI support" do
83
- subject.with_model :extra_columns => {:type => :string} do |model|
84
- subclass1 = Object.const_set 'Subclass1', Class.new(model)
85
- (class << subclass1; self; end).send(:define_method, :model_name) do
86
- Struct.new(:human, :underscore).new 'Subclass1', 'subclass1'
87
- end
88
- subclass2 = Object.const_set 'Subclass2', Class.new(model)
89
- (class << subclass2; self; end).send(:define_method, :model_name) do
90
- Struct.new(:human, :underscore).new 'Subclass1', 'subclass1'
91
- end
92
-
93
- node1 = subclass1.create
94
- node2 = subclass2.create :parent => node1
95
- node3 = subclass1.create :parent => node2
96
- node4 = subclass2.create :parent => node3
97
- node5 = subclass1.create :parent => node4
98
-
99
- model.all.each do |node|
100
- [subclass1, subclass2].include?(node.class).should be_true
101
- end
102
-
103
- node1.descendants.map(&:id).should eql([node2.id, node3.id, node4.id, node5.id])
104
- node1.subtree.map(&:id).should eql([node1.id, node2.id, node3.id, node4.id, node5.id])
105
- node5.ancestors.map(&:id).should eql([node1.id, node2.id, node3.id, node4.id])
106
- node5.path.map(&:id).should eql([node1.id, node2.id, node3.id, node4.id, node5.id])
107
- end
108
- end
109
-
110
- end
@@ -1,300 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MongoidAncestry do
4
-
5
- subject { MongoidAncestry }
6
-
7
- it "should have scopes" do
8
- subject.with_model :depth => 3, :width => 3 do |model, roots|
9
- # Roots assertion
10
- model.roots.all.to_a.should eql(roots.map(&:first))
11
-
12
- model.all.each do |test_node|
13
- # Assertions for ancestors_of named scope
14
- model.ancestors_of(test_node).all.should == test_node.ancestors.all
15
- model.ancestors_of(test_node.id).all.to_a.should eql(test_node.ancestors.all.to_a)
16
- # Assertions for children_of named scope
17
- model.children_of(test_node).all.to_a.should eql(test_node.children.all.to_a)
18
- model.children_of(test_node.id).all.to_a.should eql(test_node.children.all.to_a)
19
- # Assertions for descendants_of named scope
20
- model.descendants_of(test_node).all.should == (test_node.descendants.all)
21
- model.descendants_of(test_node.id).all.to_a.should eql(test_node.descendants.all.to_a)
22
- # Assertions for subtree_of named scope
23
- model.subtree_of(test_node).all.to_a.should eql(test_node.subtree.all.to_a)
24
- model.subtree_of(test_node.id).all.to_a.should eql(test_node.subtree.all.to_a)
25
- # Assertions for siblings_of named scope
26
- model.siblings_of(test_node).all.to_a.should eql(test_node.siblings.all.to_a)
27
- model.siblings_of(test_node.id).all.to_a.should eql(test_node.siblings.all.to_a)
28
- end
29
- end
30
- end
31
-
32
- it "should be arranged" do
33
- subject.with_model :depth => 3, :width => 3 do |model, roots|
34
- id_sorter = Proc.new {|a, b|; a.to_param <=> b.to_param }
35
- arranged_nodes = model.arrange
36
- arranged_nodes.size.should eql(3)
37
- arranged_nodes.each do |node, children|
38
- children.keys.sort(&id_sorter).should eql(node.children.sort(&id_sorter))
39
- children.each do |node, children|
40
- children.keys.sort(&id_sorter).should eql(node.children.sort(&id_sorter))
41
- children.each do |node, children|
42
- children.size.should eql(0)
43
- end
44
- end
45
- end
46
- end
47
- end
48
-
49
- it "should have arrange order option" do
50
- subject.with_model :width => 3, :depth => 3 do |model, roots|
51
- descending_nodes_lvl0 = model.arrange :order => [:_id, :desc]
52
- ascending_nodes_lvl0 = model.arrange :order => [:_id, :asc]
53
-
54
- descending_nodes_lvl0.keys.zip(ascending_nodes_lvl0.keys.reverse).each do |descending_node, ascending_node|
55
- ascending_node.should eql(descending_node)
56
- descending_nodes_lvl1 = descending_nodes_lvl0[descending_node]
57
- ascending_nodes_lvl1 = ascending_nodes_lvl0[ascending_node]
58
- descending_nodes_lvl1.keys.zip(ascending_nodes_lvl1.keys.reverse).each do |descending_node, ascending_node|
59
- ascending_node.should eql(descending_node)
60
- descending_nodes_lvl2 = descending_nodes_lvl1[descending_node]
61
- ascending_nodes_lvl2 = ascending_nodes_lvl1[ascending_node]
62
- descending_nodes_lvl2.keys.zip(ascending_nodes_lvl2.keys.reverse).each do |descending_node, ascending_node|
63
- ascending_node.should eql(descending_node)
64
- descending_nodes_lvl3 = descending_nodes_lvl2[descending_node]
65
- ascending_nodes_lvl3 = ascending_nodes_lvl2[ascending_node]
66
- descending_nodes_lvl3.keys.zip(ascending_nodes_lvl3.keys.reverse).each do |descending_node, ascending_node|
67
- ascending_node.should eql(descending_node)
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
74
-
75
- it "should have valid orphan rootify strategy" do
76
- subject.with_model :depth => 3, :width => 3 do |model, roots|
77
- model.orphan_strategy = :rootify
78
- root = roots.first.first
79
- children = root.children.all
80
- root.destroy
81
- children.each do |child|
82
- child.reload
83
- child.is_root?.should be_true
84
- child.children.size.should eql(3)
85
- end
86
- end
87
- end
88
-
89
- it "should have valid orphan destroy strategy" do
90
- subject.with_model :depth => 3, :width => 3 do |model, roots|
91
- model.orphan_strategy = :destroy
92
- root = roots.first.first
93
- expect { root.destroy }.to change(model, :count).by(-root.subtree.size)
94
- node = model.roots.first.children.first
95
- expect { node.destroy }.to change(model, :count).by(-node.subtree.size)
96
- end
97
- end
98
-
99
- it "should have valid orphan restrict strategy" do
100
- subject.with_model :depth => 3, :width => 3 do |model, roots|
101
- model.orphan_strategy = :restrict
102
- root = roots.first.first
103
- expect { root.destroy }.to raise_error Mongoid::Ancestry::Error
104
- expect { root.children.first.children.first.destroy }.to_not raise_error Mongoid::Ancestry::Error
105
- end
106
- end
107
-
108
- it "should check that there are no errors on a valid tree" do
109
- subject.with_model :width => 3, :depth => 3 do |model, roots|
110
- expect { model.check_ancestry_integrity! }.to_not raise_error(Mongoid::Ancestry::Error)
111
- model.check_ancestry_integrity!(:report => :list).size.should eql(0)
112
- end
113
- end
114
-
115
- it "should check detection of invalid format for ancestry field" do
116
- subject.with_model :width => 3, :depth => 3 do |model, roots|
117
- roots.first.first.update_attribute model.ancestry_field, 'invalid_ancestry'
118
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
119
- model.check_ancestry_integrity!(:report => :list).size.should eql(1)
120
- end
121
- end
122
-
123
- it "should check detection of non-existent ancestor" do
124
- subject.with_model :width => 3, :depth => 3 do |model, roots|
125
- node = roots.first.first
126
- node.without_ancestry_callbacks do
127
- node.update_attribute model.ancestry_field, 35
128
- end
129
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
130
- model.check_ancestry_integrity!(:report => :list).size.should eql(1)
131
- end
132
- end
133
-
134
- it "should check detection of cyclic ancestry" do
135
- subject.with_model :width => 3, :depth => 3 do |model, roots|
136
- node = roots.first.first
137
- node.update_attribute model.ancestry_field, node.id
138
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
139
- model.check_ancestry_integrity!(:report => :list).size.should eql(1)
140
- end
141
- end
142
-
143
- it "should check detection of conflicting parent id" do
144
- subject.with_model do |model|
145
- model.destroy_all
146
- model.create!(model.ancestry_field => model.create!(model.ancestry_field => model.create!(model.ancestry_field => nil).id).id)
147
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
148
- model.check_ancestry_integrity!(:report => :list).size.should eql(1)
149
- end
150
- end
151
-
152
- def assert_integrity_restoration model
153
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
154
- model.restore_ancestry_integrity!
155
- expect { model.check_ancestry_integrity! }.to_not raise_error(Mongoid::Ancestry::IntegrityError)
156
- end
157
-
158
- it "should check that integrity is restored for invalid format for ancestry field" do
159
- subject.with_model :width => 3, :depth => 3 do |model, roots|
160
- roots.first.first.update_attribute model.ancestry_field, 'invalid_ancestry'
161
- assert_integrity_restoration model
162
- end
163
- end
164
-
165
- it "should check that integrity is restored for non-existent ancestor" do
166
- subject.with_model :width => 3, :depth => 3 do |model, roots|
167
- roots.first.first.update_attribute model.ancestry_field, 35
168
- assert_integrity_restoration model
169
- end
170
- end
171
-
172
- it "should check that integrity is restored for cyclic ancestry" do
173
- subject.with_model :width => 3, :depth => 3 do |model, roots|
174
- node = roots.first.first
175
- node.update_attribute model.ancestry_field, node.id
176
- assert_integrity_restoration model
177
- end
178
- end
179
-
180
- it "should check that integrity is restored for conflicting parent id" do
181
- subject.with_model do |model|
182
- model.destroy_all
183
- model.create!(model.ancestry_field => model.create!(model.ancestry_field => model.create!(model.ancestry_field => nil).id).id)
184
- assert_integrity_restoration model
185
- end
186
- end
187
-
188
- it "should create node through scope" do
189
- subject.with_model do |model|
190
- node = model.create!
191
- child = node.children.create # doesn't pass with .create!
192
- child.parent.should eql(node)
193
-
194
- other_child = child.siblings.create # doesn't pass with .create!
195
- other_child.parent.should eql(node)
196
-
197
- grandchild = model.children_of(child).build # doesn't pass with .new
198
- grandchild.save
199
- grandchild.parent.should eql(child)
200
-
201
- other_grandchild = model.siblings_of(grandchild).build # doesn't pass with .new
202
- other_grandchild.save!
203
- other_grandchild.parent.should eql(child)
204
- end
205
- end
206
-
207
- it "should have depth scopes" do
208
- subject.with_model :depth => 4, :width => 2, :cache_depth => true do |model, roots|
209
- model.before_depth(2).all? { |node| node.depth < 2 }.should be_true
210
- model.to_depth(2).all? { |node| node.depth <= 2 }.should be_true
211
- model.at_depth(2).all? { |node| node.depth == 2 }.should be_true
212
- model.from_depth(2).all? { |node| node.depth >= 2 }.should be_true
213
- model.after_depth(2).all? { |node| node.depth > 2 }.should be_true
214
- end
215
- end
216
-
217
- it "should raise error on invalid scopes" do
218
- subject.with_model do |model|
219
- expect { model.before_depth(1) } .to raise_error(Mongoid::Ancestry::Error)
220
- expect { model.to_depth(1) } .to raise_error(Mongoid::Ancestry::Error)
221
- expect { model.at_depth(1) } .to raise_error(Mongoid::Ancestry::Error)
222
- expect { model.from_depth(1) } .to raise_error(Mongoid::Ancestry::Error)
223
- expect { model.after_depth(1) } .to raise_error(Mongoid::Ancestry::Error)
224
- end
225
- end
226
-
227
- it "should raise error on invalid has_ancestry options" do
228
- subject.with_model do |model|
229
- expect { model.has_ancestry :this_option_doesnt_exist => 42 }.to raise_error(Mongoid::Ancestry::Error)
230
- expect { model.has_ancestry :not_a_hash }.to raise_error(Mongoid::Ancestry::Error)
231
- end
232
- end
233
-
234
- it "should build ancestry from parent ids" do
235
- subject.with_model :skip_ancestry => true, :extra_columns => {:parent_id => :integer} do |model|
236
- [model.create!].each do |parent1|
237
- (Array.new(5) { model.create :parent_id => parent1.id }).each do |parent2|
238
- (Array.new(5) { model.create :parent_id => parent2.id }).each do |parent3|
239
- (Array.new(5) { model.create :parent_id => parent3.id })
240
- end
241
- end
242
- end
243
-
244
- # Assert all nodes where created
245
- model.count.should eql((0..3).map { |n| 5 ** n }.sum)
246
- end
247
-
248
- subject.with_model do |model|
249
-
250
- model.build_ancestry_from_parent_ids!
251
-
252
- # Assert ancestry integrity
253
- model.check_ancestry_integrity!
254
-
255
- roots = model.roots.all
256
- ## Assert single root node
257
- roots.size.should eql(1)
258
-
259
- ## Assert it has 5 children
260
- roots.each do |parent|
261
- parent.children.count.should eql(5)
262
- parent.children.each do |parent|
263
- parent.children.count.should eql(5)
264
- parent.children.each do |parent|
265
- parent.children.count.should eql(5)
266
- parent.children.each do |parent|
267
- parent.children.count.should eql(0)
268
- end
269
- end
270
- end
271
- end
272
- end
273
- end
274
-
275
- it "should rebuild depth cache" do
276
- subject.with_model :depth => 3, :width => 3, :cache_depth => true, :depth_cache_field => :depth_cache do |model, roots|
277
- model.update_all(:depth_cache => nil)
278
-
279
- # Assert cache was emptied correctly
280
- model.all.each do |test_node|
281
- test_node.depth_cache.should eql(nil)
282
- end
283
-
284
- # Rebuild cache
285
- model.rebuild_depth_cache!
286
-
287
- # Assert cache was rebuild correctly
288
- model.all.each do |test_node|
289
- test_node.depth_cache.should eql(test_node.depth)
290
- end
291
- end
292
- end
293
-
294
- it "should raise exception when rebuilding depth cache for model without depth caching" do
295
- subject.with_model do |model|
296
- expect { model.rebuild_depth_cache! }.to raise_error(Mongoid::Ancestry::Error)
297
- end
298
- end
299
-
300
- end