cancancan-squeel 0.1.2 → 0.1.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/lib/cancancan/squeel/attribute_mapper.rb +79 -12
- data/lib/cancancan/squeel/expression_builder.rb +38 -7
- data/lib/cancancan/squeel/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee0d8f0d270a3449f4c1373eb89857cc047553ea
|
4
|
+
data.tar.gz: ddc057b7c68e47e087dbed2b707005ccf581b6f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0756bbd6699c2eea5eee163425bcc389180028edfcad1b0c839e19bcfea821f0644987083d77069e3235e8db4d103143cb8125d1a5b897a360b669438f89a72d
|
7
|
+
data.tar.gz: 0db5510c60e8cfe778e6e6cd709ae95fd63ba47467c1b4f0a374561d749fc3a2dcd281530ef5f23020ca604dffaccce0968bc9bda86e7a839f8472fb174fb105
|
data/CHANGELOG.md
CHANGED
@@ -11,20 +11,34 @@ module CanCanCan::Squeel::AttributeMapper
|
|
11
11
|
# Picks the appropriate column, comparator, and value to use in the Squeel expression.
|
12
12
|
#
|
13
13
|
# This checks for association references: this will use the appropriate column name.
|
14
|
-
#
|
15
14
|
# Array values are interpreted as alternative choices allowed or disallowed.
|
15
|
+
# Ranges are converted to appropriate comparator pairs.
|
16
|
+
#
|
17
|
+
# The return value is a tuple:
|
18
|
+
#
|
19
|
+
# - The first element is a combinator to be used on the comparisons.
|
20
|
+
# - The second element is an array of comparisons: each comparison is a tuple of
|
21
|
+
# (key, comparator, value)
|
22
|
+
#
|
23
|
+
# The appropriate expression is the combination of all the comparisons, using the combinator
|
24
|
+
# returned.
|
25
|
+
#
|
26
|
+
# @example Attribute Ranges
|
27
|
+
# squeel_comparison_for(User, :id, :==, 1..5) #=> [:&, [[:id, :>=, 1], [:id, :<=, 5]]]
|
28
|
+
# @example Association Objects
|
29
|
+
# squeel_comparison_for(Post, :comment, :==, comment) #=> [:&, [[:comment_id, :==, 1]]]
|
16
30
|
#
|
17
31
|
# @param [Class] model_class The model class which the key references.
|
18
32
|
# @param [Symbol] key The column being compared.
|
19
33
|
# @param [Symbol] comparator The comparator to get the appropriate Squeel comparator for.
|
20
34
|
# @param value The value to be comparing against.
|
21
|
-
# @return [Array<(Symbol, Symbol, Object)>] A
|
22
|
-
#
|
35
|
+
# @return [Array<(Symbol, Array<(Symbol, Symbol, Object)>)>] A tuple containing the combinator for
|
36
|
+
# the comparisons, and a sequence of comparisons.
|
23
37
|
def squeel_comparison_for(model_class, key, comparator, value)
|
24
38
|
key, value = map_association(model_class, key, value)
|
25
39
|
|
26
|
-
|
27
|
-
[
|
40
|
+
combinator, comparisons = squeel_comparator_for(comparator, value)
|
41
|
+
[combinator, comparisons.map { |comp| comp.unshift(key) }]
|
28
42
|
end
|
29
43
|
|
30
44
|
# Picks the table column to compare the value against for the given key.
|
@@ -48,17 +62,70 @@ module CanCanCan::Squeel::AttributeMapper
|
|
48
62
|
#
|
49
63
|
# Array values are interpreted as alternative choices allowed or disallowed.
|
50
64
|
#
|
65
|
+
# Ranges are interpreted as start/end pairs, respecting the exclusion of the end point.
|
66
|
+
#
|
51
67
|
# @param [Symbol] comparator The comparator to get the appropriate Squeel comparator for.
|
52
68
|
# @param value The value to be comparing against.
|
53
|
-
# @return [Symbol]
|
69
|
+
# @return [Array<Array<(Symbol, Object)>>] An array of comparisons, each with the comparator
|
70
|
+
# to use, and the value to compare against.
|
54
71
|
def squeel_comparator_for(comparator, value)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
72
|
+
case value
|
73
|
+
when Array then comparator_for_array(comparator, value)
|
74
|
+
when Range then comparator_for_range(comparator, value)
|
75
|
+
else [:&, [[comparator, value]]]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Maps the given comparator to the IN/NOT IN operator.
|
80
|
+
#
|
81
|
+
# @param [Symbol] comparator The comparator to get the SqueeL comparator for.
|
82
|
+
# @param [Array] value The acceptable/rejected values.
|
83
|
+
# @return [Array<(Symbol, Array<(Symbol, Object)>)>] The combinator, and an array of comparisons,
|
84
|
+
# each with the comparator to use, and the value to compare against.
|
85
|
+
def comparator_for_array(comparator, value)
|
86
|
+
case comparator
|
87
|
+
when :== then [:&, [[:>>, value]]]
|
88
|
+
when :!= then [:&, [[:<<, value]]]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Maps the given comparator to a range comparison.
|
93
|
+
#
|
94
|
+
# @param [Symbol] comparator The comparator to get the Squeel comparator for.
|
95
|
+
# @param [Range] value The acceptable/rejected values.
|
96
|
+
# @return [Array<(Symbol, Array<(Symbol, Object)>)>] The combinator, and an array of comparisons,
|
97
|
+
# each with the comparator to use, and the value to compare against.
|
98
|
+
def comparator_for_range(comparator, value)
|
99
|
+
if value.exclude_end?
|
100
|
+
comparator_for_exclusive_range(comparator, value)
|
60
101
|
else
|
61
|
-
comparator
|
102
|
+
comparator_for_inclusive_range(comparator, value)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Maps the given comparator to a range comparison.
|
107
|
+
#
|
108
|
+
# @param [Symbol] comparator The comparator to get the Squeel comparator for.
|
109
|
+
# @param [Range] value The acceptable/rejected values.
|
110
|
+
# @return [Array<Array<(Symbol, Object)>>] An array of comparisons, each with the comparator
|
111
|
+
# to use, and the value to compare against.
|
112
|
+
def comparator_for_exclusive_range(comparator, value)
|
113
|
+
case comparator
|
114
|
+
when :== then [:&, [[:>=, value.first], [:<, value.last]]]
|
115
|
+
when :!= then [:|, [[:<, value.first], [:>=, value.last]]]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Maps the given comparator to a range comparison.
|
120
|
+
#
|
121
|
+
# @param [Symbol] comparator The comparator to get the Squeel comparator for.
|
122
|
+
# @param [Range] value The acceptable/rejected values.
|
123
|
+
# @return [Array<Array<(Symbol, Object)>>] An array of comparisons, each with the comparator
|
124
|
+
# to use, and the value to compare against.
|
125
|
+
def comparator_for_inclusive_range(comparator, value)
|
126
|
+
case comparator
|
127
|
+
when :== then [:&, [[:>=, value.first], [:<=, value.last]]]
|
128
|
+
when :!= then [:|, [[:<, value.first], [:>, value.last]]]
|
62
129
|
end
|
63
130
|
end
|
64
131
|
end
|
@@ -51,14 +51,45 @@ module CanCanCan::Squeel::ExpressionBuilder
|
|
51
51
|
# @param value The value to compare the column against.
|
52
52
|
def build_comparison_node(node, model_class, key, comparator, value)
|
53
53
|
if value.is_a?(Hash)
|
54
|
-
|
55
|
-
expression, joins = build_expression_node(node.__send__(key), reflection_class, comparator,
|
56
|
-
value)
|
57
|
-
[expression, joins.map { |join| join.unshift(key) }.unshift([key])]
|
54
|
+
build_association_comparison_node(node, model_class, key, comparator, value)
|
58
55
|
else
|
59
|
-
key, comparator, value
|
60
|
-
squeel_comparison_for(model_class, key, comparator, value)
|
61
|
-
[node.__send__(key).public_send(comparator, value), []]
|
56
|
+
build_scalar_comparison_node(node, model_class, key, comparator, value)
|
62
57
|
end
|
63
58
|
end
|
59
|
+
|
60
|
+
# Builds a comparison node for the given association and association attributes.
|
61
|
+
#
|
62
|
+
# @param node The node context to build the comparison.
|
63
|
+
# @param [Class] model_class The model class which the conditions reference.
|
64
|
+
# @param [Symbol] key The association to compare against.
|
65
|
+
# @param [Symbol] comparator The comparator to compare the column against the value.
|
66
|
+
# @param [Hash] value The attributes to compare the column against.
|
67
|
+
def build_association_comparison_node(node, model_class, key, comparator, value)
|
68
|
+
reflection_class = model_class.reflect_on_association(key).klass
|
69
|
+
expression, joins = build_expression_node(node.__send__(key), reflection_class, comparator,
|
70
|
+
value)
|
71
|
+
[expression, joins.map { |join| join.unshift(key) }.unshift([key])]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Builds a comparison node for the given attribute and value.
|
75
|
+
#
|
76
|
+
# @param node The node context to build the comparison.
|
77
|
+
# @param [Class] model_class The model class which the conditions reference.
|
78
|
+
# @param [Symbol] key The column to compare against.
|
79
|
+
# @param [Symbol] comparator The comparator to compare the column against the value.
|
80
|
+
# @param value The value to compare the column against.
|
81
|
+
def build_scalar_comparison_node(node, model_class, key, comparator, value)
|
82
|
+
combinator, comparisons = CanCanCan::Squeel::AttributeMapper.
|
83
|
+
squeel_comparison_for(model_class, key, comparator, value)
|
84
|
+
attribute = node.__send__(comparisons.first.first)
|
85
|
+
|
86
|
+
expression = comparisons.reduce(nil) do |left_expression, (_, comparator, value)|
|
87
|
+
right_expression = attribute.dup.public_send(comparator, value)
|
88
|
+
next right_expression unless left_expression
|
89
|
+
|
90
|
+
left_expression.public_send(combinator, right_expression)
|
91
|
+
end
|
92
|
+
|
93
|
+
[expression, []]
|
94
|
+
end
|
64
95
|
end
|