From 2bfbca3135516dfaf8bd4251c739cc7f8c39d549 Mon Sep 17 00:00:00 2001 From: "Michael J. Giarlo" Date: Mon, 8 Apr 2024 16:14:01 -0700 Subject: [PATCH] Update the opened repository object version with values from Cocina instance Fixes #4789 --- app/models/repository_object.rb | 6 ++ app/models/repository_object_version.rb | 21 +++++++ ...object_version_cocina_version_to_string.rb | 5 ++ db/structure.sql | 4 +- spec/models/repository_object_spec.rb | 18 ++++++ spec/models/repository_object_version_spec.rb | 56 +++++++++++++++++++ 6 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240408230311_change_repository_object_version_cocina_version_to_string.rb diff --git a/app/models/repository_object.rb b/app/models/repository_object.rb index 420499533..7549ff0fa 100644 --- a/app/models/repository_object.rb +++ b/app/models/repository_object.rb @@ -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? diff --git a/app/models/repository_object_version.rb b/app/models/repository_object_version.rb index 3187efd4b..70e33ea1a 100644 --- a/app/models/repository_object_version.rb +++ b/app/models/repository_object_version.rb @@ -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 diff --git a/db/migrate/20240408230311_change_repository_object_version_cocina_version_to_string.rb b/db/migrate/20240408230311_change_repository_object_version_cocina_version_to_string.rb new file mode 100644 index 000000000..e22dc7e7c --- /dev/null +++ b/db/migrate/20240408230311_change_repository_object_version_cocina_version_to_string.rb @@ -0,0 +1,5 @@ +class ChangeRepositoryObjectVersionCocinaVersionToString < ActiveRecord::Migration[7.1] + def change + change_column :repository_object_versions, :cocina_version, :string + end +end diff --git a/db/structure.sql b/db/structure.sql index 6dd938a2e..acb450ad0 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -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, @@ -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'), @@ -952,4 +953,3 @@ INSERT INTO "schema_migrations" (version) VALUES ('20191209192646'), ('20191015193638'), ('20190917215521'); - diff --git a/spec/models/repository_object_spec.rb b/spec/models/repository_object_spec.rb index ebbb97bd1..2343957de 100644 --- a/spec/models/repository_object_spec.rb +++ b/spec/models/repository_object_spec.rb @@ -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 diff --git a/spec/models/repository_object_version_spec.rb b/spec/models/repository_object_version_spec.rb index 0510f646c..0d9a2340c 100644 --- a/spec/models/repository_object_version_spec.rb +++ b/spec/models/repository_object_version_spec.rb @@ -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