Class: ActionBlocks::SelectionsViaWhereEngine

Inherits:
Object
  • Object
show all
Defined in:
lib/action_blocks/data_engine/selections_via_where_engine.rb

Overview

Data Engine

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root_klass, user: nil, table_alias_prefix: nil, type: :many_to_many, selection_filter_reqs: [], selection_match_reqs: [], additional_where: nil) ⇒ SelectionsViaWhereEngine

Returns a new instance of SelectionsViaWhereEngine.



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 6

def initialize(root_klass, user: nil, table_alias_prefix: nil, type: :many_to_many, selection_filter_reqs: [], selection_match_reqs: [], additional_where: nil)
  @root_klass = root_klass
  @table_alias_prefix = table_alias_prefix
  @tables = {}
  @joins = {}
  @wheres = []
  @froms = []
  @type = type

  @additional_where = additional_where

  # I named them selection_match_reqs because
  # the DataEngine may work with match_reqs in
  # different contexts.  It may use them for
  # summary fields or it may use them for
  # a filtering a query to the children of some
  # base models 'children'
  @selection_match_reqs = selection_match_reqs
  @selection_filter_reqs = selection_filter_reqs
end

Instance Attribute Details

#joinsObject

Returns the value of attribute joins.



4
5
6
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 4

def joins
  @joins
end

#root_klassObject

Returns the value of attribute root_klass.



4
5
6
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 4

def root_klass
  @root_klass
end

#selection_filter_reqsObject

Returns the value of attribute selection_filter_reqs.



4
5
6
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 4

def selection_filter_reqs
  @selection_filter_reqs
end

#selection_match_reqsObject

Returns the value of attribute selection_match_reqs.



4
5
6
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 4

def selection_match_reqs
  @selection_match_reqs
end

#selectsObject

Returns the value of attribute selects.



4
5
6
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 4

def selects
  @selects
end

#tablesObject

Returns the value of attribute tables.



4
5
6
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 4

def tables
  @tables
end

Instance Method Details

#fromsObject



92
93
94
95
96
97
98
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 92

def froms
  if @type == :many_to_many
    [@root_table]
  else
    @froms
  end
end

#ordered_joinsObject



100
101
102
103
104
105
106
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 100

def ordered_joins
  if @type == :many_to_many
    []
  else
    @joins.values
  end
end

#processObject



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 27

def process
  @root_table = @root_klass.arel_table.alias([@table_alias_prefix, @root_klass.to_s.underscore.pluralize].compact.join('_'))
  root_key = [@table_alias_prefix, @root_klass.to_s.underscore.pluralize].compact.join('_').to_sym

  @froms << @root_table
  # Add base table to tables
  @tables[root_key.to_sym] = @root_table

  [@selection_match_reqs, @selection_filter_reqs].flatten.compact.each do |matchreq|
    node, *rest = matchreq[:base_path]
    # puts "base node: #{node} rest #{rest}"
    base_expression = walk_selection_match_path(@root_klass, node, root_key, rest)

    node, *rest = matchreq[:related_path]
    # puts "related node: #{node} rest #{rest}"
    related_expression = walk_selection_match_path(@root_klass, node, root_key, rest)

    where = if base_expression.class.ancestors.include?(Arel::Attributes::Attribute)
              base_expression.send(matchreq[:predicate], related_expression)
            else
              related_expression.send(matchreq[:predicate], base_expression)
            end
    @wheres << where
  end
end

#queryObject



128
129
130
131
132
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 128

def query
  @root_klass
   .joins(ordered_joins)
    .where(wheres)
end

#subquery_for_many_to_many_selectionsObject



119
120
121
122
123
124
125
126
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 119

def subquery_for_many_to_many_selections
  # Arel::Distinct.new(@rook_klasas[:id])
  @root_klass
    .from([@froms].flatten)
    .select(@root_table[:id])
    .joins(@joins.values)
    .where(@wheres.reduce(&:and))
end

#walk_selection_match_path(klass, node, parent_key, col_path) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 53

def walk_selection_match_path(klass, node, parent_key, col_path)
  # puts "klass: #{klass} node: #{node} parent_key #{parent_key.inspect} col_path #{col_path.inspect}"
  # pp [key, rest_col_path]
  key = if node.class == Class
          [@table_alias_prefix, node.to_s.underscore.pluralize].compact.join('_').to_sym
        else
          [@table_alias_prefix, parent_key, node].compact.join('_').to_sym
        end
  return node if node.class != Symbol && node.class != Class
  if !col_path.empty?
    # Create Arel Table Alias
    if node.class != Class
      relation = klass.reflections[node.to_s]
      klass = relation.klass
      @tables[key] = klass.arel_table.alias(key) unless @tables[key]
      # Create Join
      fk = relation.join_foreign_key
      pk = relation.join_primary_key
      join_on = @tables[key].create_on(@tables[parent_key][fk].eq(@tables[key][pk]))
      @joins[key] = @tables[parent_key].create_join(@tables[key], join_on, Arel::Nodes::OuterJoin)
    else
      klass = node
      unless @tables[key]
        @tables[key] = klass.arel_table.alias(key) unless @tables[key]
        @froms << @tables[key]
      end
    end
    # Recurse
    next_node, *rest = col_path
    return walk_selection_match_path(klass, next_node, key, rest)
  else
    # Return expression
    # puts "parent_key: #{node.to_sym}"
    # puts "node: #{node.to_sym}"
    return @tables[parent_key][node.to_sym]
  end
end

#wheresObject



108
109
110
111
112
113
114
115
116
117
# File 'lib/action_blocks/data_engine/selections_via_where_engine.rb', line 108

def wheres
  @wheres << @additional_where if @additional_where
  if @type == :many_to_many && (!@selection_match_reqs.empty? || !@selection_filter_reqs.empty?)
    subquery_arel = subquery_for_many_to_many_selections.arel
    # w = Arel::Nodes::In.new(@root_table[:id], subquery.ast)
    @root_table[:id].in(subquery_arel)
  else
    @wheres.reduce(&:and)
  end
end