mongoid_orderable 6.0.4 → 6.0.6

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +101 -93
  3. data/LICENSE.txt +20 -20
  4. data/README.md +280 -275
  5. data/Rakefile +24 -24
  6. data/lib/config/locales/en.yml +12 -12
  7. data/lib/mongoid/orderable/configs/field_config.rb +81 -81
  8. data/lib/mongoid/orderable/configs/global_config.rb +26 -26
  9. data/lib/mongoid/orderable/errors/invalid_target_position.rb +19 -19
  10. data/lib/mongoid/orderable/errors/transaction_failed.rb +20 -20
  11. data/lib/mongoid/orderable/generators/base.rb +21 -21
  12. data/lib/mongoid/orderable/generators/helpers.rb +37 -37
  13. data/lib/mongoid/orderable/generators/listable.rb +41 -41
  14. data/lib/mongoid/orderable/generators/lock_collection.rb +39 -39
  15. data/lib/mongoid/orderable/generators/movable.rb +62 -62
  16. data/lib/mongoid/orderable/generators/position.rb +26 -26
  17. data/lib/mongoid/orderable/generators/scope.rb +26 -26
  18. data/lib/mongoid/orderable/handlers/base.rb +215 -189
  19. data/lib/mongoid/orderable/handlers/document.rb +32 -24
  20. data/lib/mongoid/orderable/handlers/document_embedded.rb +14 -14
  21. data/lib/mongoid/orderable/handlers/document_transactional.rb +32 -35
  22. data/lib/mongoid/orderable/handlers/transaction.rb +75 -71
  23. data/lib/mongoid/orderable/installer.rb +64 -64
  24. data/lib/mongoid/orderable/mixins/callbacks.rb +45 -43
  25. data/lib/mongoid/orderable/mixins/cascadeable.rb +15 -15
  26. data/lib/mongoid/orderable/mixins/helpers.rb +39 -39
  27. data/lib/mongoid/orderable/mixins/listable.rb +49 -49
  28. data/lib/mongoid/orderable/mixins/movable.rb +64 -60
  29. data/lib/mongoid/orderable/version.rb +7 -7
  30. data/lib/mongoid/orderable.rb +29 -29
  31. data/lib/mongoid_orderable.rb +34 -34
  32. metadata +6 -93
  33. data/spec/integration/cascadeable_spec.rb +0 -12
  34. data/spec/integration/concurrency_spec.rb +0 -232
  35. data/spec/integration/conditional_spec.rb +0 -36
  36. data/spec/integration/customized_spec.rb +0 -31
  37. data/spec/integration/embedded_spec.rb +0 -63
  38. data/spec/integration/foreign_key_spec.rb +0 -33
  39. data/spec/integration/inherited_spec.rb +0 -54
  40. data/spec/integration/multiple_fields_spec.rb +0 -554
  41. data/spec/integration/multiple_scoped_spec.rb +0 -63
  42. data/spec/integration/no_indexed_spec.rb +0 -23
  43. data/spec/integration/scoped_spec.rb +0 -151
  44. data/spec/integration/simple_spec.rb +0 -184
  45. data/spec/integration/string_scoped_spec.rb +0 -28
  46. data/spec/integration/zero_based_spec.rb +0 -161
  47. data/spec/spec_helper.rb +0 -42
  48. data/spec/support/models.rb +0 -134
@@ -1,24 +1,32 @@
1
- # frozen_string_literal: true
2
-
3
- module Mongoid
4
- module Orderable
5
- module Handlers
6
- class Document < Base
7
- def before_create
8
- apply_all_positions
9
- end
10
-
11
- def after_create; end
12
-
13
- def before_update
14
- return unless any_field_changed?
15
- apply_all_positions
16
- end
17
-
18
- def after_destroy
19
- remove_all_positions
20
- end
21
- end
22
- end
23
- end
24
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Orderable
5
+ module Handlers
6
+ class Document < Base
7
+ def before_create
8
+ set_new_record_positions
9
+ apply_all_positions
10
+ end
11
+
12
+ def after_create
13
+ reset
14
+ end
15
+
16
+ def before_update
17
+ return unless any_field_changed?
18
+ apply_all_positions
19
+ end
20
+
21
+ def after_update
22
+ reset
23
+ end
24
+
25
+ def after_destroy
26
+ remove_all_positions
27
+ reset
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,14 +1,14 @@
1
- # frozen_string_literal: true
2
-
3
- module Mongoid
4
- module Orderable
5
- module Handlers
6
- class DocumentEmbedded < Document
7
- def after_destroy
8
- return if doc._root.destroyed?
9
- super
10
- end
11
- end
12
- end
13
- end
14
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Orderable
5
+ module Handlers
6
+ class DocumentEmbedded < Document
7
+ def after_destroy
8
+ return if doc._root.destroyed?
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,35 +1,32 @@
1
- # frozen_string_literal: true
2
-
3
- module Mongoid
4
- module Orderable
5
- module Handlers
6
- class DocumentTransactional < Document
7
- def before_create
8
- clear_all_positions
9
- end
10
-
11
- def after_create
12
- apply_all_positions
13
- end
14
-
15
- protected
16
-
17
- def apply_all_positions
18
- with_transaction { super }
19
- end
20
-
21
- def clear_all_positions
22
- orderable_keys.each {|field| doc.send("orderable_#{field}_position=", nil) }
23
- end
24
-
25
- def use_transactions
26
- true
27
- end
28
-
29
- def with_transaction(&block)
30
- Mongoid::Orderable::Handlers::Transaction.new(doc).with_transaction(&block)
31
- end
32
- end
33
- end
34
- end
35
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Orderable
5
+ module Handlers
6
+ class DocumentTransactional < Document
7
+ def before_create
8
+ set_new_record_positions
9
+ end
10
+
11
+ def after_create
12
+ apply_all_positions
13
+ super
14
+ end
15
+
16
+ private
17
+
18
+ def apply_all_positions
19
+ with_transaction { super }
20
+ end
21
+
22
+ def use_transactions
23
+ true
24
+ end
25
+
26
+ def with_transaction(&block)
27
+ Mongoid::Orderable::Handlers::Transaction.new(doc).with_transaction(&block)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,71 +1,75 @@
1
- # frozen_string_literal: true
2
-
3
- module Mongoid
4
- module Orderable
5
- module Handlers
6
- # Executes a block within the context of a MongoDB transaction.
7
- class Transaction
8
- THREAD_KEY = :__mongoid_orderable_in_txn
9
- RETRY_SLEEP = 0.001
10
-
11
- attr_reader :doc
12
-
13
- def initialize(doc)
14
- @doc = doc
15
- end
16
-
17
- def with_transaction(&block)
18
- Mongoid::QueryCache.uncached do
19
- if Thread.current[THREAD_KEY]
20
- yield
21
- else
22
- Thread.current[THREAD_KEY] = true
23
- retries = transaction_max_retries
24
- begin
25
- do_transaction(&block)
26
- rescue Mongo::Error::OperationFailure => e
27
- sleep(RETRY_SLEEP)
28
- retries -= 1
29
- retry if retries >= 0
30
- raise Mongoid::Orderable::Errors::TransactionFailed.new(e)
31
- ensure
32
- Thread.current[THREAD_KEY] = nil
33
- end
34
- end
35
- end
36
- end
37
-
38
- protected
39
-
40
- def do_transaction(&_block)
41
- doc.class.with_session(session_opts) do |session|
42
- doc.class.with(persistence_opts) do
43
- session.start_transaction(transaction_opts)
44
- yield
45
- session.commit_transaction
46
- end
47
- end
48
- end
49
-
50
- def session_opts
51
- { read: { mode: :primary },
52
- causal_consistency: true }
53
- end
54
-
55
- def persistence_opts
56
- { read: { mode: :primary } }
57
- end
58
-
59
- def transaction_opts
60
- { read: { mode: :primary },
61
- read_concern: { level: 'majority' },
62
- write_concern: { w: 'majority' } }
63
- end
64
-
65
- def transaction_max_retries
66
- doc.orderable_keys.map {|k| doc.class.orderable_configs.dig(k, :transaction_max_retries) }.compact.max
67
- end
68
- end
69
- end
70
- end
71
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Orderable
5
+ module Handlers
6
+ # Executes a block within the context of a MongoDB transaction.
7
+ class Transaction
8
+ THREAD_KEY = :__mongoid_orderable_in_txn
9
+ RETRY_SLEEP = 0.001
10
+
11
+ attr_reader :doc
12
+
13
+ def initialize(doc)
14
+ @doc = doc
15
+ end
16
+
17
+ def with_transaction(&block)
18
+ query_cache.uncached do
19
+ if Thread.current[THREAD_KEY]
20
+ yield
21
+ else
22
+ Thread.current[THREAD_KEY] = true
23
+ retries = transaction_max_retries
24
+ begin
25
+ do_transaction(&block)
26
+ rescue Mongo::Error::OperationFailure => e
27
+ sleep(RETRY_SLEEP)
28
+ retries -= 1
29
+ retry if retries >= 0
30
+ raise Mongoid::Orderable::Errors::TransactionFailed.new(e)
31
+ ensure
32
+ Thread.current[THREAD_KEY] = nil
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def do_transaction(&_block)
41
+ doc.class.with_session(session_opts) do |session|
42
+ doc.class.with(persistence_opts) do
43
+ session.start_transaction(transaction_opts)
44
+ yield
45
+ session.commit_transaction
46
+ end
47
+ end
48
+ end
49
+
50
+ def session_opts
51
+ { read: { mode: :primary },
52
+ causal_consistency: true }
53
+ end
54
+
55
+ def persistence_opts
56
+ { read: { mode: :primary } }
57
+ end
58
+
59
+ def transaction_opts
60
+ { read: { mode: :primary },
61
+ read_concern: { level: 'majority' },
62
+ write_concern: { w: 'majority' } }
63
+ end
64
+
65
+ def transaction_max_retries
66
+ doc.orderable_keys.map {|k| doc.class.orderable_configs.dig(k, :transaction_max_retries) }.compact.max
67
+ end
68
+
69
+ def query_cache
70
+ defined?(Mongo::QueryCache) ? Mongo::QueryCache : Mongoid::QueryCache
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,64 +1,64 @@
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(spec.to_h)
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
- klass.send :prepend, Mixins::Cascadeable if klass.embedded?
52
- end
53
-
54
- def generate_all_helpers
55
- Generators::Scope.new(klass).generate(field_name, order_scope)
56
- Generators::Position.new(klass).generate(field_name)
57
- Generators::Movable.new(klass).generate(field_name)
58
- Generators::Listable.new(klass).generate(field_name)
59
- Generators::Helpers.new(klass).generate
60
- Generators::LockCollection.new.generate(config[:lock_collection])
61
- end
62
- end
63
- end
64
- end
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
+ private
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(spec.to_h)
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
+ klass.send :prepend, Mixins::Cascadeable if klass.embedded?
52
+ end
53
+
54
+ def generate_all_helpers
55
+ Generators::Scope.new(klass).generate(field_name, order_scope)
56
+ Generators::Position.new(klass).generate(field_name)
57
+ Generators::Movable.new(klass).generate(field_name)
58
+ Generators::Listable.new(klass).generate(field_name)
59
+ Generators::Helpers.new(klass).generate
60
+ Generators::LockCollection.new.generate(config[:lock_collection])
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,43 +1,45 @@
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
- before_create :orderable_before_create
13
- after_create :orderable_after_create, prepend: true
14
- before_update :orderable_before_update
15
- after_destroy :orderable_after_destroy, prepend: true
16
-
17
- delegate :before_create,
18
- :after_create,
19
- :before_update,
20
- :after_destroy,
21
- to: :orderable_handler,
22
- prefix: :orderable
23
-
24
- protected
25
-
26
- def orderable_handler
27
- @orderable_handler ||= self.class.orderable_handler_class.new(self)
28
- end
29
-
30
- def self.orderable_handler_class
31
- if embedded?
32
- Mongoid::Orderable::Handlers::DocumentEmbedded
33
- elsif orderable_configs.values.any? {|c| c[:use_transactions] }
34
- Mongoid::Orderable::Handlers::DocumentTransactional
35
- else
36
- Mongoid::Orderable::Handlers::Document
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
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
+ before_create :orderable_before_create
13
+ after_create :orderable_after_create, prepend: true
14
+ before_update :orderable_before_update
15
+ after_update :orderable_after_update, prepend: true
16
+ after_destroy :orderable_after_destroy, prepend: true
17
+
18
+ delegate :before_create,
19
+ :after_create,
20
+ :before_update,
21
+ :after_update,
22
+ :after_destroy,
23
+ to: :orderable_handler,
24
+ prefix: :orderable
25
+
26
+ private
27
+
28
+ def orderable_handler
29
+ @orderable_handler ||= self.class.orderable_handler_class.new(self)
30
+ end
31
+
32
+ def self.orderable_handler_class
33
+ if embedded?
34
+ Mongoid::Orderable::Handlers::DocumentEmbedded
35
+ elsif orderable_configs.values.any? {|c| c[:use_transactions] }
36
+ Mongoid::Orderable::Handlers::DocumentTransactional
37
+ else
38
+ Mongoid::Orderable::Handlers::Document
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,15 +1,15 @@
1
- # frozen_string_literal: true
2
-
3
- module Mongoid
4
- module Orderable
5
- module Mixins
6
- # This is required to trigger callbacks on embedded objects.
7
- # Otherwise, the #move_to parameter won't work when saving the parent.
8
- module Cascadeable
9
- def in_callback_state?(kind)
10
- super || move_all.present?
11
- end
12
- end
13
- end
14
- end
15
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Orderable
5
+ module Mixins
6
+ # This is required to trigger callbacks on embedded objects.
7
+ # Otherwise, the #move_to parameter won't work when saving the parent.
8
+ module Cascadeable
9
+ def in_callback_state?(kind)
10
+ super || move_all.present?
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,39 +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
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