mongoid-sleeping_king_studios 0.6.2 → 0.7.0

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
  SHA1:
3
- metadata.gz: fdd1c69e257d2151ecdb439fc1f9ab974628c9ba
4
- data.tar.gz: cf273c392e0fde12e79b244819c1c880de8e11dd
3
+ metadata.gz: 218763356e4b6bc56393162ae45be295d7ccc478
4
+ data.tar.gz: 3fa4cfd1063e65e22322c5be1b183a6f04f10fc7
5
5
  SHA512:
6
- metadata.gz: 0e20060ad75456272818d391425dad43a7deca8babe64f104a586a946221db0aa0e57d227bb16acee3ac7a3921d272a12d8da2bde3a4d2794b85a6f8233965b8
7
- data.tar.gz: 6ab47ee0aed555756fd7ab7dadabe617985abe5c32d61efc1e4374546427abc0afebcb60185c84dfe50b87e083f8ca8ec10038120cc8480cca4adfdf7a54c8bf
6
+ metadata.gz: 1c2f385e2cc2184c33009e5907a15b8b052780dfbe90345dfa3bc9679a637e955df9acac88f2d429a207d53ba738d491db5d8ab491b2e4fa170b95f885803367
7
+ data.tar.gz: 7b579653a20b03b32db94736019d9c0caec715884948b9eff640397cae9d518c3f364d47c25e09a4bb2795151531f7f35316940aca01ee01629b1a4dd3c669d0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0
4
+
5
+ * Add Orderable concern.
6
+
3
7
  ## 0.6.2
4
8
 
5
9
  * Update dependencies (no user-facing changes).
data/README.md CHANGED
@@ -77,6 +77,58 @@ slower and more resource-intensive. Do not use this option outside of
77
77
  read-heavy applications with very specific requirements, e.g. a directory
78
78
  structure where you must access all parent directories on each page view.
79
79
 
80
+ ### Orderable
81
+
82
+ require 'mongoid/sleeping_king_studios/orderable'
83
+
84
+ Adds a field that tracks the index of each record with respect to the provided
85
+ sort order parameters.
86
+
87
+ **How To Use:**
88
+
89
+ class OrderedDocument
90
+ include Mongoid::Document
91
+ include Mongoid::SleepingKingStudios::Orderable
92
+
93
+ cache_ordering :created_at.desc, :as => :most_recent_order
94
+ end # class
95
+
96
+ The ::cache_ordering method accepts a subset of the params for an Origin
97
+ \#order_by query operation, e.g.:
98
+
99
+ - :first_field.desc, :second_field
100
+ - { :first_field => -1, :second_field => :asc }
101
+ - [[:first_field, :desc], [:second_field, 1]]
102
+
103
+ #### Helpers
104
+
105
+ Creating an ordering cache also creates the following helpers:
106
+
107
+ ##### ::reorder_ordering_name!
108
+
109
+ Loops through the collection and sets each item's field to the appropriate
110
+ ordered index. Normally, this is handled on item save, but this helper allows
111
+ a bulk update of the collection when adding the concern to an existing model,
112
+ or if data corruption or other issues have broken the existing values.
113
+
114
+ #### Options
115
+
116
+ ##### As
117
+
118
+ cache_ordering sort_params, :as => :named_order
119
+
120
+ Sets the name of the generated order field and helpers. If no name is
121
+ specified, one will be automatically generated of the form
122
+ first_field_desc_second_field_asc_order.
123
+
124
+ ##### Filter
125
+
126
+ cache_ordering sort_params, :filter => { :published => true }
127
+
128
+ Restricts which records from the collection will be sorted to generate the
129
+ ordering values. If a record is filtered out, its ordering field will be set
130
+ to nil.
131
+
80
132
  ### Sluggable
81
133
 
82
134
  require 'mongoid/sleeping_king_studios/sluggable'
@@ -0,0 +1,172 @@
1
+ # lib/mongoid/sleeping_king_studios/orderable.rb
2
+
3
+ require 'mongoid/sleeping_king_studios/orderable/metadata'
4
+
5
+ module Mongoid::SleepingKingStudios
6
+ # Adds an order field that stores the index of the record relative to the
7
+ # specified sort query. Storing the order in this fashion allows, for
8
+ # example, finding the next or previous records in the set without needing to
9
+ # perform the full sort query each time.
10
+ #
11
+ # @example Order by Most Recently Created:
12
+ # class SortedDocument
13
+ # include Mongoid::Document
14
+ # include Mongoid::SleepingKingStudios::Ordering
15
+ #
16
+ # cache_ordering :created_at.desc, :as => :most_recent_order
17
+ # end # class
18
+ #
19
+ # @see ClassMethods#cache_ordering
20
+ #
21
+ # @since 0.7.0
22
+ module Orderable
23
+ extend ActiveSupport::Concern
24
+ extend Mongoid::SleepingKingStudios::Concern
25
+
26
+ # @api private
27
+ #
28
+ # Sets up the orderable relation, creating fields, callbacks and helper
29
+ # methods.
30
+ #
31
+ # @param [Class] base The base class into which the concern is mixed in.
32
+ # @param [Symbol, Array, Hash] sort_params The params used to sort the
33
+ # collection, generating the cached order index.
34
+ # @param [Hash] options The options for the relation.
35
+ def self.apply base, sort_params, options
36
+ name = :orderable
37
+ validate_options name, options
38
+ options.update :sort_params => sort_params
39
+ meta = characterize name, options, Metadata
40
+
41
+ relate base, name, meta
42
+
43
+ define_fields base, meta
44
+ define_callbacks base, meta
45
+ define_helpers base, meta
46
+ end # module method apply
47
+
48
+ # @api private
49
+ #
50
+ # Creates an order field of type Integer on the base class, and sets the
51
+ # writer to private.
52
+ #
53
+ # @param [Class] base The base class into which the concern is mixed in.
54
+ # @param [Metadata] metadata The metadata for the relation.
55
+ def self.define_fields base, metadata
56
+ base.send :field, metadata.field_name, :type => Integer
57
+
58
+ base.send :private, metadata.field_writer
59
+ end # module method define_fields
60
+
61
+ # @api private
62
+ #
63
+ # Adds an after_save callback to update the index of the record and all
64
+ # subsequent records in the ordering.
65
+ #
66
+ # @param [Class] base The base class into which the concern is mixed in.
67
+ # @param [Metadata] metadata The metadata for the relation.
68
+ def self.define_callbacks base, metadata
69
+ base.after_save do
70
+ criteria = metadata.sort_criteria(base)
71
+ ordering = criteria.to_a
72
+ order_index = ordering.index(self)
73
+
74
+ if order_index.nil?
75
+ if send(metadata.field_was).nil?
76
+ # Both the old and new values are nil, so mission accomplished.
77
+ return
78
+ else
79
+ # The old value wasn't nil, so remember it and set the new value,
80
+ # then start looping through the ordered collection at the old
81
+ # value.
82
+ order_index = send(metadata.field_was)
83
+
84
+ # Update the current instance.
85
+ self[metadata.field_name] = nil
86
+
87
+ # Set the value in the datastore.
88
+ set(metadata.field_name => order_index)
89
+ end # unless
90
+ else
91
+ # Update the current instance.
92
+ self[metadata.field_name] = order_index
93
+ end # if
94
+
95
+ ordering[order_index..-1].each_with_index do |object, i|
96
+ object.set(metadata.field_name => (order_index + i))
97
+ end # each
98
+ end # callback
99
+ end # module method define_callbacks
100
+
101
+ # @api private
102
+ #
103
+ # Adds a class-level reorder! helper that loops through the entire
104
+ # collection and updates the ordering of each item.
105
+ #
106
+ # @param [Class] base The base class into which the concern is mixed in.
107
+ # @param [Metadata] metadata The metadata for the relation.
108
+ def self.define_helpers base, metadata
109
+ name = :"reorder_#{metadata.field_name.to_s.gsub(/_order\z/,'')}!"
110
+ meta = class << base; self; end
111
+ meta.send :define_method, name do
112
+ base.update_all(metadata.field_name => nil)
113
+
114
+ criteria = metadata.sort_criteria(base)
115
+ ordering = criteria.to_a
116
+
117
+ ordering.each_with_index do |record, index|
118
+ record.set(metadata.field_name => index)
119
+ end # each
120
+ end # method
121
+ end # module method define_helpers
122
+
123
+ # Returns a list of options that are valid for this concern.
124
+ #
125
+ # @return [Array<Symbol>] The list of valid options.
126
+ def self.valid_options
127
+ super + %i(
128
+ as
129
+ filter
130
+ ) # end array
131
+ end # module method valid options
132
+
133
+ # Class methods added to the base class via #extend.
134
+ module ClassMethods
135
+ # @overload cache_ordering sort_params, options = {}
136
+ # Creates the order field and sets up the callbacks and helpers.
137
+ #
138
+ # @param [Array] sort_params The sort query used to order the
139
+ # collection. Accepts a subset of the options for a default
140
+ # Origin sort operation:
141
+ # - :field_name.desc, :another_field
142
+ # - { :field_name => -1, :another_field => 1 }
143
+ # - \[[:field_name, -1], [:another_field, :asc]]
144
+ # @param [Hash] options The options for the relation.
145
+ # @option options [Symbol] :as
146
+ # Sets the name of the generated field and helpers. By default,
147
+ # uses the name(s) and direction(s) of the fields from the sort
148
+ # query, e.g. :field_name_asc_another_field_desc_order.
149
+ # @option options [Hash] :filter
150
+ # Sets a filter that excludes collection items from the ordering
151
+ # process. Accepts the same parameters as a Mongoid #where query.
152
+ #
153
+ # @raise [Mongoid::Errors::InvalidOptions] If any of the provided
154
+ # options are invalid.
155
+ def cache_ordering *sort_params, **options
156
+ concern = Mongoid::SleepingKingStudios::Orderable
157
+ concern.apply self, sort_params, options
158
+ end # class method slugify
159
+
160
+ # @!method reorder_ordering_name!
161
+ # Iterates through the entire collection and sets the cached order of
162
+ # each item to its current order index. Filtered items have their order
163
+ # set to nil. Normally, this should be taken care of when the items are
164
+ # saved, but this method allows the process to be reset in case of data
165
+ # corruption or other issues.
166
+ #
167
+ # The generated name of this method will depend on the sort params or
168
+ # the :as option provided. For example, :as => :alphabetical_order will
169
+ # result in a class method ::reorder_alphabetical!
170
+ end # module
171
+ end # module
172
+ end # module
@@ -0,0 +1,111 @@
1
+ # lib/mongoid/sleeping_king_studios/orderable/metadata.rb
2
+
3
+ require 'mongoid/sleeping_king_studios/concern/metadata'
4
+
5
+ module Mongoid::SleepingKingStudios
6
+ module Orderable
7
+ # Stores information about an Orderable concern.
8
+ class Metadata < Mongoid::SleepingKingStudios::Concern::Metadata
9
+ # @param [Symbol, String] name The name of the concern or relation.
10
+ # @param [Hash] properties The properties of the concern or relation.
11
+ def initialize name, properties = {}
12
+ super
13
+
14
+ self[:sort_params] = case properties[:sort_params]
15
+ when Array
16
+ properties[:sort_params].reduce({}) do |hsh, param|
17
+ hsh.merge parse_sort_param(param)
18
+ end # each
19
+ when Hash
20
+ properties[:sort_params].each.with_object({}) do |(key, value), hsh|
21
+ hsh[key] = parse_sort_direction(value)
22
+ end # each
23
+ when Symbol, Origin::Key
24
+ parse_sort_param(properties[:sort_params])
25
+ end # case
26
+ end # method initialize
27
+
28
+ # The name of the field used to store the order.
29
+ #
30
+ # @return [Symbol] The field name.
31
+ def field_name
32
+ fetch(:as, default_field_name).intern
33
+ end # method field_name
34
+
35
+ # @return [Boolean] True if a custom field name is defined; otherwise
36
+ # false.
37
+ def field_name?
38
+ !!self[:as]
39
+ end # method field_name
40
+
41
+ # The name of the dirty tracking method for the order field.
42
+ #
43
+ # @return [Symbol] The method name.
44
+ def field_was
45
+ :"#{field_name}_was"
46
+ end # method field_was
47
+
48
+ # The name of the writer for the order field.
49
+ #
50
+ # @return [Symbol] The method name.
51
+ def field_writer
52
+ :"#{field_name}="
53
+ end # method field_writer
54
+
55
+ # The criteria to filter only the desired collection items to sort.
56
+ #
57
+ # @param [Mongoid::Criteria] criteria The base criteria to modify using
58
+ # the filter params.
59
+ #
60
+ # @return [Mongoid::Criteria]
61
+ def filter_criteria criteria
62
+ filter_params? ? criteria.where(filter_params) : criteria
63
+ end # method filter_criteria
64
+
65
+ # The options (if any) to filter the collection by prior to sorting.
66
+ #
67
+ # @return [Hash]
68
+ def filter_params
69
+ self[:filter]
70
+ end # method filter_params
71
+
72
+ # @return [Boolean] True if filter params are defined; otherwise false.
73
+ def filter_params?
74
+ !!self[:filter]
75
+ end # method filter_params?
76
+
77
+ # The criteria to be used when sorting the collection.
78
+ #
79
+ # @param [Mongoid::Criteria] criteria The base criteria to modify using
80
+ # the sort params.
81
+ #
82
+ # @return [Mongoid::Criteria]
83
+ def sort_criteria criteria
84
+ filter_criteria(criteria).order_by(self[:sort_params])
85
+ end # method sort_criteria
86
+
87
+ private
88
+
89
+ def default_field_name
90
+ self[:sort_params].map { |key, value|
91
+ "#{key}_#{value == 1 ? 'asc' : 'desc'}"
92
+ }.join('_') + '_order'
93
+ end # method default_field_name
94
+
95
+ def parse_sort_param param
96
+ case param
97
+ when Array
98
+ { param[0] => parse_sort_direction(param[1]) }
99
+ when Origin::Key
100
+ { param.name => param.operator }
101
+ when Symbol
102
+ { param => 1 }
103
+ end # case
104
+ end # method sort_param=
105
+
106
+ def parse_sort_direction direction
107
+ (direction == -1 || direction.to_s.downcase == 'desc') ? -1 : 1
108
+ end # method parse_sort_direction
109
+ end # class
110
+ end # module
111
+ end # module
@@ -3,6 +3,6 @@
3
3
  module Mongoid
4
4
  module SleepingKingStudios
5
5
  # The current version of the gem.
6
- VERSION = '0.6.2'
6
+ VERSION = '0.7.0'
7
7
  end # module
8
8
  end # module
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-sleeping_king_studios
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob "Merlin" Smith
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ~>
123
123
  - !ruby/object:Gem::Version
124
124
  version: '1.2'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: '0.9'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: '0.9'
125
139
  description: |2
126
140
  A collection of concerns and extensions to add functionality to Mongoid
127
141
  documents and collections. The features can be included individually or by
@@ -143,6 +157,8 @@ files:
143
157
  - lib/mongoid/sleeping_king_studios/has_tree/metadata.rb
144
158
  - lib/mongoid/sleeping_king_studios/has_tree/parent/metadata.rb
145
159
  - lib/mongoid/sleeping_king_studios/has_tree.rb
160
+ - lib/mongoid/sleeping_king_studios/orderable/metadata.rb
161
+ - lib/mongoid/sleeping_king_studios/orderable.rb
146
162
  - lib/mongoid/sleeping_king_studios/sluggable/metadata.rb
147
163
  - lib/mongoid/sleeping_king_studios/sluggable.rb
148
164
  - lib/mongoid/sleeping_king_studios/version.rb