Module: CanCanCan::BabySqueel::AttributeMapper

Defined in:
lib/cancancan/baby_squeel/attribute_mapper.rb

Overview

Implements mapping attributes, values, and comparators for a given model to appropriate database equivalents.

This implements:

- comparing values against an array: interpreted as any value for ==, none of the values for !=.
- mapping foreign keys to IDs

Class Method Summary collapse

Class Method Details

.comparator_for_array(comparator, value) ⇒ Array<(Symbol, Array<(Symbol, Object)>)>

Maps the given comparator to the IN/NOT IN operator.

Parameters:

  • comparator (Symbol)

    The comparator to get the SqueeL comparator for.

  • value (Array)

    The acceptable/rejected values.

Returns:

  • (Array<(Symbol, Array<(Symbol, Object)>)>)

    The combinator, and an array of comparisons, each with the comparator to use, and the value to compare against.



86
87
88
89
90
91
# File 'lib/cancancan/baby_squeel/attribute_mapper.rb', line 86

def comparator_for_array(comparator, value)
  case comparator
  when :eq then [:and, [[:in, value]]]
  when :not_eq then [:and, [[:not_in, value]]]
  end
end

.comparator_for_exclusive_range(comparator, value) ⇒ Array<Array<(Symbol, Object)>>

Maps the given comparator to a range comparison.

Parameters:

  • comparator (Symbol)

    The comparator to get the Squeel comparator for.

  • value (Range)

    The acceptable/rejected values.

Returns:

  • (Array<Array<(Symbol, Object)>>)

    An array of comparisons, each with the comparator to use, and the value to compare against.



113
114
115
116
117
118
# File 'lib/cancancan/baby_squeel/attribute_mapper.rb', line 113

def comparator_for_exclusive_range(comparator, value)
  case comparator
  when :eq then [:and, [[:gteq, value.first], [:lt, value.last]]]
  when :not_eq then [:or, [[:lt, value.first], [:gteq, value.last]]]
  end
end

.comparator_for_inclusive_range(comparator, value) ⇒ Array<Array<(Symbol, Object)>>

Maps the given comparator to a range comparison.

Parameters:

  • comparator (Symbol)

    The comparator to get the Squeel comparator for.

  • value (Range)

    The acceptable/rejected values.

Returns:

  • (Array<Array<(Symbol, Object)>>)

    An array of comparisons, each with the comparator to use, and the value to compare against.



126
127
128
129
130
131
# File 'lib/cancancan/baby_squeel/attribute_mapper.rb', line 126

def comparator_for_inclusive_range(comparator, value)
  case comparator
  when :eq then [:and, [[:gteq, value.first], [:lteq, value.last]]]
  when :not_eq then [:or, [[:lt, value.first], [:gt, value.last]]]
  end
end

.comparator_for_range(comparator, value) ⇒ Array<(Symbol, Array<(Symbol, Object)>)>

Maps the given comparator to a range comparison.

Parameters:

  • comparator (Symbol)

    The comparator to get the Squeel comparator for.

  • value (Range)

    The acceptable/rejected values.

Returns:

  • (Array<(Symbol, Array<(Symbol, Object)>)>)

    The combinator, and an array of comparisons, each with the comparator to use, and the value to compare against.



99
100
101
102
103
104
105
# File 'lib/cancancan/baby_squeel/attribute_mapper.rb', line 99

def comparator_for_range(comparator, value)
  if value.exclude_end?
    comparator_for_exclusive_range(comparator, value)
  else
    comparator_for_inclusive_range(comparator, value)
  end
end

.map_association(model_class, key, value) ⇒ Array<(Symbol, Object)>

Picks the table column to compare the value against for the given key.

This sets associations to use the proper foreign key column.

Parameters:

  • model_class (Class)

    The model class which the key references.

  • key (Symbol)

    The column being compared.

  • value

    The value to be comparing against.

Returns:

  • (Array<(Symbol, Object)>)

    A tuple containing the column to compare with and the value to compare with.



53
54
55
56
57
58
59
60
# File 'lib/cancancan/baby_squeel/attribute_mapper.rb', line 53

def map_association(model_class, key, value)
  if (association = model_class.reflect_on_association(key))
    key = association.foreign_key
    value = value.id
  end

  [key, value]
end

.squeel_comparator_for(comparator, value) ⇒ Array<Array<(Symbol, Object)>>

Maps the given comparator to a comparator appropriate for the given value.

Array values are interpreted as alternative choices allowed or disallowed.

Ranges are interpreted as start/end pairs, respecting the exclusion of the end point.

Parameters:

  • comparator (Symbol)

    The comparator to get the appropriate Squeel comparator for.

  • value

    The value to be comparing against.

Returns:

  • (Array<Array<(Symbol, Object)>>)

    An array of comparisons, each with the comparator to use, and the value to compare against.



72
73
74
75
76
77
78
# File 'lib/cancancan/baby_squeel/attribute_mapper.rb', line 72

def squeel_comparator_for(comparator, value)
  case value
  when Array then comparator_for_array(comparator, value)
  when Range then comparator_for_range(comparator, value)
  else [:and, [[comparator, value]]]
  end
end

.squeel_comparison_for(model_class, key, comparator, value) ⇒ Array<(Symbol, Array<(Symbol, Symbol, Object)>)>

Picks the appropriate column, comparator, and value to use in the Squeel expression.

This checks for association references: this will use the appropriate column name. Array values are interpreted as alternative choices allowed or disallowed. Ranges are converted to appropriate comparator pairs.

The return value is a tuple:

- The first element is a combinator to be used on the comparisons.
- The second element is an array of comparisons: each comparison is a tuple of
  (key, comparator, value)

The appropriate expression is the combination of all the comparisons, using the combinator returned.

Examples:

Attribute Ranges

squeel_comparison_for(User, :id, :eq, 1..5) #=> [:and, [[:id, :gteq, 1], [:id, :lteq, 5]]]

Association Objects

squeel_comparison_for(Post, :comment, :eq, comment) #=> [:and, [[:comment_id, :eq, 1]]]

Parameters:

  • model_class (Class)

    The model class which the key references.

  • key (Symbol)

    The column being compared.

  • comparator (Symbol)

    The comparator to get the appropriate Squeel comparator for.

  • value

    The value to be comparing against.

Returns:

  • (Array<(Symbol, Array<(Symbol, Symbol, Object)>)>)

    A tuple containing the combinator for the comparisons, and a sequence of comparisons.



37
38
39
40
41
42
# File 'lib/cancancan/baby_squeel/attribute_mapper.rb', line 37

def squeel_comparison_for(model_class, key, comparator, value)
  key, value = map_association(model_class, key, value)

  combinator, comparisons = squeel_comparator_for(comparator, value)
  [combinator, comparisons.map { |comp| comp.unshift(key) }]
end