Skip to content

Commit

Permalink
Cache virtual object membership
Browse files Browse the repository at this point in the history
This is required for adding relatedItem entries on the public xml.
Fixes #585
  • Loading branch information
jcoyne committed Mar 30, 2023
1 parent 3d975ea commit 1f0c931
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 46 deletions.
9 changes: 9 additions & 0 deletions app/models/cocina_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ def collections
cocina_object.dro? ? cocina_object.structural.isMemberOf : []
end

# Find virtual objects in argo via:
# https://argo-stage.stanford.edu/catalog?f%5Bhas_constituents_ssim%5D%5B%5D=has_constituents
# @return [Array<String>] The members of this virtual object
def virtual_object_constituents
return [] unless cocina_object.dro? && cocina_object.structural.hasMemberOrders.present?

cocina_object.structural.hasMemberOrders.first.members
end

private

# from https://github.com/sul-dlss/dor-services-app/blob/f51bbcea710b7612f251a3922c5164ec69ba39aa/app/services/publish/public_xml_service.rb#L99
Expand Down
1 change: 1 addition & 0 deletions app/models/purl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ class Purl < ApplicationRecord
has_and_belongs_to_many :collections
has_many :release_tags, dependent: :destroy
has_one :public_xml, dependent: :destroy
has_many :virtual_object_constituents, dependent: :destroy

accepts_nested_attributes_for :public_xml, update_only: true
paginates_per 100
Expand Down
4 changes: 4 additions & 0 deletions app/models/virtual_object_constituent.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class VirtualObjectConstituent < ApplicationRecord
default_scope { order(ordinal: :asc) }
belongs_to :purl
end
7 changes: 6 additions & 1 deletion app/services/purl_cocina_updater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def initialize(active_record, cocina_object)

attr_reader :active_record, :cocina_data

delegate :collections, :releases, to: :cocina_data
delegate :collections, :releases, :virtual_object_constituents, to: :cocina_data

def attributes
{
Expand All @@ -30,6 +30,11 @@ def update
# public xml
active_record.refresh_collections(collections)

active_record.virtual_object_constituents = []
virtual_object_constituents.each.with_index do |member, i|
active_record.virtual_object_constituents.build(has_member: member, ordinal: i)
end

# add the release tags, and reuse tags if already associated with this PURL
active_record.refresh_release_tags(releases)

Expand Down
12 changes: 12 additions & 0 deletions db/migrate/20230330202410_create_virtual_object_constituents.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateVirtualObjectConstituents < ActiveRecord::Migration[7.0]
def change
create_table :virtual_object_constituents do |t|
t.references :purl, null: false, foreign_key: true
t.string :has_member, null: false, index: true
t.integer :ordinal, null: false
t.index [:purl_id, :has_member], unique: true
t.index [:purl_id, :ordinal], unique: true
t.timestamps
end
end
end
58 changes: 35 additions & 23 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2022_01_03_184105) do

ActiveRecord::Schema[7.0].define(version: 2023_03_30_202410) do
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.integer "record_id", null: false
t.integer "blob_id", null: false
t.datetime "created_at", precision: 6, null: false
t.bigint "record_id", null: false
t.bigint "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
Expand All @@ -30,20 +29,20 @@
t.string "service_name", null: false
t.integer "byte_size", null: false
t.string "checksum"
t.datetime "created_at", precision: 6, null: false
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end

create_table "active_storage_variant_records", force: :cascade do |t|
t.integer "blob_id", null: false
t.bigint "blob_id", null: false
t.string "variation_digest", null: false
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end

create_table "collections", force: :cascade do |t|
t.string "druid", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.index ["druid"], name: "index_collections_on_druid", unique: true
end

Expand All @@ -56,30 +55,30 @@

create_table "listener_logs", force: :cascade do |t|
t.integer "process_id", null: false
t.datetime "started_at", precision: 6, null: false
t.datetime "active_at", precision: 6
t.datetime "ended_at", precision: 6
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.datetime "started_at", precision: nil, null: false
t.datetime "active_at", precision: nil
t.datetime "ended_at", precision: nil
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.index ["process_id"], name: "index_listener_logs_on_process_id"
t.index ["started_at"], name: "index_listener_logs_on_started_at"
end

create_table "public_xmls", force: :cascade do |t|
t.integer "purl_id"
t.binary "data"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.binary "data", limit: 16777216
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["purl_id"], name: "index_public_xmls_on_purl_id"
end

create_table "purls", force: :cascade do |t|
t.string "druid", null: false
t.string "object_type"
t.datetime "deleted_at", precision: 6
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.datetime "published_at", precision: 6
t.datetime "deleted_at", precision: nil
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.datetime "published_at", precision: nil
t.text "title"
t.string "catkey"
t.index ["deleted_at"], name: "index_purls_on_deleted_at"
Expand All @@ -94,13 +93,26 @@
t.string "name", null: false
t.boolean "release_type", null: false
t.integer "purl_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.index ["name", "purl_id"], name: "index_release_tags_on_name_and_purl_id", unique: true
t.index ["purl_id"], name: "index_release_tags_on_purl_id"
t.index ["release_type"], name: "index_release_tags_on_release_type"
end

create_table "virtual_object_constituents", force: :cascade do |t|
t.integer "purl_id", null: false
t.string "has_member", null: false
t.integer "ordinal", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["has_member"], name: "index_virtual_object_constituents_on_has_member"
t.index ["purl_id", "has_member"], name: "index_virtual_object_constituents_on_purl_id_and_has_member", unique: true
t.index ["purl_id", "ordinal"], name: "index_virtual_object_constituents_on_purl_id_and_ordinal", unique: true
t.index ["purl_id"], name: "index_virtual_object_constituents_on_purl_id"
end

add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "virtual_object_constituents", "purls"
end
87 changes: 66 additions & 21 deletions spec/consumers/purl_updates_consumer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,75 @@
let(:message) { instance_double(Racecar::Message, value: message_value) }
let!(:purl_object) { create(:purl) }

let(:message_value) do
build(:dro, id: purl_object.druid,
title: "The Information Paradox for Black Holes",
collection_ids: ['druid:xb432gf1111'])
.new(administrative: {
hasAdminPolicy: "druid:hv992ry2431",
releaseTags: [
{ to: 'Searchworks', release: true },
{ to: 'Earthworks', release: false }
]
})
.to_json
end

before do
described_class.new.process(message)
end

it "updates the purl record with the provided data" do
purl_object.reload
expect(purl_object.title).to eq "The Information Paradox for Black Holes"
expect(purl_object.true_targets).to eq ["Searchworks", "SearchWorksPreview", "ContentSearch"]
expect(purl_object.false_targets).to eq ['Earthworks']
expect(purl_object.collections.size).to eq 1
expect(purl_object.collections.first.druid).to eq 'druid:xb432gf1111'
context 'with a DRO' do
let(:message_value) do
build(:dro, id: purl_object.druid,
title: "The Information Paradox for Black Holes",
collection_ids: ['druid:xb432gf1111'])
.new(administrative: {
hasAdminPolicy: "druid:hv992ry2431",
releaseTags: [
{ to: 'Searchworks', release: true },
{ to: 'Earthworks', release: false }
]
})
.to_json
end

it "updates the purl record with the provided data" do
purl_object.reload
expect(purl_object.title).to eq "The Information Paradox for Black Holes"
expect(purl_object.true_targets).to eq ["Searchworks", "SearchWorksPreview", "ContentSearch"]
expect(purl_object.false_targets).to eq ['Earthworks']
expect(purl_object.collections.size).to eq 1
expect(purl_object.collections.first.druid).to eq 'druid:xb432gf1111'
end
end

context 'with a virtual object' do
let(:message_value) do
build(:dro, id: purl_object.druid, title: "The Information Paradox for Black Holes")
.new(administrative: {
hasAdminPolicy: "druid:hv992ry2431",
releaseTags: [
{ to: 'Searchworks', release: true },
{ to: 'Earthworks', release: false }
]
},
structural: {
isMemberOf: ['druid:xb432gf1111'],
hasMemberOrders: [{
members: [
'druid:kq126jw7402',
'druid:cv761kr7119',
'druid:kn300wd1779',
'druid:rz617vr4473',
'druid:sd322dt2118',
'druid:hp623ch4433',
'druid:sq217qj5005',
'druid:vd823mb5658',
'druid:zp230ft8517',
'druid:xx933wk5286',
'druid:qf828rv2163'
]
}]
})
.to_json
end

it "updates the purl record with the provided data" do
purl_object.reload
expect(purl_object.title).to eq "The Information Paradox for Black Holes"
expect(purl_object.true_targets).to eq ["Searchworks", "SearchWorksPreview", "ContentSearch"]
expect(purl_object.false_targets).to eq ['Earthworks']
expect(purl_object.collections.size).to eq 1
expect(purl_object.collections.first.druid).to eq 'druid:xb432gf1111'
expect(purl_object.virtual_object_constituents.first.has_member).to eq 'druid:kq126jw7402'
expect(purl_object.virtual_object_constituents.size).to eq 11
end
end
end
2 changes: 1 addition & 1 deletion spec/factories/purl.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FactoryBot.define do
factory :purl do
sequence :druid do |n|
"druid:zz#{n.to_s * 3}yy#{n.to_s * 4}"
"druid:zz#{"%03d" % rand(1000)}yy#{"%04d" % rand(10000)}"
end
end
end

0 comments on commit 1f0c931

Please sign in to comment.