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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +52 -0
- data/lib/mongoid/sleeping_king_studios/orderable.rb +172 -0
- data/lib/mongoid/sleeping_king_studios/orderable/metadata.rb +111 -0
- data/lib/mongoid/sleeping_king_studios/version.rb +1 -1
- metadata +17 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 218763356e4b6bc56393162ae45be295d7ccc478
|
4
|
+
data.tar.gz: 3fa4cfd1063e65e22322c5be1b183a6f04f10fc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c2f385e2cc2184c33009e5907a15b8b052780dfbe90345dfa3bc9679a637e955df9acac88f2d429a207d53ba738d491db5d8ab491b2e4fa170b95f885803367
|
7
|
+
data.tar.gz: 7b579653a20b03b32db94736019d9c0caec715884948b9eff640397cae9d518c3f364d47c25e09a4bb2795151531f7f35316940aca01ee01629b1a4dd3c669d0
|
data/CHANGELOG.md
CHANGED
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
|
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.
|
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
|