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 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