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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +83 -22
- data/LICENSE.txt +20 -0
- data/README.md +256 -149
- data/Rakefile +24 -6
- data/lib/config/locales/en.yml +12 -9
- data/lib/mongoid/orderable.rb +29 -22
- data/lib/mongoid/orderable/configs/field_config.rb +79 -0
- data/lib/mongoid/orderable/configs/global_config.rb +26 -0
- data/lib/mongoid/orderable/errors/invalid_target_position.rb +19 -18
- data/lib/mongoid/orderable/errors/transaction_failed.rb +20 -0
- data/lib/mongoid/orderable/generators/base.rb +21 -0
- data/lib/mongoid/orderable/generators/helpers.rb +29 -0
- data/lib/mongoid/orderable/generators/listable.rb +41 -0
- data/lib/mongoid/orderable/generators/lock_collection.rb +37 -0
- data/lib/mongoid/orderable/generators/movable.rb +62 -0
- data/lib/mongoid/orderable/generators/position.rb +26 -0
- data/lib/mongoid/orderable/generators/scope.rb +26 -0
- data/lib/mongoid/orderable/handlers/base.rb +167 -0
- data/lib/mongoid/orderable/handlers/document.rb +24 -0
- data/lib/mongoid/orderable/handlers/document_embedded.rb +14 -0
- data/lib/mongoid/orderable/handlers/document_transactional.rb +35 -0
- data/lib/mongoid/orderable/handlers/transaction.rb +71 -0
- data/lib/mongoid/orderable/installer.rb +63 -0
- data/lib/mongoid/orderable/mixins/callbacks.rb +43 -0
- data/lib/mongoid/orderable/mixins/helpers.rb +39 -0
- data/lib/mongoid/orderable/mixins/listable.rb +49 -0
- data/lib/mongoid/orderable/mixins/movable.rb +60 -0
- data/lib/mongoid/orderable/version.rb +7 -0
- data/lib/mongoid_orderable.rb +33 -54
- data/spec/integration/concurrency_spec.rb +232 -0
- data/spec/integration/customized_spec.rb +31 -0
- data/spec/integration/embedded_spec.rb +41 -0
- data/spec/integration/foreign_key_spec.rb +33 -0
- data/spec/integration/inherited_spec.rb +54 -0
- data/spec/integration/multiple_fields_spec.rb +554 -0
- data/spec/integration/multiple_scoped_spec.rb +63 -0
- data/spec/integration/no_indexed_spec.rb +23 -0
- data/spec/integration/scoped_spec.rb +151 -0
- data/spec/integration/simple_spec.rb +184 -0
- data/spec/integration/string_scoped_spec.rb +28 -0
- data/spec/integration/zero_based_spec.rb +161 -0
- data/spec/spec_helper.rb +42 -30
- data/spec/support/models.rb +122 -0
- metadata +75 -41
- data/.gitignore +0 -4
- data/.rspec +0 -2
- data/.rvmrc +0 -1
- data/.travis.yml +0 -14
- data/Gemfile +0 -18
- data/lib/mongoid/orderable/callbacks.rb +0 -75
- data/lib/mongoid/orderable/configuration.rb +0 -60
- data/lib/mongoid/orderable/errors.rb +0 -2
- data/lib/mongoid/orderable/errors/mongoid_orderable_error.rb +0 -14
- data/lib/mongoid/orderable/generator.rb +0 -34
- data/lib/mongoid/orderable/generator/helpers.rb +0 -29
- data/lib/mongoid/orderable/generator/listable.rb +0 -41
- data/lib/mongoid/orderable/generator/movable.rb +0 -62
- data/lib/mongoid/orderable/generator/position.rb +0 -26
- data/lib/mongoid/orderable/generator/scope.rb +0 -17
- data/lib/mongoid/orderable/helpers.rb +0 -50
- data/lib/mongoid/orderable/listable.rb +0 -49
- data/lib/mongoid/orderable/movable.rb +0 -58
- data/lib/mongoid/orderable/orderable_class.rb +0 -51
- data/lib/mongoid_orderable/mongoid/contexts/enumerable.rb +0 -15
- data/lib/mongoid_orderable/mongoid/contexts/mongo.rb +0 -18
- data/lib/mongoid_orderable/mongoid/contextual/memory.rb +0 -15
- data/lib/mongoid_orderable/mongoid/criteria.rb +0 -4
- data/lib/mongoid_orderable/version.rb +0 -3
- data/mongoid_orderable.gemspec +0 -26
- data/spec/mongoid/orderable_spec.rb +0 -1413
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm use 2.2@mongoid_orderable --create
|
data/.travis.yml
DELETED
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,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
|