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

Extracting object from .load_instance_from_solr #51

Merged
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
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gemspec
group :development, :test do
gem 'simplecov', :platforms => [:mri_19]#, :mri_20]
gem 'simplecov-rcov', :platforms => [:mri_19]#, :mri_20]
gem 'debugger', :platforms => [:mri_19, :mri_20]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, don't commit debugger to git. It's not necessary that everyone have this

end

gem 'jruby-openssl', :platform=> :jruby
1 change: 1 addition & 0 deletions lib/active_fedora.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class RecordNotSaved < RuntimeError; end # :nodoc:
autoload :DatastreamCollections
autoload :Predicates
autoload :Validations
autoload :SolrInstanceLoader
end


Expand Down
53 changes: 11 additions & 42 deletions lib/active_fedora/indexing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ module Indexing

# Return a Hash representation of this object where keys in the hash are appropriate Solr field names.
# @param [Hash] solr_doc (optional) Hash to insert the fields into
# @param [Hash] opts (optional)
# If opts[:model_only] == true, the base object metadata and the RELS-EXT datastream will be omitted. This is mainly to support shelver, which calls .to_solr for each model an object subscribes to.
# @param [Hash] opts (optional)
# If opts[:model_only] == true, the base object metadata and the RELS-EXT datastream will be omitted. This is mainly to support shelver, which calls .to_solr for each model an object subscribes to.
def to_solr(solr_doc = Hash.new, opts={})
unless opts[:model_only]
c_time = create_date
Expand Down Expand Up @@ -43,7 +43,7 @@ def solrize_profile(solr_doc = Hash.new) # :nodoc:
self.datastreams.each_pair { |dsid,ds| profile_hash['datastreams'][dsid] = ds.solrize_profile }
solr_doc[self.class.profile_solr_name] = profile_hash.to_json
end

# Serialize the datastream's RDF relationships to solr
# @param [Hash] solr_doc @deafult an empty Hash
def solrize_relationships(solr_doc = Hash.new)
Expand All @@ -58,7 +58,7 @@ def solrize_relationships(solr_doc = Hash.new)

# Updates Solr index with self.
def update_index
if defined?( Solrizer::Fedora::Solrizer )
if defined?( Solrizer::Fedora::Solrizer )
#logger.info("Trying to solrize pid: #{pid}")
solrizer = Solrizer::Fedora::Solrizer.new
solrizer.solrize( self )
Expand All @@ -70,63 +70,32 @@ def update_index


module ClassMethods
# This method can be used instead of ActiveFedora::Model::ClassMethods.find.
# This method can be used instead of ActiveFedora::Model::ClassMethods.find.
# It works similarly except it populates an object from Solr instead of Fedora.
# It is most useful for objects used in read-only displays in order to speed up loading time. If only
# a pid is passed in it will query solr for a corresponding solr document and then use it
# to populate this object.
#
#
# If a value is passed in for optional parameter solr_doc it will not query solr again and just use the
# one passed to populate the object.
#
# It will anything stored within solr such as metadata and relationships. Non-metadata datastreams will not
# be loaded and if needed you should use find instead.
def load_instance_from_solr(pid,solr_doc=nil)
if solr_doc.nil?
result = find_with_conditions(:id=>pid)
raise ActiveFedora::ObjectNotFoundError, "Object #{pid} not found in solr" if result.empty?
solr_doc = result.first
#double check pid and id in record match
raise ActiveFedora::ObjectNotFoundError, "Object #{pid} not found in Solr" unless !result.nil? && !solr_doc.nil? && pid == solr_doc[SOLR_DOCUMENT_ID]
else
raise "Solr document record id and pid do not match" unless pid == solr_doc[SOLR_DOCUMENT_ID]
end
klass = if class_str = solr_doc[ActiveFedora::SolrService.solr_name('has_model', :symbol)]
ActiveFedora::SolrService.class_from_solr_document(solr_doc)
else
ActiveFedora::Base
end

profile_json = Array(solr_doc[ActiveFedora::Base.profile_solr_name]).first
unless profile_json.present?
raise ActiveFedora::ObjectNotFoundError, "Object #{pid} does not contain a solrized profile"
end
profile_hash = ActiveSupport::JSON.decode(profile_json)
obj = klass.allocate.init_with(SolrDigitalObject.new(solr_doc, profile_hash, klass))
#set by default to load any dependent relationship objects from solr as well
#need to call rels_ext once so it exists when iterating over datastreams
obj.rels_ext
obj.datastreams.each_value do |ds|
if ds.respond_to?(:profile_from_hash) and (ds_prof = profile_hash['datastreams'][ds.dsid])
ds.profile_from_hash(ds_prof)
end
ds.from_solr(solr_doc) if ds.respond_to?(:from_solr)
end
obj.inner_object.freeze
obj
SolrInstanceLoader.new(self, pid, solr_doc).object
end
# Using the fedora search (not solr), get every object and reindex it.

# Using the fedora search (not solr), get every object and reindex it.
def reindex_everything
connections.each do |conn|
conn.search(nil) do |object|
ActiveFedora::Base.find(object.pid, :cast=>true).update_index
end
end
end
end

private

def connections
if ActiveFedora.config.sharded?
return ActiveFedora.config.credentials.map { |cred| ActiveFedora::RubydoraConnection.new(cred).connection}
Expand Down
93 changes: 93 additions & 0 deletions lib/active_fedora/solr_instance_loader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
module ActiveFedora
class FedoraSolrMismatchError < ActiveFedora::ObjectNotFoundError
def initialize(pid, solr_document_id)
super("Solr record id and pid do not match; Solr ID=#{solr_document_id}, PID=#{pid}")
end
end

# Responsible for loading an ActiveFedora::Base proxy from a Solr document.
class SolrInstanceLoader
attr_reader :context, :pid
private :context, :pid
def initialize(context, pid, solr_doc = nil)
@context = context
@pid = pid
@solr_doc = solr_doc
validate_solr_doc_and_pid!(@solr_doc)
end

def object
return @object if @object
@object = allocate_object
@object.rels_ext
load_object_datastreams(@object)
@object.inner_object.freeze
@object
end

private

def allocate_object
active_fedora_class.allocate.init_with(solr_digital_object)
end

def solr_digital_object
SolrDigitalObject.new(solr_doc, profile_hash, active_fedora_class)
end


def load_object_datastreams(obj)
obj.datastreams.each_value do |ds|
if ds.respond_to?(:profile_from_hash) and (ds_prof = profile_hash['datastreams'][ds.dsid])
ds.profile_from_hash(ds_prof)
end
ds.from_solr(solr_doc) if ds.respond_to?(:from_solr)
end
end

def solr_doc
@solr_doc ||= begin
result = context.find_with_conditions(:id=>pid)
if result.empty?
raise ActiveFedora::ObjectNotFoundError, "Object #{pid} not found in solr"
end
@solr_doc = result.first
validate_solr_doc_and_pid!(@solr_doc)
@solr_doc
end
end

def validate_solr_doc_and_pid!(document)
return true if document.nil?
solr_id = document[SOLR_DOCUMENT_ID]
if pid != solr_id
raise ActiveFedora::FedoraSolrMismatchError.new(pid, solr_id)
end
end

def active_fedora_class
@active_fedora_class ||= begin
if solr_doc[ActiveFedora::SolrService.solr_name('has_model', :symbol)]
ActiveFedora::SolrService.class_from_solr_document(solr_doc)
else
ActiveFedora::Base
end
end
end

def profile_json
@profile_json ||= begin
profile_json = Array(solr_doc[ActiveFedora::Base.profile_solr_name]).first
unless profile_json.present?
raise ActiveFedora::ObjectNotFoundError, "Object #{pid} does not contain a solrized profile"
end
profile_json
end
end

def profile_hash
@profile_hash ||= ActiveSupport::JSON.decode(profile_json)
end

end
end
62 changes: 62 additions & 0 deletions spec/integration/solr_instance_loader_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
require 'spec_helper'

require 'active_fedora'

describe ActiveFedora::SolrInstanceLoader do
let(:context) { ActiveFedora::Base }
let(:pid) { nil }
let(:solr_doc) { nil }
let(:active_fedora_object) { ActiveFedora::Base.find(pid, :cast => true) }
subject { ActiveFedora::SolrInstanceLoader.new(context, pid, solr_doc) }

describe 'existing pid' do
let(:pid) { 'hydrangea:fixture_mods_article1' }
describe 'without a solr document' do
it 'it finds the SOLR document and casts into an AF::Base object' do
expect(subject.object).to eq(active_fedora_object)
end
end
describe 'with matching solr document' do
let(:solr_doc) { ActiveFedora::Base.find_with_conditions(:id=>pid).first }
it 'it casts the SOLR document and casts into an AF::Base object' do
expect(subject.object).to eq(active_fedora_object)
end
end
describe 'with a mismatching solr document' do
let(:mismatching_pid) { 'hydrangea:fixture_mods_article2' }
let(:solr_doc) { ActiveFedora::Base.find_with_conditions(:id=>mismatching_pid).first }
it 'it raise ObjectNotFoundError' do
expect {
subject
}.to raise_error(ActiveFedora::ObjectNotFoundError)
end
end
end
describe 'missing pid' do
let(:pid) { 'hydrangea:fixture_mods_article8675309' }
describe 'without a solr document' do
it 'it raise ObjectNotFoundError' do
expect {
subject.object
}.to raise_error(ActiveFedora::ObjectNotFoundError)
end
end
describe 'with matching solr document' do
let(:solr_doc) { ActiveFedora::Base.find_with_conditions(:id=>pid).first }
it 'it raise ObjectNotFoundError' do
expect {
subject.object
}.to raise_error(ActiveFedora::ObjectNotFoundError)
end
end
describe 'with a mismatching solr document' do
let(:mismatching_pid) { 'hydrangea:fixture_mods_article2' }
let(:solr_doc) { ActiveFedora::Base.find_with_conditions(:id=>mismatching_pid).first }
it 'it raise ObjectNotFoundError' do
expect {
subject
}.to raise_error(ActiveFedora::ObjectNotFoundError)
end
end
end
end