cancancan-squeel 0.1.2 → 0.1.3

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: edbfe73803fc60f8f004514ca962dcb92818cbb4
4
- data.tar.gz: fc92e4d84a7557edf512293ebcfefd8995496d82
3
+ metadata.gz: ee0d8f0d270a3449f4c1373eb89857cc047553ea
4
+ data.tar.gz: ddc057b7c68e47e087dbed2b707005ccf581b6f7
5
5
  SHA512:
6
- metadata.gz: ca8e2455b16e3bc007829341fffdce9682cdebfccc1089e1f0874a6edfcdc35433a955388814dd79b929e79a43e55b0b198fcd959587429d40fba178a4d9fe39
7
- data.tar.gz: 9ea2d0969b402e28030d14b1a3c464aafaf8a34d13385056a9853bea7123b5b1e23e10d7ec602ba7f1894a06fbb6b2948fe1beaea158e841092d65bf726101e7
6
+ metadata.gz: 0756bbd6699c2eea5eee163425bcc389180028edfcad1b0c839e19bcfea821f0644987083d77069e3235e8db4d103143cb8125d1a5b897a360b669438f89a72d
7
+ data.tar.gz: 0db5510c60e8cfe778e6e6cd709ae95fd63ba47467c1b4f0a374561d749fc3a2dcd281530ef5f23020ca604dffaccce0968bc9bda86e7a839f8472fb174fb105
data/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
- ## master
1
+ ## 0.1.3
2
+
3
+ ### enhancements
4
+
5
+ - Support ranges in conditions [@lowjoel](https://github.com/lowjoel)
6
+
7
+ ## 0.1.2
2
8
 
3
9
  ### enhancements
4
10
 
@@ -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 triple containing the column to compare with, the
22
- # comparator to use, and the value to compare with.
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
- comparator = squeel_comparator_for(comparator, value)
27
- [key, comparator, value]
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] The comparator for the desired effect, suitable for the given type.
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
- if value.is_a?(Array)
56
- case comparator
57
- when :== then :>>
58
- when :!= then :<<
59
- end
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
- reflection_class = model_class.reflect_on_association(key).klass
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 = CanCanCan::Squeel::AttributeMapper.
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module CanCanCan; end
3
3
  module CanCanCan::Squeel
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cancancan-squeel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Low