-
Notifications
You must be signed in to change notification settings - Fork 23
/
query_service.rb
116 lines (100 loc) · 3.71 KB
/
query_service.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
115
116
# frozen_string_literal: true
module Valkyrie::Persistence::Postgres
class QueryService
attr_reader :adapter
delegate :resource_factory, to: :adapter
delegate :orm_class, to: :resource_factory
def initialize(adapter:)
@adapter = adapter
end
# (see Valkyrie::Persistence::Memory::QueryService#find_all)
def find_all
orm_class.all.lazy.map do |orm_object|
resource_factory.to_resource(object: orm_object)
end
end
# (see Valkyrie::Persistence::Memory::QueryService#find_all_of_model)
def find_all_of_model(model:)
orm_class.where(internal_resource: model.to_s).lazy.map do |orm_object|
resource_factory.to_resource(object: orm_object)
end
end
# (see Valkyrie::Persistence::Memory::QueryService#find_by)
def find_by(id:)
id = Valkyrie::ID.new(id.to_s) if id.is_a?(String)
validate_id(id)
resource_factory.to_resource(object: orm_class.find(id.to_s))
rescue ActiveRecord::RecordNotFound
raise Valkyrie::Persistence::ObjectNotFoundError
end
# (see Valkyrie::Persistence::Memory::QueryService#find_members)
def find_members(resource:, model: nil)
return [] if resource.id.blank?
if model
run_query(find_members_with_type_query, resource.id.to_s, model.to_s)
else
run_query(find_members_query, resource.id.to_s)
end
end
# (see Valkyrie::Persistence::Memory::QueryService#find_parents)
def find_parents(resource:)
find_inverse_references_by(resource: resource, property: :member_ids)
end
# (see Valkyrie::Persistence::Memory::QueryService#find_references_by)
def find_references_by(resource:, property:)
return [] if resource.id.blank? || resource[property].blank?
run_query(find_references_query, property, resource.id.to_s)
end
# (see Valkyrie::Persistence::Memory::QueryService#find_inverse_references_by)
def find_inverse_references_by(resource:, property:)
validate_id resource.id
internal_array = "{\"#{property}\": [{\"id\": \"#{resource.id}\"}]}"
run_query(find_inverse_references_query, internal_array)
end
def run_query(query, *args)
orm_class.find_by_sql(([query] + args)).lazy.map do |object|
resource_factory.to_resource(object: object)
end
end
def find_members_query
<<-SQL
SELECT member.* FROM orm_resources a,
jsonb_array_elements(a.metadata->'member_ids') WITH ORDINALITY AS b(member, member_pos)
JOIN orm_resources member ON (b.member->>'id')::#{id_type} = member.id WHERE a.id = ?
ORDER BY b.member_pos
SQL
end
def find_members_with_type_query
<<-SQL
SELECT member.* FROM orm_resources a,
jsonb_array_elements(a.metadata->'member_ids') WITH ORDINALITY AS b(member, member_pos)
JOIN orm_resources member ON (b.member->>'id')::#{id_type} = member.id WHERE a.id = ?
AND member.internal_resource = ?
ORDER BY b.member_pos
SQL
end
def find_inverse_references_query
<<-SQL
SELECT * FROM orm_resources WHERE
metadata @> ?
SQL
end
def find_references_query
<<-SQL
SELECT member.* FROM orm_resources a,
jsonb_array_elements(a.metadata->?) AS b(member)
JOIN orm_resources member ON (b.member->>'id')::#{id_type} = member.id WHERE a.id = ?
SQL
end
def custom_queries
@custom_queries ||= ::Valkyrie::Persistence::CustomQueryContainer.new(query_service: self)
end
private
def validate_id(id)
raise ArgumentError, 'id must be a Valkyrie::ID' unless id.is_a? Valkyrie::ID
end
def id_type
@id_type ||= orm_class.columns_hash["id"].type
end
end
end