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
|
# File 'lib/graphql/models/loader.rb', line 10
def perform(load_requests)
relations = []
id_requests = load_requests.select { |r| r.load_type == :id }
id_relation = model_class.where(id: id_requests.map(&:load_target))
relations.push(id_relation) if id_requests.any?
relations_to_requests = {}
load_requests.select { |r| r.load_type == :relation }.each do |request|
relation = request.load_target
relations.push(relation) unless relations.detect { |r| r.object_id == relation.object_id }
relations_to_requests[relation.object_id] ||= []
relations_to_requests[relation.object_id].push(request)
end
selection_clauses = relations.map do |relation|
relation.unscope(:select).select(model_class.primary_key).to_sql
end
slicing_columns = relations.each_with_index.map do |relation, index|
%{ CASE WHEN "#{model_class.table_name}"."#{model_class.primary_key}" IN (#{selection_clauses[index]}) THEN 1 ELSE 0 END AS "in_relation_#{index}" }
end
sorting_columns = relations.each_with_index.map do |relation, index|
arel = relation.arel
next nil unless arel.orders.any?
order_by = arel.orders.map do |expr|
if expr.is_a?(Arel::Nodes::SqlLiteral)
expr.to_s
else
expr.to_sql
end
end
%{ RANK() OVER (ORDER BY #{order_by.join(', ')}) AS "sort_relation_#{index}" }
end
sorting_columns.compact!
main_relation = model_class
.where("id in ((#{selection_clauses.join(") UNION (")}))")
.select(%{ "#{model_class.table_name}".* })
main_relation = slicing_columns.reduce(main_relation) { |relation, memo| relation.select(memo) }
main_relation = sorting_columns.reduce(main_relation) { |relation, memo| relation.select(memo) }
result = main_relation.to_a
relations.each_with_index do |relation, index|
slice_col = "in_relation_#{index}"
sort_col = "sort_relation_#{index}"
matching_rows = result.select { |r| r[slice_col] == 1 }.sort_by { |r| r[sort_col] }
if relation.object_id == id_relation.object_id
pk = relation.klass.primary_key
id_requests.each do |request|
row = matching_rows.detect { |r| r[pk] == request.load_target }
fulfill(request, row)
end
else
relations_to_requests[relation.object_id].each do |request|
fulfill_request(request, matching_rows)
end
end
end
end
|