mongoid_orderable 5.0.0 → 6.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.
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
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- *.gem
2
- .bundle
3
- Gemfile.lock
4
- pkg/*
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --colour
2
- --format=documentation
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm use 2.2@mongoid_orderable --create
@@ -1,14 +0,0 @@
1
- rvm:
2
- - 1.9.3
3
- - 2.0.0
4
- - 2.1
5
- - 2.2
6
- # - rbx
7
-
8
- env:
9
- - MONGOID_VERSION=2
10
- - MONGOID_VERSION=3
11
- - MONGOID_VERSION=4
12
- - MONGOID_VERSION=5
13
-
14
- services: mongodb
data/Gemfile DELETED
@@ -1,18 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in mongoid_orderable.gemspec
4
- gemspec
5
-
6
- case version = ENV['MONGOID_VERSION'] || '5.0'
7
- when /^5/
8
- gem 'mongoid', '~> 5.0'
9
- when /^4/
10
- gem 'mongoid', '~> 4.0'
11
- when /^3/
12
- gem 'mongoid', '~> 3.1'
13
- when /^2/
14
- gem 'mongoid', '~> 2.0'
15
- gem 'bson_ext', platforms: :ruby
16
- else
17
- gem 'mongoid', version
18
- end
@@ -1,75 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Callbacks
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
-
8
- protected
9
-
10
- def add_to_list
11
- self.orderable_keys.each do |column|
12
- apply_position column, move_all[column]
13
- end
14
- end
15
-
16
- def remove_from_list
17
- self.orderable_keys.each do |column|
18
- remove_position_from_list column
19
- end
20
- end
21
-
22
- def remove_position_from_list(column)
23
- col, pos = orderable_column(column), orderable_position(column)
24
- MongoidOrderable.inc orderable_scoped(column).where(col.gt => pos), col, -1
25
- end
26
-
27
- def apply_position column, target_position
28
- if persisted? && !embedded? && orderable_scope_changed?(column)
29
- self.class.unscoped.find(_id).remove_position_from_list(column)
30
- self.send("orderable_#{column}_position=", nil)
31
- end
32
-
33
- return if !target_position && in_list?(column)
34
-
35
- target_position = target_position_to_position column, target_position
36
- scope, col, pos = orderable_scoped(column), orderable_column(column), orderable_position(column)
37
-
38
- unless in_list?(column)
39
- MongoidOrderable.inc scope.where(col.gte => target_position), col, 1
40
- else
41
- MongoidOrderable.inc(scope.where(col.gte => target_position, col.lt => pos), col, 1) if target_position < pos
42
- MongoidOrderable.inc(scope.where(col.gt => pos, col.lte => target_position), col, -1) if target_position > pos
43
- end
44
-
45
- self.send("orderable_#{column}_position=", target_position)
46
- end
47
-
48
- def target_position_to_position column, target_position
49
- target_position = :bottom unless target_position
50
-
51
- target_position = case target_position.to_s
52
- when 'top' then orderable_base(column)
53
- when 'bottom' then bottom_orderable_position(column)
54
- when 'higher' then orderable_position(column).pred
55
- when 'lower' then orderable_position(column).next
56
- when /\A\d+\Z/ then target_position.to_i
57
- else raise Mongoid::Orderable::Errors::InvalidTargetPosition.new target_position
58
- end unless target_position.is_a? Numeric
59
-
60
- target_position = orderable_base(column) if target_position < orderable_base(column)
61
- target_position = bottom_orderable_position(column) if target_position > bottom_orderable_position(column)
62
- target_position
63
- end
64
-
65
- end
66
-
67
- module ClassMethods
68
- def add_orderable_callbacks
69
- before_save :add_to_list
70
- after_destroy :remove_from_list
71
- end
72
- end
73
- end
74
- end
75
- end
@@ -1,60 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- class Configuration
4
-
5
- CONFIG_OPTIONS = %w(column scope foreign_key inherited base index default).map(&:to_sym)
6
- FIELD_OPTIONS = %w(as).map(&:to_sym)
7
- VALID_OPTIONS = CONFIG_OPTIONS + FIELD_OPTIONS
8
-
9
- attr_reader :orderable_class, :options
10
-
11
- def initialize(parent, options = {})
12
- @orderable_class = parent
13
- set_options(options)
14
- set_field_options
15
- set_orderable_scope
16
- end
17
-
18
- def default_configuration
19
- { :column => :position,
20
- :index => true,
21
- :scope => nil,
22
- :base => 1,
23
- :field_opts => { :type => Integer }}
24
- end
25
-
26
- def self.build(parent, options = {})
27
- new(parent, options).options
28
- end
29
-
30
- protected
31
-
32
- def set_options(options)
33
- @options = default_configuration
34
- return unless options.is_a? Hash
35
- @options.merge! options.symbolize_keys.slice(*VALID_OPTIONS)
36
- end
37
-
38
- def set_field_options
39
- FIELD_OPTIONS.each do |key|
40
- next unless options.has_key? key
41
- @options[:field_opts][key] = options.delete(key)
42
- end
43
- end
44
-
45
- def set_orderable_scope
46
- if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
47
- scope_relation = @orderable_class.relations[options[:scope].to_s]
48
- if scope_relation
49
- @options[:scope] = scope_relation.key.to_sym
50
- else
51
- @options[:scope] = "#{options[:scope]}_id".to_sym
52
- end
53
- elsif options[:scope].is_a?(String)
54
- @options[:scope] = options[:scope].to_sym
55
- end
56
- end
57
-
58
- end
59
- end
60
- end
@@ -1,2 +0,0 @@
1
- require 'mongoid/orderable/errors/mongoid_orderable_error'
2
- require 'mongoid/orderable/errors/invalid_target_position'
@@ -1,14 +0,0 @@
1
- module Mongoid::Orderable
2
- module Errors
3
- class MongoidOrderableError < ::Mongoid::Errors::MongoidError
4
-
5
- if ::Mongoid::Compatibility::Version.mongoid2?
6
- def translate key, options
7
- [:message, :summary, :resolution].map do |section|
8
- ::I18n.translate "#{BASE_KEY}.#{key}.#{section}", options
9
- end.join ' '
10
- end
11
- end
12
- end
13
- end
14
- end
@@ -1,34 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Generator
4
- include Mongoid::Orderable::Generator::Scope
5
- include Mongoid::Orderable::Generator::Position
6
- include Mongoid::Orderable::Generator::Movable
7
- include Mongoid::Orderable::Generator::Listable
8
- include Mongoid::Orderable::Generator::Helpers
9
-
10
- def column_name
11
- configuration[:field_opts][:as] || configuration[:column]
12
- end
13
-
14
- def order_scope
15
- configuration[:scope]
16
- end
17
-
18
- def generate_all_helpers
19
- generate_scope_helpers(column_name, order_scope)
20
- generate_position_helpers(column_name)
21
- generate_movable_helpers(column_name)
22
- generate_listable_helpers(column_name)
23
- generate_orderable_helpers
24
- end
25
-
26
- protected
27
-
28
- def generate_method(name, &block)
29
- klass.send(:define_method, name, &block)
30
- end
31
-
32
- end
33
- end
34
- end
@@ -1,29 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Generator
4
- module Helpers
5
-
6
- def generate_orderable_helpers
7
- self_class = klass
8
-
9
- klass.class_eval <<-eos
10
- def orderable_base(column = nil)
11
- column ||= default_orderable_column
12
- #{self_class}.orderable_configurations[column][:base]
13
- end
14
-
15
- def orderable_column(column = nil)
16
- column ||= default_orderable_column
17
- #{self_class}.orderable_configurations[column][:column]
18
- end
19
- eos
20
-
21
- generate_method(:orderable_inherited_class) do
22
- self_class.orderable_configurations.any?{ |col, conf| conf[:inherited] } ? self_class : self.class
23
- end
24
- end
25
-
26
- end
27
- end
28
- end
29
- end
@@ -1,41 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Generator
4
- module Listable
5
-
6
- def generate_listable_helpers(column_name)
7
- generate_list_helpers(column_name)
8
- generate_aliased_helpers(column_name)
9
- end
10
-
11
- protected
12
-
13
- def generate_list_helpers(column_name)
14
- generate_method("next_#{column_name}_item") do
15
- next_item(column_name)
16
- end
17
-
18
- generate_method("next_#{column_name}_items") do
19
- next_items(column_name)
20
- end
21
-
22
- generate_method("previous_#{column_name}_item") do
23
- previous_item(column_name)
24
- end
25
-
26
- generate_method("previous_#{column_name}_items") do
27
- previous_items(column_name)
28
- end
29
- end
30
-
31
- def generate_aliased_helpers(column_name)
32
- klass.class_eval do
33
- alias_method "prev_#{column_name}_items", "previous_#{column_name}_items"
34
- alias_method "prev_#{column_name}_item", "previous_#{column_name}_item"
35
- end
36
- end
37
-
38
- end
39
- end
40
- end
41
- end
@@ -1,62 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Generator
4
- module Movable
5
-
6
- def generate_movable_helpers(column_name)
7
- generate_move_to_helpers(column_name)
8
- generate_insert_at_helpers(column_name)
9
- generate_shorthand_helpers(column_name)
10
- end
11
-
12
- protected
13
-
14
- def generate_move_to_helpers(column_name)
15
- generate_method("move_#{column_name}_to") do |target_position|
16
- move_column_to target_position, :column => column_name
17
- end
18
-
19
- generate_method("move_#{column_name}_to!") do |target_position|
20
- move_column_to target_position, :column => column_name
21
- save
22
- end
23
-
24
- generate_method("move_#{column_name}_to=") do |target_position|
25
- move_column_to target_position, :column => column_name
26
- end
27
- end
28
-
29
- def generate_insert_at_helpers(column_name)
30
- klass.class_eval do
31
- alias_method "insert_#{column_name}_at!", "move_#{column_name}_to!"
32
- alias_method "insert_#{column_name}_at", "move_#{column_name}_to"
33
- alias_method "insert_#{column_name}_at=", "move_#{column_name}_to="
34
- end
35
- end
36
-
37
- def generate_shorthand_helpers(column_name)
38
- [:top, :bottom].each do |symbol|
39
- generate_method "move_#{column_name}_to_#{symbol}" do
40
- move_to symbol, :column => column_name
41
- end
42
-
43
- generate_method "move_#{column_name}_to_#{symbol}!" do
44
- move_to! symbol, :column => column_name
45
- end
46
- end
47
-
48
- [:higher, :lower].each do |symbol|
49
- generate_method "move_#{column_name}_#{symbol}" do
50
- move_to symbol, :column => column_name
51
- end
52
-
53
- generate_method "move_#{column_name}_#{symbol}!" do
54
- move_to! symbol, :column => column_name
55
- end
56
- end
57
- end
58
-
59
- end
60
- end
61
- end
62
- end
@@ -1,26 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Generator
4
- module Position
5
-
6
- def generate_position_helpers(column_name)
7
- klass.class_eval <<-eos
8
- def orderable_position(column = nil)
9
- column ||= default_orderable_column
10
- send "orderable_\#{column}_position"
11
- end
12
- eos
13
-
14
- generate_method("orderable_#{column_name}_position") do
15
- send column_name
16
- end
17
-
18
- generate_method("orderable_#{column_name}_position=") do |value|
19
- send "#{column_name}=", value
20
- end
21
- end
22
-
23
- end
24
- end
25
- end
26
- end
@@ -1,17 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Generator
4
- module Scope
5
- def generate_scope_helpers(column_name, order_scope)
6
- klass.class_eval do
7
- scope "orderable_#{column_name}_scope", case order_scope
8
- when Symbol then lambda { |document| where(order_scope => document.send(order_scope)) }
9
- when Proc then order_scope
10
- else lambda { |document| where({}) }
11
- end
12
- end
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,50 +0,0 @@
1
- module Mongoid
2
- module Orderable
3
- module Helpers
4
-
5
- def orderable_keys
6
- Array orderable_inherited_class.orderable_configurations.try(:keys)
7
- end
8
-
9
- def default_orderable_column
10
- self.class.orderable_configurations.detect{ |c, conf| conf[:default] }.try(:first) || self.orderable_keys.first
11
- end
12
-
13
- private
14
-
15
- def orderable_scoped(column = nil)
16
- column ||= default_orderable_column
17
-
18
- if embedded?
19
- send(MongoidOrderable.metadata(self).inverse).send(MongoidOrderable.metadata(self).name).send("orderable_#{column}_scope", self)
20
- else
21
- self.orderable_inherited_class.send("orderable_#{column}_scope", self)
22
- end
23
- end
24
-
25
- def orderable_scope_changed?(column)
26
- if Mongoid.respond_to?(:unit_of_work)
27
- Mongoid.unit_of_work do
28
- orderable_scope_changed_query(column)
29
- end
30
- else
31
- orderable_scope_changed_query(column)
32
- end
33
- end
34
-
35
- def orderable_scope_changed_query(column)
36
- !orderable_scoped(column).where(:_id => _id).exists?
37
- end
38
-
39
- def bottom_orderable_position(column = nil)
40
- column ||= default_orderable_column
41
- @bottom_orderable_position = begin
42
- positions_list = orderable_scoped(column).distinct(orderable_column(column)).compact
43
- return orderable_base(column) if positions_list.empty?
44
- max = positions_list.map(&:to_i).max.to_i
45
- in_list?(column) ? max : max.next
46
- end
47
- end
48
- end
49
- end
50
- end