mongoid_orderable 4.1.1 → 6.0.1
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.
- checksums.yaml +5 -5
 - data/CHANGELOG.md +77 -17
 - data/LICENSE.txt +20 -0
 - data/README.md +256 -127
 - 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/engine.rb +206 -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/installer.rb +63 -0
 - data/lib/mongoid/orderable/mixins/callbacks.rb +29 -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 +29 -56
 - data/spec/mongoid/orderable_spec.rb +1486 -1408
 - data/spec/spec_helper.rb +21 -37
 - metadata +62 -42
 - data/.gitignore +0 -4
 - data/.rspec +0 -1
 - data/.rvmrc +0 -1
 - data/.travis.yml +0 -20
 - data/Gemfile +0 -15
 - 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 -25
 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Errors
         
     | 
| 
      
 6 
     | 
    
         
            +
              class TransactionFailed < ::Mongoid::Errors::MongoidError
         
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(error)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  super _compose_message(error)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                private
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def _compose_message(error)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  compose_message 'transaction_failed'
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @summary = error.message
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Generators
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :klass
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(klass)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @klass = klass
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                protected
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def generate_method(name, &block)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  klass.send(:define_method, name, &block)
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Generators
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Helpers < Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                def generate
         
     | 
| 
      
 8 
     | 
    
         
            +
                  self_class = klass
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  klass.class_eval <<~KLASS, __FILE__, __LINE__ + 1
         
     | 
| 
      
 11 
     | 
    
         
            +
                    def orderable_top(field = nil)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      field ||= default_orderable_field
         
     | 
| 
      
 13 
     | 
    
         
            +
                      #{self_class}.orderable_configs[field][:base]
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    def orderable_field(field = nil)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      field ||= default_orderable_field
         
     | 
| 
      
 18 
     | 
    
         
            +
                      #{self_class}.orderable_configs[field][:field]
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  KLASS
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  generate_method(:orderable_inherited_class) do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    self_class.orderable_configs.any? {|_field, conf| conf[:inherited] } ? self_class : self.class
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Generators
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Listable < Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                def generate(field_name)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  generate_list_helpers(field_name)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  generate_aliased_helpers(field_name)
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                protected
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def generate_list_helpers(field_name)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  generate_method("next_#{field_name}_item") do
         
     | 
| 
      
 16 
     | 
    
         
            +
                    next_item(field_name)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  generate_method("next_#{field_name}_items") do
         
     | 
| 
      
 20 
     | 
    
         
            +
                    next_items(field_name)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  generate_method("previous_#{field_name}_item") do
         
     | 
| 
      
 24 
     | 
    
         
            +
                    previous_item(field_name)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  generate_method("previous_#{field_name}_items") do
         
     | 
| 
      
 28 
     | 
    
         
            +
                    previous_items(field_name)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def generate_aliased_helpers(field_name)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  klass.class_eval do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    alias_method "prev_#{field_name}_items", "previous_#{field_name}_items"
         
     | 
| 
      
 35 
     | 
    
         
            +
                    alias_method "prev_#{field_name}_item",  "previous_#{field_name}_item"
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Generators
         
     | 
| 
      
 6 
     | 
    
         
            +
              class LockCollection
         
     | 
| 
      
 7 
     | 
    
         
            +
                def generate(collection_name)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  return unless collection_name
         
     | 
| 
      
 9 
     | 
    
         
            +
                  model_name = collection_name.to_s.singularize.classify
         
     | 
| 
      
 10 
     | 
    
         
            +
                  return if model_exists?(model_name)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  ::Mongoid::Orderable.class_eval <<~KLASS, __FILE__, __LINE__ + 1
         
     | 
| 
      
 12 
     | 
    
         
            +
                    module Models
         
     | 
| 
      
 13 
     | 
    
         
            +
                      class #{model_name}
         
     | 
| 
      
 14 
     | 
    
         
            +
                        include Mongoid::Document
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                        store_in collection: :#{collection_name}
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                        field :scope, type: String
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                        index({ scope: 1 }, { unique: 1 })
         
     | 
| 
      
 21 
     | 
    
         
            +
                      end
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  KLASS
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                protected
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def model_exists?(model_name)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  base = ::Mongoid::Orderable::Models
         
     | 
| 
      
 30 
     | 
    
         
            +
                  !!(defined?(base) && base.const_get(model_name))
         
     | 
| 
      
 31 
     | 
    
         
            +
                rescue NameError
         
     | 
| 
      
 32 
     | 
    
         
            +
                  false
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Generators
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Movable < Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                def generate(field_name)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  generate_move_to_helpers(field_name)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  generate_insert_at_helpers(field_name)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  generate_shorthand_helpers(field_name)
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                protected
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def generate_move_to_helpers(field_name)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  generate_method("move_#{field_name}_to") do |target_position|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    move_field_to target_position, field: field_name
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  generate_method("move_#{field_name}_to!") do |target_position|
         
     | 
| 
      
 21 
     | 
    
         
            +
                    move_field_to target_position, field: field_name
         
     | 
| 
      
 22 
     | 
    
         
            +
                    save
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  generate_method("move_#{field_name}_to=") do |target_position|
         
     | 
| 
      
 26 
     | 
    
         
            +
                    move_field_to target_position, field: field_name
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def generate_insert_at_helpers(field_name)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  klass.class_eval do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    alias_method "insert_#{field_name}_at!", "move_#{field_name}_to!"
         
     | 
| 
      
 33 
     | 
    
         
            +
                    alias_method "insert_#{field_name}_at",  "move_#{field_name}_to"
         
     | 
| 
      
 34 
     | 
    
         
            +
                    alias_method "insert_#{field_name}_at=", "move_#{field_name}_to="
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def generate_shorthand_helpers(field_name)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  %i[top bottom].each do |symbol|
         
     | 
| 
      
 40 
     | 
    
         
            +
                    generate_method "move_#{field_name}_to_#{symbol}" do
         
     | 
| 
      
 41 
     | 
    
         
            +
                      move_to symbol, field: field_name
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    generate_method "move_#{field_name}_to_#{symbol}!" do
         
     | 
| 
      
 45 
     | 
    
         
            +
                      move_to! symbol, field: field_name
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  %i[higher lower].each do |symbol|
         
     | 
| 
      
 50 
     | 
    
         
            +
                    generate_method "move_#{field_name}_#{symbol}" do
         
     | 
| 
      
 51 
     | 
    
         
            +
                      move_to symbol, field: field_name
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    generate_method "move_#{field_name}_#{symbol}!" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                      move_to! symbol, field: field_name
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
            end
         
     | 
| 
      
 61 
     | 
    
         
            +
            end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Generators
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Position < Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                def generate(field_name)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  klass.class_eval <<~KLASS, __FILE__, __LINE__ + 1
         
     | 
| 
      
 9 
     | 
    
         
            +
                    def orderable_position(field = nil)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      field ||= default_orderable_field
         
     | 
| 
      
 11 
     | 
    
         
            +
                      send "orderable_\#{field}_position"
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                  KLASS
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  generate_method("orderable_#{field_name}_position") do
         
     | 
| 
      
 16 
     | 
    
         
            +
                    send field_name
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  generate_method("orderable_#{field_name}_position=") do |value|
         
     | 
| 
      
 20 
     | 
    
         
            +
                    send "#{field_name}=", value
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Generators
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Scope < Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                def generate(field_name, order_scope)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  criteria = criteria(order_scope)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  klass.class_eval do
         
     | 
| 
      
 10 
     | 
    
         
            +
                    scope "orderable_#{field_name}_scope", criteria
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                protected
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def criteria(order_scope)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  case order_scope
         
     | 
| 
      
 18 
     | 
    
         
            +
                  when Proc then order_scope
         
     | 
| 
      
 19 
     | 
    
         
            +
                  when Array then ->(doc) { where(order_scope.each_with_object({}) {|f, h| h[f] = doc.send(f) }) }
         
     | 
| 
      
 20 
     | 
    
         
            +
                  else ->(_doc) { where({}) }
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Installer
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :klass, :config
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(klass, options = {})
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @klass = klass
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @config = Mongoid::Orderable::Configs::FieldConfig.new(klass, options).options
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def setup
         
     | 
| 
      
 14 
     | 
    
         
            +
                  add_db_field
         
     | 
| 
      
 15 
     | 
    
         
            +
                  add_db_index if config[:index]
         
     | 
| 
      
 16 
     | 
    
         
            +
                  save_config
         
     | 
| 
      
 17 
     | 
    
         
            +
                  include_mixins
         
     | 
| 
      
 18 
     | 
    
         
            +
                  generate_all_helpers
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                protected
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def field_name
         
     | 
| 
      
 24 
     | 
    
         
            +
                  config[:field_options][:as] || config[:field]
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def order_scope
         
     | 
| 
      
 28 
     | 
    
         
            +
                  config[:scope]
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def add_db_field
         
     | 
| 
      
 32 
     | 
    
         
            +
                  klass.field(config[:field], { type: Integer }.reverse_merge(config[:field_options]))
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def add_db_index
         
     | 
| 
      
 36 
     | 
    
         
            +
                  spec = [[config[:field], 1]]
         
     | 
| 
      
 37 
     | 
    
         
            +
                  config[:scope].each {|field| spec.unshift([field, 1]) } if config[:scope].is_a?(Array)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  klass.index(Hash[spec])
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def save_config
         
     | 
| 
      
 42 
     | 
    
         
            +
                  klass.orderable_configs ||= {}
         
     | 
| 
      
 43 
     | 
    
         
            +
                  klass.orderable_configs = klass.orderable_configs.merge(field_name => config)
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def include_mixins
         
     | 
| 
      
 47 
     | 
    
         
            +
                  klass.send :include, Mixins::Helpers
         
     | 
| 
      
 48 
     | 
    
         
            +
                  klass.send :include, Mixins::Callbacks
         
     | 
| 
      
 49 
     | 
    
         
            +
                  klass.send :include, Mixins::Movable
         
     | 
| 
      
 50 
     | 
    
         
            +
                  klass.send :include, Mixins::Listable
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def generate_all_helpers
         
     | 
| 
      
 54 
     | 
    
         
            +
                  Generators::Scope.new(klass).generate(field_name, order_scope)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  Generators::Position.new(klass).generate(field_name)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  Generators::Movable.new(klass).generate(field_name)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  Generators::Listable.new(klass).generate(field_name)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  Generators::Helpers.new(klass).generate
         
     | 
| 
      
 59 
     | 
    
         
            +
                  Generators::LockCollection.new.generate(config[:lock_collection])
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Mixins
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Callbacks
         
     | 
| 
      
 7 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                ORDERABLE_TRANSACTION_KEY = :__mongoid_orderable_in_txn
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                included do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  around_save :orderable_update_positions
         
     | 
| 
      
 13 
     | 
    
         
            +
                  after_destroy :orderable_remove_positions, unless: -> { embedded? && _root.destroyed? }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  delegate :update_positions,
         
     | 
| 
      
 16 
     | 
    
         
            +
                           :remove_positions,
         
     | 
| 
      
 17 
     | 
    
         
            +
                           to: :orderable_engine,
         
     | 
| 
      
 18 
     | 
    
         
            +
                           prefix: :orderable
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def orderable_engine
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @orderable_engine ||= Mongoid::Orderable::Engine.new(self)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Mixins
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Helpers
         
     | 
| 
      
 7 
     | 
    
         
            +
                def orderable_keys
         
     | 
| 
      
 8 
     | 
    
         
            +
                  Array(orderable_inherited_class.orderable_configs.try(:keys))
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def default_orderable_field
         
     | 
| 
      
 12 
     | 
    
         
            +
                  self.class.orderable_configs.detect {|_c, conf| conf[:default] }.try(:first) || orderable_keys.first
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def orderable_scope(field = nil)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  field ||= default_orderable_field
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  if embedded?
         
     | 
| 
      
 19 
     | 
    
         
            +
                    _parent.send(_association.name).send("orderable_#{field}_scope", self)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  else
         
     | 
| 
      
 21 
     | 
    
         
            +
                    orderable_inherited_class.send("orderable_#{field}_scope", self)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def orderable_scope_changed?(field)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  !orderable_scope(field).where(_id: _id).exists?
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def orderable_bottom(field = nil, in_list = true)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  field ||= default_orderable_field
         
     | 
| 
      
 31 
     | 
    
         
            +
                  f = orderable_field(field)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  max = orderable_scope(field).ne(f => nil).max(f)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  return orderable_top(field) unless max
         
     | 
| 
      
 34 
     | 
    
         
            +
                  in_list ? max : max.next
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Mongoid
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Orderable
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Mixins
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Listable
         
     | 
| 
      
 7 
     | 
    
         
            +
                def in_list?(field = nil)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  persisted? && !orderable_position(field).nil?
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                # Returns items above the current document.
         
     | 
| 
      
 12 
     | 
    
         
            +
                # Items with a position lower than this document's position.
         
     | 
| 
      
 13 
     | 
    
         
            +
                def previous_items(field = nil)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  field ||= default_orderable_field
         
     | 
| 
      
 15 
     | 
    
         
            +
                  orderable_scope(field).lt(orderable_field(field) => send(field))
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
                alias prev_items previous_items
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                # Returns items below the current document.
         
     | 
| 
      
 20 
     | 
    
         
            +
                # Items with a position greater than this document's position.
         
     | 
| 
      
 21 
     | 
    
         
            +
                def next_items(field = nil)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  field ||= default_orderable_field
         
     | 
| 
      
 23 
     | 
    
         
            +
                  orderable_scope(field).gt(orderable_field(field) => send(field))
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                # Returns the previous item in the list
         
     | 
| 
      
 27 
     | 
    
         
            +
                def previous_item(field = nil)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  field ||= default_orderable_field
         
     | 
| 
      
 29 
     | 
    
         
            +
                  orderable_scope(field).where(orderable_field(field) => send(field) - 1).first
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
                alias prev_item previous_item
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # Returns the next item in the list
         
     | 
| 
      
 34 
     | 
    
         
            +
                def next_item(field = nil)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  field ||= default_orderable_field
         
     | 
| 
      
 36 
     | 
    
         
            +
                  orderable_scope(field).where(orderable_field(field) => send(field) + 1).first
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def first?(field = nil)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  in_list?(field) && orderable_position(field) == orderable_top(field)
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def last?(field = nil)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  in_list?(field) && orderable_position(field) == orderable_bottom(field)
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
      
 48 
     | 
    
         
            +
            end
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     |