-
Notifications
You must be signed in to change notification settings - Fork 23
Queries
Queries in Valkyrie are being added as they're needed for the logic of a digital repository, to better enable a wide array of inter-operable backend solutions. Currently, there are only seven that are supported by all adapters (shared spec):
Use Case: Re-indexing.
metadata_adapter.query_service.find_all # => [#<Book:0x007fe383479988>]
Use Case: Populate a collection drop-down with all available collections.
collection = metadata_adapter.persister.save(resource: Collection.new)
metadata_adapter.query_service.find_all_of_model(model: Collection) # => [collection]
Use Case: Finding an object for an item record page.
metadata_adapter.query_service.find_by(id: Valkyrie::ID.new("692ccfd5-414a-42f9-a8d5-c1605e7baef9"))
# => #<Book:0x007fe383479988
@id=#<Valkyrie::ID:0x007fe38353ac78 @id="692ccfd5-414a-42f9-a8d5-c1605e7baef9">,
@title=[],
@member_ids=[]>
Use Case: Retrieve a set of records for batch updating
[1] pry(main)> id_list = ["d0e66e56-83f0-48f4-9b44-6c921b65215a", "af32397f-33cc-4bb1-ac9b-7d1419e50234"]
[4] pry(main)> metadata_adapter.query_service.find_many_by_ids(ids: id_list)
#=> [
#<ScannedResource
id=#<Valkyrie::ID:0x00007fc559785890 @id="d0e66e56-83f0-48f4-9b44-6c921b65215a">
created_at="2019-10-22T21:31:17.194Z"
updated_at="2019-10-22T21:31:17.194Z"
title=["Curious Resource"]>,
#<ScannedResource id=#<Valkyrie::ID:0x00007fc55976f040
@id="af32397f-33cc-4bb1-ac9b-7d1419e50234">
internal_resource="ScannedResource"
created_at="2019-10-22T21:31:16.679Z"
title=["Culturally Significant Resource"]>
]
Use Case: Finding an object for an item record page, based on a ARK, DOI, or other kind of ID that isn't the Valkyrie ID.
metadata_adapter.query_service.find_by_alternate_identifier(alternate_identifier: "abc123"))
# => #<Book:0x007fe383479988
@id=#<Valkyrie::ID:0x007fe38353ac78 @id="692ccfd5-414a-42f9-a8d5-c1605e7baef9">,
@alternate_identifier=["abc123"],
@title=[],
@member_ids=[]>
Use Case: List all members on a record page.
child_book = metadata_adapter.persister.save(resource: Book.new)
parent_book = metadata_adapter.persister.save(resource: Book.new(member_ids: child_book.id))
metadata_adapter.query_service.find_members(resource: parent_book) # => [child_book]
Use Case: Clean-up parent associations when deleting a child.
child_book = metadata_adapter.persister.save(resource: Book.new)
parent_book = metadata_adapter.persister.save(resource: Book.new(member_ids: child_book.id))
metadata_adapter.query_service.find_parents(resource: child_book) # => [parent_book]
Use Case: Find associated objects by a property, but not in order.
referenced_book = metadata_adapter.persister.save(resource: Book.new)
book = metadata_adapter.persister.save(resource: Book.new(referenced_book_id:
referenced_book.id))
metadata_adapter.query_service.find_references_by(resource: book, property: :referenced_book_id) # => [referenced_book]
Use Case: Find everything that references me, so I can clean them up when being deleted.
referenced_book = metadata_adapter.persister.save(resource: Book.new)
book = metadata_adapter.persister.save(resource: Book.new(referenced_book_id:
referenced_book.id))
metadata_adapter.query_service.find_inverse_references_by(resource: referenced_book, property: :referenced_book_id) # => [book]
In order to add custom queries to Valkyrie, the queries themselves must be Classes which follow a number of conventions. Typically, a query is added into app/queries
for an Application, such as app/queries/find_by_my_query.rb
:
class FindByMyQuery
def self.queries
[:find_by_my_query]
end
attr_reader :query_service
delegate :resource_factory, to: :query_service
delegate :orm_class, to: :resource_factory
def initialize(query_service:)
@query_service = query_service
end
def find_by_my_query(my_value)
internal_array = "[\"#{my_value}\"]"
run_query(query, internal_array)
end
def query
<<-SQL
select * FROM orm_resources WHERE
metadata->'my_property' @> ?
SQL
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
end
In this example, FindByMyQuery
permits a query to be structured for PostgreSQL which queries for some arbitrary metadata property (my_property
). The value of this property is passed in the method identical to the Class name in the snake case find_by_my_query
, and the SQL query itself merely searches for an equal value in the resource metadata. Also note that this method name symbolized and exposed within an array returned from the Class method self.queries
. At this time, this structure is currently not enforced or validated.
With regards to how this is loaded into the query_service
, one must add or modify the following within config/initializers/valkyrie.rb
:
[FindByMyQuery].each do |query_handler|
Valkyrie.config.metadata_adapter.query_service.custom_queries.register_query_handler(query_handler)
end
Now, one can issue the query using the following invocation:
query_service.custom_queries.find_by_my_query("foo")
As with the standard queries outlined above, resource_factory
will ensure that elements in the result set are cast into the appropriate Valkyrie Resource
Class.