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.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +83 -22
  3. data/LICENSE.txt +20 -0
  4. data/README.md +256 -149
  5. data/Rakefile +24 -6
  6. data/lib/config/locales/en.yml +12 -9
  7. data/lib/mongoid/orderable.rb +29 -22
  8. data/lib/mongoid/orderable/configs/field_config.rb +79 -0
  9. data/lib/mongoid/orderable/configs/global_config.rb +26 -0
  10. data/lib/mongoid/orderable/errors/invalid_target_position.rb +19 -18
  11. data/lib/mongoid/orderable/errors/transaction_failed.rb +20 -0
  12. data/lib/mongoid/orderable/generators/base.rb +21 -0
  13. data/lib/mongoid/orderable/generators/helpers.rb +29 -0
  14. data/lib/mongoid/orderable/generators/listable.rb +41 -0
  15. data/lib/mongoid/orderable/generators/lock_collection.rb +37 -0
  16. data/lib/mongoid/orderable/generators/movable.rb +62 -0
  17. data/lib/mongoid/orderable/generators/position.rb +26 -0
  18. data/lib/mongoid/orderable/generators/scope.rb +26 -0
  19. data/lib/mongoid/orderable/handlers/base.rb +167 -0
  20. data/lib/mongoid/orderable/handlers/document.rb +24 -0
  21. data/lib/mongoid/orderable/handlers/document_embedded.rb +14 -0
  22. data/lib/mongoid/orderable/handlers/document_transactional.rb +35 -0
  23. data/lib/mongoid/orderable/handlers/transaction.rb +71 -0
  24. data/lib/mongoid/orderable/installer.rb +63 -0
  25. data/lib/mongoid/orderable/mixins/callbacks.rb +43 -0
  26. data/lib/mongoid/orderable/mixins/helpers.rb +39 -0
  27. data/lib/mongoid/orderable/mixins/listable.rb +49 -0
  28. data/lib/mongoid/orderable/mixins/movable.rb +60 -0
  29. data/lib/mongoid/orderable/version.rb +7 -0
  30. data/lib/mongoid_orderable.rb +33 -54
  31. data/spec/integration/concurrency_spec.rb +232 -0
  32. data/spec/integration/customized_spec.rb +31 -0
  33. data/spec/integration/embedded_spec.rb +41 -0
  34. data/spec/integration/foreign_key_spec.rb +33 -0
  35. data/spec/integration/inherited_spec.rb +54 -0
  36. data/spec/integration/multiple_fields_spec.rb +554 -0
  37. data/spec/integration/multiple_scoped_spec.rb +63 -0
  38. data/spec/integration/no_indexed_spec.rb +23 -0
  39. data/spec/integration/scoped_spec.rb +151 -0
  40. data/spec/integration/simple_spec.rb +184 -0
  41. data/spec/integration/string_scoped_spec.rb +28 -0
  42. data/spec/integration/zero_based_spec.rb +161 -0
  43. data/spec/spec_helper.rb +42 -30
  44. data/spec/support/models.rb +122 -0
  45. metadata +75 -41
  46. data/.gitignore +0 -4
  47. data/.rspec +0 -2
  48. data/.rvmrc +0 -1
  49. data/.travis.yml +0 -14
  50. data/Gemfile +0 -18
  51. data/lib/mongoid/orderable/callbacks.rb +0 -75
  52. data/lib/mongoid/orderable/configuration.rb +0 -60
  53. data/lib/mongoid/orderable/errors.rb +0 -2
  54. data/lib/mongoid/orderable/errors/mongoid_orderable_error.rb +0 -14
  55. data/lib/mongoid/orderable/generator.rb +0 -34
  56. data/lib/mongoid/orderable/generator/helpers.rb +0 -29
  57. data/lib/mongoid/orderable/generator/listable.rb +0 -41
  58. data/lib/mongoid/orderable/generator/movable.rb +0 -62
  59. data/lib/mongoid/orderable/generator/position.rb +0 -26
  60. data/lib/mongoid/orderable/generator/scope.rb +0 -17
  61. data/lib/mongoid/orderable/helpers.rb +0 -50
  62. data/lib/mongoid/orderable/listable.rb +0 -49
  63. data/lib/mongoid/orderable/movable.rb +0 -58
  64. data/lib/mongoid/orderable/orderable_class.rb +0 -51
  65. data/lib/mongoid_orderable/mongoid/contexts/enumerable.rb +0 -15
  66. data/lib/mongoid_orderable/mongoid/contexts/mongo.rb +0 -18
  67. data/lib/mongoid_orderable/mongoid/contextual/memory.rb +0 -15
  68. data/lib/mongoid_orderable/mongoid/criteria.rb +0 -4
  69. data/lib/mongoid_orderable/version.rb +0 -3
  70. data/mongoid_orderable.gemspec +0 -26
  71. data/spec/mongoid/orderable_spec.rb +0 -1413
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a966ef4b59309d05845a832163936ce54e339a1e
4
- data.tar.gz: 16b32ccd0fdb0a2ae9a61424d8842de9eba00d4e
2
+ SHA256:
3
+ metadata.gz: b3a80c8eb058adeffe1ead4c0fa20ce10660ea49a2df1405d46048419f2af965
4
+ data.tar.gz: d68f6f64f52f132295e588dfcd59ad27d22a68237e5b29ab7682a37e3c940ca5
5
5
  SHA512:
6
- metadata.gz: ee3e6de12801d857bb9345dc6035c698c56ee119f9b2e78fc15584caf6108351904487b888fa2091636bc750be62e6076b06bf74f38f44b2bd2fa68bc36611ac
7
- data.tar.gz: 5fc8fe3f744fff60b38ac3d0136dcc5c84c069042beda3a7c623c9d6da743e67219e29da920bd983d4a5f506f081cbac9614e14630647dbc58593fa3dfb877d9
6
+ metadata.gz: 6c2d9da294dda836b17047aaf3ebc6329b3c382fb793c83fe57dd63a07512d2e1da65af3559b12e75ce3924b1edfaaefad8317f4acaa488cb94ad2392d84b474
7
+ data.tar.gz: 58e8c15554183674cef20639c2cb888cb6e793471ecf7f55ea76360f2ca7de351d218f417e34db220d2daa32c6ab5dc11da23bce7acec0f77a1f99718e713705
@@ -1,22 +1,83 @@
1
- # master
2
-
3
- # 5.0.0
4
-
5
- * Mongoid 5 support (@dblock)
6
- * Ruby 1.8 support dropped
7
-
8
- # 4.1.1
9
-
10
- * Fix: index should respect scope (@joeyAghion)
11
-
12
- # 4.1.0
13
-
14
- * Resolving scope foreign key form passed relation name (@dsci)
15
- * Fix: relation metadata quering (@pjkelly)
16
- * `previous_items` and `next_items` methods (@mrjlynch)
17
-
18
- # 4.0.0
19
-
20
- * Semantic versioning
21
- * Added Mongoid 4 support (@dblock)
22
- * Fixes by @johnnyshields and @zhengjia
1
+ ### 6.0.3 (Next)
2
+
3
+ * Your contribution here.
4
+
5
+ ### 6.0.2 (2021/01/26)
6
+
7
+ * [#70](https://github.com/mongoid/mongoid_orderable/pull/70): Fix: Transactions should not use around callbacks - [@johnnyshields](https://github.com/johnnyshields).
8
+ * [#70](https://github.com/mongoid/mongoid_orderable/pull/70): Refactor: Partially reduce code complexity of handler classes - [@johnnyshields](https://github.com/johnnyshields).
9
+ * [#70](https://github.com/mongoid/mongoid_orderable/pull/70): Tests: Run all tests both with and without transactions - [@johnnyshields](https://github.com/johnnyshields).
10
+
11
+ ### 6.0.1 (2021/01/26)
12
+
13
+ * [#69](https://github.com/mongoid/mongoid_orderable/pull/69): Fix: Transactions should force read from primary - [@johnnyshields](https://github.com/johnnyshields).
14
+
15
+ ### 6.0.0 (2021/01/23)
16
+
17
+ * [#65](https://github.com/mongoid/mongoid_orderable/pull/65): Feature: Add transaction support with lock table - [@johnnyshields](https://github.com/johnnyshields).
18
+ * [#65](https://github.com/mongoid/mongoid_orderable/pull/65): Feature: Avoid calling position function if neither position nor scope is changing - [@johnnyshields](https://github.com/johnnyshields).
19
+ * [#62](https://github.com/mongoid/mongoid_orderable/pull/62): Feature: Allow scope parameter to be an Array - [@johnnyshields](https://github.com/johnnyshields).
20
+ * [#62](https://github.com/mongoid/mongoid_orderable/pull/62): Feature: Add global configurability - [@johnnyshields](https://github.com/johnnyshields).
21
+ * [#65](https://github.com/mongoid/mongoid_orderable/pull/65): Fix: Do not run embedded destroy callbacks when the root object has been destroyed - [@johnnyshields](https://github.com/johnnyshields).
22
+ * [#62](https://github.com/mongoid/mongoid_orderable/pull/62): Refactor: rename "column" to "field" - [@johnnyshields](https://github.com/johnnyshields).
23
+ * [#60](https://github.com/mongoid/mongoid_orderable/pull/60): Refactor: Drop support for Mongoid 6.x and lower - [@johnnyshields](https://github.com/johnnyshields).
24
+ * [#60](https://github.com/mongoid/mongoid_orderable/pull/60): Refactor: Remove Mongoid Compatibility (no longer needed) - [@johnnyshields](https://github.com/johnnyshields).
25
+
26
+ ### 5.2.0 (2018/05/01)
27
+
28
+ * [#57](https://github.com/mongoid/mongoid_orderable/pull/57): Compatibility with Mongoid 7 - [@tomasc](https://github.com/tomasc).
29
+ * [#52](https://github.com/mongoid/mongoid_orderable/pull/52): Test against Mongoid 6 - [@dblock](https://github.com/dblock).
30
+
31
+ ### 5.1.0 (2017/06/04)
32
+
33
+ * [#50](https://github.com/mongoid/mongoid_orderable/pull/50): Added Danger, PR linter - [@dblock](https://github.com/dblock).
34
+ * [#51](https://github.com/mongoid/mongoid_orderable/pull/51): Added RuboCop - [@dblock](https://github.com/dblock).
35
+ * [#49](https://github.com/mongoid/mongoid_orderable/pull/49): Fix orderable on embedded documents inside an inherited model - [@rafaelgaspar](https://github.com/rafaelgaspar).
36
+
37
+ ### 5.0.0 (2015/10/21)
38
+
39
+ * [#41](https://github.com/mongoid/mongoid_orderable/pull/41): Mongoid 5 support - [@dblock](https://github.com/dblock).
40
+ * [#41](https://github.com/mongoid/mongoid_orderable/pull/41): Dropped support for ruby 1.8 - [@dblock](https://github.com/dblock).
41
+
42
+ ### 4.1.1 (2014/12/19)
43
+
44
+ * [#34](https://github.com/mongoid/mongoid_orderable/pull/34): Fix: index should respect scope - [@joeyAghion](https://github.com/joeyAghion).
45
+
46
+ ### 4.1.0 (2014/3/19)
47
+
48
+ * [#30](https://github.com/mongoid/mongoid_orderable/pull/30): Fix: reset a single field when `orderable_scope` changed instead of removing it from list - [@Bharat311](https://github.com/Bharat311).
49
+ * [#29](https://github.com/mongoid/mongoid_orderable/pull/29): Fix: incorrect position when orderable base is set - [@Bharat311](https://github.com/Bharat311).
50
+ * [#28](https://github.com/mongoid/mongoid_orderable/pull/28): Inherited `orderable_configurations` - [@johnny-miyake](https://github.com/johnny-miyake).
51
+ * [#27](https://github.com/mongoid/mongoid_orderable/pull/27): Allowed numeric string to specify a target position - [@johnny-miyake](https://github.com/johnny-miyake).
52
+ * [#26](https://github.com/mongoid/mongoid_orderable/pull/26): Added support for multiple orderable fields - [@Bharat311](https://github.com/Bharat311).
53
+ * [#22](https://github.com/mongoid/mongoid_orderable/pull/22): Added lazy support for scopes with different foreign key names - [@dsci](https://github.com/dsci).
54
+ * [#21](https://github.com/mongoid/mongoid_orderable/pull/21): Accounting for change in Mongoid's metadata API - [@pjkelly](https://github.com/pjkelly).
55
+ * [#20](https://github.com/mongoid/mongoid_orderable/pull/20): Added next and previous item methods - [@mrjlynch](https://github.com/mrjlynch).
56
+ * [#19](https://github.com/mongoid/mongoid_orderable/pull/19): Added lower and higher item methods - [@mrjlynch](https://github.com/mrjlynch).
57
+
58
+ ### 4.0.0 (2013/10/22)
59
+
60
+ * [#18](https://github.com/mongoid/mongoid_orderable/pull/18): Added Mongoid 4 support - [@dblock](https://github.com/dblock).
61
+ * [#16](https://github.com/mongoid/mongoid_orderable/pull/16): Fix for Mongoid identity map combined with scoped orderable - [@johnnyshields](https://github.com/johnnyshields).
62
+ * [#15](https://github.com/mongoid/mongoid_orderable/pull/15): Support pass-thru of Mongoid field alias (`:as` parameter) - [@johnnyshields](https://github.com/johnnyshields).
63
+ * [#13](https://github.com/mongoid/mongoid_orderable/pull/13): Support inheritance - [@zhengjia](https://github.com/zhengjia).
64
+
65
+ ### 1.2.0 (2013/1/10)
66
+
67
+ * [#12](https://github.com/mongoid/mongoid_orderable/pull/12): Added support for "base" in config options, in order to do a zero-based position - [@johnnyshields](https://github.com/johnnyshields).
68
+
69
+ ### 1.1.0 (2012/5/23)
70
+
71
+ * Added Mongoid 3 support - [@pyromaniac](https://github.com/pyromaniac).
72
+
73
+ ### 1.0.0 (2012/2/14)
74
+
75
+ * [#5](https://github.com/mongoid/mongoid_orderable/pull/5): Allow for use with default scopes - [@mattiassvedhem](https://github.com/mattiassvedhem).
76
+
77
+ ### 0.9.1 (2012/2/3)
78
+
79
+ ### 0.9.0 (2011/11/23)
80
+
81
+ ### 0.0.1 (2011/11/1)
82
+
83
+ * Initial public release - [@pyromaniac](https://github.com/pyromaniac).
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011-2017 Arkadiy Zabazhanov & Contributors
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,149 +1,256 @@
1
- [![Gem Version](https://badge.fury.io/rb/mongoid_orderable.svg)](https://badge.fury.io/rb/mongoid_orderable)
2
- [![Build Status](https://travis-ci.org/pyromaniac/mongoid_orderable.svg?branch=master)](https://travis-ci.org/pyromaniac/mongoid_orderable)
3
-
4
- # What?
5
-
6
- Mongoid::Orderable is a ordered list implementation for your Mongoid 2, 3, 4 and 5 models.
7
-
8
- # Why?
9
-
10
- * It uses native mongo batch increment feature
11
- * It supports mutators api
12
- * It correctly assigns the position while moving document between scopes
13
- * It supports mongoid 2, 3 and 4
14
- * It supports specifying multiple orderable columns
15
-
16
- # How?
17
-
18
- ```ruby
19
- gem 'mongoid_orderable'
20
- ```
21
-
22
- Gem has the same api as others. Just include Mongoid::Orderable into your model and call `orderable` method.
23
- Embedded objects are automatically scoped by their parent.
24
-
25
- ```ruby
26
- class Item
27
- include Mongoid::Document
28
- include Mongoid::Orderable
29
-
30
- # belongs_to :group
31
- # belongs_to :drawer, class_name: "Office::Drawer",
32
- # foreign_key: "legacy_drawer_key_id"
33
-
34
- # orderable
35
- # orderable scope: :group, column: :pos
36
- # orderable scope: :drawer, column: :pos # resolves scope foreign key from relation
37
- # orderable scope: 'drawer', column: :pos # but if you pass a string - it will use it as is, as the column name for scope
38
- # orderable scope: lambda { |document| where(group_id: document.group_id) }
39
- # orderable index: false # this one if you want specify indexes manually
40
- # orderable base: 0 # count position from zero as the top-most value (1 is the default value)
41
- end
42
- ```
43
-
44
- # Usage
45
-
46
- ```ruby
47
- item.move_to 2 # just change position
48
- item.move_to! 2 # and save
49
- item.move_to = 2 # assignable method
50
-
51
- # symbol position
52
- item.move_to :top
53
- item.move_to :bottom
54
- item.move_to :higher
55
- item.move_to :lower
56
-
57
- # generated methods
58
- item.move_to_top
59
- item.move_to_bottom
60
- item.move_higher
61
- item.move_lower
62
-
63
- item.next_items # return a collection of items higher on the list
64
- item.previous_items # return a collection of items lower on the list
65
-
66
- item.next_item # returns the next item in the list
67
- item.previous_item # returns the previous item in the list
68
- ```
69
-
70
- # Multiple Columns
71
-
72
- You can also define multiple orderable columns for any class including the Mongoid::Orderable module.
73
-
74
- ```ruby
75
- class Book
76
- include Mongoid::Document
77
- include Mongoid::Orderable
78
-
79
- orderable base: 0
80
- orderable column: sno, as: :serial_no
81
- end
82
- ```
83
-
84
- The above defines two different orderable_columns on Book - *position* and *serial_no*.
85
- The following helpers are generated in this case:
86
-
87
- ```ruby
88
- item.move_#{column_name}_to
89
- item.move_#{column_name}_to=
90
- item.move_#{column_name}_to!
91
-
92
- item.move_#{column_name}_to_top
93
- item.move_#{column_name}_to_bottom
94
- item.move_#{column_name}_higher
95
- item.move_#{column_name}_lower
96
-
97
- item.next_#{column_name}_items
98
- item.previous_#{column_name}_items
99
-
100
- item.next_#{column_name}_item
101
- item.previous_#{column_name}_item
102
- ```
103
-
104
- *where column_name is either **position** or **serial_no**.*
105
-
106
- When a model defines multiple orderable columns, the original helpers are also available and work on the first orderable column.
107
-
108
- ```ruby
109
- @book1 = Book.create!
110
- @book2 = Book.create!
111
- @book2 => #<Book _id: 53a16a2ba1bde4f746000001, serial_no: 1, position: 1>
112
- @book2.move_to! :top # this will change the :position of the book to 0 (not serial_no)
113
- @book2 => #<Book _id: 53a16a2ba1bde4f746000001, serial_no: 1, position: 0>
114
- ```
115
-
116
- To specify any other orderable column as default pass the **default: true** option with orderable.
117
-
118
- ```ruby
119
- orderable column: sno, as: :serial_no, default: true
120
- ```
121
-
122
- # Embedded documents
123
- ```ruby
124
- class Question
125
- include Mongoid::Document
126
- include Mongoid::Orderable
127
-
128
- embedded_in :survey
129
-
130
- orderable
131
- end
132
- ```
133
- If you bulk import embedded documents without specifying their position, no field `position` will be written.
134
- ```ruby
135
- class Survey
136
- include Mongoid::Document
137
-
138
- embeds_many :questions, cascade_callbacks: true
139
- end
140
- ```
141
- To ensure the position is written correctly, you will need to provide the cascade callbacks option to the relation.
142
-
143
- # Contributing
144
-
145
- Fork && Patch && Spec && Push && Pull request.
146
-
147
- # License
148
-
149
- Mongoid::Orderable is released under the MIT license.
1
+ [![Gem Version](https://badge.fury.io/rb/mongoid_orderable.svg)](https://badge.fury.io/rb/mongoid_orderable)
2
+ [![Build Status](https://travis-ci.org/mongoid/mongoid_orderable.svg?branch=master)](https://travis-ci.org/mongoid/mongoid_orderable)
3
+
4
+ # Mongoid Orderable
5
+
6
+ Mongoid::Orderable is a ordered list implementation for your Mongoid 7+ projects.
7
+
8
+ ### Core Features
9
+
10
+ * Sets a position index field on your documents which allows you to sort them in order.
11
+ * Uses MongoDB's `$inc` operator to batch-update position.
12
+ * Supports scope for position index, including changing scopes.
13
+ * Supports multiple position indexes on the same document.
14
+ * (Optional) Uses [MongoDB transactions](https://docs.mongodb.com/manual/core/transactions/) to ensure order integrity during concurrent updates.
15
+
16
+ ### Version Support
17
+
18
+ As of version 6.0.0, Mongoid::Orderable supports the following dependency versions:
19
+
20
+ * Ruby 2.6+
21
+ * Mongoid 7.0+
22
+ * Rails 5.2+
23
+
24
+ For older versions, please use Mongoid::Orderable 5.x and earlier.
25
+
26
+ Transaction support requires MongoDB 4.2+ (4.4+ recommended.)
27
+
28
+ ## Usage
29
+
30
+ ### Getting Started
31
+
32
+ ```ruby
33
+ gem 'mongoid_orderable'
34
+ ```
35
+
36
+ Include `Mongoid::Orderable` into your model and call `orderable` method.
37
+ Embedded objects are automatically scoped to their parent.
38
+
39
+ ```ruby
40
+ class MyModel
41
+ include Mongoid::Document
42
+ include Mongoid::Orderable
43
+
44
+ belongs_to :group
45
+ belongs_to :drawer, class_name: "Office::Drawer",
46
+ foreign_key: "legacy_drawer_key_id"
47
+
48
+ orderable
49
+
50
+ # if you set :scope as a symbol, it will resolve the foreign key from relation
51
+ orderable scope: :drawer, field: :pos
52
+
53
+ # if you set :scope as a string, it will use it as the field name for scope
54
+ orderable scope: 'drawer', field: :pos
55
+
56
+ # scope can also be a proc
57
+ orderable scope: ->(doc) { where(group_id: doc.group_id) }
58
+
59
+ # this one if you want specify indexes manually
60
+ orderable index: false
61
+
62
+ # count position from zero as the top-most value (1 is the default value)
63
+ orderable base: 0
64
+ end
65
+ ```
66
+
67
+ You can also set default config values in an initializer, which will be
68
+ applied when calling the `orderable` macro in a model.
69
+
70
+ ```ruby
71
+ # configs/initializers/mongoid_orderable.rb
72
+ Mongoid::Orderable.configure do |config|
73
+ config.field = :pos
74
+ config.base = 0
75
+ config.index = false
76
+ end
77
+ ```
78
+
79
+ ### Moving Position
80
+
81
+ ```ruby
82
+ item.move_to 2 # just change position
83
+ item.move_to! 2 # and save
84
+ item.move_to = 2 # assignable method
85
+
86
+ # symbol position
87
+ item.move_to :top
88
+ item.move_to :bottom
89
+ item.move_to :higher
90
+ item.move_to :lower
91
+
92
+ # generated methods
93
+ item.move_to_top
94
+ item.move_to_bottom
95
+ item.move_higher
96
+ item.move_lower
97
+
98
+ item.next_items # return a collection of items higher on the list
99
+ item.previous_items # return a collection of items lower on the list
100
+
101
+ item.next_item # returns the next item in the list
102
+ item.previous_item # returns the previous item in the list
103
+ ```
104
+
105
+ ### Multiple Fields
106
+
107
+ You can also define multiple orderable fields for any class including the Mongoid::Orderable module.
108
+
109
+ ```ruby
110
+ class Book
111
+ include Mongoid::Document
112
+ include Mongoid::Orderable
113
+
114
+ orderable base: 0
115
+ orderable field: sno, as: :serial_no
116
+ end
117
+ ```
118
+
119
+ The above defines two different orderable_fields on Book - *position* and *serial_no*.
120
+ The following helpers are generated in this case:
121
+
122
+ ```ruby
123
+ book.move_#{field}_to
124
+ book.move_#{field}_to=
125
+ book.move_#{field}_to!
126
+
127
+ book.move_#{field}_to_top
128
+ book.move_#{field}_to_bottom
129
+ book.move_#{field}_higher
130
+ book.move_#{field}_lower
131
+
132
+ book.next_#{field}_items
133
+ book.previous_#{field}_items
134
+
135
+ book.next_#{field}_item
136
+ book.previous_#{field}_item
137
+ ```
138
+
139
+ where `#{field}` is either `position` or `serial_no`.
140
+
141
+ When a model defines multiple orderable fields, the original helpers are also available and work on the first orderable field.
142
+
143
+ ```ruby
144
+ @book1 = Book.create!
145
+ @book2 = Book.create!
146
+ @book2 # => <Book _id: 53a16a2ba1bde4f746000001, serial_no: 1, position: 1>
147
+ @book2.move_to! :top # this will change the :position of the book to 0 (not serial_no)
148
+ @book2 # => <Book _id: 53a16a2ba1bde4f746000001, serial_no: 1, position: 0>
149
+ ```
150
+
151
+ To specify any other orderable field as default pass the **default: true** option with orderable.
152
+
153
+ ```ruby
154
+ orderable field: sno, as: :serial_no, default: true
155
+ ```
156
+
157
+ ### Embedded Documents
158
+
159
+ ```ruby
160
+ class Question
161
+ include Mongoid::Document
162
+ include Mongoid::Orderable
163
+
164
+ embedded_in :survey
165
+
166
+ orderable
167
+ end
168
+ ```
169
+
170
+ If you bulk import embedded documents without specifying their position,
171
+ no field `position` will be written.
172
+
173
+ ```ruby
174
+ class Survey
175
+ include Mongoid::Document
176
+
177
+ embeds_many :questions, cascade_callbacks: true
178
+ end
179
+ ```
180
+
181
+ To ensure the position is written correctly, you will need to set
182
+ `cascade_callbacks: true` on the relation.
183
+
184
+ ## Transaction Support
185
+
186
+ By default, Mongoid Orderable does not guarantee ordering consistency
187
+ when doing multiple concurrent updates on documents. This means that
188
+ instead of having positions `1, 2, 3, 4, 5`, after running your system
189
+ in production at scale your position data will become corrupted, e.g.
190
+ `1, 1, 4, 4, 6`. To remedy this, this Mongoid Orderable can use
191
+ [MongoDB transactions](https://docs.mongodb.com/manual/core/transactions/)
192
+
193
+ ### Prerequisites
194
+
195
+ * MongoDB version 4.2+ (4.4+ recommended.)
196
+ * Requires [MongoDB Replica Set](https://docs.mongodb.com/manual/tutorial/deploy-replica-set/) topology
197
+
198
+ ### Configuration
199
+
200
+ You may enable transactions on both the global and model configs:
201
+
202
+ ```ruby
203
+ Mongoid::Orderable.configure do |config|
204
+ config.use_transactions = true # default: false
205
+ config.transaction_max_retries = 10 # default: 10
206
+ end
207
+
208
+ class MyModel
209
+ orderable :position, use_transactions: false
210
+ end
211
+ ```
212
+
213
+ When two transactions are attempted at the same time, database-level
214
+ `WriteConflict` failures may result and retries will be attempted.
215
+ After `transaction_max_retries` has been exceeded, a
216
+ `Mongoid::Orderable::Errors::TransactionFailed` error will be raised.
217
+
218
+ ### Locks
219
+
220
+ When using transactions, Mongoid Orderable creates a collection
221
+ `mongoid_orderable_locks` which is used to store temporary lock objects.
222
+ This collection accumulate documents overtime; it is safe to delete it periodically.
223
+
224
+ You can change the lock collection name globally or per model:
225
+
226
+ ```ruby
227
+ Mongoid::Orderable.configure do |config|
228
+ config.lock_collection = "my_locks" # default: "mongoid_orderable_locks"
229
+ end
230
+
231
+ class MyModel
232
+ orderable :position, lock_collection: "my_model_locks"
233
+ end
234
+ ```
235
+
236
+ ### MongoDB 4.2 Support
237
+
238
+ In MongoDB 4.2, collections cannot be created within transactions.
239
+ Therefore, you will need to manually run the following command once
240
+ to initialize the lock collection:
241
+
242
+ ```ruby
243
+ Mongoid::Orderable::Models::Lock.create!
244
+ ```
245
+
246
+ This step is not necessary when using MongoDB 4.4+.
247
+
248
+ ### Contributing
249
+
250
+ Please fork the project on Github and raise a pull request including passing specs.
251
+
252
+ ### Copyright & License
253
+
254
+ Copyright (c) 2011 Arkadiy Zabazhanov, Johnny Shields, and contributors.
255
+
256
+ MIT license, see [LICENSE](LICENSE.txt) for details.