Module: Refine::FlatQueryTools

Defined in:
app/models/refine/flat_query_tools.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#applied_conditions ⇒ Object

Returns the value of attribute applied_conditions.



6
7
8
# File 'app/models/refine/flat_query_tools.rb', line 6

def applied_conditions
  @applied_conditions
end

#needs_distinct ⇒ Object

Returns the value of attribute needs_distinct.



6
7
8
# File 'app/models/refine/flat_query_tools.rb', line 6

def needs_distinct
  @needs_distinct
end

#pending_joins ⇒ Object

Returns the value of attribute pending_joins.



6
7
8
# File 'app/models/refine/flat_query_tools.rb', line 6

def pending_joins
  @pending_joins
end

Instance Method Details

#apply_flat_condition(criterion) ⇒ Object

Same as Filter.apply_condition but uses supports_flat_queries helpers instead of default path



74
75
76
77
78
79
80
81
82
# File 'app/models/refine/flat_query_tools.rb', line 74

def apply_flat_condition(criterion)
  begin
    get_condition_for_criterion(criterion)&.apply_flat(criterion[:input], table, initial_query, false)
  rescue Refine::Conditions::Errors::ConditionClauseError => e
    e.errors.each do |error|
      errors.add(:base, error.full_message, criterion_uid: criterion[:uid])
    end
  end
end

#apply_pending_joins ⇒ Object

Called at the end of the filter's construct_flat_query. Applies joins from pending_joins hash constructed by individual conditions



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/models/refine/flat_query_tools.rb', line 85

def apply_pending_joins
  if pending_joins.present?
    join_count = 0
    pending_joins.each do |relation, join_data|
      if join_data[:type] == :left
        @relation = @relation.left_joins(join_data[:joins_block]).distinct
      else
        @relation = @relation.joins(join_data[:joins_block]).distinct
      end
      join_count += 1
    end
  end
end

#can_use_flat_query? ⇒ Boolean

Meant to be overridden by Filter classes to add or replace with custom logic

Returns:

  • (Boolean)


113
114
115
# File 'app/models/refine/flat_query_tools.rb', line 113

def can_use_flat_query?
  !uses_or? && !uses_negative_clause? && !has_duplicate_conditions?
end

#condition_already_applied?(criterion) ⇒ Boolean

Returns:

  • (Boolean)


107
108
109
110
# File 'app/models/refine/flat_query_tools.rb', line 107

def condition_already_applied?(criterion)
  applied_conditions[criterion[:condition_id]] && 
    applied_conditions[criterion[:condition_id]].include?(criterion[:input])
end

#construct_flat_query ⇒ Object

This iterates through each blueprint item and applies the conditions. It is meant to be idempotent hence it checks for already applied conditions



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'app/models/refine/flat_query_tools.rb', line 38

def construct_flat_query
  groups = []
  blueprint.each do |criteria_or_conjunction|
    if criteria_or_conjunction[:type] == "conjunction"
      if criteria_or_conjunction[:word] == "or"
        puts "This is an OR"
        # Reset applied conditions since we're in a new group
        @applied_conditions = {}
      end
    else
      unless condition_already_applied?(criteria_or_conjunction)
        node = apply_flat_condition(criteria_or_conjunction)
        if node.is_a?(Arel::Nodes::Grouping)
          @relation = @relation.where(node)
        elsif node.is_a?(Array)
          error = node.filter{ |n| n.is_a?(ActiveModel::Error) }.first
          if error
            filter.errors.add(:base, error.full_message)
          end
        else
          @relation = @relation.where(Arel::Nodes::Grouping.new(node))
        end
        track_condition_applied(criteria_or_conjunction)
      end
    end
  end
  if pending_joins.present?
    apply_pending_joins
  end
  if needs_distinct?
    @relation = @relation.distinct
  end
  @relation
end

#get_flat_query ⇒ Object



20
21
22
23
24
25
26
27
28
# File 'app/models/refine/flat_query_tools.rb', line 20

def get_flat_query
  raise "Initial query must exist" if initial_query.nil?
  raise "Cannot make flat query for a filter using OR conditions" if uses_or?
  if blueprint.present?
    construct_flat_query
  else
    @relation
  end
end

#get_flat_query! ⇒ Object



30
31
32
33
34
# File 'app/models/refine/flat_query_tools.rb', line 30

def get_flat_query!
  result = get_flat_query
  raise Refine::InvalidFilterError.new(filter: self) unless errors.none?
  result
end

#needs_distinct? ⇒ Boolean

Returns:

  • (Boolean)


16
17
18
# File 'app/models/refine/flat_query_tools.rb', line 16

def needs_distinct?
  @needs_distinct ||= false
end

#track_condition_applied(criterion) ⇒ Object



99
100
101
102
103
104
105
# File 'app/models/refine/flat_query_tools.rb', line 99

def track_condition_applied(criterion)
  if applied_conditions[criterion[:condition_id]].nil?
    applied_conditions[criterion[:condition_id]] = [criterion[:input]]
  else
    applied_conditions[criterion[:condition_id]] << criterion[:input]
  end
end