Module: CanCanCan::BabySqueel::ExpressionBuilder

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

Overview

Builds Squeel expressions from the given scope, model class, and a hash of conditions.

This is used by building a set of rules for retrieving all accessible records, as well as for building queries instead of loading all records into memory.

Class Method Summary collapse

Class Method Details

.build(squeel, model_class, comparator, conditions) ⇒ Array<(Squeel::Nodes::Node, Array<Array<Symbol>>)>

Builds a new Squeel expression node given a model class, the comparator, and the conditions.

Parameters:

  • squeel

    The Squeel context. This is the value of self within a where DSL block.

  • model_class (Class)

    The model class which the conditions reference.

  • comparator (Symbol)

    The comparator to use when generating the comparison.

  • conditions (Hash)

    The values to compare the given node’s attributes against.

Returns:

  • (Array<(Squeel::Nodes::Node, Array<Array<Symbol>>)>)

    A tuple containing the Squeel expression representing the rule’s conditions, as well as an array of joins which the Squeel expression must be joined to.



18
19
20
# File 'lib/cancancan/baby_squeel/expression_builder.rb', line 18

def build(squeel, model_class, comparator, conditions)
  build_expression_node(squeel, model_class, comparator, conditions, true)
end

.build_association_comparison_node(node, model_class, key, comparator, value) ⇒ Object

Builds a comparison node for the given association and association attributes.

Parameters:

  • node

    The node context to build the comparison.

  • model_class (Class)

    The model class which the conditions reference.

  • key (Symbol)

    The association to compare against.

  • comparator (Symbol)

    The comparator to compare the column against the value.

  • value (Hash)

    The attributes to compare the column against.



67
68
69
70
71
72
# File 'lib/cancancan/baby_squeel/expression_builder.rb', line 67

def build_association_comparison_node(node, model_class, key, comparator, value)
  reflection_class = model_class.reflect_on_association(key).klass
  expression, joins = build_expression_node(node.__send__(key), reflection_class, comparator,
                                            value)
  [expression, joins.map { |join| join.unshift(key) }.unshift([key])]
end

.build_comparison_node(node, model_class, key, comparator, value) ⇒ Object

Builds a comparison node for the given key and value.

Parameters:

  • node

    The node context to build the comparison.

  • model_class (Class)

    The model class which the conditions reference.

  • key (Symbol)

    The column to compare against.

  • comparator (Symbol)

    The comparator to compare the column against the value.

  • value

    The value to compare the column against.



52
53
54
55
56
57
58
# File 'lib/cancancan/baby_squeel/expression_builder.rb', line 52

def build_comparison_node(node, model_class, key, comparator, value)
  if value.is_a?(Hash)
    build_association_comparison_node(node, model_class, key, comparator, value)
  else
    build_scalar_comparison_node(node, model_class, key, comparator, value)
  end
end

.build_expression_node(node, model_class, comparator, conditions, root = false) ⇒ Array<(Squeel::Nodes::Node, Array<Array<Symbol>>)>

Builds a new Squeel expression node.

Parameters:

  • node

    The parent node context.

  • model_class (Class)

    The model class which the conditions reference.

  • comparator (Symbol)

    The comparator to use when generating the comparison.

  • conditions (Hash)

    The values to compare the given node’s attributes against.

  • root (Boolean) (defaults to: false)

    True if the node being built is from the root. The root node is special because it does not mutate itself; all other nodes do.

Returns:

  • (Array<(Squeel::Nodes::Node, Array<Array<Symbol>>)>)

    A tuple containing the Squeel expression representing the rule’s conditions, as well as an array of joins which the Squeel expression must be joined to.



33
34
35
36
37
38
39
40
41
42
43
# File 'lib/cancancan/baby_squeel/expression_builder.rb', line 33

def build_expression_node(node, model_class, comparator, conditions, root = false)
  conditions.reduce([nil, []]) do |(left_expression, joins), (key, value)|
    comparison_node, node_joins = build_comparison_node(root ? node : node.dup, model_class,
                                                        key, comparator, value)
    if left_expression
      [left_expression.and(comparison_node), joins.concat(node_joins)]
    else
      [comparison_node, node_joins]
    end
  end
end

.build_scalar_comparison_node(node, model_class, key, comparator, value) ⇒ Object

Builds a comparison node for the given attribute and value.

Parameters:

  • node

    The node context to build the comparison.

  • model_class (Class)

    The model class which the conditions reference.

  • key (Symbol)

    The column to compare against.

  • comparator (Symbol)

    The comparator to compare the column against the value.

  • value

    The value to compare the column against.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/cancancan/baby_squeel/expression_builder.rb', line 81

def build_scalar_comparison_node(node, model_class, key, comparator, value)
  combinator, comparisons = CanCanCan::BabySqueel::AttributeMapper.
                            squeel_comparison_for(model_class, key, comparator, value)
  attribute = node.__send__(comparisons.first.first)

  expression = comparisons.reduce(nil) do |left_expression, (_, comparator, value)|
    right_expression = attribute.dup.public_send(comparator, value)
    next right_expression unless left_expression

    left_expression.public_send(combinator, right_expression)
  end

  [expression, []]
end