Skip to content

Commit

Permalink
RDF datastreams should properly de/serialize integers
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoyne committed Dec 30, 2013
1 parent 10f79d8 commit 03db519
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 87 deletions.
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ rvm:
- 2.0.0
- 1.9.3

matrix:
allow_failures:
- rvm: 2.1.0


gemfile:
- gemfiles/gemfile.rails3
- gemfiles/gemfile.rails4
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require "active-fedora"
Bundler::GemHelper.install_tasks

# load rake tasks defined in lib/tasks that are not loaded in lib/active_fedora.rb
load "lib/tasks/active_fedora_dev.rake" if defined?(Rake)
load "lib/tasks/active_fedora_dev.rake"

CLEAN.include %w[**/.DS_Store tmp *.log *.orig *.tmp **/*~]

Expand Down
1 change: 1 addition & 0 deletions lib/active_fedora/rdf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ module Rdf
extend ActiveSupport::Autoload
autoload :NestedAttributes
autoload :NodeConfig
autoload :Indexing
end
end
59 changes: 59 additions & 0 deletions lib/active_fedora/rdf/indexing.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module ActiveFedora
module Rdf
module Indexing
extend ActiveSupport::Concern

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

def to_solr(solr_doc = Hash.new) # :nodoc:
fields.each do |field_key, field_info|
values = get_values(rdf_subject, field_key)
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
end


module ClassMethods
def 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 primary_solr_name(dsid, field)
ActiveFedora::SolrService.solr_name(prefix(dsid, field), config_for_term_or_uri(field).behaviors.first)
end
end

private
# returns a Hash, e.g.: {field => {:values => [], :type => :something, :behaviors => []}, ...}
def fields
field_map = {}.with_indifferent_access

rdf_subject = self.rdf_subject
query = RDF::Query.new do
pattern [rdf_subject, :predicate, :value]
end

query.execute(graph).each do |solution|
predicate = solution.predicate
value = solution.value

name, config = self.class.config_for_predicate(predicate)
next unless config
type = config.type
behaviors = config.behaviors
next unless type and behaviors
field_map[name] ||= {:values => [], :type => type, :behaviors => behaviors}
field_map[name][:values] << value.to_s
end
field_map
end
end
end
end
50 changes: 1 addition & 49 deletions lib/active_fedora/rdf_datastream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class RDFDatastream < Datastream
end
end
include RdfNode
include Rdf::Indexing

class << self
##
Expand All @@ -28,19 +29,6 @@ def metadata?
true
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 @@ -57,19 +45,6 @@ def content_changed?
@content = serialize
super
end

def to_solr(solr_doc = Hash.new) # :nodoc:
fields.each do |field_key, field_info|
values = get_values(rdf_subject, field_key)
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
end


# Populate a RDFDatastream object based on the "datastream" content
# Assumes that the datastream contains RDF content
# @param [String] data the "rdf" node
Expand Down Expand Up @@ -129,29 +104,6 @@ def update_subjects_to_use_a_real_pid!
@graph = new_repository
end

# returns a Hash, e.g.: {field => {:values => [], :type => :something, :behaviors => []}, ...}
def fields
field_map = {}.with_indifferent_access

rdf_subject = self.rdf_subject
query = RDF::Query.new do
pattern [rdf_subject, :predicate, :value]
end

query.execute(graph).each do |solution|
predicate = solution.predicate
value = solution.value

name, config = self.class.config_for_predicate(predicate)
next unless config
type = config.type
behaviors = config.behaviors
next unless type and behaviors
field_map[name] ||= {:values => [], :type => type, :behaviors => behaviors}
field_map[name][:values] << value.to_s
end
field_map
end
end
end

51 changes: 30 additions & 21 deletions lib/active_fedora/rdf_node/term_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,33 +75,42 @@ def target

# Get the values off of the rdf nodes this proxy targets
def load_values
values = []
values = parent.query(subject, options.predicate)
.map {|solution| coerce_to_primitive_type(solution.value)}
.select { |v| correct_rdf_type_for_term?(v)}
.map {|v| coerce_to_rdf_type(v) }

parent.query(subject, options.predicate).each do |solution|
v = solution.value
v = v.to_s if v.is_a? RDF::Literal
if options.type == :date
v = Date.parse(v)
end
# If the user provided options[:class_name], we should query to make sure this
# potential solution is of the right RDF.type
if options.class_name
klass = class_from_rdf_type(v)
values << v if klass == ActiveFedora.class_from_string(options.class_name, parent.class)
else
values << v
end
end

if options.class_name
values = values.map{ |found_subject| class_from_rdf_type(found_subject).new(parent.graph, found_subject)}
end

options.multivalue ? values : values.first
end

private

def coerce_to_rdf_type(v)
if options.class_name
class_from_rdf_type(v).new(parent.graph, v)
else
v
end
end

# If the user provided options[:class_name], we should query to make sure this
# potential solution is of the right RDF.type
def correct_rdf_type_for_term?(v)
!options.class_name || (options.class_name && class_from_rdf_type(v) == ActiveFedora.class_from_string(options.class_name, parent.class))
end

def coerce_to_primitive_type(v)
v = v.to_s if v.is_a? RDF::Literal
case options.type
when :date
Date.parse(v)
when :integer
v.to_i
else
v
end
end

def target_class
parent.target_class(options)
end
Expand Down
6 changes: 2 additions & 4 deletions lib/tasks/active_fedora_dev.rake
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ JETTY_ZIP_BASENAME = 'master'
Jettywrapper.url = "https://github.com/projecthydra/hydra-jetty/archive/#{JETTY_ZIP_BASENAME}.zip"

namespace :active_fedora do
require 'active-fedora'

# Use yard to build docs
begin
require 'yard'
Expand All @@ -26,11 +24,11 @@ namespace :active_fedora do
end
end

require 'rspec/core/rake_task'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:rspec) do |spec|
spec.pattern = FileList['spec/**/*_spec.rb']
spec.pattern += FileList['spec/*_spec.rb']
spec.rspec_opts = ['--backtrace']
spec.rspec_opts = ['--backtrace'] if ENV['CI']
end

RSpec::Core::RakeTask.new(:rcov) do |spec|
Expand Down
2 changes: 1 addition & 1 deletion spec/integration/autosave_association_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class MockAFBaseRelationship < ActiveFedora::Base
subject.stub(:marked_for_destruction?).and_return(false)
end
it {
expect { subject.changed_for_autosave? }.to_not raise_error(NoMethodError)
expect { subject.changed_for_autosave? }.to_not raise_error
}
end
end
40 changes: 29 additions & 11 deletions spec/integration/ntriples_datastream_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,33 @@

describe ActiveFedora::NtriplesRDFDatastream do
before do

class FileVocabulary < RDF::Vocabulary("http://downlode.org/Code/RDF/File_Properties/schema#")
property :size
end

class MyDatastream < ActiveFedora::NtriplesRDFDatastream
map_predicates do |map|
map.title(:in => RDF::DC) do |index|
map.title(in: RDF::DC) do |index|
index.as :stored_searchable, :facetable
end
map.date_uploaded(:to => "dateSubmitted", :in => RDF::DC) do |index|
map.date_uploaded(to: "dateSubmitted", in: RDF::DC) do |index|
index.type :date
index.as :stored_searchable, :sortable
end
map.part(:to => "hasPart", :in => RDF::DC)
map.based_near(:in => RDF::FOAF)
map.related_url(:to => "seeAlso", :in => RDF::RDFS)
map.size(in: FileVocabulary) do |index|
index.type :integer
index.as :stored_sortable
end
map.part(to: "hasPart", in: RDF::DC)
map.based_near(in: RDF::FOAF)
map.related_url(to: "seeAlso", in: RDF::RDFS)
end
end
class RdfTest < ActiveFedora::Base
has_metadata :name=>'rdf', :type=>MyDatastream
has_attributes :based_near, :related_url, :part, :date_uploaded, datastream: 'rdf', multiple: true
has_attributes :title, datastream: 'rdf', multiple: false
has_attributes :title, :size, datastream: 'rdf', multiple: false
end
@subject = RdfTest.new
end
Expand All @@ -31,6 +40,7 @@ class RdfTest < ActiveFedora::Base
after do
Object.send(:remove_const, :RdfTest)
Object.send(:remove_const, :MyDatastream)
Object.send(:remove_const, :FileVocabulary)
end

it "should not try to send an empty datastream" do
Expand Down Expand Up @@ -64,11 +74,19 @@ class RdfTest < ActiveFedora::Base
foo.save
end

it "should serialize dates" do
subject.date_uploaded = Date.parse('2012-11-02')
subject.date_uploaded.first.should be_kind_of Date
solr_document = subject.to_solr
solr_document[ActiveFedora::SolrService.solr_name('rdf__date_uploaded', type: :date)].should == ['2012-11-02T00:00:00Z']
describe "serializing" do
it "should handle dates" do
subject.date_uploaded = Date.parse('2012-11-02')
subject.date_uploaded.first.should be_kind_of Date
solr_document = subject.to_solr
solr_document[ActiveFedora::SolrService.solr_name('rdf__date_uploaded', type: :date)].should == ['2012-11-02T00:00:00Z']
end
it "should handle integers" do
subject.size = 12345
subject.size.should be_kind_of Fixnum
solr_document = subject.to_solr
solr_document[ActiveFedora::SolrService.solr_name('rdf__size', :stored_sortable, type: :integer)].should == '12345'
end
end

it "should produce a solr document" do
Expand Down

0 comments on commit 03db519

Please sign in to comment.