Class: Valkyrie::Persistence::Postgres::QueryService

Inherits:
Object
  • Object
show all
Defined in:
lib/valkyrie/persistence/postgres/query_service.rb

Overview

Query Service for the Postgres Metadata Adapter

Most queries are delegated through to the ActiveRecord model ORM::Resource

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(adapter:, resource_factory:) ⇒ QueryService

Returns a new instance of QueryService.

Parameters:


14
15
16
17
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 14

def initialize(adapter:, resource_factory:)
  @resource_factory = resource_factory
  @adapter = adapter
end

Instance Attribute Details

#adapterObject (readonly)

Returns the value of attribute adapter


10
11
12
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 10

def adapter
  @adapter
end

#resource_factoryObject (readonly)

Returns the value of attribute resource_factory


10
11
12
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 10

def resource_factory
  @resource_factory
end

Instance Method Details

#count_all_of_model(model:) ⇒ Object

Count all records for a specific resource type

Parameters:

  • model (Class)

Returns:

  • integer


41
42
43
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 41

def count_all_of_model(model:)
  orm_class.where(internal_resource: model.to_s).count
end

#custom_queriesValkyrie::Persistence::CustomQueryContainer

Constructs a Valkyrie::Persistence::CustomQueryContainer using this query service


248
249
250
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 248

def custom_queries
  @custom_queries ||= ::Valkyrie::Persistence::CustomQueryContainer.new(query_service: self)
end

#find_allArray<Valkyrie::Resource>

Retrieve all records for the resource and construct Valkyrie Resources

for each record

Returns:


22
23
24
25
26
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 22

def find_all
  orm_class.all.lazy.map do |orm_object|
    resource_factory.to_resource(object: orm_object)
  end
end

#find_all_of_model(model:) ⇒ Array<Valkyrie::Resource>

Retrieve all records for a specific resource type and construct Valkyrie

Resources for each record

Parameters:

  • model (Class)

Returns:


32
33
34
35
36
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 32

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

#find_by(id:) ⇒ Valkyrie::Resource

Find a record using a Valkyrie ID, and map it to a Valkyrie Resource

Parameters:

Returns:

Raises:


49
50
51
52
53
54
55
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 49

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

#find_by_alternate_identifier(alternate_identifier:) ⇒ Valkyrie::Resource

Find and a record using a Valkyrie ID for an alternate ID, and construct

a Valkyrie Resource

Parameters:

Returns:


61
62
63
64
65
66
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 61

def find_by_alternate_identifier(alternate_identifier:)
  alternate_identifier = Valkyrie::ID.new(alternate_identifier.to_s) if alternate_identifier.is_a?(String)
  validate_id(alternate_identifier)
  internal_array = "{\"alternate_ids\": [{\"id\": \"#{alternate_identifier}\"}]}"
  run_query(find_inverse_references_query, internal_array).first || raise(Valkyrie::Persistence::ObjectNotFoundError)
end

#find_inverse_references_by(resource: nil, id: nil, property:, model: nil) ⇒ Array<Valkyrie::Resource>

Get all resources which link to a resource with a given property.

Parameters:

  • resource (Valkyrie::Resource) (defaults to: nil)

    The resource which is being referenced by other resources. Requires either resource or id parameter to be specified.

  • id (Valkyrie::ID) (defaults to: nil)

    ID of the resource which is being reference by other resources. Requires either resource or id parameter to be specified.

  • property (Symbol)

    The property which, on other resources, is referencing the given `resource`

  • model (Class) (defaults to: nil)

    Filter results to include only instances of this model. (optional)

Returns:

  • (Array<Valkyrie::Resource>)

    All resources in the persistence backend which have the ID of the given `resource` in their `property` property. Not in order.

Raises:

  • (ArgumentError)

    Raised when the ID is not in the persistence backend.


116
117
118
119
120
121
122
123
124
125
126
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 116

def find_inverse_references_by(resource: nil, id: nil, property:, model: nil)
  raise ArgumentError, "Provide resource or id" unless resource || id
  ensure_persisted(resource) if resource
  id ||= resource.id
  internal_array = "{\"#{property}\": [{\"id\": \"#{id}\"}]}"
  if model
    run_query(find_inverse_references_with_type_query, internal_array, model)
  else
    run_query(find_inverse_references_query, internal_array)
  end
end

#find_inverse_references_queryString

Generate the SQL query for retrieving member resources in PostgreSQL using a

JSON object literal as an argument (e. g. { "alternate_ids": [{"id": "d6e88f80-41b3-4dbf-a2a0-cd79e20f6d10"}] }).

This uses JSON functions in order to retrieve JSON property values


181
182
183
184
185
186
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 181

def find_inverse_references_query
  <<-SQL
    SELECT * FROM orm_resources WHERE
    metadata @> ?
  SQL
end

#find_inverse_references_with_type_queryString

Generate the SQL query for retrieving member resources in PostgreSQL using a

JSON object literal (e. g. { "alternate_ids": [{"id": "d6e88f80-41b3-4dbf-a2a0-cd79e20f6d10"}] }).
and resource type as arguments

This uses JSON functions in order to retrieve JSON property values


195
196
197
198
199
200
201
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 195

def find_inverse_references_with_type_query
  <<-SQL
    SELECT * FROM orm_resources WHERE
    metadata @> ?
    AND internal_resource = ?
  SQL
end

#find_many_by_ids(ids:) ⇒ Array<Valkyrie::Resource>

Find records using a set of Valkyrie IDs, and map each to Valkyrie

Resources

Parameters:

Returns:


72
73
74
75
76
77
78
79
80
81
82
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 72

def find_many_by_ids(ids:)
  ids.map! do |id|
    id = Valkyrie::ID.new(id.to_s) if id.is_a?(String)
    validate_id(id)
    id.to_s
  end

  orm_class.where(id: ids).map do |orm_resource|
    resource_factory.to_resource(object: orm_resource)
  end
end

#find_members(resource:, model: nil) ⇒ Array<Valkyrie::Resource>

Find all member resources for a given Valkyrie Resource

Parameters:

Returns:


88
89
90
91
92
93
94
95
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 88

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

#find_members_queryString

Note:

this uses a CROSS JOIN for all combinations of member IDs with the IDs of their parents

Generate the SQL query for retrieving member resources in PostgreSQL using a

resource ID as an argument.

This also uses JSON functions in order to retrieve JSON property values


147
148
149
150
151
152
153
154
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 147

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

#find_members_with_type_queryString

Note:

this uses a CROSS JOIN for all combinations of member IDs with the IDs of their parents

Generate the SQL query for retrieving member resources in PostgreSQL using a

resource ID and resource type as arguments.

This also uses JSON functions in order to retrieve JSON property values


165
166
167
168
169
170
171
172
173
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 165

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

#find_ordered_references_queryObject


228
229
230
231
232
233
234
235
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 228

def find_ordered_references_query
  <<-SQL
    SELECT member.* FROM orm_resources a,
    jsonb_array_elements(a.metadata->?) 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

#find_ordered_references_with_type_queryObject


237
238
239
240
241
242
243
244
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 237

def find_ordered_references_with_type_query
  <<-SQL
    SELECT member.* FROM orm_resources a,
    jsonb_array_elements(a.metadata->?) 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

#find_parents(resource:) ⇒ Array<Valkyrie::Resource>

Find all parent resources for a given Valkyrie Resource

Parameters:

Returns:


100
101
102
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 100

def find_parents(resource:)
  find_inverse_references_by(resource: resource, property: :member_ids)
end

#find_references_by(resource:, property:, model: nil) ⇒ Array<Valkyrie::Resource>

Get all resources referenced from a resource with a given property.

Parameters:

  • resource (Valkyrie::Resource)

    Model whose property is being searched.

  • property (Symbol)

    Property which, on the `resource`, contains IDs which are to be de-referenced.

  • model (Class) (defaults to: nil)

    Filter results to include only instances of this model. (optional)

Returns:

  • (Array<Valkyrie::Resource>)

    All objects which are referenced by the `property` property on `resource`. Not necessarily in order.


105
106
107
108
109
110
111
112
113
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 105

def find_references_by(resource:, property:, model: nil)
  return [] if resource.id.blank? || resource[property].blank?
  # only return ordered if needed to avoid performance penalties
  if ordered_property?(resource: resource, property: property)
    find_ordered_references_by(resource: resource, property: property, model: model)
  else
    find_unordered_references_by(resource: resource, property: property, model: model)
  end
end

#find_references_queryString

Note:

this uses a CROSS JOIN for all combinations of member IDs with the IDs of their parents

Generate the SQL query for retrieving member resources in PostgreSQL using a

JSON object literal and resource ID as arguments.

This also uses JSON functions in order to retrieve JSON property values


212
213
214
215
216
217
218
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 212

def find_references_query
  <<-SQL
    SELECT DISTINCT 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

#find_references_with_type_queryObject


220
221
222
223
224
225
226
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 220

def find_references_with_type_query
  <<-SQL
    SELECT DISTINCT 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 = ? AND member.internal_resource = ?
  SQL
end

#run_query(query, *args) ⇒ Array<Valkyrie::Resource>

Execute a query in SQL for resource records and map them to Valkyrie

Resources

Parameters:

  • query (String)

Returns:


132
133
134
135
136
# File 'lib/valkyrie/persistence/postgres/query_service.rb', line 132

def run_query(query, *args)
  orm_class.find_by_sql(([query] + args)).lazy.map do |object|
    resource_factory.to_resource(object: object)
  end
end