mongoid_orderable 6.0.2 → 6.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3a80c8eb058adeffe1ead4c0fa20ce10660ea49a2df1405d46048419f2af965
4
- data.tar.gz: d68f6f64f52f132295e588dfcd59ad27d22a68237e5b29ab7682a37e3c940ca5
3
+ metadata.gz: 8882038ec4e57486bd693bc1732f935f2d01f949aeedc7f71b3c54bca5ac0b44
4
+ data.tar.gz: c0c82c4802280dfe6005e89122e9f7905fabcdf261bc9b3864016d10a70c112c
5
5
  SHA512:
6
- metadata.gz: 6c2d9da294dda836b17047aaf3ebc6329b3c382fb793c83fe57dd63a07512d2e1da65af3559b12e75ce3924b1edfaaefad8317f4acaa488cb94ad2392d84b474
7
- data.tar.gz: 58e8c15554183674cef20639c2cb888cb6e793471ecf7f55ea76360f2ca7de351d218f417e34db220d2daa32c6ab5dc11da23bce7acec0f77a1f99718e713705
6
+ metadata.gz: 64332b6ae9d7786864d238accdd3ec81c8defa059ff1d7e1763e487a271c2dffb2f25b3a1a2332947a3b262ecc6cb8da33aae0acdab0cd04bd3ac6e0a2a2ca44
7
+ data.tar.gz: 918ea29f2b71caf6cfba5cdc7e145bba69d0d90d2561e1983676fa13a3517f87eaabd7f66d628fbae1ec45df56fe82a11a723de632bbd1650697f39939d10534
data/CHANGELOG.md CHANGED
@@ -1,7 +1,12 @@
1
- ### 6.0.3 (Next)
1
+ ### 6.0.4 (Next)
2
2
 
3
3
  * Your contribution here.
4
4
 
5
+ ### 6.0.3 (2021/06/27)
6
+
7
+ * [#72](https://github.com/mongoid/mongoid_orderable/pull/72): Feature: Add :if and :unless conditions which disable callbacks.
8
+ * [#71](https://github.com/mongoid/mongoid_orderable/pull/71): Fix: Add TTL index to locks table.
9
+
5
10
  ### 6.0.2 (2021/01/26)
6
11
 
7
12
  * [#70](https://github.com/mongoid/mongoid_orderable/pull/70): Fix: Transactions should not use around callbacks - [@johnnyshields](https://github.com/johnnyshields).
data/README.md CHANGED
@@ -138,7 +138,8 @@ book.previous_#{field}_item
138
138
 
139
139
  where `#{field}` is either `position` or `serial_no`.
140
140
 
141
- When a model defines multiple orderable fields, the original helpers are also available and work on the first orderable field.
141
+ When a model defines multiple orderable fields, the original helpers are also available and work
142
+ on the first orderable field.
142
143
 
143
144
  ```ruby
144
145
  @book1 = Book.create!
@@ -181,6 +182,24 @@ end
181
182
  To ensure the position is written correctly, you will need to set
182
183
  `cascade_callbacks: true` on the relation.
183
184
 
185
+ ### Disable Ordering
186
+
187
+ You can disable position tracking for specific documents using the `:if` and `:unless` options.
188
+ This is in advanced scenarios where you want to control position manually for certain documents.
189
+ In general, the disable condition should match a specific scope.
190
+ **Warning:** If used improperly, this will cause your documents to become out-of-order.
191
+
192
+ ```ruby
193
+ class Book
194
+ include Mongoid::Document
195
+ include Mongoid::Orderable
196
+
197
+ field :track_position, type: Boolean
198
+
199
+ orderable if: :track_position, unless: -> { created_at < Date.parse('2020-01-01') }
200
+ end
201
+ ```
202
+
184
203
  ## Transaction Support
185
204
 
186
205
  By default, Mongoid Orderable does not guarantee ordering consistency
@@ -219,7 +238,7 @@ After `transaction_max_retries` has been exceeded, a
219
238
 
220
239
  When using transactions, Mongoid Orderable creates a collection
221
240
  `mongoid_orderable_locks` which is used to store temporary lock objects.
222
- This collection accumulate documents overtime; it is safe to delete it periodically.
241
+ Lock collections use a TTL index which auto-deletes objects older than 1 day.
223
242
 
224
243
  You can change the lock collection name globally or per model:
225
244
 
@@ -11,6 +11,8 @@ module Configs
11
11
  base
12
12
  index
13
13
  default
14
+ if
15
+ unless
14
16
  use_transactions
15
17
  transaction_max_retries
16
18
  lock_collection].freeze
@@ -17,6 +17,14 @@ module Generators
17
17
  field ||= default_orderable_field
18
18
  #{self_class}.orderable_configs[field][:field]
19
19
  end
20
+
21
+ def orderable_if(field)
22
+ #{self_class}.orderable_configs[field][:if]
23
+ end
24
+
25
+ def orderable_unless(field)
26
+ #{self_class}.orderable_configs[field][:unless]
27
+ end
20
28
  KLASS
21
29
 
22
30
  generate_method(:orderable_inherited_class) do
@@ -12,12 +12,14 @@ module Generators
12
12
  module Models
13
13
  class #{model_name}
14
14
  include Mongoid::Document
15
+ include Mongoid::Timestamps::Updated::Short
15
16
 
16
17
  store_in collection: :#{collection_name}
17
18
 
18
19
  field :scope, type: String
19
20
 
20
21
  index({ scope: 1 }, { unique: 1 })
22
+ index({ updated_at: 1 }, { expire_after_seconds: 86400 })
21
23
  end
22
24
  end
23
25
  KLASS
@@ -15,6 +15,8 @@ module Handlers
15
15
  delegate :orderable_keys,
16
16
  :orderable_field,
17
17
  :orderable_position,
18
+ :orderable_if,
19
+ :orderable_unless,
18
20
  :orderable_scope,
19
21
  :orderable_scope_changed?,
20
22
  :orderable_top,
@@ -39,7 +41,7 @@ module Handlers
39
41
  end
40
42
 
41
43
  def apply_one_position(field, target_position)
42
- return unless changed?(field)
44
+ return unless allowed?(field) && changed?(field)
43
45
 
44
46
  set_lock(field) if use_transactions
45
47
 
@@ -94,6 +96,7 @@ module Handlers
94
96
  end
95
97
 
96
98
  def remove_one_position(field)
99
+ return unless allowed?(field)
97
100
  f = orderable_field(field)
98
101
  current = orderable_position(field)
99
102
  set_lock(field) if use_transactions
@@ -127,6 +130,25 @@ module Handlers
127
130
  target_position
128
131
  end
129
132
 
133
+ def allowed?(field)
134
+ cond_if = orderable_if(field)
135
+ cond_unless = orderable_unless(field)
136
+
137
+ (cond_if.nil? || resolve_condition(cond_if)) &&
138
+ (cond_unless.nil? || !resolve_condition(cond_unless))
139
+ end
140
+
141
+ def resolve_condition(condition)
142
+ case condition
143
+ when Proc
144
+ condition.arity.zero? ? doc.instance_exec(&condition) : condition.call(doc)
145
+ when Symbol
146
+ doc.send(condition)
147
+ else
148
+ condition || false
149
+ end
150
+ end
151
+
130
152
  def changed?(field)
131
153
  return true if new_record? || !doc.send(orderable_field(field)) || move_all[field]
132
154
  changeable_keys(field).any? {|f| doc.send("#{f}_changed?") }
@@ -153,7 +175,7 @@ module Handlers
153
175
  model_name = doc.class.orderable_configs[field][:lock_collection].to_s.singularize.classify
154
176
  model = Mongoid::Orderable::Models.const_get(model_name)
155
177
  attrs = lock_scope(field, generic)
156
- model.where(attrs).find_one_and_update(attrs, { upsert: true })
178
+ model.where(attrs).find_one_and_update(attrs.merge(updated_at: Time.now), { upsert: true })
157
179
  end
158
180
 
159
181
  def lock_scope(field, generic = false)
@@ -35,7 +35,7 @@ module Orderable
35
35
  def add_db_index
36
36
  spec = [[config[:field], 1]]
37
37
  config[:scope].each {|field| spec.unshift([field, 1]) } if config[:scope].is_a?(Array)
38
- klass.index(Hash[spec])
38
+ klass.index(spec.to_h)
39
39
  end
40
40
 
41
41
  def save_config
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Mongoid
4
4
  module Orderable
5
- VERSION = '6.0.2'
5
+ VERSION = '6.0.3'
6
6
  end
7
7
  end
@@ -0,0 +1,36 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe ConditionalOrderable do
4
+
5
+ shared_examples_for 'conditional_orderable' do
6
+
7
+ before :each do
8
+ ConditionalOrderable.create!(cond_a: false, cond_b: nil)
9
+ ConditionalOrderable.create!(cond_a: false, cond_b: 1)
10
+ ConditionalOrderable.create!(cond_a: true, cond_b: 2)
11
+ ConditionalOrderable.create!(cond_a: false, cond_b: 3)
12
+ ConditionalOrderable.create!(cond_a: true, cond_b: 4)
13
+ ConditionalOrderable.create!(cond_a: true, cond_b: 5)
14
+ end
15
+
16
+ it 'should have proper position field' do
17
+ orderables = ConditionalOrderable.all.sort_by {|x| x.cond_b || 0 }
18
+
19
+ expect(orderables.map(&:pos_a)).to eq [nil, nil, 1, nil, 2, 3]
20
+ expect(orderables.map(&:pos_b)).to eq [nil, 1, 2, 3, 4, nil]
21
+ expect(orderables.map(&:pos_c)).to eq [1, 2, 3, 4, 5, 6]
22
+ end
23
+ end
24
+
25
+ context 'with transactions' do
26
+ enable_transactions!
27
+
28
+ it_behaves_like 'conditional_orderable'
29
+ end
30
+
31
+ context 'without transactions' do
32
+ disable_transactions!
33
+
34
+ it_behaves_like 'conditional_orderable'
35
+ end
36
+ end
@@ -13,6 +13,18 @@ class SimpleOrderable
13
13
  orderable
14
14
  end
15
15
 
16
+ class ConditionalOrderable
17
+ include Mongoid::Document
18
+ include Mongoid::Orderable
19
+
20
+ field :cond_a, type: Boolean
21
+ field :cond_b, type: Integer
22
+
23
+ orderable field: :pos_a, if: :cond_a, unless: ->(obj) { obj.cond_b&.<(2) }
24
+ orderable field: :pos_b, if: -> { cond_b&.<=(4) }
25
+ orderable field: :pos_c, unless: false
26
+ end
27
+
16
28
  class ScopedGroup
17
29
  include Mongoid::Document
18
30
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid_orderable
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.2
4
+ version: 6.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - pyromaniac
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-27 00:00:00.000000000 Z
11
+ date: 2021-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -117,6 +117,7 @@ files:
117
117
  - lib/mongoid/orderable/version.rb
118
118
  - lib/mongoid_orderable.rb
119
119
  - spec/integration/concurrency_spec.rb
120
+ - spec/integration/conditional_spec.rb
120
121
  - spec/integration/customized_spec.rb
121
122
  - spec/integration/embedded_spec.rb
122
123
  - spec/integration/foreign_key_spec.rb
@@ -131,7 +132,8 @@ files:
131
132
  - spec/spec_helper.rb
132
133
  - spec/support/models.rb
133
134
  homepage: https://github.com/mongoid/mongoid_orderable
134
- licenses: []
135
+ licenses:
136
+ - MIT
135
137
  metadata: {}
136
138
  post_install_message:
137
139
  rdoc_options: []
@@ -148,12 +150,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
150
  - !ruby/object:Gem::Version
149
151
  version: '0'
150
152
  requirements: []
151
- rubygems_version: 3.1.2
153
+ rubygems_version: 3.2.9
152
154
  signing_key:
153
155
  specification_version: 4
154
156
  summary: Mongoid orderable list implementation
155
157
  test_files:
156
158
  - spec/integration/concurrency_spec.rb
159
+ - spec/integration/conditional_spec.rb
157
160
  - spec/integration/customized_spec.rb
158
161
  - spec/integration/embedded_spec.rb
159
162
  - spec/integration/foreign_key_spec.rb