References
Creating a Valkyrie based app
Create Rails app
rails new valkyrie_pg_demo --database=postgresql cd valkyrie_pg_demo
vi Gemfile # add gem 'valkyrie' and save bundle install --path=vendor/bundle
# Ignore vendor/cache /vendor/cache /vendor/bundle
Setup Postgres
Prerequisite: Installation of Postgres (for mac: Install Postgres with Homebrew; for windows: ???)
psql postgres create role _USER_NAME_ with login encrypted password '_PASSWORD_' createdb; create database valkyrie_pg_demo_development with owner _USER_NAME_ encoding 'utf8'; alter user _USER_NAME_ with SUPERUSER; \q vi config/database.yml # uncomment and set the following under development... database: valkyrie_pg_demo_development username: _USER_NAME_ as created in pg password: _PASSWORD_ as set in pg host: localhost port: 5432 bin/rails valkyrie_engine:install:migrations bin/rails db:migrate
Configure app to use Valkyrie with Postgres
Terminology
- metadata adapter
- provides access to persister and query service for a datasource (e.g. postgres, solr, etc.) See definitions for persister and query service under Test Direct Persistence
Valkyrie::MetadataAdapter.register( Valkyrie::Persistence::Postgres::MetadataAdapter.new, :postgres }
module ValkyriePgDemo def self.pg_persister Valkyrie::MetadataAdapter.find(:postgres).persister end def self.pg_query_service Valkyrie::MetadataAdapter.find(:postgres).query_service end end # prefixed with `pg_` to allow for easily adding methods for another adapter with different prefix (e.g. `solr_`)
Define Resources
Reference: Valkyrie Wiki (example resource | supported types | modifiers of type)
# frozen_string_literal: true class Book < Valkyrie::Resource attribute :title, Valkyrie::Types::Set # Set - de-duplicate values .of(Valkyrie::Types::String) # .of - restricts values to type String .meta(ordered: true) # .meta(ordered) - maintains order attribute :author, Valkyrie::Types::Set .of(Valkyrie::Types::String) .meta(ordered: true) attribute :series, Valkyrie::Types::String # single value with type String .optional # .optional - nil if not set attribute :member_ids, Valkyrie::Types::Array # Array - allows duplicate values .of(Valkyrie::Types::ID).optional # .of - restricts values to type end
NOTE: If member_ids was restricted to type Page, then the entire Page resource is saved with the Book resource.
# frozen_string_literal: true class Page < Valkyrie::Resource attribute :page_num, Valkyrie::Types::String.optional # single value that must be a String attribute :structure, Valkyrie::Types::String.optional attribute :image_id, Valkyrie::Types::ID.optional # ID of stored file for image end
Test Direct Persistence
Terminology
- persister
- provides methods for saving resources
- resources are passed to the persister
- see shared specs for list of methods and how they are expected to behave
- query service
- provides methods for finding resources
- see shared specs for list of methods and how they are expected to behave
In rails console...
book = Book.new(title: 'Free Fall', author: 'Robert Crais', series: 'Elvis Cole/Joe Pike') saved_book = ValkyriePgDemo.pg_persister.save(resource: book) book.id # nil book.persisted? # false # book object was NOT updated by the save method saved_book.id # #<Valkyrie::ID:0x00007faf9bb499a0 @id="ad494304-ca12-42d6-a28b-34e60d63fb92"> saved_book.persisted? true retrieved_book = ValkyriePgDemo.pg_query_service.find_by(id: saved_book.id) retrieved_book.persisted? #true retrieved_book.title # ['Free Fall'] retrieved_book.title = "Lullaby Town" retrieved_book.title # ["Lullaby Town"] retrieved_book.persisted? # true - persisted? indicated only that the resource exists in the database
id | metadata | created_at | updated_at | internal_resource | lock_version --------------------------------------+---------------------------------------------------------------------------------------------------------------+----------------------------+----------------------------+-------------------+-------------- c9f0e8e8-6814-4419-8640-066792e4b1ae | {"title": ["Free Fall"], "author": ["Robert Crais"], "series": ["Elvis Cole/Joe Pike"], "new_record": [true]} | 2019-12-02 18:58:39.833058 | 2019-12-02 18:58:39.833058 | Book |
In rails console...
page = Page.new(page_num: '1', structure: 'title page') page = ValkyriePgDemo.pg_persister.save(resource: page) book = ValkyriePgDemo.pg_query_service.find_all_of_model(model: Book).first book.member_ids = [page.id] book = ValkyriePgDemo.pg_persister.save(resource: book) child_pages = ValkyriePgDemo.pg_query_service.find_members(resource: book) child_pages.first.structure # ['title page']
id | metadata | created_at | updated_at | internal_resource | lock_version --------------------------------------+---------------------------------------------------------------------------------------------------------------+----------------------------+----------------------------+-------------------+-------------- 6c899645-80ef-402a-81e3-8cbe48712f06 | {"page_num": ["1"], "structure": ["title page"], "new_record": [true]} | 2019-12-02 22:13:23.521958 | 2019-12-02 22:13:23.521958 | Page | c9f0e8e8-6814-4419-8640-066792e4b1ae | {"title": ["Free Fall"], "author": ["Robert Crais"], "series": ["Elvis Cole/Joe Pike"], "member_ids": [{"id": "6c899645-80ef-402a-81e3-8cbe48712f06"}], "new_record": [false]} | 2019-12-02 22:11:59.430456 | 2019-12-02 22:13:53.898564 | Book |
Change Sets: Beyond here be dragons...
The discussion on Change Sets is under construction and possible wrong at this point.
Valkyrie in Hyrax
Define non-work resource
Defining resources is basically the same as for a non-Hyrax Valkyrie app. But it inherits from Hyrax::Resource instead of Valkyrie::Resource. In this case the resource is supporting and not part of the PCDM model.
# frozen_string_literal: true class CollectionType < Hyrax::Resource attribute :title, Valkyrie::Types::String attribute :description, Valkyrie::Types::String attribute :machine_id, Valkyrie::Types::ID end
Define work resource
# frozen_string_literal: true class Book < Hyrax::Work # Hyrax::Work isa Hyrax::Resource isa Valkyrie::Resource include Hyrax::Schema(:core_metadata) attribute :author, Valkyrie::Types::Set.of(Valkyrie::Types::String).meta(ordered: true) attribute :series, Valkyrie::Types::String.optional end
NOTE: This produces basically the same attribute definitions as those created for the Valkyrie app. The title attribute is defined by the Hyrax::Schema. The member_ids attribute is defined by Hyrax::Work.
NOTE: You could also use include Hyrax::Schema(:basic_metadata)
to use the default metadata defined by Hyrax instead of defining it all in the Book work.
Core and Basic metadata defined in... https://github.com/samvera/hyrax/tree/master/config/metadata
These are loaded using... https://github.com/samvera/hyrax/blob/master/app/services/hyrax/simple_schema_loader.rb
# frozen_string_literal: true class Page < Hyrax::Work include Hyrax::Schema(:core_metadata) attribute :page_num, Valkyrie::Types::String.optional attribute :structure, Valkyrie::Types::String.optional attribute :image_id, Valkyrie::Types::ID.optional end