Skip to content

Commit

Permalink
Merge pull request #4810 from sul-dlss/add-methods-repo-object#4789
Browse files Browse the repository at this point in the history
Update the opened repository object version with values from Cocina instance
  • Loading branch information
justinlittman authored Apr 9, 2024
2 parents cb875f1 + 2bfbca3 commit 4e25704
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 2 deletions.
6 changes: 6 additions & 0 deletions app/models/repository_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ def current_scope_prefix
end
end

# @param [Cocina::Models::DRO, Cocina::Models::Collection, Cocina::Models::AdminPolicy] cocina_object a Cocina
# model instance, either a DRO, collection, or APO.
def update_opened_version_from(cocina_object:)
opened_version.update!(**RepositoryObjectVersion.to_model_hash(cocina_object))
end

def open_version!
raise VersionAlreadyOpened, "Cannot open new version because one is already open: #{head_version.version}" if open?

Expand Down
21 changes: 21 additions & 0 deletions app/models/repository_object_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,25 @@ class RepositoryObjectVersion < ApplicationRecord
scope :members_of_collection, ->(collection_druid) { where("structural -> 'isMemberOf' ? :druid", druid: collection_druid) }

validates :version, :version_description, presence: true

# @param [Cocina::Models::DRO, Cocina::Models::Collection, Cocina::Models::AdminPolicy] cocina_object a Cocina
# model instance, either a DRO, collection, or APO.
# @return [Hash] Hash representation of a Cocina object suitable to be passed to an object type-specific AR update
def self.to_model_hash(cocina_object)
cocina_object
.to_h
.except(:externalIdentifier, :version)
.tap do |object_hash|
object_hash[:cocina_version] = object_hash.delete(:cocinaVersion)
if cocina_object.dro?
object_hash[:content_type] = object_hash.delete(:type)
object_hash[:geographic] ||= nil
elsif cocina_object.collection?
object_hash[:content_type] = object_hash.delete(:type)
elsif cocina_object.admin_policy?
object_hash.delete(:type)
object_hash[:description] ||= nil
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class ChangeRepositoryObjectVersionCocinaVersionToString < ActiveRecord::Migration[7.1]
def change
change_column :repository_object_versions, :cocina_version, :string
end
end
4 changes: 2 additions & 2 deletions db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ CREATE TABLE public.repository_object_versions (
repository_object_id bigint NOT NULL,
version integer NOT NULL,
version_description character varying NOT NULL,
cocina_version integer,
cocina_version character varying,
content_type character varying,
label character varying,
access jsonb,
Expand Down Expand Up @@ -923,6 +923,7 @@ ALTER TABLE ONLY public.repository_objects
SET search_path TO "$user", public;

INSERT INTO "schema_migrations" (version) VALUES
('20240408230311'),
('20240408184127'),
('20240402155058'),
('20240328144814'),
Expand Down Expand Up @@ -952,4 +953,3 @@ INSERT INTO "schema_migrations" (version) VALUES
('20191209192646'),
('20191015193638'),
('20190917215521');

18 changes: 18 additions & 0 deletions spec/models/repository_object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,22 @@
end
end
end

describe '#update_opened_version_from' do
subject(:repository_object) { create(:repository_object, **attrs) }

let(:cocina_object) { build(:dro) }

it 'updates the opened version using a object type-specific Cocina hash' do
expect { repository_object.update_opened_version_from(cocina_object:) }
.to change(repository_object.opened_version, :cocina_version).from(nil).to(Cocina::Models::VERSION)
.and change(repository_object.opened_version, :content_type).from(nil).to(Cocina::Models::ObjectType.object)
.and change(repository_object.opened_version, :label).from(nil).to('factory DRO label')
.and change(repository_object.opened_version, :access).from(nil).to(instance_of(Hash))
.and change(repository_object.opened_version, :administrative).from(nil).to(instance_of(Hash))
.and change(repository_object.opened_version, :description).from(nil).to(instance_of(Hash))
.and change(repository_object.opened_version, :identification).from(nil).to(instance_of(Hash))
.and change(repository_object.opened_version, :structural).from(nil).to(instance_of(Hash))
end
end
end
56 changes: 56 additions & 0 deletions spec/models/repository_object_version_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,60 @@
end
end
end

describe '.to_model_hash' do
subject(:model_hash) { described_class.to_model_hash(cocina_instance) }

let(:cocina_instance) { build(cocina_object_type) }

context 'with a DRO' do
let(:cocina_object_type) { :dro }

it { is_expected.to be_a(Hash) }
it { is_expected.not_to include(:externalIdentifier) }
it { is_expected.not_to include(:version) }
it { is_expected.to include(cocina_version: Cocina::Models::VERSION) }
it { is_expected.to include(content_type: Cocina::Models::ObjectType.object) }
it { is_expected.to include(geographic: nil) }

context 'with geographic metadata' do
let(:cocina_instance) do
build(:dro).new(geographic: { iso19139: 'some gross XML string' })
end

it { is_expected.to include(geographic: { iso19139: 'some gross XML string' }) }
end
end

context 'with a collection' do
let(:cocina_object_type) { :collection }

it { is_expected.to be_a(Hash) }
it { is_expected.not_to include(:externalIdentifier) }
it { is_expected.not_to include(:version) }
it { is_expected.to include(cocina_version: Cocina::Models::VERSION) }
it { is_expected.to include(content_type: Cocina::Models::ObjectType.collection) }
end

context 'with an admin policy' do
let(:cocina_object_type) { :admin_policy }

it { is_expected.to be_a(Hash) }
it { is_expected.not_to include(:externalIdentifier) }
it { is_expected.not_to include(:version) }
it { is_expected.to include(cocina_version: Cocina::Models::VERSION) }
it { is_expected.not_to include(:content_type) }
it { is_expected.to include(description: hash_including(:title)) }

context 'with no description' do
let(:cocina_instance) do
# NOTE: The cocina-models factories (as of v0.96.0) don't seem to
# provide a better way to build an APO sans description.
Cocina::Models::AdminPolicy.new(build(:admin_policy).to_h.except(:description))
end

it { is_expected.to include(description: nil) }
end
end
end
end

0 comments on commit 4e25704

Please sign in to comment.