mongoid_orderable 5.0.0 → 6.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +83 -22
  3. data/LICENSE.txt +20 -0
  4. data/README.md +256 -149
  5. data/Rakefile +24 -6
  6. data/lib/config/locales/en.yml +12 -9
  7. data/lib/mongoid/orderable.rb +29 -22
  8. data/lib/mongoid/orderable/configs/field_config.rb +79 -0
  9. data/lib/mongoid/orderable/configs/global_config.rb +26 -0
  10. data/lib/mongoid/orderable/errors/invalid_target_position.rb +19 -18
  11. data/lib/mongoid/orderable/errors/transaction_failed.rb +20 -0
  12. data/lib/mongoid/orderable/generators/base.rb +21 -0
  13. data/lib/mongoid/orderable/generators/helpers.rb +29 -0
  14. data/lib/mongoid/orderable/generators/listable.rb +41 -0
  15. data/lib/mongoid/orderable/generators/lock_collection.rb +37 -0
  16. data/lib/mongoid/orderable/generators/movable.rb +62 -0
  17. data/lib/mongoid/orderable/generators/position.rb +26 -0
  18. data/lib/mongoid/orderable/generators/scope.rb +26 -0
  19. data/lib/mongoid/orderable/handlers/base.rb +167 -0
  20. data/lib/mongoid/orderable/handlers/document.rb +24 -0
  21. data/lib/mongoid/orderable/handlers/document_embedded.rb +14 -0
  22. data/lib/mongoid/orderable/handlers/document_transactional.rb +35 -0
  23. data/lib/mongoid/orderable/handlers/transaction.rb +71 -0
  24. data/lib/mongoid/orderable/installer.rb +63 -0
  25. data/lib/mongoid/orderable/mixins/callbacks.rb +43 -0
  26. data/lib/mongoid/orderable/mixins/helpers.rb +39 -0
  27. data/lib/mongoid/orderable/mixins/listable.rb +49 -0
  28. data/lib/mongoid/orderable/mixins/movable.rb +60 -0
  29. data/lib/mongoid/orderable/version.rb +7 -0
  30. data/lib/mongoid_orderable.rb +33 -54
  31. data/spec/integration/concurrency_spec.rb +232 -0
  32. data/spec/integration/customized_spec.rb +31 -0
  33. data/spec/integration/embedded_spec.rb +41 -0
  34. data/spec/integration/foreign_key_spec.rb +33 -0
  35. data/spec/integration/inherited_spec.rb +54 -0
  36. data/spec/integration/multiple_fields_spec.rb +554 -0
  37. data/spec/integration/multiple_scoped_spec.rb +63 -0
  38. data/spec/integration/no_indexed_spec.rb +23 -0
  39. data/spec/integration/scoped_spec.rb +151 -0
  40. data/spec/integration/simple_spec.rb +184 -0
  41. data/spec/integration/string_scoped_spec.rb +28 -0
  42. data/spec/integration/zero_based_spec.rb +161 -0
  43. data/spec/spec_helper.rb +42 -30
  44. data/spec/support/models.rb +122 -0
  45. metadata +75 -41
  46. data/.gitignore +0 -4
  47. data/.rspec +0 -2
  48. data/.rvmrc +0 -1
  49. data/.travis.yml +0 -14
  50. data/Gemfile +0 -18
  51. data/lib/mongoid/orderable/callbacks.rb +0 -75
  52. data/lib/mongoid/orderable/configuration.rb +0 -60
  53. data/lib/mongoid/orderable/errors.rb +0 -2
  54. data/lib/mongoid/orderable/errors/mongoid_orderable_error.rb +0 -14
  55. data/lib/mongoid/orderable/generator.rb +0 -34
  56. data/lib/mongoid/orderable/generator/helpers.rb +0 -29
  57. data/lib/mongoid/orderable/generator/listable.rb +0 -41
  58. data/lib/mongoid/orderable/generator/movable.rb +0 -62
  59. data/lib/mongoid/orderable/generator/position.rb +0 -26
  60. data/lib/mongoid/orderable/generator/scope.rb +0 -17
  61. data/lib/mongoid/orderable/helpers.rb +0 -50
  62. data/lib/mongoid/orderable/listable.rb +0 -49
  63. data/lib/mongoid/orderable/movable.rb +0 -58
  64. data/lib/mongoid/orderable/orderable_class.rb +0 -51
  65. data/lib/mongoid_orderable/mongoid/contexts/enumerable.rb +0 -15
  66. data/lib/mongoid_orderable/mongoid/contexts/mongo.rb +0 -18
  67. data/lib/mongoid_orderable/mongoid/contextual/memory.rb +0 -15
  68. data/lib/mongoid_orderable/mongoid/criteria.rb +0 -4
  69. data/lib/mongoid_orderable/version.rb +0 -3
  70. data/mongoid_orderable.gemspec +0 -26
  71. data/spec/mongoid/orderable_spec.rb +0 -1413
@@ -1,49 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Listable
4
-
5
- ##
6
- # Returns items above the current document.
7
- # Items with a position lower than this document's position.
8
- def previous_items(column=nil)
9
- column = column || default_orderable_column
10
- orderable_scoped(column).where(orderable_column(column).lt => send(column))
11
- end
12
- alias_method :prev_items, :previous_items
13
-
14
- ##
15
- # Returns items below the current document.
16
- # Items with a position greater than this document's position.
17
- def next_items(column=nil)
18
- column = column || default_orderable_column
19
- orderable_scoped(column).where(orderable_column(column).gt => send(column))
20
- end
21
-
22
- # returns the previous item in the list
23
- def previous_item(column=nil)
24
- column = column || default_orderable_column
25
- orderable_scoped(column).where(orderable_column(column) => send(column) - 1).first
26
- end
27
- alias_method :prev_item, :previous_item
28
-
29
- # returns the next item in the list
30
- def next_item(column=nil)
31
- column = column || default_orderable_column
32
- orderable_scoped(column).where(orderable_column(column) => send(column) + 1).first
33
- end
34
-
35
- def first?(column=nil)
36
- in_list?(column) && orderable_position(column) == orderable_base(column)
37
- end
38
-
39
- def last?(column=nil)
40
- in_list?(column) && orderable_position(column) == bottom_orderable_position(column)
41
- end
42
-
43
- def in_list?(column=nil)
44
- !orderable_position(column).nil?
45
- end
46
-
47
- end
48
- end
49
- end
@@ -1,58 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Movable
4
-
5
- def move_to!(target_position, options={})
6
- move_column_to target_position, options
7
- save
8
- end
9
- alias_method :insert_at!, :move_to!
10
-
11
- def move_to(target_position, options={})
12
- move_column_to target_position, options
13
- end
14
- alias_method :insert_at, :move_to
15
-
16
- def move_to=(target_position, options={})
17
- move_column_to target_position, options
18
- end
19
- alias_method :insert_at=, :move_to=
20
-
21
- [:top, :bottom].each do |symbol|
22
- class_eval <<-eos
23
- def move_to_#{symbol}(options = {})
24
- move_to :#{symbol}, options
25
- end
26
-
27
- def move_to_#{symbol}!(options = {})
28
- move_to! :#{symbol}, options
29
- end
30
- eos
31
- end
32
-
33
- [:higher, :lower].each do |symbol|
34
- class_eval <<-eos
35
- def move_#{symbol}(options = {})
36
- move_to :#{symbol}, options
37
- end
38
-
39
- def move_#{symbol}!(options = {})
40
- move_to! :#{symbol}, options
41
- end
42
- eos
43
- end
44
-
45
- protected
46
-
47
- def move_all
48
- @move_all || {}
49
- end
50
-
51
- def move_column_to(position, options)
52
- column = options[:column] || default_orderable_column
53
- @move_all = move_all.merge(column => position)
54
- end
55
-
56
- end
57
- end
58
- end
@@ -1,51 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- class OrderableClass
4
- include Mongoid::Orderable::Generator
5
-
6
- attr_reader :klass, :configuration
7
-
8
- def initialize klass, configuration
9
- @klass = klass
10
- @configuration = configuration
11
- end
12
-
13
- def setup
14
- add_db_field
15
- add_db_index if configuration[:index]
16
- save_configuration
17
- generate_all_helpers
18
- add_callbacks
19
- end
20
-
21
- def self.setup(klass, configuration={})
22
- new(klass, configuration).setup
23
- end
24
-
25
- protected
26
-
27
- def add_db_field
28
- klass.field configuration[:column], configuration[:field_opts]
29
- end
30
-
31
- def add_db_index
32
- spec = [[configuration[:column], 1]]
33
- spec.unshift([configuration[:scope], 1]) if configuration[:scope].is_a?(Symbol)
34
- if ::Mongoid::Compatibility::Version.mongoid2?
35
- klass.index(spec)
36
- else
37
- klass.index(Hash[spec])
38
- end
39
- end
40
-
41
- def save_configuration
42
- klass.orderable_configurations ||= {}
43
- klass.orderable_configurations = klass.orderable_configurations.merge(column_name => configuration)
44
- end
45
-
46
- def add_callbacks
47
- klass.add_orderable_callbacks
48
- end
49
- end
50
- end
51
- end
@@ -1,15 +0,0 @@
1
- module MongoidOrderable #:nodoc:
2
- module Mongoid #:nodoc:
3
- module Contexts #:nodoc:
4
- module Enumerable #:nodoc:
5
- def inc attribute, value
6
- iterate do |doc|
7
- MongoidOrderable.inc doc, attribute, value
8
- end
9
- end
10
- end
11
- end
12
- end
13
- end
14
-
15
- Mongoid::Contexts::Enumerable.send :include, MongoidOrderable::Mongoid::Contexts::Enumerable
@@ -1,18 +0,0 @@
1
- module MongoidOrderable #:nodoc:
2
- module Mongoid #:nodoc:
3
- module Contexts #:nodoc:
4
- module Mongo #:nodoc:
5
- def inc attribute, value
6
- klass.collection.update(
7
- selector,
8
- { "$inc" => {attribute => value} },
9
- :multi => true,
10
- :safe => ::Mongoid.persist_in_safe_mode
11
- )
12
- end
13
- end
14
- end
15
- end
16
- end
17
-
18
- Mongoid::Contexts::Mongo.send :include, MongoidOrderable::Mongoid::Contexts::Mongo
@@ -1,15 +0,0 @@
1
- module MongoidOrderable #:nodoc:
2
- module Mongoid #:nodoc:
3
- module Contextual #:nodoc:
4
- module Memory #:nodoc:
5
- def inc(* args)
6
- each do |document|
7
- document.inc *args
8
- end
9
- end
10
- end
11
- end
12
- end
13
- end
14
-
15
- Mongoid::Contextual::Memory.send :include, MongoidOrderable::Mongoid::Contextual::Memory
@@ -1,4 +0,0 @@
1
- Mongoid::Criteria.delegate :inc, :to => :context
2
- Mongoid::Finders.send :define_method, :inc do |*args|
3
- criteria.send :inc, *args
4
- end
@@ -1,3 +0,0 @@
1
- module MongoidOrderable
2
- VERSION = '5.0.0'
3
- end
@@ -1,26 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "mongoid_orderable/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "mongoid_orderable"
7
- s.version = MongoidOrderable::VERSION
8
- s.authors = ["pyromaniac"]
9
- s.email = ["kinwizard@gmail.com"]
10
- s.homepage = ""
11
- s.summary = %q{Acts as list mongoid implementation}
12
- s.description = %q{Gem allows mongoid model behave as orderable list}
13
-
14
- s.rubyforge_project = "mongoid_orderable"
15
-
16
- s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ["lib"]
20
-
21
- # specify any dependencies here; for example:
22
- s.add_development_dependency "rake"
23
- s.add_development_dependency "rspec"
24
- s.add_runtime_dependency "mongoid"
25
- s.add_runtime_dependency "mongoid-compatibility"
26
- end
@@ -1,1413 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Mongoid::Orderable do
4
-
5
- class SimpleOrderable
6
- include Mongoid::Document
7
- include Mongoid::Orderable
8
-
9
- orderable
10
- end
11
-
12
- class ScopedGroup
13
- include Mongoid::Document
14
-
15
- has_many :scoped_orderables
16
- has_many :multiple_columns_orderables
17
- end
18
-
19
- class ScopedOrderable
20
- include Mongoid::Document
21
- include Mongoid::Orderable
22
-
23
- field :group_id
24
- belongs_to :scoped_group
25
-
26
- orderable :scope => :group
27
- end
28
-
29
- class StringScopedOrderable
30
- include Mongoid::Document
31
- include Mongoid::Orderable
32
-
33
- field :some_scope, :type => Integer
34
-
35
- orderable :scope => 'some_scope'
36
- end
37
-
38
- class EmbedsOrderable
39
- include Mongoid::Document
40
-
41
- embeds_many :embedded_orderables
42
- end
43
-
44
- class EmbeddedOrderable
45
- include Mongoid::Document
46
- include Mongoid::Orderable
47
-
48
- embedded_in :embeds_orderable
49
-
50
- orderable
51
- end
52
-
53
- class CustomizedOrderable
54
- include Mongoid::Document
55
- include Mongoid::Orderable
56
-
57
- orderable :column => :pos, :as => :my_position
58
- end
59
-
60
- class NoIndexOrderable
61
- include Mongoid::Document
62
- include Mongoid::Orderable
63
-
64
- orderable :index => false
65
- end
66
-
67
- class ZeroBasedOrderable
68
- include Mongoid::Document
69
- include Mongoid::Orderable
70
-
71
- orderable :base => 0
72
- end
73
-
74
- class Fruit
75
- include Mongoid::Document
76
- include Mongoid::Orderable
77
-
78
- orderable :inherited => true
79
- end
80
-
81
- class Apple < Fruit
82
- end
83
-
84
- class Orange < Fruit
85
- end
86
-
87
- class ForeignKeyDiffersOrderable
88
- include Mongoid::Document
89
- include Mongoid::Orderable
90
-
91
- belongs_to :different_scope, :class_name => "ForeignKeyDiffersOrderable",
92
- :foreign_key => "different_orderable_id"
93
-
94
- orderable :scope => :different_scope
95
- end
96
-
97
- class MultipleColumnsOrderable
98
- include Mongoid::Document
99
- include Mongoid::Orderable
100
-
101
- field :group_id
102
-
103
- belongs_to :scoped_group
104
-
105
- orderable :column => :pos, :base => 0, :index => false, :as => :position
106
- orderable :column => :serial_no, :default => true
107
- orderable :column => :groups, :scope => :group
108
- end
109
-
110
- class MultipleScopedOrderable
111
- include Mongoid::Document
112
- include Mongoid::Orderable
113
-
114
- belongs_to :apple
115
- belongs_to :orange
116
-
117
- orderable :column => :posa, :scope => :apple_id
118
- orderable :column => :poso, :scope => :orange_id
119
- end
120
-
121
- describe SimpleOrderable do
122
-
123
- before :each do
124
- SimpleOrderable.delete_all
125
- 5.times do
126
- SimpleOrderable.create!
127
- end
128
- end
129
-
130
- def positions
131
- SimpleOrderable.all.map(&:position).sort
132
- end
133
-
134
- it 'should have proper position column' do
135
- expect(SimpleOrderable.fields.key?('position')).to be true
136
- expect(SimpleOrderable.fields['position'].options[:type]).to eq(Integer)
137
- end
138
-
139
- it 'should have index on position column' do
140
- if ::Mongoid::Compatibility::Version.mongoid2?
141
- expect(SimpleOrderable.index_options[[[:position, 1]]]).not_to be_nil
142
- elsif ::Mongoid::Compatibility::Version.mongoid3?
143
- expect(SimpleOrderable.index_options[{:position => 1}]).not_to be_nil
144
- else
145
- expect(SimpleOrderable.index_specifications.detect { |spec| spec.key == {:position => 1} }).not_to be_nil
146
- end
147
- end
148
-
149
- it 'should have a orderable base of 1' do
150
- expect(SimpleOrderable.create!.orderable_base).to eq(1)
151
- end
152
-
153
- it 'should set proper position while creation' do
154
- expect(positions).to eq([1, 2, 3, 4, 5])
155
- end
156
-
157
- describe 'removement' do
158
-
159
- it 'top' do
160
- SimpleOrderable.where(:position => 1).destroy
161
- expect(positions).to eq([1, 2, 3, 4])
162
- end
163
-
164
- it 'bottom' do
165
- SimpleOrderable.where(:position => 5).destroy
166
- expect(positions).to eq([1, 2, 3, 4])
167
- end
168
-
169
- it 'middle' do
170
- SimpleOrderable.where(:position => 3).destroy
171
- expect(positions).to eq([1, 2, 3, 4])
172
- end
173
- end
174
-
175
- describe 'inserting' do
176
-
177
- it 'top' do
178
- newbie = SimpleOrderable.create! :move_to => :top
179
- expect(positions).to eq([1, 2, 3, 4, 5, 6])
180
- expect(newbie.position).to eq(1)
181
- end
182
-
183
- it 'bottom' do
184
- newbie = SimpleOrderable.create! :move_to => :bottom
185
- expect(positions).to eq([1, 2, 3, 4, 5, 6])
186
- expect(newbie.position).to eq(6)
187
- end
188
-
189
- it 'middle' do
190
- newbie = SimpleOrderable.create! :move_to => 4
191
- expect(positions).to eq([1, 2, 3, 4, 5, 6])
192
- expect(newbie.position).to eq(4)
193
- end
194
-
195
- it 'middle (with a numeric string)' do
196
- newbie = SimpleOrderable.create! :move_to => '4'
197
- expect(positions).to eq([1, 2, 3, 4, 5, 6])
198
- expect(newbie.position).to eq(4)
199
- end
200
-
201
- it 'middle (with a non-numeric string)' do
202
- expect do
203
- SimpleOrderable.create! :move_to => 'four'
204
- end.to raise_error Mongoid::Orderable::Errors::InvalidTargetPosition
205
- end
206
- end
207
-
208
- describe 'movement' do
209
-
210
- it 'higher from top' do
211
- record = SimpleOrderable.where(:position => 1).first
212
- record.update_attributes :move_to => :higher
213
- expect(positions).to eq([1, 2, 3, 4, 5])
214
- expect(record.reload.position).to eq(1)
215
- end
216
-
217
- it 'higher from bottom' do
218
- record = SimpleOrderable.where(:position => 5).first
219
- record.update_attributes :move_to => :higher
220
- expect(positions).to eq([1, 2, 3, 4, 5])
221
- expect(record.reload.position).to eq(4)
222
- end
223
-
224
- it 'higher from middle' do
225
- record = SimpleOrderable.where(:position => 3).first
226
- record.update_attributes :move_to => :higher
227
- expect(positions).to eq([1, 2, 3, 4, 5])
228
- expect(record.reload.position).to eq(2)
229
- end
230
-
231
- it 'lower from top' do
232
- record = SimpleOrderable.where(:position => 1).first
233
- record.update_attributes :move_to => :lower
234
- expect(positions).to eq([1, 2, 3, 4, 5])
235
- expect(record.reload.position).to eq(2)
236
- end
237
-
238
- it 'lower from bottom' do
239
- record = SimpleOrderable.where(:position => 5).first
240
- record.update_attributes :move_to => :lower
241
- expect(positions).to eq([1, 2, 3, 4, 5])
242
- expect(record.reload.position).to eq(5)
243
- end
244
-
245
- it 'lower from middle' do
246
- record = SimpleOrderable.where(:position => 3).first
247
- record.update_attributes :move_to => :lower
248
- expect(positions).to eq([1, 2, 3, 4, 5])
249
- expect(record.reload.position).to eq(4)
250
- end
251
-
252
- it 'does nothing if position not change' do
253
- record = SimpleOrderable.where(:position => 3).first
254
- record.save
255
- expect(positions).to eq([1, 2, 3, 4, 5])
256
- expect(record.reload.position).to eq(3)
257
- end
258
- end
259
-
260
- describe 'utiity methods' do
261
-
262
- it "should return a collection of items lower/higher on the list for next_items/previous_items" do
263
- record_1 = SimpleOrderable.where(:position => 1).first
264
- record_2 = SimpleOrderable.where(:position => 2).first
265
- record_3 = SimpleOrderable.where(:position => 3).first
266
- record_4 = SimpleOrderable.where(:position => 4).first
267
- record_5 = SimpleOrderable.where(:position => 5).first
268
- expect(record_1.next_items.to_a).to eq([record_2, record_3, record_4, record_5])
269
- expect(record_5.previous_items.to_a).to eq([record_1, record_2, record_3, record_4])
270
- expect(record_3.previous_items.to_a).to eq([record_1, record_2])
271
- expect(record_3.next_items.to_a).to eq([record_4, record_5])
272
- end
273
- end
274
- end
275
-
276
- describe ScopedOrderable do
277
-
278
- before :each do
279
- ScopedOrderable.delete_all
280
- 2.times do
281
- ScopedOrderable.create! :group_id => 1
282
- end
283
- 3.times do
284
- ScopedOrderable.create! :group_id => 2
285
- end
286
- end
287
-
288
- def positions
289
- ScopedOrderable.order_by([:group_id, :asc], [:position, :asc]).map(&:position)
290
- end
291
-
292
- it 'should set proper position while creation' do
293
- expect(positions).to eq([1, 2, 1, 2, 3])
294
- end
295
-
296
- describe 'removement' do
297
-
298
- it 'top' do
299
- ScopedOrderable.where(:position => 1, :group_id => 1).destroy
300
- expect(positions).to eq([1, 1, 2, 3])
301
- end
302
-
303
- it 'bottom' do
304
- ScopedOrderable.where(:position => 3, :group_id => 2).destroy
305
- expect(positions).to eq([1, 2, 1, 2])
306
- end
307
-
308
- it 'middle' do
309
- ScopedOrderable.where(:position => 2, :group_id => 2).destroy
310
- expect(positions).to eq([1, 2, 1, 2])
311
- end
312
- end
313
-
314
- describe 'inserting' do
315
-
316
- it 'top' do
317
- newbie = ScopedOrderable.create! :move_to => :top, :group_id => 1
318
- expect(positions).to eq([1, 2, 3, 1, 2, 3])
319
- expect(newbie.position).to eq(1)
320
- end
321
-
322
- it 'bottom' do
323
- newbie = ScopedOrderable.create! :move_to => :bottom, :group_id => 2
324
- expect(positions).to eq([1, 2, 1, 2, 3, 4])
325
- expect(newbie.position).to eq(4)
326
- end
327
-
328
- it 'middle' do
329
- newbie = ScopedOrderable.create! :move_to => 2, :group_id => 2
330
- expect(positions).to eq([1, 2, 1, 2, 3, 4])
331
- expect(newbie.position).to eq(2)
332
- end
333
-
334
- it 'middle (with a numeric string)' do
335
- newbie = ScopedOrderable.create! :move_to => '2', :group_id => 2
336
- expect(positions).to eq([1, 2, 1, 2, 3, 4])
337
- expect(newbie.position).to eq(2)
338
- end
339
-
340
- it 'middle (with a non-numeric string)' do
341
- expect do
342
- ScopedOrderable.create! :move_to => 'two', :group_id => 2
343
- end.to raise_error Mongoid::Orderable::Errors::InvalidTargetPosition
344
- end
345
- end
346
-
347
- describe 'index' do
348
-
349
- it 'is not on position alone' do
350
- if ::Mongoid::Compatibility::Version.mongoid2?
351
- expect(ScopedOrderable.index_options[[[:position, 1]]]).to be_nil
352
- elsif ::Mongoid::Compatibility::Version.mongoid3?
353
- expect(ScopedOrderable.index_options[{:position => 1}]).to be_nil
354
- else
355
- expect(ScopedOrderable.index_specifications.detect { |spec| spec.key == {:position => 1} }).to be_nil
356
- end
357
- end
358
-
359
- it 'is on compound fields' do
360
- if ::Mongoid::Compatibility::Version.mongoid2?
361
- expect(ScopedOrderable.index_options[[[:group_id, 1], [:position, 1]]]).to_not be_nil
362
- elsif ::Mongoid::Compatibility::Version.mongoid3?
363
- expect(ScopedOrderable.index_options[{:group_id => 1, :position => 1}]).to_not be_nil
364
- else
365
- expect(ScopedOrderable.index_specifications.detect { |spec| spec.key == {:group_id => 1, :position => 1} }).to_not be_nil
366
- end
367
- end
368
- end
369
-
370
- describe 'scope movement' do
371
-
372
- let(:record){ ScopedOrderable.where(:group_id => 2, :position => 2).first }
373
-
374
- it 'to a new scope group' do
375
- record.update_attributes :group_id => 3
376
- expect(positions).to eq([1, 2, 1, 2, 1])
377
- expect(record.position).to eq(1)
378
- end
379
-
380
- context 'when moving to an existing scope group' do
381
-
382
- it 'without a position' do
383
- record.update_attributes :group_id => 1
384
- expect(positions).to eq([1, 2, 3, 1, 2])
385
- expect(record.reload.position).to eq(3)
386
- end
387
-
388
- it 'with symbol position' do
389
- record.update_attributes :group_id => 1, :move_to => :top
390
- expect(positions).to eq([1, 2, 3, 1, 2])
391
- expect(record.reload.position).to eq(1)
392
- end
393
-
394
- it 'with point position' do
395
- record.update_attributes :group_id => 1, :move_to => 2
396
- expect(positions).to eq([1, 2, 3, 1, 2])
397
- expect(record.reload.position).to eq(2)
398
- end
399
-
400
- it 'with point position (with a numeric string)' do
401
- record.update_attributes :group_id => 1, :move_to => '2'
402
- expect(positions).to eq([1, 2, 3, 1, 2])
403
- expect(record.reload.position).to eq(2)
404
- end
405
-
406
- it 'with point position (with a non-numeric string)' do
407
- expect do
408
- record.update_attributes :group_id => 1, :move_to => 'two'
409
- end.to raise_error Mongoid::Orderable::Errors::InvalidTargetPosition
410
- end
411
- end
412
- end
413
-
414
- if defined?(Mongoid::IdentityMap)
415
-
416
- context 'when identity map is enabled' do
417
-
418
- let(:record){ ScopedOrderable.where(:group_id => 2, :position => 2).first }
419
-
420
- before do
421
- Mongoid.identity_map_enabled = true
422
- Mongoid::IdentityMap[ScopedOrderable.collection_name] = { record.id => record }
423
- end
424
-
425
- after do
426
- Mongoid.identity_map_enabled = false
427
- end
428
-
429
- it 'to a new scope group' do
430
- record.update_attributes :group_id => 3
431
- expect(positions).to eq([1, 2, 1, 2, 1])
432
- expect(record.position).to eq(1)
433
- end
434
-
435
- it 'to an existing scope group' do
436
- record.update_attributes :group_id => 1, :move_to => 2
437
- expect(positions).to eq([1, 2, 3, 1, 2])
438
- expect(record.reload.position).to eq(2)
439
- end
440
-
441
- it 'to an existing scope group (with a numeric string)' do
442
- record.update_attributes :group_id => 1, :move_to => '2'
443
- expect(positions).to eq([1, 2, 3, 1, 2])
444
- expect(record.reload.position).to eq(2)
445
- end
446
-
447
- it 'to an existing scope group (with a non-numeric string)' do
448
- expect do
449
- record.update_attributes :group_id => 1, :move_to => 'two'
450
- end.to raise_error Mongoid::Orderable::Errors::InvalidTargetPosition
451
- end
452
- end
453
- end
454
-
455
- describe 'utility methods' do
456
-
457
- before do
458
- ScopedOrderable.delete_all
459
- 5.times { ScopedOrderable.create! }
460
- end
461
-
462
- it "should return a collection of items lower/higher on the list for next_items/previous_items" do
463
- record_1 = ScopedOrderable.where(:position => 1).first
464
- record_2 = ScopedOrderable.where(:position => 2).first
465
- record_3 = ScopedOrderable.where(:position => 3).first
466
- record_4 = ScopedOrderable.where(:position => 4).first
467
- record_5 = ScopedOrderable.where(:position => 5).first
468
- expect(record_1.next_items.to_a).to eq([record_2, record_3, record_4, record_5])
469
- expect(record_5.previous_items.to_a).to eq([record_1, record_2, record_3, record_4])
470
- expect(record_3.previous_items.to_a).to eq([record_1, record_2])
471
- expect(record_3.next_items.to_a).to eq([record_4, record_5])
472
- # next_item & previous_item testing
473
- expect(record_1.next_item).to eq(record_2)
474
- expect(record_2.previous_item).to eq(record_1)
475
- expect(record_1.previous_item).to eq(nil)
476
- expect(record_5.next_item).to eq(nil)
477
- end
478
- end
479
- end
480
-
481
- describe StringScopedOrderable do
482
-
483
- it 'uses the foreign key of the relationship as scope' do
484
- orderable1 = StringScopedOrderable.create!(:some_scope => 1)
485
- orderable2 = StringScopedOrderable.create!(:some_scope => 1)
486
- orderable3 = StringScopedOrderable.create!(:some_scope => 2)
487
- expect(orderable1.position).to eq 1
488
- expect(orderable2.position).to eq 2
489
- expect(orderable3.position).to eq 1
490
- end
491
- end
492
-
493
- describe EmbeddedOrderable do
494
-
495
- before :each do
496
- EmbedsOrderable.delete_all
497
- eo = EmbedsOrderable.create!
498
- 2.times do
499
- eo.embedded_orderables.create!
500
- end
501
- eo = EmbedsOrderable.create!
502
- 3.times do
503
- eo.embedded_orderables.create!
504
- end
505
- end
506
-
507
- def positions
508
- EmbedsOrderable.order_by(:position => 1).all.map { |eo| eo.embedded_orderables.map(&:position).sort }
509
- end
510
-
511
- it 'sets proper position while creation' do
512
- expect(positions).to eq([[1, 2], [1, 2, 3]])
513
- end
514
-
515
- it 'moves an item returned by a query to position' do
516
- embedded_orderable_1 = EmbedsOrderable.first.embedded_orderables.where(:position => 1).first
517
- embedded_orderable_2 = EmbedsOrderable.first.embedded_orderables.where(:position => 2).first
518
- embedded_orderable_1.move_to! 2
519
- expect(embedded_orderable_2.reload.position).to eq(1)
520
- end
521
- end
522
-
523
- describe CustomizedOrderable do
524
-
525
- it 'does not have default position field' do
526
- expect(CustomizedOrderable.fields).not_to have_key('position')
527
- end
528
-
529
- it 'should have custom pos field' do
530
- expect(CustomizedOrderable.fields).to have_key('pos')
531
- end
532
-
533
- it 'should have an alias my_position which points to pos field on Mongoid 3+' do
534
- if CustomizedOrderable.respond_to?(:database_field_name)
535
- expect(CustomizedOrderable.database_field_name('my_position')).to eq('pos')
536
- end
537
- end
538
- end
539
-
540
- describe NoIndexOrderable do
541
-
542
- it 'should not have index on position column' do
543
- if ::Mongoid::Compatibility::Version.mongoid2? || ::Mongoid::Compatibility::Version.mongoid3?
544
- expect(NoIndexOrderable.index_options[[[:position, 1]]]).to be_nil
545
- else
546
- expect(NoIndexOrderable.index_specifications.detect { |spec| spec.key == :position }).to be_nil
547
- end
548
- end
549
- end
550
-
551
- describe ZeroBasedOrderable do
552
-
553
- before :each do
554
- ZeroBasedOrderable.delete_all
555
- 5.times do
556
- ZeroBasedOrderable.create!
557
- end
558
- end
559
-
560
- def positions
561
- ZeroBasedOrderable.all.map(&:position).sort
562
- end
563
-
564
- it 'should have a orderable base of 0' do
565
- expect(ZeroBasedOrderable.create!.orderable_base).to eq(0)
566
- end
567
-
568
- it 'should set proper position while creation' do
569
- expect(positions).to eq([0, 1, 2, 3, 4])
570
- end
571
-
572
- describe 'reset position' do
573
- before{ ZeroBasedOrderable.update_all({:position => nil}) }
574
- it 'should properly reset position' do
575
- ZeroBasedOrderable.all.map(&:save)
576
- expect(positions).to eq([0, 1, 2, 3, 4])
577
- end
578
- end
579
-
580
- describe 'removement' do
581
-
582
- it 'top' do
583
- ZeroBasedOrderable.where(:position => 0).destroy
584
- expect(positions).to eq([0, 1, 2, 3])
585
- end
586
-
587
- it 'bottom' do
588
- ZeroBasedOrderable.where(:position => 4).destroy
589
- expect(positions).to eq([0, 1, 2, 3])
590
- end
591
-
592
- it 'middle' do
593
- ZeroBasedOrderable.where(:position => 2).destroy
594
- expect(positions).to eq([0, 1, 2, 3])
595
- end
596
- end
597
-
598
- describe 'inserting' do
599
-
600
- it 'top' do
601
- newbie = ZeroBasedOrderable.create! :move_to => :top
602
- expect(positions).to eq([0, 1, 2, 3, 4, 5])
603
- expect(newbie.position).to eq(0)
604
- end
605
-
606
- it 'bottom' do
607
- newbie = ZeroBasedOrderable.create! :move_to => :bottom
608
- expect(positions).to eq([0, 1, 2, 3, 4, 5])
609
- expect(newbie.position).to eq(5)
610
- end
611
-
612
- it 'middle' do
613
- newbie = ZeroBasedOrderable.create! :move_to => 3
614
- expect(positions).to eq([0, 1, 2, 3, 4, 5])
615
- expect(newbie.position).to eq(3)
616
- end
617
-
618
- it 'middle (with a numeric string)' do
619
- newbie = ZeroBasedOrderable.create! :move_to => '3'
620
- expect(positions).to eq([0, 1, 2, 3, 4, 5])
621
- expect(newbie.position).to eq(3)
622
- end
623
-
624
- it 'middle (with a non-numeric string)' do
625
- expect do
626
- ZeroBasedOrderable.create! :move_to => 'three'
627
- end.to raise_error Mongoid::Orderable::Errors::InvalidTargetPosition
628
- end
629
- end
630
-
631
- describe 'movement' do
632
-
633
- it 'higher from top' do
634
- record = ZeroBasedOrderable.where(:position => 0).first
635
- record.update_attributes :move_to => :higher
636
- expect(positions).to eq([0, 1, 2, 3, 4])
637
- expect(record.reload.position).to eq(0)
638
- end
639
-
640
- it 'higher from bottom' do
641
- record = ZeroBasedOrderable.where(:position => 4).first
642
- record.update_attributes :move_to => :higher
643
- expect(positions).to eq([0, 1, 2, 3, 4])
644
- expect(record.reload.position).to eq(3)
645
- end
646
-
647
- it 'higher from middle' do
648
- record = ZeroBasedOrderable.where(:position => 3).first
649
- record.update_attributes :move_to => :higher
650
- expect(positions).to eq([0, 1, 2, 3, 4])
651
- expect(record.reload.position).to eq(2)
652
- end
653
-
654
- it 'lower from top' do
655
- record = ZeroBasedOrderable.where(:position => 0).first
656
- record.update_attributes :move_to => :lower
657
- expect(positions).to eq([0, 1, 2, 3, 4])
658
- expect(record.reload.position).to eq(1)
659
- end
660
-
661
- it 'lower from bottom' do
662
- record = ZeroBasedOrderable.where(:position => 4).first
663
- record.update_attributes :move_to => :lower
664
- expect(positions).to eq([0, 1, 2, 3, 4])
665
- expect(record.reload.position).to eq(4)
666
- end
667
-
668
- it 'lower from middle' do
669
- record = ZeroBasedOrderable.where(:position => 2).first
670
- record.update_attributes :move_to => :lower
671
- expect(positions).to eq([0, 1, 2, 3, 4])
672
- expect(record.reload.position).to eq(3)
673
- end
674
-
675
- it 'does nothing if position not change' do
676
- record = ZeroBasedOrderable.where(:position => 3).first
677
- record.save
678
- expect(positions).to eq([0, 1, 2, 3, 4])
679
- expect(record.reload.position).to eq(3)
680
- end
681
- end
682
-
683
- describe 'utiity methods' do
684
-
685
- it "should return a collection of items lower/higher on the list for next_items/previous_items" do
686
- record_1 = SimpleOrderable.where(:position => 1).first
687
- record_2 = SimpleOrderable.where(:position => 2).first
688
- record_3 = SimpleOrderable.where(:position => 3).first
689
- record_4 = SimpleOrderable.where(:position => 4).first
690
- record_5 = SimpleOrderable.where(:position => 5).first
691
- expect(record_1.next_items.to_a).to eq([record_2, record_3, record_4, record_5])
692
- expect(record_5.previous_items.to_a).to eq([record_1, record_2, record_3, record_4])
693
- expect(record_3.previous_items.to_a).to eq([record_1, record_2])
694
- expect(record_3.next_items.to_a).to eq([record_4, record_5])
695
- # next_item & previous_item testing
696
- expect(record_1.next_item).to eq(record_2)
697
- expect(record_2.previous_item).to eq(record_1)
698
- expect(record_1.previous_item).to eq(nil)
699
- expect(record_5.next_item).to eq(nil)
700
- end
701
- end
702
- end
703
-
704
- describe Fruit do
705
-
706
- it 'should set proper position' do
707
- fruit1 = Apple.create
708
- fruit2 = Orange.create
709
- expect(fruit1.position).to eq(1)
710
- expect(fruit2.position).to eq(2)
711
- end
712
-
713
- describe 'movement' do
714
- before :each do
715
- Fruit.delete_all
716
- 5.times do
717
- Apple.create!
718
- end
719
- end
720
-
721
- it 'with symbol position' do
722
- first_apple = Apple.asc(:_id).first
723
- top_pos = first_apple.position
724
- bottom_pos = Apple.asc(:_id).last.position
725
- expect do
726
- first_apple.move_to! :bottom
727
- end.to change(first_apple, :position).from(top_pos).to bottom_pos
728
- end
729
-
730
- it 'with point position' do
731
- first_apple = Apple.asc(:_id).first
732
- top_pos = first_apple.position
733
- bottom_pos = Apple.asc(:_id).last.position
734
- expect do
735
- first_apple.move_to! bottom_pos
736
- end.to change(first_apple, :position).from(top_pos).to bottom_pos
737
- end
738
- end
739
-
740
- describe 'add orderable configurations in inherited class' do
741
- it 'does not affect the orderable configurations of parent class and sibling class' do
742
- class Apple
743
- orderable :column => :serial
744
- end
745
- expect(Fruit.orderable_configurations).not_to eq Apple.orderable_configurations
746
- expect(Orange.orderable_configurations).not_to eq Apple.orderable_configurations
747
- expect(Fruit.orderable_configurations).to eq Orange.orderable_configurations
748
- end
749
- end
750
- end
751
-
752
- describe ForeignKeyDiffersOrderable do
753
-
754
- it 'uses the foreign key of the relationship as scope' do
755
- orderable1, orderable2, orderable3 = nil
756
- parent_scope1 = ForeignKeyDiffersOrderable.create
757
- parent_scope2 = ForeignKeyDiffersOrderable.create
758
- expect do
759
- orderable1 = ForeignKeyDiffersOrderable.create!(:different_scope => parent_scope1)
760
- orderable2 = ForeignKeyDiffersOrderable.create!(:different_scope => parent_scope1)
761
- orderable3 = ForeignKeyDiffersOrderable.create!(:different_scope => parent_scope2)
762
- end.to_not raise_error
763
- expect(orderable1.position).to eq 1
764
- expect(orderable2.position).to eq 2
765
- expect(orderable3.position).to eq 1
766
- end
767
- end
768
-
769
- describe MultipleColumnsOrderable do
770
-
771
- before :each do
772
- MultipleColumnsOrderable.delete_all
773
- 5.times do
774
- MultipleColumnsOrderable.create!
775
- end
776
- end
777
-
778
- context 'default orderable' do
779
- let(:serial_nos){ MultipleColumnsOrderable.all.map(&:serial_no).sort }
780
-
781
- describe 'inserting' do
782
- let(:newbie){ MultipleColumnsOrderable.create! }
783
-
784
- before { @position = newbie.position }
785
-
786
- it 'top' do
787
- newbie.move_to! :top
788
- expect(serial_nos).to eq([1, 2, 3, 4, 5, 6])
789
- expect(newbie.serial_no).to eq(1)
790
- expect(newbie.position).to eq(@position)
791
- end
792
-
793
- it 'bottom' do
794
- newbie.move_to! :bottom
795
- expect(serial_nos).to eq([1, 2, 3, 4, 5, 6])
796
- expect(newbie.serial_no).to eq(6)
797
- expect(newbie.position).to eq(@position)
798
- end
799
-
800
- it 'middle' do
801
- newbie.move_to! 4
802
- expect(serial_nos).to eq([1, 2, 3, 4, 5, 6])
803
- expect(newbie.serial_no).to eq(4)
804
- expect(newbie.position).to eq(@position)
805
- end
806
- end
807
-
808
- describe 'movement' do
809
- it 'higher from top' do
810
- record = MultipleColumnsOrderable.where(:serial_no => 1).first
811
- position = record.position
812
- record.move_higher!
813
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
814
- expect(record.serial_no).to eq(1)
815
- expect(record.position).to eq(position)
816
- end
817
-
818
- it 'higher from bottom' do
819
- record = MultipleColumnsOrderable.where(:serial_no => 5).first
820
- position = record.position
821
- record.move_higher!
822
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
823
- expect(record.serial_no).to eq(4)
824
- expect(record.position).to eq(position)
825
- end
826
-
827
- it 'higher from middle' do
828
- record = MultipleColumnsOrderable.where(:serial_no => 3).first
829
- position = record.position
830
- record.move_higher!
831
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
832
- expect(record.serial_no).to eq(2)
833
- expect(record.position).to eq(position)
834
- end
835
-
836
- it 'lower from top' do
837
- record = MultipleColumnsOrderable.where(:serial_no => 1).first
838
- position = record.position
839
- record.move_lower!
840
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
841
- expect(record.serial_no).to eq(2)
842
- expect(record.position).to eq(position)
843
- end
844
-
845
- it 'lower from bottom' do
846
- record = MultipleColumnsOrderable.where(:serial_no => 5).first
847
- position = record.position
848
- record.move_lower!
849
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
850
- expect(record.serial_no).to eq(5)
851
- expect(record.position).to eq(position)
852
- end
853
-
854
- it 'lower from middle' do
855
- record = MultipleColumnsOrderable.where(:serial_no => 3).first
856
- position = record.position
857
- record.move_lower!
858
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
859
- expect(record.serial_no).to eq(4)
860
- expect(record.position).to eq(position)
861
- end
862
- end
863
-
864
- describe 'utility methods' do
865
-
866
- before do
867
- @record_1 = MultipleColumnsOrderable.where(:serial_no => 1).first
868
- @record_2 = MultipleColumnsOrderable.where(:serial_no => 2).first
869
- @record_3 = MultipleColumnsOrderable.where(:serial_no => 3).first
870
- @record_4 = MultipleColumnsOrderable.where(:serial_no => 4).first
871
- @record_5 = MultipleColumnsOrderable.where(:serial_no => 5).first
872
- end
873
-
874
- it "should return the lower/higher item on the list for next_item/previous_item" do
875
- expect(@record_1.next_item).to eq(@record_2)
876
- expect(@record_3.next_item).to eq(@record_4)
877
- expect(@record_5.next_item).to eq(nil)
878
- expect(@record_1.prev_item).to eq(nil)
879
- expect(@record_3.prev_item).to eq(@record_2)
880
- expect(@record_5.prev_item).to eq(@record_4)
881
- end
882
-
883
- it "should return a collection of items lower/higher on the list for next_items/previous_items" do
884
- expect(@record_1.next_items.to_a).to eq([@record_2, @record_3, @record_4, @record_5])
885
- expect(@record_3.next_items.to_a).to eq([@record_4, @record_5])
886
- expect(@record_5.next_items.to_a).to eq([])
887
- expect(@record_1.previous_items.to_a).to eq([])
888
- expect(@record_3.previous_items.to_a).to eq([@record_1, @record_2])
889
- expect(@record_5.previous_items.to_a).to eq([@record_1, @record_2, @record_3, @record_4])
890
- end
891
- end
892
- end
893
-
894
- context 'serial_no orderable' do
895
-
896
- let(:serial_nos){ MultipleColumnsOrderable.all.map(&:serial_no).sort }
897
-
898
- it 'should have proper serial_no column' do
899
- expect(MultipleColumnsOrderable.fields.key?('serial_no')).to be true
900
- expect(MultipleColumnsOrderable.fields['serial_no'].options[:type]).to eq(Integer)
901
- end
902
-
903
- it 'should have index on serial_no column' do
904
- if ::Mongoid::Compatibility::Version.mongoid2?
905
- expect(MultipleColumnsOrderable.index_options[[[:serial_no, 1]]]).not_to be_nil
906
- elsif ::Mongoid::Compatibility::Version.mongoid3?
907
- expect(MultipleColumnsOrderable.index_options[{:serial_no => 1}]).not_to be_nil
908
- else
909
- expect(MultipleColumnsOrderable.index_specifications.detect { |spec| spec.key == {:serial_no => 1} }).not_to be_nil
910
- end
911
- end
912
-
913
- it 'should have a orderable base of 1' do
914
- expect(MultipleColumnsOrderable.first.orderable_base(:serial_no)).to eq(1)
915
- end
916
-
917
- it 'should set proper position while creation' do
918
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
919
- end
920
-
921
- describe 'removement' do
922
-
923
- it 'top' do
924
- MultipleColumnsOrderable.where(:serial_no => 1).destroy
925
- expect(serial_nos).to eq([1, 2, 3, 4])
926
- end
927
-
928
- it 'bottom' do
929
- MultipleColumnsOrderable.where(:serial_no => 5).destroy
930
- expect(serial_nos).to eq([1, 2, 3, 4])
931
- end
932
-
933
- it 'middle' do
934
- MultipleColumnsOrderable.where(:serial_no => 3).destroy
935
- expect(serial_nos).to eq([1, 2, 3, 4])
936
- end
937
- end
938
-
939
- describe 'inserting' do
940
- let(:newbie){ MultipleColumnsOrderable.create! }
941
-
942
- before { @position = newbie.position }
943
-
944
- it 'top' do
945
- newbie.move_serial_no_to! :top
946
- expect(serial_nos).to eq([1, 2, 3, 4, 5, 6])
947
- expect(newbie.serial_no).to eq(1)
948
- expect(newbie.position).to eq(@position)
949
- end
950
-
951
- it 'bottom' do
952
- newbie.move_serial_no_to! :bottom
953
- expect(serial_nos).to eq([1, 2, 3, 4, 5, 6])
954
- expect(newbie.serial_no).to eq(6)
955
- expect(newbie.position).to eq(@position)
956
- end
957
-
958
- it 'middle' do
959
- newbie.move_serial_no_to! 4
960
- expect(serial_nos).to eq([1, 2, 3, 4, 5, 6])
961
- expect(newbie.serial_no).to eq(4)
962
- expect(newbie.position).to eq(@position)
963
- end
964
- end
965
-
966
- describe 'movement' do
967
- it 'higher from top' do
968
- record = MultipleColumnsOrderable.where(:serial_no => 1).first
969
- position = record.position
970
- record.move_serial_no_higher!
971
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
972
- expect(record.serial_no).to eq(1)
973
- expect(record.position).to eq(position)
974
- end
975
-
976
- it 'higher from bottom' do
977
- record = MultipleColumnsOrderable.where(:serial_no => 5).first
978
- position = record.position
979
- record.move_serial_no_higher!
980
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
981
- expect(record.serial_no).to eq(4)
982
- expect(record.position).to eq(position)
983
- end
984
-
985
- it 'higher from middle' do
986
- record = MultipleColumnsOrderable.where(:serial_no => 3).first
987
- position = record.position
988
- record.move_serial_no_higher!
989
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
990
- expect(record.serial_no).to eq(2)
991
- expect(record.position).to eq(position)
992
- end
993
-
994
- it 'lower from top' do
995
- record = MultipleColumnsOrderable.where(:serial_no => 1).first
996
- position = record.position
997
- record.move_serial_no_lower!
998
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
999
- expect(record.serial_no).to eq(2)
1000
- expect(record.position).to eq(position)
1001
- end
1002
-
1003
- it 'lower from bottom' do
1004
- record = MultipleColumnsOrderable.where(:serial_no => 5).first
1005
- position = record.position
1006
- record.move_serial_no_lower!
1007
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
1008
- expect(record.serial_no).to eq(5)
1009
- expect(record.position).to eq(position)
1010
- end
1011
-
1012
- it 'lower from middle' do
1013
- record = MultipleColumnsOrderable.where(:serial_no => 3).first
1014
- position = record.position
1015
- record.move_serial_no_lower!
1016
- expect(serial_nos).to eq([1, 2, 3, 4, 5])
1017
- expect(record.serial_no).to eq(4)
1018
- expect(record.position).to eq(position)
1019
- end
1020
- end
1021
-
1022
- describe 'utility methods' do
1023
-
1024
- before do
1025
- @record_1 = MultipleColumnsOrderable.where(:serial_no => 1).first
1026
- @record_2 = MultipleColumnsOrderable.where(:serial_no => 2).first
1027
- @record_3 = MultipleColumnsOrderable.where(:serial_no => 3).first
1028
- @record_4 = MultipleColumnsOrderable.where(:serial_no => 4).first
1029
- @record_5 = MultipleColumnsOrderable.where(:serial_no => 5).first
1030
- end
1031
-
1032
- it "should return the lower/higher item on the list for next_item/previous_item" do
1033
- expect(@record_1.next_serial_no_item).to eq(@record_2)
1034
- expect(@record_3.next_serial_no_item).to eq(@record_4)
1035
- expect(@record_5.next_serial_no_item).to eq(nil)
1036
- expect(@record_1.prev_serial_no_item).to eq(nil)
1037
- expect(@record_3.prev_serial_no_item).to eq(@record_2)
1038
- expect(@record_5.prev_serial_no_item).to eq(@record_4)
1039
- end
1040
-
1041
- it "should return a collection of items lower/higher on the list for next_items/previous_items" do
1042
- expect(@record_1.next_serial_no_items.to_a).to eq([@record_2, @record_3, @record_4, @record_5])
1043
- expect(@record_3.next_serial_no_items.to_a).to eq([@record_4, @record_5])
1044
- expect(@record_5.next_serial_no_items.to_a).to eq([])
1045
- expect(@record_1.previous_serial_no_items.to_a).to eq([])
1046
- expect(@record_3.previous_serial_no_items.to_a).to eq([@record_1, @record_2])
1047
- expect(@record_5.previous_serial_no_items.to_a).to eq([@record_1, @record_2, @record_3, @record_4])
1048
- end
1049
- end
1050
-
1051
- end
1052
-
1053
- context 'position orderable' do
1054
-
1055
- let(:positions){ MultipleColumnsOrderable.all.map(&:position).sort }
1056
-
1057
- it 'should not have default position field' do
1058
- expect(MultipleColumnsOrderable.fields).not_to have_key('position')
1059
- end
1060
-
1061
- it 'should have custom pos field' do
1062
- expect(MultipleColumnsOrderable.fields).to have_key('pos')
1063
- expect(MultipleColumnsOrderable.fields['pos'].options[:type]).to eq(Integer)
1064
- end
1065
-
1066
- it 'should have index on position column' do
1067
- if ::Mongoid::Compatibility::Version.mongoid2?
1068
- expect(MultipleColumnsOrderable.index_options[[[:position, 1]]]).to be_nil
1069
- elsif ::Mongoid::Compatibility::Version.mongoid3?
1070
- expect(MultipleColumnsOrderable.index_options[{:position => 1}]).to be_nil
1071
- else
1072
- expect(MultipleColumnsOrderable.index_specifications.detect { |spec| spec.key == {:position => 1} }).to be_nil
1073
- end
1074
- end
1075
-
1076
- it 'should have a orderable base of 0' do
1077
- expect(MultipleColumnsOrderable.first.orderable_base(:position)).to eq(0)
1078
- end
1079
-
1080
- it 'should set proper position while creation' do
1081
- expect(positions).to eq([0, 1, 2, 3, 4])
1082
- end
1083
-
1084
- describe 'removement' do
1085
-
1086
- it 'top' do
1087
- MultipleColumnsOrderable.where(:pos => 1).destroy
1088
- expect(positions).to eq([0, 1, 2, 3])
1089
- end
1090
-
1091
- it 'bottom' do
1092
- MultipleColumnsOrderable.where(:pos => 4).destroy
1093
- expect(positions).to eq([0, 1, 2, 3])
1094
- end
1095
-
1096
- it 'middle' do
1097
- MultipleColumnsOrderable.where(:pos => 3).destroy
1098
- expect(positions).to eq([0, 1, 2, 3])
1099
- end
1100
- end
1101
-
1102
- describe 'inserting' do
1103
- let(:newbie){ MultipleColumnsOrderable.create! }
1104
-
1105
- before { @serial_no = newbie.serial_no }
1106
-
1107
- it 'top' do
1108
- newbie.move_position_to! :top
1109
- expect(positions).to eq([0, 1, 2, 3, 4, 5])
1110
- expect(newbie.position).to eq(0)
1111
- expect(newbie.serial_no).to eq(@serial_no)
1112
- end
1113
-
1114
- it 'bottom' do
1115
- newbie.move_position_to! :bottom
1116
- expect(positions).to eq([0, 1, 2, 3, 4, 5])
1117
- expect(newbie.position).to eq(5)
1118
- expect(newbie.serial_no).to eq(@serial_no)
1119
- end
1120
-
1121
- it 'middle' do
1122
- newbie.move_position_to! 4
1123
- expect(positions).to eq([0, 1, 2, 3, 4, 5])
1124
- expect(newbie.position).to eq(4)
1125
- expect(newbie.serial_no).to eq(@serial_no)
1126
- end
1127
- end
1128
-
1129
- describe 'movement' do
1130
- it 'higher from top' do
1131
- record = MultipleColumnsOrderable.where(:pos => 0).first
1132
- position = record.serial_no
1133
- record.move_position_higher!
1134
- expect(positions).to eq([0, 1, 2, 3, 4])
1135
- expect(record.position).to eq(0)
1136
- expect(record.serial_no).to eq(position)
1137
- end
1138
-
1139
- it 'higher from bottom' do
1140
- record = MultipleColumnsOrderable.where(:pos => 4).first
1141
- position = record.serial_no
1142
- record.move_position_higher!
1143
- expect(positions).to eq([0, 1, 2, 3, 4])
1144
- expect(record.position).to eq(3)
1145
- expect(record.serial_no).to eq(position)
1146
- end
1147
-
1148
- it 'higher from middle' do
1149
- record = MultipleColumnsOrderable.where(:pos => 3).first
1150
- position = record.serial_no
1151
- record.move_position_higher!
1152
- expect(positions).to eq([0, 1, 2, 3, 4])
1153
- expect(record.position).to eq(2)
1154
- expect(record.serial_no).to eq(position)
1155
- end
1156
-
1157
- it 'lower from top' do
1158
- record = MultipleColumnsOrderable.where(:pos => 0).first
1159
- position = record.serial_no
1160
- record.move_position_lower!
1161
- expect(positions).to eq([0, 1, 2, 3, 4])
1162
- expect(record.position).to eq(1)
1163
- expect(record.serial_no).to eq(position)
1164
- end
1165
-
1166
- it 'lower from bottom' do
1167
- record = MultipleColumnsOrderable.where(:pos => 4).first
1168
- position = record.serial_no
1169
- record.move_position_lower!
1170
- expect(positions).to eq([0, 1, 2, 3, 4])
1171
- expect(record.position).to eq(4)
1172
- expect(record.serial_no).to eq(position)
1173
- end
1174
-
1175
- it 'lower from middle' do
1176
- record = MultipleColumnsOrderable.where(:pos => 3).first
1177
- position = record.serial_no
1178
- record.move_position_lower!
1179
- expect(positions).to eq([0, 1, 2, 3, 4])
1180
- expect(record.position).to eq(4)
1181
- expect(record.serial_no).to eq(position)
1182
- end
1183
- end
1184
-
1185
- describe 'utility methods' do
1186
-
1187
- before do
1188
- @record_1 = MultipleColumnsOrderable.where(:pos => 0).first
1189
- @record_2 = MultipleColumnsOrderable.where(:pos => 1).first
1190
- @record_3 = MultipleColumnsOrderable.where(:pos => 2).first
1191
- @record_4 = MultipleColumnsOrderable.where(:pos => 3).first
1192
- @record_5 = MultipleColumnsOrderable.where(:pos => 4).first
1193
- end
1194
-
1195
- it "should return the lower/higher item on the list for next_item/previous_item" do
1196
- expect(@record_1.next_position_item).to eq(@record_2)
1197
- expect(@record_3.next_position_item).to eq(@record_4)
1198
- expect(@record_5.next_position_item).to eq(nil)
1199
- expect(@record_1.prev_position_item).to eq(nil)
1200
- expect(@record_3.prev_position_item).to eq(@record_2)
1201
- expect(@record_5.prev_position_item).to eq(@record_4)
1202
- end
1203
-
1204
- it "should return a collection of items lower/higher on the list for next_items/previous_items" do
1205
- expect(@record_1.next_position_items.to_a).to eq([@record_2, @record_3, @record_4, @record_5])
1206
- expect(@record_3.next_position_items.to_a).to eq([@record_4, @record_5])
1207
- expect(@record_5.next_position_items.to_a).to eq([])
1208
- expect(@record_1.previous_position_items.to_a).to eq([])
1209
- expect(@record_3.previous_position_items.to_a).to eq([@record_1, @record_2])
1210
- expect(@record_5.previous_position_items.to_a).to eq([@record_1, @record_2, @record_3, @record_4])
1211
- end
1212
- end
1213
-
1214
- end
1215
-
1216
- context 'group_count orderable' do
1217
- before :each do
1218
- MultipleColumnsOrderable.delete_all
1219
- 2.times { MultipleColumnsOrderable.create! :group_id => 1 }
1220
- 3.times { MultipleColumnsOrderable.create! :group_id => 2 }
1221
- end
1222
-
1223
- let(:all_groups){ MultipleColumnsOrderable.order_by([:group_id, :asc], [:groups, :asc]).map(&:groups) }
1224
-
1225
- it 'should set proper position while creation' do
1226
- expect(all_groups).to eq([1, 2, 1, 2, 3])
1227
- end
1228
-
1229
- describe 'removement' do
1230
-
1231
- it 'top' do
1232
- MultipleColumnsOrderable.where(:groups => 1, :group_id => 1).destroy
1233
- expect(all_groups).to eq([1, 1, 2, 3])
1234
- end
1235
-
1236
- it 'bottom' do
1237
- MultipleColumnsOrderable.where(:groups => 3, :group_id => 2).destroy
1238
- expect(all_groups).to eq([1, 2, 1, 2])
1239
- end
1240
-
1241
- it 'middle' do
1242
- MultipleColumnsOrderable.where(:groups => 2, :group_id => 2).destroy
1243
- expect(all_groups).to eq([1, 2, 1, 2])
1244
- end
1245
- end
1246
-
1247
- describe 'inserting' do
1248
-
1249
- it 'top' do
1250
- newbie = MultipleColumnsOrderable.create! :group_id => 1
1251
- newbie.move_groups_to! :top
1252
- expect(all_groups).to eq([1, 2, 3, 1, 2, 3])
1253
- expect(newbie.groups).to eq(1)
1254
- end
1255
-
1256
- it 'bottom' do
1257
- newbie = MultipleColumnsOrderable.create! :group_id => 2
1258
- newbie.move_groups_to! :bottom
1259
- expect(all_groups).to eq([1, 2, 1, 2, 3, 4])
1260
- expect(newbie.groups).to eq(4)
1261
- end
1262
-
1263
- it 'middle' do
1264
- newbie = MultipleColumnsOrderable.create! :group_id => 2
1265
- newbie.move_groups_to! 2
1266
- expect(all_groups).to eq([1, 2, 1, 2, 3, 4])
1267
- expect(newbie.groups).to eq(2)
1268
- end
1269
- end
1270
-
1271
- describe 'scope movement' do
1272
-
1273
- let(:record){ MultipleColumnsOrderable.where(:group_id => 2, :groups => 2).first }
1274
-
1275
- it 'to a new scope group' do
1276
- record.update_attributes :group_id => 3
1277
- expect(all_groups).to eq([1, 2, 1, 2, 1])
1278
- expect(record.groups).to eq(1)
1279
- end
1280
-
1281
- context 'when moving to an existing scope group' do
1282
-
1283
- it 'without a position' do
1284
- record.update_attributes :group_id => 1
1285
- expect(all_groups).to eq([1, 2, 3, 1, 2])
1286
- expect(record.reload.groups).to eq(3)
1287
- end
1288
-
1289
- it 'with symbol position' do
1290
- record.update_attributes :group_id => 1
1291
- record.move_groups_to! :top
1292
- expect(all_groups).to eq([1, 2, 3, 1, 2])
1293
- expect(record.reload.groups).to eq(1)
1294
- end
1295
-
1296
- it 'with point position' do
1297
- record.update_attributes :group_id => 1
1298
- record.move_groups_to! 2
1299
- expect(all_groups).to eq([1, 2, 3, 1, 2])
1300
- expect(record.reload.groups).to eq(2)
1301
- end
1302
- end
1303
- end
1304
-
1305
- if defined?(Mongoid::IdentityMap)
1306
-
1307
- context 'when identity map is enabled' do
1308
-
1309
- let(:record){ MultipleColumnsOrderable.where(:group_id => 2, :groups => 2).first }
1310
-
1311
- before do
1312
- Mongoid.identity_map_enabled = true
1313
- Mongoid::IdentityMap[MultipleColumnsOrderable.collection_name] = { record.id => record }
1314
- end
1315
-
1316
- after { Mongoid.identity_map_enabled = false }
1317
-
1318
- it 'to a new scope group' do
1319
- record.update_attributes :group_id => 3
1320
- expect(all_groups).to eq([1, 2, 1, 2, 1])
1321
- expect(record.groups).to eq(1)
1322
- end
1323
-
1324
- it 'to an existing scope group' do
1325
- record.update_attributes :group_id => 1
1326
- record.move_groups_to! 2
1327
- expect(all_groups).to eq([1, 2, 3, 1, 2])
1328
- expect(record.groups).to eq(2)
1329
- end
1330
- end
1331
- end
1332
-
1333
- describe 'utility methods' do
1334
-
1335
- before do
1336
- @record_1 = MultipleColumnsOrderable.where(:group_id => 2, :groups => 1).first
1337
- @record_2 = MultipleColumnsOrderable.where(:group_id => 2, :groups => 2).first
1338
- @record_3 = MultipleColumnsOrderable.where(:group_id => 2, :groups => 3).first
1339
- @record_4 = MultipleColumnsOrderable.where(:group_id => 1, :groups => 1).first
1340
- @record_5 = MultipleColumnsOrderable.where(:group_id => 1, :groups => 2).first
1341
- end
1342
-
1343
- it "should return the lower/higher item on the list for next_item/previous_item" do
1344
- expect(@record_1.next_groups_item).to eq(@record_2)
1345
- expect(@record_4.next_groups_item).to eq(@record_5)
1346
- expect(@record_3.next_groups_item).to eq(nil)
1347
- expect(@record_1.prev_groups_item).to eq(nil)
1348
- expect(@record_3.prev_groups_item).to eq(@record_2)
1349
- expect(@record_5.prev_groups_item).to eq(@record_4)
1350
- end
1351
-
1352
- it "should return a collection of items lower/higher on the list for next_items/previous_items" do
1353
- expect(@record_1.next_groups_items.to_a).to eq([@record_2, @record_3])
1354
- expect(@record_3.next_groups_items.to_a).to eq([])
1355
- expect(@record_4.next_groups_items.to_a).to eq([@record_5])
1356
- expect(@record_1.previous_groups_items.to_a).to eq([])
1357
- expect(@record_3.previous_groups_items.to_a).to eq([@record_1, @record_2])
1358
- expect(@record_5.previous_groups_items.to_a).to eq([@record_4])
1359
- end
1360
- end
1361
- end
1362
- end
1363
-
1364
- describe MultipleScopedOrderable do
1365
- before :each do
1366
- Apple.delete_all; Orange.delete_all;
1367
- MultipleScopedOrderable.delete_all
1368
-
1369
- 3.times do
1370
- Apple.create; Orange.create
1371
- end
1372
-
1373
- MultipleScopedOrderable.create! :apple_id => 1, :orange_id => 1
1374
- MultipleScopedOrderable.create! :apple_id => 2, :orange_id => 1
1375
- MultipleScopedOrderable.create! :apple_id => 2, :orange_id => 2
1376
- MultipleScopedOrderable.create! :apple_id => 1, :orange_id => 3
1377
- MultipleScopedOrderable.create! :apple_id => 1, :orange_id => 1
1378
- MultipleScopedOrderable.create! :apple_id => 3, :orange_id => 3
1379
- MultipleScopedOrderable.create! :apple_id => 2, :orange_id => 3
1380
- MultipleScopedOrderable.create! :apple_id => 3, :orange_id => 2
1381
- MultipleScopedOrderable.create! :apple_id => 1, :orange_id => 3
1382
- end
1383
-
1384
- def apple_positions
1385
- MultipleScopedOrderable.order_by([:apple_id, :asc], [:posa, :asc]).map(&:posa)
1386
- end
1387
-
1388
- def orange_positions
1389
- MultipleScopedOrderable.order_by([:orange_id, :asc], [:poso, :asc]).map(&:poso)
1390
- end
1391
-
1392
- describe 'default positions' do
1393
- it { expect(apple_positions).to eq([1, 2, 3, 4, 1, 2, 3, 1, 2]) }
1394
- it { expect(orange_positions).to eq([1, 2, 3, 1, 2, 1, 2, 3, 4]) }
1395
- end
1396
-
1397
- describe 'change the scope of the apple' do
1398
- let(:record) { MultipleScopedOrderable.first }
1399
- before do
1400
- record.update_attribute(:apple_id, 2)
1401
- end
1402
-
1403
- it 'should properly set the apple positions' do
1404
- expect(apple_positions).to eq([1, 2, 3, 1, 2, 3, 4, 1, 2])
1405
- end
1406
-
1407
- it 'should not affect the orange positions' do
1408
- expect(orange_positions).to eq([1, 2, 3, 1, 2, 1, 2, 3, 4])
1409
- end
1410
- end
1411
- end
1412
-
1413
- end