-
Notifications
You must be signed in to change notification settings - Fork 0
/
query_relation.rb
114 lines (94 loc) · 3.22 KB
/
query_relation.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
52
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# frozen_string_literal: true
module Dragnet
module DataGrid
class QueryRelation
include Dragnet
prepend Memoizable
attr_reader :sort_by, :sort_direction, :filter_by
def initialize(base_relation, params)
@base_relation = base_relation
@sort_by, @sort_direction, @filter_by =
params.values_at(:sort_by, :sort_direction, :filter_by)
end
# @return [ActiveRecord::Relation<Reply>]
def build
ordered_records(filtered_records(@base_relation))
end
private
attr_writer :join_alias_index
def join_alias_index
@join_alias_index ||= 0
end
def next_join_alias
"answers_#{join_alias_index}".tap do
self.join_alias_index += 1
end
end
def join_aliases
filter_by.each_with_object({}) do |(field, _), aliases|
aliases[field] = next_join_alias if uuid?(field)
end
end
memoize :join_aliases
def join_alias(question_id)
join_aliases.fetch(question_id) do
raise "unknown join alias for `#{question_id}`"
end
end
def no_joins?
join_aliases.count.zero?
end
def sort_by_question?
uuid?(sort_by)
end
def ordered_records(scope)
if !sort_by_question?
scope.order(sort_by => sort_direction)
else
question = Question.includes(:question_type).find(sort_by)
sorted_records(question, sorting_scope(scope, question))
end
end
def sorting_scope(scope, question)
if no_joins?
scope.joins(:answers).where(answers: { question_id: question.id })
else
join_name = next_join_alias
join_aliases[:sorting] = join_name
scope
.joins(Arel.sql("inner join answers #{join_name} on replies.id = #{join_name}.reply_id"))
.where(join_name => { question_id: question.id })
end
end
def sorted_records(question, scope)
Perspectives::DataGridSortQuery
.get(question.question_type)
.sort(question, scope, sort_direction, join_aliases.fetch(:sorting, :answers))
end
SIMPLE_FILTER_ATTRIBUTES = %i[created_at user_id].to_set.freeze
private_constant :SIMPLE_FILTER_ATTRIBUTES
def filtered_records(scope)
return scope if filter_by.empty?
filter_by.reduce(scope) do |current_scope, (field, value)|
if SIMPLE_FILTER_ATTRIBUTES.include?(field)
current_scope.where(field => value)
elsif question?(field)
join_name = join_alias(field)
narrowed = narrowed_scope(current_scope, field, join_name)
filtered_values(narrowed, question(field), join_name, value)
else
current_scope
end
end
end
def narrowed_scope(scope, field, join_name)
scope
.joins(Arel.sql("inner join answers #{join_name} on replies.id = #{join_name}.reply_id"))
.where(join_name => { question_id: field })
end
def filtered_values(scope, question, table, value)
Perspectives::DataGridFilterQuery.get(question.question_type).filter(question, scope, table, value)
end
end
end
end