plucky 0.5.2 → 0.6.0
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.
- data/.bundle/config +4 -0
- data/.gitignore +3 -1
- data/.travis.yml +2 -2
- data/Gemfile +13 -3
- data/Guardfile +13 -0
- data/README.md +1 -1
- data/Rakefile +3 -17
- data/examples/query.rb +1 -1
- data/lib/plucky.rb +13 -0
- data/lib/plucky/criteria_hash.rb +85 -56
- data/lib/plucky/normalizers/criteria_hash_key.rb +17 -0
- data/lib/plucky/normalizers/criteria_hash_value.rb +83 -0
- data/lib/plucky/normalizers/fields_value.rb +26 -0
- data/lib/plucky/normalizers/integer.rb +19 -0
- data/lib/plucky/normalizers/options_hash_key.rb +23 -0
- data/lib/plucky/normalizers/options_hash_value.rb +85 -0
- data/lib/plucky/normalizers/sort_value.rb +55 -0
- data/lib/plucky/options_hash.rb +56 -85
- data/lib/plucky/pagination/decorator.rb +3 -2
- data/lib/plucky/pagination/paginator.rb +15 -6
- data/lib/plucky/query.rb +93 -51
- data/lib/plucky/version.rb +1 -1
- data/script/criteria_hash.rb +21 -0
- data/{test → spec}/helper.rb +12 -8
- data/spec/plucky/criteria_hash_spec.rb +166 -0
- data/spec/plucky/normalizers/criteria_hash_key_spec.rb +37 -0
- data/spec/plucky/normalizers/criteria_hash_value_spec.rb +193 -0
- data/spec/plucky/normalizers/fields_value_spec.rb +45 -0
- data/spec/plucky/normalizers/integer_spec.rb +24 -0
- data/spec/plucky/normalizers/options_hash_key_spec.rb +23 -0
- data/spec/plucky/normalizers/options_hash_value_spec.rb +99 -0
- data/spec/plucky/normalizers/sort_value_spec.rb +94 -0
- data/spec/plucky/options_hash_spec.rb +64 -0
- data/{test/plucky/pagination/test_decorator.rb → spec/plucky/pagination/decorator_spec.rb} +8 -10
- data/spec/plucky/pagination/paginator_spec.rb +118 -0
- data/spec/plucky/query_spec.rb +839 -0
- data/spec/plucky_spec.rb +68 -0
- data/{test/test_symbol_operator.rb → spec/symbol_operator_spec.rb} +14 -16
- data/spec/symbol_spec.rb +9 -0
- metadata +58 -23
- data/test/plucky/pagination/test_paginator.rb +0 -120
- data/test/plucky/test_criteria_hash.rb +0 -359
- data/test/plucky/test_options_hash.rb +0 -302
- data/test/plucky/test_query.rb +0 -843
- data/test/test_plucky.rb +0 -48
- data/test/test_symbol.rb +0 -11
@@ -0,0 +1,26 @@
|
|
1
|
+
module Plucky
|
2
|
+
module Normalizers
|
3
|
+
class FieldsValue
|
4
|
+
|
5
|
+
# Public: Given a value returns it normalized for Mongo's fields option
|
6
|
+
def call(value)
|
7
|
+
return nil if value.respond_to?(:empty?) && value.empty?
|
8
|
+
|
9
|
+
case value
|
10
|
+
when Array
|
11
|
+
if value.size == 1 && value.first.is_a?(Hash)
|
12
|
+
value.first
|
13
|
+
else
|
14
|
+
value.flatten
|
15
|
+
end
|
16
|
+
when Symbol
|
17
|
+
[value]
|
18
|
+
when String
|
19
|
+
value.split(',').map { |v| v.strip }
|
20
|
+
else
|
21
|
+
value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Plucky
|
2
|
+
module Normalizers
|
3
|
+
class Integer
|
4
|
+
|
5
|
+
# Public: Returns value coerced to integer or nil
|
6
|
+
#
|
7
|
+
# value - The value to normalize to an integer
|
8
|
+
#
|
9
|
+
# Returns an Integer or nil
|
10
|
+
def call(value)
|
11
|
+
if value.nil?
|
12
|
+
nil
|
13
|
+
else
|
14
|
+
value.to_i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Plucky
|
2
|
+
module Normalizers
|
3
|
+
class OptionsHashKey
|
4
|
+
|
5
|
+
# Internal: Keys with values that they should normalize to
|
6
|
+
NormalizedKeys = {
|
7
|
+
:order => :sort,
|
8
|
+
:select => :fields,
|
9
|
+
:offset => :skip,
|
10
|
+
:id => :_id,
|
11
|
+
}
|
12
|
+
|
13
|
+
# Public: Normalizes an options hash key
|
14
|
+
#
|
15
|
+
# key - The key to normalize
|
16
|
+
#
|
17
|
+
# Returns a Symbol.
|
18
|
+
def call(key)
|
19
|
+
NormalizedKeys.fetch key.to_sym, key
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'plucky/normalizers/integer'
|
2
|
+
require 'plucky/normalizers/fields_value'
|
3
|
+
require 'plucky/normalizers/sort_value'
|
4
|
+
|
5
|
+
module Plucky
|
6
|
+
module Normalizers
|
7
|
+
class OptionsHashValue
|
8
|
+
|
9
|
+
# Public: Initialize an OptionsHashValue.
|
10
|
+
#
|
11
|
+
# args - The hash of arguments (default: {})
|
12
|
+
# :key_normalizer - The key normalizer to use, must respond to call
|
13
|
+
# :value_normalizers - Hash where key is name of options hash key
|
14
|
+
# to normalize and value is what should be used
|
15
|
+
# to normalize the value accordingly (must respond
|
16
|
+
# to call). Allows adding normalizers for new keys
|
17
|
+
# and overriding existing default normalizers.
|
18
|
+
#
|
19
|
+
#
|
20
|
+
# Examples
|
21
|
+
#
|
22
|
+
# Plucky::Normalizers::OptionsHashValue.new({
|
23
|
+
# :key_normalizer => lambda { |key| key}, # key normalizer must responds to call
|
24
|
+
# :value_normalizers => {
|
25
|
+
# :new_key => lambda { |key| key.to_s.upcase }, # add normalizer for :new_key
|
26
|
+
# :fields => lambda { |key| key }, # override normalizer for fields to one that does nothing
|
27
|
+
# }
|
28
|
+
# })
|
29
|
+
#
|
30
|
+
# Returns the duplicated String.
|
31
|
+
def initialize(args = {})
|
32
|
+
@key_normalizer = args.fetch(:key_normalizer) {
|
33
|
+
raise ArgumentError, "Missing required key :key_normalizer"
|
34
|
+
}
|
35
|
+
|
36
|
+
@value_normalizers = {
|
37
|
+
:fields => default_fields_value_normalizer,
|
38
|
+
:sort => default_sort_value_normalizer,
|
39
|
+
:limit => default_limit_value_normalizer,
|
40
|
+
:skip => default_skip_value_normalizer,
|
41
|
+
}
|
42
|
+
|
43
|
+
if (value_normalizers = args[:value_normalizers])
|
44
|
+
@value_normalizers.update(value_normalizers)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Returns value normalized for Mongo
|
49
|
+
#
|
50
|
+
# key - The name of the key whose value is being normalized
|
51
|
+
# value - The value to normalize
|
52
|
+
#
|
53
|
+
# Returns value normalized for Mongo.
|
54
|
+
def call(key, value)
|
55
|
+
if (value_normalizer = @value_normalizers[key])
|
56
|
+
value_normalizer.call(value)
|
57
|
+
else
|
58
|
+
value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Private
|
63
|
+
def default_fields_value_normalizer
|
64
|
+
Normalizers::FieldsValue.new
|
65
|
+
end
|
66
|
+
|
67
|
+
# Private
|
68
|
+
def default_sort_value_normalizer
|
69
|
+
Normalizers::SortValue.new({
|
70
|
+
:key_normalizer => @key_normalizer,
|
71
|
+
})
|
72
|
+
end
|
73
|
+
|
74
|
+
# Private
|
75
|
+
def default_limit_value_normalizer
|
76
|
+
Normalizers::Integer.new
|
77
|
+
end
|
78
|
+
|
79
|
+
# Private
|
80
|
+
def default_skip_value_normalizer
|
81
|
+
Normalizers::Integer.new
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Plucky
|
2
|
+
module Normalizers
|
3
|
+
class SortValue
|
4
|
+
|
5
|
+
# Public: Initializes a Plucky::Normalizers::SortValue
|
6
|
+
#
|
7
|
+
# args - The hash of arguments
|
8
|
+
# :key_normalizer - What to use to normalize keys, must
|
9
|
+
# respond to call.
|
10
|
+
#
|
11
|
+
def initialize(args = {})
|
12
|
+
@key_normalizer = args.fetch(:key_normalizer) {
|
13
|
+
raise ArgumentError, "Missing required key :key_normalizer"
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Public: Given a value returns it normalized for Mongo's sort option
|
18
|
+
def call(value)
|
19
|
+
case value
|
20
|
+
when Array
|
21
|
+
if value.size == 1 && value[0].is_a?(String)
|
22
|
+
normalized_sort_piece(value[0])
|
23
|
+
else
|
24
|
+
value.compact.map { |v| normalized_sort_piece(v).flatten }
|
25
|
+
end
|
26
|
+
else
|
27
|
+
normalized_sort_piece(value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Private
|
32
|
+
def normalized_sort_piece(value)
|
33
|
+
case value
|
34
|
+
when SymbolOperator
|
35
|
+
[normalized_direction(value.field, value.operator)]
|
36
|
+
when String
|
37
|
+
value.split(',').map do |piece|
|
38
|
+
normalized_direction(*piece.split(' '))
|
39
|
+
end
|
40
|
+
when Symbol
|
41
|
+
[normalized_direction(value)]
|
42
|
+
else
|
43
|
+
value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Private
|
48
|
+
def normalized_direction(field, direction=nil)
|
49
|
+
direction ||= 'ASC'
|
50
|
+
direction = direction.upcase == 'ASC' ? 1 : -1
|
51
|
+
[@key_normalizer.call(field).to_s, direction]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/plucky/options_hash.rb
CHANGED
@@ -1,127 +1,98 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'plucky/normalizers/options_hash_key'
|
4
|
+
require 'plucky/normalizers/options_hash_value'
|
5
|
+
|
2
6
|
module Plucky
|
3
7
|
class OptionsHash
|
8
|
+
|
9
|
+
# Private: The Hash that stores the query options
|
4
10
|
attr_reader :source
|
5
11
|
|
6
|
-
|
12
|
+
# Private: The Hash that stores instance options
|
13
|
+
attr_reader :options
|
14
|
+
|
15
|
+
# Public
|
16
|
+
def initialize(hash={}, options={})
|
7
17
|
@source = {}
|
18
|
+
@options = options
|
8
19
|
hash.each { |key, value| self[key] = value }
|
9
20
|
end
|
10
21
|
|
11
|
-
def initialize_copy(
|
22
|
+
def initialize_copy(original)
|
12
23
|
super
|
13
24
|
@source = @source.dup
|
14
|
-
each do |key, value|
|
25
|
+
@source.each do |key, value|
|
15
26
|
self[key] = value.clone if value.duplicable?
|
16
27
|
end
|
17
28
|
end
|
18
29
|
|
30
|
+
# Public
|
31
|
+
def [](key)
|
32
|
+
@source[key]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Public
|
19
36
|
def []=(key, value)
|
20
37
|
key = normalized_key(key)
|
21
|
-
source[key] = normalized_value(key, value)
|
38
|
+
@source[key] = normalized_value(key, value)
|
22
39
|
end
|
23
40
|
|
41
|
+
# Public
|
42
|
+
def keys
|
43
|
+
@source.keys
|
44
|
+
end
|
45
|
+
|
46
|
+
# Public
|
24
47
|
def ==(other)
|
25
|
-
source == other.source
|
48
|
+
@source == other.source
|
26
49
|
end
|
27
50
|
|
51
|
+
# Public
|
28
52
|
def to_hash
|
29
|
-
source
|
53
|
+
@source
|
30
54
|
end
|
31
55
|
|
56
|
+
# Public
|
32
57
|
def fields?
|
33
58
|
!self[:fields].nil?
|
34
59
|
end
|
35
60
|
|
61
|
+
# Public
|
36
62
|
def merge(other)
|
37
63
|
self.class.new(to_hash.merge(other.to_hash))
|
38
64
|
end
|
39
65
|
|
66
|
+
# Public
|
40
67
|
def merge!(other)
|
41
68
|
other.to_hash.each { |key, value| self[key] = value }
|
42
69
|
self
|
43
70
|
end
|
44
71
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
NormalizedKeys = {
|
51
|
-
:order => :sort,
|
52
|
-
:select => :fields,
|
53
|
-
:offset => :skip,
|
54
|
-
:id => :_id,
|
55
|
-
}
|
56
|
-
|
57
|
-
def normalized_key(key)
|
58
|
-
NormalizedKeys.default = key
|
59
|
-
NormalizedKeys[key.to_sym]
|
60
|
-
end
|
61
|
-
|
62
|
-
def normalized_value(key, value)
|
63
|
-
case key
|
64
|
-
when :fields
|
65
|
-
normalized_fields(value)
|
66
|
-
when :sort
|
67
|
-
normalized_sort(value)
|
68
|
-
when :limit, :skip
|
69
|
-
value.nil? ? nil : value.to_i
|
70
|
-
else
|
71
|
-
value
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def normalized_fields(value)
|
76
|
-
return nil if value.respond_to?(:empty?) && value.empty?
|
77
|
-
case value
|
78
|
-
when Array
|
79
|
-
if value.size == 1 && value.first.is_a?(Hash)
|
80
|
-
value.first
|
81
|
-
else
|
82
|
-
value.flatten
|
83
|
-
end
|
84
|
-
when Symbol
|
85
|
-
[value]
|
86
|
-
when String
|
87
|
-
value.split(',').map { |v| v.strip }
|
88
|
-
else
|
89
|
-
value
|
90
|
-
end
|
91
|
-
end
|
72
|
+
# Private
|
73
|
+
def normalized_key(key)
|
74
|
+
key_normalizer.call(key)
|
75
|
+
end
|
92
76
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
normalized_sort_piece(value[0])
|
98
|
-
else
|
99
|
-
value.compact.map { |v| normalized_sort_piece(v).flatten }
|
100
|
-
end
|
101
|
-
else
|
102
|
-
normalized_sort_piece(value)
|
103
|
-
end
|
104
|
-
end
|
77
|
+
# Private
|
78
|
+
def normalized_value(key, value)
|
79
|
+
value_normalizer.call(key, value)
|
80
|
+
end
|
105
81
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
normalized_direction(*piece.split(' '))
|
113
|
-
end
|
114
|
-
when Symbol
|
115
|
-
[normalized_direction(value)]
|
116
|
-
else
|
117
|
-
value
|
118
|
-
end
|
119
|
-
end
|
82
|
+
# Private
|
83
|
+
def key_normalizer
|
84
|
+
@key_normalizer ||= @options.fetch(:key_normalizer) {
|
85
|
+
Normalizers::OptionsHashKey.new
|
86
|
+
}
|
87
|
+
end
|
120
88
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
89
|
+
# Private
|
90
|
+
def value_normalizer
|
91
|
+
@value_normalizer ||= @options.fetch(:value_normalizer) {
|
92
|
+
Normalizers::OptionsHashValue.new({
|
93
|
+
:key_normalizer => key_normalizer,
|
94
|
+
})
|
95
|
+
}
|
96
|
+
end
|
126
97
|
end
|
127
|
-
end
|
98
|
+
end
|
@@ -8,9 +8,10 @@ module Plucky
|
|
8
8
|
:total_entries, :total_pages,
|
9
9
|
:current_page, :per_page,
|
10
10
|
:previous_page, :next_page,
|
11
|
-
:skip, :limit,
|
11
|
+
:skip, :limit,
|
12
12
|
:offset, :out_of_bounds?
|
13
13
|
|
14
|
+
# Public
|
14
15
|
def paginator(p=nil)
|
15
16
|
return @paginator if p.nil?
|
16
17
|
@paginator = p
|
@@ -18,4 +19,4 @@ module Plucky
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
21
|
-
end
|
22
|
+
end
|
@@ -4,34 +4,43 @@ module Plucky
|
|
4
4
|
class Paginator
|
5
5
|
attr_reader :total_entries, :current_page, :per_page
|
6
6
|
|
7
|
+
# Public
|
7
8
|
def initialize(total, page, per_page=nil)
|
8
9
|
@total_entries = total.to_i
|
9
10
|
@current_page = [page.to_i, 1].max
|
10
11
|
@per_page = (per_page || 25).to_i
|
11
12
|
end
|
12
13
|
|
14
|
+
# Public
|
13
15
|
def total_pages
|
14
|
-
(total_entries / per_page.to_f).ceil
|
16
|
+
(@total_entries / @per_page.to_f).ceil
|
15
17
|
end
|
16
18
|
|
19
|
+
# Public
|
17
20
|
def out_of_bounds?
|
18
|
-
current_page > total_pages
|
21
|
+
@current_page > total_pages
|
19
22
|
end
|
20
23
|
|
24
|
+
# Public
|
21
25
|
def previous_page
|
22
|
-
current_page > 1 ? (current_page - 1) : nil
|
26
|
+
@current_page > 1 ? (@current_page - 1) : nil
|
23
27
|
end
|
24
28
|
|
29
|
+
# Public
|
25
30
|
def next_page
|
26
|
-
current_page < total_pages ? (current_page + 1) : nil
|
31
|
+
@current_page < total_pages ? (@current_page + 1) : nil
|
27
32
|
end
|
28
33
|
|
34
|
+
# Public
|
29
35
|
def skip
|
30
|
-
(current_page - 1) * per_page
|
36
|
+
(@current_page - 1) * @per_page
|
31
37
|
end
|
32
38
|
|
39
|
+
# Public
|
33
40
|
alias :limit :per_page
|
41
|
+
|
42
|
+
# Public
|
34
43
|
alias :offset :skip
|
35
44
|
end
|
36
45
|
end
|
37
|
-
end
|
46
|
+
end
|