mongoid-ancestry-fixes 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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