Skip to content

Commit

Permalink
Merge pull request #293 from projecthydra/field_to_solr_name
Browse files Browse the repository at this point in the history
Add a way to get the primary solr name for a field
  • Loading branch information
mbklein committed Dec 30, 2013
2 parents e492188 + cb02723 commit 10f79d8
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 48 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
source "http://rubygems.org"
source "https://rubygems.org"

# Bundler will rely on active-fedora.gemspec for dependency information.

Expand Down
2 changes: 2 additions & 0 deletions lib/active_fedora.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class ConfigurationError < RuntimeError; end # :nodoc:
class AssociationTypeMismatch < RuntimeError; end # :nodoc:
class UnregisteredPredicateError < RuntimeError; end # :nodoc:
class RecordNotSaved < RuntimeError; end # :nodoc:
class IllegalOperation < RuntimeError; end # :nodoc:


eager_autoload do
Expand All @@ -35,6 +36,7 @@ class RecordNotSaved < RuntimeError; end # :nodoc:
autoload :Config
autoload :Core
autoload :Datastream
autoload :DatastreamAttribute
autoload :DatastreamHash
autoload :Datastreams
autoload :DigitalObject
Expand Down
44 changes: 11 additions & 33 deletions lib/active_fedora/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ def array_reader(field, *args)
end
raise UnknownAttributeError, "#{self.class} does not have an attribute `#{field}'" unless self.class.defined_attributes.key?(field)
if args.present?
instance_exec(*args, &self.class.defined_attributes[field][:reader])
instance_exec(*args, &self.class.defined_attributes[field].reader)
else
instance_exec &self.class.defined_attributes[field][:reader]
instance_exec &self.class.defined_attributes[field].reader
end
end

Expand All @@ -57,7 +57,7 @@ def array_setter(field, args)
return association.id_writer(args) if association
end
raise UnknownAttributeError, "#{self.class} does not have an attribute `#{field}'" unless self.class.defined_attributes.key?(field)
instance_exec(args, &self.class.defined_attributes[field][:setter])
instance_exec(args, &self.class.defined_attributes[field].writer)
end

# @return [Boolean] true if there is an reader method and it returns a
Expand Down Expand Up @@ -108,49 +108,27 @@ def unique?(field)
# @param [Symbol] field the field to query
# @return [Boolean]
def multiple?(field)
defined_attributes[field][:multiple]
defined_attributes[field].multiple
end

private

def find_or_create_defined_attribute(field, dsid, args)
self.defined_attributes[field] ||= DatastreamAttribute.new(field, dsid, datastream_class_for_name(dsid), args)
end

private
def create_attribute_reader(field, dsid, args)
self.defined_attributes[field] ||= {}
self.defined_attributes[field][:reader] = lambda do |*opts|
ds = datastream_for_attribute(dsid)
if ds.kind_of?(ActiveFedora::RDFDatastream)
ds.send(field)
else
terminology = args[:at] || [field]
if terminology.length == 1 && opts.present?
ds.send(terminology.first, *opts)
else
ds.send(:term_values, *terminology)
end
end
end

self.defined_attributes[field][:multiple] = args[:multiple].nil? ? false : args[:multiple]
def create_attribute_reader(field, dsid, args)
find_or_create_defined_attribute(field, dsid, args)

define_method field do |*opts|
val = array_reader(field, *opts)
self.class.multiple?(field) ? val : val.first
end
end


def create_attribute_setter(field, dsid, args)
self.defined_attributes[field] ||= {}
self.defined_attributes[field][:setter] = lambda do |v|
ds = datastream_for_attribute(dsid)
mark_as_changed(field) if value_has_changed?(field, v)
if ds.kind_of?(ActiveFedora::RDFDatastream)
ds.send("#{field}=", v)
else
terminology = args[:at] || [field]
ds.send(:update_indexed_attributes, {terminology => v})
end
end
find_or_create_defined_attribute(field, dsid, args)
define_method "#{field}=".to_sym do |v|
self[field]=v
end
Expand Down
61 changes: 61 additions & 0 deletions lib/active_fedora/datastream_attribute.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
module ActiveFedora
# Represents the mapping between a model attribute and a field in a datastream
class DatastreamAttribute

attr_accessor :dsid, :field, :klass, :at, :reader, :writer, :multiple

def initialize(field, dsid, klass, args={})
self.field = field
self.dsid = dsid
self.klass = klass
self.multiple = args[:multiple].nil? ? false : args[:multiple]
self.at = args[:at]

initialize_reader!
initialize_writer!
end

# Gives the primary solr name for a column. If there is more than one indexer on the field definition, it gives the first
def primary_solr_name
if klass.respond_to?(:primary_solr_name)
klass.primary_solr_name(dsid, field)
else
raise IllegalOperation, "the class '#{klass}' doesn't respond to 'primary_solr_name'"
end
end

private

def initialize_writer!
this = self
self.writer = lambda do |v|
ds = datastream_for_attribute(this.dsid)
mark_as_changed(this.field) if value_has_changed?(this.field, v)
if ds.kind_of?(ActiveFedora::RDFDatastream)
ds.send("#{this.field}=", v)
else
terminology = this.at || [this.field]
ds.send(:update_indexed_attributes, {terminology => v})
end
end
end

def initialize_reader!
this = self
self.reader = lambda do |*opts|
ds = datastream_for_attribute(this.dsid)
if ds.kind_of?(ActiveFedora::RDFDatastream)
ds.send(this.field)
else
terminology = this.at || [this.field]
if terminology.length == 1 && opts.present?
ds.send(terminology.first, *opts)
else
ds.send(:term_values, *terminology)
end
end
end
end

end
end
19 changes: 12 additions & 7 deletions lib/active_fedora/rdf_datastream.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module ActiveFedora
class RDFDatastream < Datastream

include Solrizer::Common

before_save do
if content.blank?
logger.warn "Cowardly refusing to save a datastream with empty content: #{self.inspect}"
Expand Down Expand Up @@ -31,9 +29,18 @@ def metadata?
end

def prefix(name)
self.class.prefix(dsid, name)
end

def self.prefix(dsid, name)
"#{dsid.underscore}__#{name}".to_sym
end

# Gives the primary solr name for a column. If there is more than one indexer on the field definition, it gives the first
def self.primary_solr_name(dsid, field)
ActiveFedora::SolrService.solr_name(prefix(dsid, field), config_for_term_or_uri(field).behaviors.first)
end

# Overriding so that one can call ds.content on an unsaved datastream and they will see the serialized format
def content
serialize
Expand All @@ -54,11 +61,9 @@ def content_changed?
def to_solr(solr_doc = Hash.new) # :nodoc:
fields.each do |field_key, field_info|
values = get_values(rdf_subject, field_key)
if values
Array(values).each do |val|
val = val.to_s if val.kind_of? RDF::URI
self.class.create_and_insert_terms(prefix(field_key), val, field_info[:behaviors], solr_doc)
end
Array(values).each do |val|
val = val.to_s if val.kind_of? RDF::URI
Solrizer.insert_field(solr_doc, prefix(field_key), val, *field_info[:behaviors])
end
end
solr_doc
Expand Down
19 changes: 12 additions & 7 deletions lib/active_fedora/rdf_node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,9 @@ def insert_child(predicate, node)
end


def config_for_term_or_uri(term)
case term
when RDF::URI
self.class.config.each { |k, v| return v if v.predicate == term}
else
self.class.config[term.to_sym]
end
# In Rails 4 you can do "delegate :config_for_term_or_uri, :class", but in rails 3 it breaks.
def config_for_term_or_uri(val)
self.class.config_for_term_or_uri(val)
end

# @param [Symbol, RDF::URI] term predicate the predicate to insert into the graph
Expand Down Expand Up @@ -300,6 +296,15 @@ def rdf_type(uri_or_string=nil)
@rdf_type
end

def config_for_term_or_uri(term)
case term
when RDF::URI
config.each { |k, v| return v if v.predicate == term}
else
config[term.to_sym]
end
end

def config_for_predicate(predicate)
config.each do |term, value|
return term, value if value.predicate == predicate
Expand Down
26 changes: 26 additions & 0 deletions spec/integration/field_to_solr_name_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require 'spec_helper'

describe "An object with RDF backed attributes" do

before do
class TestOne < ActiveFedora::Base
class MyMetadata < ActiveFedora::NtriplesRDFDatastream
map_predicates do |map|
map.title(in: RDF::DC) do |index|
index.as :stored_searchable
end
end
end
has_metadata 'descMetadata', type: MyMetadata
has_attributes :title, datastream: 'descMetadata'
end
end

after do
Object.send(:remove_const, :TestOne)
end

it "should be able to grab the solr name" do
expect(TestOne.defined_attributes[:title].primary_solr_name).to eq 'desc_metadata__title_tesim'
end
end
6 changes: 6 additions & 0 deletions spec/unit/ntriples_datastream_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ class MyDatastream < ActiveFedora::NtriplesRDFDatastream
@subject.should respond_to(:to_solr)
@subject.to_solr.should be_kind_of(Hash)
end

it "should have a solr_name method" do
expect(MyDatastream.primary_solr_name('descMetadata', :based_near)).to eq 'desc_metadata__based_near_sim'
expect(MyDatastream.primary_solr_name('props', :title)).to eq 'props__title_tesim'
end

it "should optionally allow you to provide the Solr::Document to add fields to and return that document when done" do
doc = Hash.new
@subject.to_solr(doc).should == doc
Expand Down

0 comments on commit 10f79d8

Please sign in to comment.