Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wings reflections handling #6298

Merged
merged 3 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions lib/wings/attribute_transformer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,36 @@ def self.for(obj)
end
end

def self.run(obj) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
attrs = obj.reflections.each_with_object({}) do |(key, reflection), mem|
def self.run(obj) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
attrs = obj.reflections.each_with_object({}) do |(key, reflection), mem| # rubocop:disable Metrics/BlockLength
case reflection
when ActiveFedora::Reflection::HasManyReflection,
ActiveFedora::Reflection::HasAndBelongsToManyReflection,
ActiveFedora::Reflection::IndirectlyContainsReflection
mem[:"#{key.to_s.singularize}_ids"] =
obj.association(key).ids_reader
when ActiveFedora::Reflection::DirectlyContainsReflection
mem[:"#{key.to_s.singularize}_ids"] =
Array(obj.public_send(reflection.name)).map(&:id)
when ActiveFedora::Reflection::FilterReflection,
ActiveFedora::Reflection::OrdersReflection,
ActiveFedora::Reflection::HasSubresourceReflection,
ActiveFedora::Reflection::BelongsToReflection,
ActiveFedora::Reflection::BasicContainsReflection
when ActiveFedora::Reflection::BelongsToReflection, # uses foreign_key SingularRDFPropertyReflection
ActiveFedora::Reflection::BasicContainsReflection, # ???
ActiveFedora::Reflection::FilterReflection, # rely on :extending_from
ActiveFedora::Reflection::HasAndBelongsToManyReflection, # uses foreign_key RDFPropertyReflection
ActiveFedora::Reflection::HasManyReflection, # captured by inverse relation
ActiveFedora::Reflection::HasSubresourceReflection, # ???
:noop
when ActiveFedora::Reflection::OrdersReflection
mem[:"#{reflection.options[:unordered_reflection].name.to_s.singularize}_ids"] ||= []
mem[:"#{reflection.options[:unordered_reflection].name.to_s.singularize}_ids"] +=
obj.association(reflection.name).target_ids_reader
when ActiveFedora::Reflection::DirectlyContainsOneReflection
mem[:"#{key.to_s.singularize}_id"] =
obj.public_send(reflection.name)&.id
when ActiveFedora::Reflection::IndirectlyContainsReflection
mem[:"#{key.to_s.singularize}_ids"] ||= []
mem[:"#{key.to_s.singularize}_ids"] +=
obj.association(key).ids_reader
when ActiveFedora::Reflection::DirectlyContainsReflection
mem[:"#{key.to_s.singularize}_ids"] ||= []
mem[:"#{key.to_s.singularize}_ids"] +=
Array(obj.public_send(reflection.name)).map(&:id)
when ActiveFedora::Reflection::RDFPropertyReflection
mem[reflection.name.to_sym] =
obj.public_send(reflection.name.to_sym)
else
mem[reflection.foreign_key.to_sym] =
obj.public_send(reflection.foreign_key.to_sym)
raise NotImplementedError, "Expected a known ActiveFedora::Reflection, but got #{reflection}"
end
end

Expand Down
8 changes: 0 additions & 8 deletions lib/wings/model_transformer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,17 +150,9 @@ def additional_attributes
{ :id => pcdm_object.id,
:created_at => pcdm_object.try(:create_date),
:updated_at => pcdm_object.try(:modified_date),
:member_ids => member_ids,
::Valkyrie::Persistence::Attributes::OPTIMISTIC_LOCK => lock_token }
end

# Prefer ordered members, but if ordered members don't exist, use non-ordered members.
def member_ids
ordered_member_ids = pcdm_object.try(:ordered_member_ids)
return ordered_member_ids if ordered_member_ids.present?
pcdm_object.try(:member_ids)
end

def lock_token
result = []
result << ::Valkyrie::Persistence::OptimisticLockToken.new(adapter_id: 'wings-fedora-etag', token: pcdm_object.etag) unless pcdm_object.new_record?
Expand Down
41 changes: 23 additions & 18 deletions lib/wings/orm_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,29 +78,34 @@ def to_model
end

# add reflection associations
ldp_reflections = (klass.try(:reflections) || []).select do |_key, reflection|
(klass.try(:reflections) || []).each do |reflection_key, reflection|
case reflection
when ActiveFedora::Reflection::FilterReflection,
ActiveFedora::Reflection::OrdersReflection,
ActiveFedora::Reflection::BasicContainsReflection,
ActiveFedora::Reflection::HasSubresourceReflection
false
else
true
end
end

ldp_reflections.each do |reflection_key, reflection|
if reflection.collection?
type = ::Valkyrie::Types::Set.of(::Valkyrie::Types::ID)
when ActiveFedora::Reflection::BelongsToReflection, # uses foreign_key SingularRDFPropertyReflection
ActiveFedora::Reflection::BasicContainsReflection, # ???
ActiveFedora::Reflection::FilterReflection, # rely on :extending_from
ActiveFedora::Reflection::HasAndBelongsToManyReflection, # uses foreign_key RDFPropertyReflection
ActiveFedora::Reflection::HasManyReflection, # captured by inverse relation
ActiveFedora::Reflection::HasSubresourceReflection, # ???
ActiveFedora::Reflection::OrdersReflection # map to :unordered_association in Wings::AttributeTransformer (but retain order)
next
when ActiveFedora::Reflection::DirectlyContainsOneReflection
attribute_name = (reflection_key.to_s.singularize + '_id').to_sym
type = ::Valkyrie::Types::ID.optional
when ActiveFedora::Reflection::DirectlyContainsReflection,
ActiveFedora::Reflection::IndirectlyContainsReflection
attribute_name = (reflection_key.to_s.singularize + '_ids').to_sym
type = ::Valkyrie::Types::Set.of(::Valkyrie::Types::ID)
when ActiveFedora::Reflection::SingularRDFPropertyReflection
attribute_name = reflection.name.to_sym
type = ::Valkyrie::Types::ID.optional
when ActiveFedora::Reflection::RDFPropertyReflection
attribute_name = reflection.name.to_sym
type = ::Valkyrie::Types::Set.of(::Valkyrie::Types::ID)
else
type = ::Valkyrie::Types::ID.optional
attribute_name = (reflection_key.to_s.singularize + '_id').to_sym
raise NotImplementedError, "Expected a known ActiveFedora::Reflection, but got #{reflection}"
end

next if fields.include?(attribute_name)
attribute attribute_name, type
attribute(attribute_name, type)
end

def internal_resource
Expand Down
37 changes: 35 additions & 2 deletions spec/wings/model_transformer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,13 @@ class Book < Hyrax::Resource
work.members << child_work2
end

it 'includes ordered_members too' do
ordered_members = [FactoryBot.create(:work), FactoryBot.create(:work)]
ordered_members.each { |w| work.ordered_members << w }

expect(factory.build.member_ids).to include(*['cw1', 'cw2'] + ordered_members.map(&:id))
end

it 'sets member_ids to the ids of the unordered members' do
expect(subject.build.member_ids).to match_valkyrie_ids_with_active_fedora_ids(['cw1', 'cw2'])
end
Expand Down Expand Up @@ -286,7 +293,7 @@ class Book < Hyrax::Resource

let(:page_class) do
ActiveFedoraPage = Class.new(ActiveFedora::Base) do
belongs_to :active_fedora_book_with_active_fedora_pages, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
belongs_to :active_fedora_monograph, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
end
end

Expand Down Expand Up @@ -324,7 +331,19 @@ class Book < Hyrax::Resource
.to have_attributes title: book.title,
contributor: book.contributor,
description: book.description
expect(subject.build.active_fedora_page_ids).to eq(['pg1', 'pg2'])
end

it "skips has_many reflections" do
expect(factory.build).not_to respond_to :active_fedora_page_ids
end

it "populates belongs_to reflections" do
monograph = book_class.create(**attributes)

expect(described_class.new(pcdm_object: page1).build)
.to have_attributes active_fedora_monograph_id: monograph.id
expect(described_class.new(pcdm_object: page2).build)
.to have_attributes active_fedora_monograph_id: monograph.id
end
end
end
Expand Down Expand Up @@ -364,6 +383,20 @@ class Book < Hyrax::Resource
end
end

context 'with an admin set' do
let(:pcdm_object) { AdminSet.create(title: ['my admin set']) }

before do
5.times do |i|
GenericWork.create(title: [i.to_s], admin_set_id: pcdm_object.id)
end
end

it 'does not have member_ids' do
expect(factory.build).not_to respond_to :member_ids
end
end

context 'build for access control' do
let(:af_object) { ActiveFedora::Base.create }
let(:permission) { { name: "admin@example.com", access: :edit.to_s, type: :person } }
Expand Down