active-fedora 2.3.1 → 2.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CONSOLE_GETTING_STARTED.textile +14 -14
- data/Gemfile.lock +6 -6
- data/NOKOGIRI_DATASTREAMS.textile +19 -17
- data/config/solr.yml +15 -0
- data/lib/active_fedora.rb +14 -7
- data/lib/active_fedora/base.rb +5 -7
- data/lib/active_fedora/datastream.rb +12 -0
- data/lib/active_fedora/semantic_node.rb +15 -254
- data/lib/active_fedora/solr_service.rb +4 -0
- data/lib/active_fedora/version.rb +1 -1
- data/lib/fedora/datastream.rb +14 -3
- data/lib/tasks/active_fedora_dev.rake +2 -2
- data/spec/fixtures/rails_root/config/fedora.yml +4 -4
- data/spec/integration/bug_spec.rb +1 -1
- data/spec/integration/model_spec.rb +1 -1
- data/spec/integration/nokogiri_datastream_spec.rb +1 -2
- data/spec/integration/semantic_node_spec.rb +2 -259
- data/spec/unit/active_fedora_spec.rb +7 -2
- data/spec/unit/base_spec.rb +16 -5
- data/spec/unit/datastream_spec.rb +41 -1
- data/spec/unit/property_spec.rb +1 -1
- data/spec/unit/relationship_spec.rb +1 -1
- data/spec/unit/rf_datastream_spec.rb +14 -0
- data/spec/unit/semantic_node_spec.rb +7 -14
- metadata +5 -5
- data/lib/active_fedora/samples/sample_af_obj_relationship_query_param.rb +0 -11
@@ -112,7 +112,7 @@ To see a more complete implementation of importing and deleting Fedora objects,
|
|
112
112
|
*When you're done playing around with importing and deleting, make sure that you leave a copy of hydrangea:fixture_mods_article1 in fedora so we can play with it.*
|
113
113
|
|
114
114
|
|
115
|
-
|
115
|
+
h2. Define a Model for Your (Active)Fedora Objects
|
116
116
|
|
117
117
|
Look at the SpecialThing model defined in lib/active_fedora/samples/special_thing.rb to see how you declare an ActiveFedora model.
|
118
118
|
|
@@ -133,7 +133,7 @@ This pid was retrieved from Fedora's getNextPid method.
|
|
133
133
|
|
134
134
|
Your object will not show up in the actual Fedora repository until you save it using newthing.save, but let's hold off on saving it for now.
|
135
135
|
|
136
|
-
|
136
|
+
h2. Fedora RELATIONSHIPS in ActiveFedora
|
137
137
|
|
138
138
|
ActiveFedora provides convenience methods for creating and editing Fedora RELS-EXT relationships. It also auto-generates methods for searching these relationships with Solr. (see https://github.com/projecthydra/solrizer and https://github.com/projecthydra/solrizer-fedora)
|
139
139
|
|
@@ -168,7 +168,7 @@ newthing.inspirations
|
|
168
168
|
|
169
169
|
This method is actually making a search request to Solr -- it is looking in Solr to see if the "newthing" object has any "inspirations" relationships.
|
170
170
|
|
171
|
-
Now we'll create another Fedora object (using the default ActiveFedora object model) and we'll use ActiveFedora's add_relationship method to relate our new object to the SpecialThing
|
171
|
+
Now we'll create another Fedora object (using the default ActiveFedora object model) and we'll use ActiveFedora's add_relationship method to relate our new object to the SpecialThing object. We'll also save our new object in our Fedora repository.
|
172
172
|
|
173
173
|
<pre>
|
174
174
|
newobj = ActiveFedora::Base.new
|
@@ -179,10 +179,10 @@ newobj.relationships
|
|
179
179
|
newobj.save
|
180
180
|
=> ...
|
181
181
|
newobj.pid
|
182
|
-
=> "changeme:164" # this is the pid you want to put in the following URLs as a replacement for
|
182
|
+
=> "changeme:164" # this is the pid you want to put in the following URLs as a replacement for (PID)
|
183
183
|
</pre>
|
184
184
|
|
185
|
-
You can see objects in Fedora by going to http://localhost:8983/fedora/objects/
|
185
|
+
You can see objects in Fedora by going to http://localhost:8983/fedora/objects/(PID) and you can see the relationships for an object by looking at the RELS-EXT datastream content: http://localhost: 8983/fedora/objects/(PID)/datastreams/RELS-EXT/content
|
186
186
|
|
187
187
|
Now let's see if the "newthing" object has an "inspiration" relationship with our "newobj"
|
188
188
|
|
@@ -200,9 +200,9 @@ Note that you didn't have to save the "newthing" object in order for this relati
|
|
200
200
|
Only the ActiveFedora object making the assertion needs to be saved in order for the search to work. In our example above, new_obj asserts :has_derivation (rather than the derivative asserting :is_derivation_of), so only new_obj had to be saved.
|
201
201
|
|
202
202
|
|
203
|
-
|
203
|
+
h2. Fedora DATASTREAMS & METADATA in ActiveFedora
|
204
204
|
|
205
|
-
|
205
|
+
h3. Blobs (a.k.a. File Datastreams, a.k.a Managed Content Datastreams)
|
206
206
|
|
207
207
|
Here we create a simple Datastream (using the default Datastream model).
|
208
208
|
|
@@ -220,7 +220,7 @@ newthing.save
|
|
220
220
|
Now use your browser to find the file datastreams in Fedora ...
|
221
221
|
|
222
222
|
|
223
|
-
|
223
|
+
h3. On auto-generating datastream ids
|
224
224
|
|
225
225
|
If you don't specify a dsid, ActiveFedora will generate one for you. In the example below, "DS1" is the dsID assigned to the new datastream
|
226
226
|
|
@@ -244,7 +244,7 @@ newthing.datastreams.keys
|
|
244
244
|
newthing.save
|
245
245
|
</pre>
|
246
246
|
|
247
|
-
h2.
|
247
|
+
h2. Retrieving Existing Fedora Repository Objects
|
248
248
|
|
249
249
|
When you want your code to interact with existing digital objects in a Fedora repository, use the ActiveFedora load_instance method.
|
250
250
|
|
@@ -316,11 +316,9 @@ This query will return a Solr::Result containing all of the objects that have co
|
|
316
316
|
|
317
317
|
h2. More About ActiveFedora Models
|
318
318
|
|
319
|
-
ActiveFedora Models don't actually do much. They mainly keep a list of datastream ids and associate them with classes that help you use the content from those datastreams.
|
319
|
+
ActiveFedora Models for Fedora objects don't actually do much. They mainly keep a list of datastream ids and associate them with classes that help you use the content from those datastreams.
|
320
320
|
|
321
|
-
|
322
|
-
|
323
|
-
For now, load an instance of the SpecialThing model and take a look at its datastreams.
|
321
|
+
Let's load an instance of the SpecialThing model and take a look at its datastreams.
|
324
322
|
|
325
323
|
<pre>
|
326
324
|
st = SpecialThing.load_instance("hydrangea:fixture_mods_article1")
|
@@ -366,5 +364,7 @@ properties:
|
|
366
364
|
|
367
365
|
Notice that properties and DC have been loaded as ActiveFedora::Datastream, RELS-EXT has been loaded as ActiveFedora::RelsExtDatastream, and the other three have been loaded as the classes specified in the Model.
|
368
366
|
|
369
|
-
|
367
|
+
h2. Where to Find More Information
|
368
|
+
|
369
|
+
You can examine the files in lib/active_fedora/samples to learn more about how to define ActiveFedora models and OM-based datastreams. We also suggest you read about "OM-based NokogiriDatastreams":https://github.com/mediashelf/active_fedora/blob/master/NOKOGIRI_DATASTREAMS.textile to learn about manipulating XML contained in datastreams.
|
370
370
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
active-fedora (2.3.
|
4
|
+
active-fedora (2.3.2)
|
5
5
|
activeresource
|
6
6
|
equivalent-xml
|
7
7
|
facets
|
@@ -18,13 +18,13 @@ GEM
|
|
18
18
|
remote: http://rubygems.org/
|
19
19
|
specs:
|
20
20
|
RedCloth (4.2.7)
|
21
|
-
activeresource (2.3.
|
22
|
-
activesupport (= 2.3.
|
23
|
-
activesupport (2.3.
|
21
|
+
activeresource (2.3.12)
|
22
|
+
activesupport (= 2.3.12)
|
23
|
+
activesupport (2.3.12)
|
24
24
|
builder (3.0.0)
|
25
25
|
columnize (0.3.2)
|
26
26
|
daemons (1.1.3)
|
27
|
-
equivalent-xml (0.2.
|
27
|
+
equivalent-xml (0.2.7)
|
28
28
|
nokogiri (>= 1.4.3)
|
29
29
|
facets (2.9.1)
|
30
30
|
git (1.2.5)
|
@@ -37,7 +37,7 @@ GEM
|
|
37
37
|
mediashelf-loggable (0.4.2)
|
38
38
|
mime-types (1.16)
|
39
39
|
mocha (0.9.12)
|
40
|
-
multipart-post (1.1.
|
40
|
+
multipart-post (1.1.2)
|
41
41
|
nokogiri (1.4.4)
|
42
42
|
om (1.2.4)
|
43
43
|
nokogiri (>= 1.4.2)
|
@@ -1,5 +1,21 @@
|
|
1
1
|
h1. Using OM-based NokogiriDatastreams
|
2
2
|
|
3
|
+
This document is about working with (Active)Fedora datastreams with XML content. Nokogiri is a ruby gem for working with xml, and OM (Opinionated Metadata) allows you to define a “terminology” to ease translation between XML and ruby objects.
|
4
|
+
|
5
|
+
h3. Learning More about OM (Opinionated Metadata)
|
6
|
+
|
7
|
+
For deeper exposure to what you can do with OM, see the "OM documentation":http://hudson.projecthydra.org/job/om/Documentation/ for "Getting Started":http://hudson.projecthydra.org/job/om/Documentation/file.GETTING_STARTED.html, "Querying Documents":http://hudson.projecthydra.org/job/om/Documentation/file.QUERYING_DOCUMENTS.html, and "Updating Documents":http://hudson.projecthydra.org/job/om/Documentation/file.UPDATING_DOCUMENTS.html. There is also information in the "solrizer":http://github.com/projecthydra/solrizer documentation about Solrizing documents.
|
8
|
+
|
9
|
+
You can run most of the examples from those tutorials against the descMetadata datastream you've created here.
|
10
|
+
|
11
|
+
<pre>
|
12
|
+
doc = st.datastreams["descMetadata"] # the datastream is the OM Document
|
13
|
+
...
|
14
|
+
doc.class
|
15
|
+
=> Hydra::ModsArticleDatastream # Hydra::ModsArticleDatastream is the Document Class
|
16
|
+
terminology = doc.class.terminology # The terminology is attached to the Document Class
|
17
|
+
</pre>
|
18
|
+
|
3
19
|
h2. Setup
|
4
20
|
|
5
21
|
This tutorial assumes that you've run script/console from the root of ActiveFedora and have imported the hydrangea:fixture_mods_article1 object. If you haven't done that, see "CONSOLE_GETTING_STARTED":https://github.com/mediashelf/active_fedora/blob/master/CONSOLE_GETTING_STARTED.textile for instructions.
|
@@ -13,9 +29,9 @@ Look in these datastream definitions to see the OM Terminologies they define. T
|
|
13
29
|
* {Marpa::DcDatastream} ( "see the code":https://github.com/mediashelf/active_fedora/blob/master/lib/active_fedora/samples/marpa-dc_datastream.rb )
|
14
30
|
|
15
31
|
|
16
|
-
h2.
|
32
|
+
h2. Using Existing OM Terminology
|
17
33
|
|
18
|
-
First, load the Fedora object as an instance of the SpecialThing Model
|
34
|
+
First, load the Fedora object as an instance of the SpecialThing ActiveFedora Model
|
19
35
|
|
20
36
|
<pre>
|
21
37
|
st = SpecialThing.load_instance("hydrangea:fixture_mods_article1")
|
@@ -64,21 +80,7 @@ mods_ds.find_by_terms(:person).length
|
|
64
80
|
mods_ds.find_by_terms(:person).each {|n| puts n.to_xml}
|
65
81
|
</pre>
|
66
82
|
|
67
|
-
|
68
|
-
h2. Learning More about OM
|
69
|
-
|
70
|
-
Hydra::ModsArticleDatastream has all of the behaviors of an OM::Document. For deeper exposure to what you can do with OM, see the "OM documentation":http://hudson.projecthydra.org/job/om/Documentation/ for "Getting Started":http://hudson.projecthydra.org/job/om/Documentation/file.GETTING_STARTED.html, "Querying Documents":http://hudson.projecthydra.org/job/om/Documentation/file.QUERYING_DOCUMENTS.html, and "Updating Documents":http://hudson.projecthydra.org/job/om/Documentation/file.UPDATING_DOCUMENTS.html. There is also information in the "solrizer":http://github.com/projecthydra/solrizer documentation about Solrizing documents.
|
71
|
-
|
72
|
-
You can run most of the examples from those tutorials against the descMetadata datastream you've created here.
|
73
|
-
|
74
|
-
<pre>
|
75
|
-
doc = st.datastreams["descMetadata"] # the datastream is the OM Document
|
76
|
-
...
|
77
|
-
doc.class
|
78
|
-
=> Hydra::ModsArticleDatastream # Hydra::ModsArticleDatastream is the Document Class
|
79
|
-
terminology = doc.class.terminology # The terminology is attached to the Document Class
|
80
|
-
</pre>
|
81
|
-
|
83
|
+
Hydra::ModsArticleDatastream has all of the behaviors of an OM::Document.
|
82
84
|
|
83
85
|
h1. Setting the XML in a NokogiriDatastream from a file
|
84
86
|
|
data/config/solr.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
development:
|
2
|
+
default:
|
3
|
+
url: http://localhost:8983/solr/development
|
4
|
+
full_text:
|
5
|
+
url: http://localhost:8983/solr/development
|
6
|
+
test:
|
7
|
+
default:
|
8
|
+
url: http://localhost:8983/solr/test
|
9
|
+
full_text:
|
10
|
+
url: http://localhost:8983/solr/test
|
11
|
+
production:
|
12
|
+
default:
|
13
|
+
url: http://localhost:8080/solr/production
|
14
|
+
full_text:
|
15
|
+
url: http://localhost:8080/solr/production
|
data/lib/active_fedora.rb
CHANGED
@@ -32,7 +32,7 @@ module ActiveFedora #:nodoc:
|
|
32
32
|
include Loggable
|
33
33
|
|
34
34
|
class << self
|
35
|
-
attr_accessor :solr_config, :fedora_config
|
35
|
+
attr_accessor :solr_config, :fedora_config, :config_env
|
36
36
|
end
|
37
37
|
|
38
38
|
# The configuration hash that gets used by RSolr.connect
|
@@ -40,13 +40,20 @@ module ActiveFedora #:nodoc:
|
|
40
40
|
@fedora_config ||= {}
|
41
41
|
|
42
42
|
# Initializes ActiveFedora's connection to Fedora and Solr based on the info in fedora.yml
|
43
|
-
# If
|
43
|
+
# If Rails.env is set, it will use that environment. Defaults to "development".
|
44
44
|
# @param [String] config_path (optional) the path to fedora.yml
|
45
45
|
# If config_path is not provided and Rails.root is set, it will look in RAILS_ENV/config/fedora.yml. Otherwise, it will look in your config/fedora.yml. Failing that, it will use localhost urls.
|
46
46
|
def self.init( config_path=nil )
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
if defined?(Rails.env)
|
49
|
+
@config_env = Rails.env
|
50
|
+
elsif defined?(ENV['environment'])
|
51
|
+
@config_env = ENV['environment']
|
52
|
+
else
|
53
|
+
@config_env = 'development'
|
54
|
+
logger.warn("No environment setting found: Using the default development environment.")
|
55
|
+
end
|
56
|
+
|
50
57
|
if config_path.nil?
|
51
58
|
if defined?(Rails.root)
|
52
59
|
config_path = "#{Rails.root}/config/fedora.yml"
|
@@ -62,9 +69,9 @@ module ActiveFedora #:nodoc:
|
|
62
69
|
|
63
70
|
logger.info("FEDORA: loading ActiveFedora config from #{File.expand_path(config_path)}")
|
64
71
|
fedora_config = YAML::load(File.open(config_path))
|
65
|
-
raise "The #{config_env} environment settings were not found in the fedora.yml config. If you already have a fedora.yml file defined, make sure it defines settings for the #{config_env} environment" unless fedora_config[config_env]
|
72
|
+
raise "The #{@config_env.to_s} environment settings were not found in the fedora.yml config. If you already have a fedora.yml file defined, make sure it defines settings for the #{@config_env} environment" unless fedora_config[@config_env]
|
66
73
|
|
67
|
-
ActiveFedora.solr_config[:url] = fedora_config[config_env]['solr']['url']
|
74
|
+
ActiveFedora.solr_config[:url] = fedora_config[@config_env]['solr']['url']
|
68
75
|
|
69
76
|
# Register Solr
|
70
77
|
logger.info("FEDORA: initializing ActiveFedora::SolrService with solr_config: #{ActiveFedora.solr_config.inspect}")
|
@@ -72,7 +79,7 @@ module ActiveFedora #:nodoc:
|
|
72
79
|
ActiveFedora::SolrService.register(ActiveFedora.solr_config[:url])
|
73
80
|
logger.info("FEDORA: initialized Solr with ActiveFedora.solr_config: #{ActiveFedora::SolrService.instance.inspect}")
|
74
81
|
|
75
|
-
ActiveFedora.fedora_config[:url] = fedora_config[config_env]['fedora']['url']
|
82
|
+
ActiveFedora.fedora_config[:url] = fedora_config[@config_env]['fedora']['url']
|
76
83
|
logger.info("FEDORA: initializing Fedora with fedora_config: #{ActiveFedora.fedora_config.inspect}")
|
77
84
|
|
78
85
|
Fedora::Repository.register(ActiveFedora.fedora_config[:url])
|
data/lib/active_fedora/base.rb
CHANGED
@@ -3,6 +3,7 @@ require 'active_fedora/model'
|
|
3
3
|
require 'active_fedora/semantic_node'
|
4
4
|
require "solrizer"
|
5
5
|
require 'nokogiri'
|
6
|
+
require "loggable"
|
6
7
|
|
7
8
|
SOLR_DOCUMENT_ID = "id" unless (defined?(SOLR_DOCUMENT_ID) && !SOLR_DOCUMENT_ID.nil?)
|
8
9
|
ENABLE_SOLR_UPDATES = true unless defined?(ENABLE_SOLR_UPDATES)
|
@@ -35,7 +36,8 @@ module ActiveFedora
|
|
35
36
|
include Model
|
36
37
|
include SemanticNode
|
37
38
|
include Solrizer::FieldNameMapper
|
38
|
-
|
39
|
+
include Loggable
|
40
|
+
|
39
41
|
attr_accessor :named_datastreams_desc
|
40
42
|
|
41
43
|
|
@@ -84,7 +86,7 @@ module ActiveFedora
|
|
84
86
|
#by any future instantiations.
|
85
87
|
def self.has_metadata(args, &block)
|
86
88
|
@ds_specs ||= Hash.new
|
87
|
-
@ds_specs[args[:name]]= [args[:type], block]
|
89
|
+
@ds_specs[args[:name]]= [args[:type], args.fetch(:label,""), block]
|
88
90
|
end
|
89
91
|
|
90
92
|
#Saves a Base object, and any dirty datastreams, then updates
|
@@ -1045,10 +1047,6 @@ module ActiveFedora
|
|
1045
1047
|
end
|
1046
1048
|
end
|
1047
1049
|
|
1048
|
-
def logger
|
1049
|
-
@logger ||= defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : Logger.new(STDOUT)
|
1050
|
-
end
|
1051
|
-
|
1052
1050
|
private
|
1053
1051
|
def configure_defined_datastreams
|
1054
1052
|
if self.class.ds_specs
|
@@ -1056,7 +1054,7 @@ module ActiveFedora
|
|
1056
1054
|
if self.datastreams.has_key?(name)
|
1057
1055
|
attributes = self.datastreams[name].attributes
|
1058
1056
|
else
|
1059
|
-
attributes = {:
|
1057
|
+
attributes = {:dsLabel=>ar[1]}
|
1060
1058
|
end
|
1061
1059
|
ds = ar.first.new(:dsid=>name)
|
1062
1060
|
# If you called has_metadata with a block, pass the block into the Datastream class
|
@@ -47,6 +47,18 @@ module ActiveFedora
|
|
47
47
|
self.attributes[:dsid] = dsid
|
48
48
|
end
|
49
49
|
|
50
|
+
def size
|
51
|
+
if !self.attributes.fetch(:dsSize,nil)
|
52
|
+
if self.new_object?
|
53
|
+
self.attributes[:dsSize]=nil
|
54
|
+
else
|
55
|
+
attrs = XmlSimple.xml_in(Fedora::Repository.instance.fetch_custom(self.pid,"datastreams/#{self.dsid}"))
|
56
|
+
self.attributes[:dsSize]=attrs["dsSize"].first
|
57
|
+
end
|
58
|
+
end
|
59
|
+
self.attributes[:dsSize]
|
60
|
+
end
|
61
|
+
|
50
62
|
#compatibility method for rails' url generators. This method will
|
51
63
|
#urlescape escape dots, which are apparently
|
52
64
|
#invalid characters in a dsid.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveFedora
|
2
2
|
module SemanticNode
|
3
3
|
include MediaShelfClassLevelInheritableAttributes
|
4
|
-
ms_inheritable_attributes :class_relationships, :internal_uri
|
4
|
+
ms_inheritable_attributes :class_relationships, :internal_uri, :class_named_relationships_desc
|
5
5
|
|
6
6
|
attr_accessor :internal_uri, :named_relationship_desc, :relationships_are_dirty, :load_from_solr
|
7
7
|
|
@@ -442,54 +442,7 @@ module ActiveFedora
|
|
442
442
|
end
|
443
443
|
xml.to_s
|
444
444
|
end
|
445
|
-
|
446
|
-
# Returns a solr query for retrieving objects specified in a relationship.
|
447
|
-
# It enables the use of query_params defined within a relationship to attach a query filter
|
448
|
-
# on top of just the predicate being used.
|
449
|
-
# Instead of this method you can also use the helper method
|
450
|
-
# [relationship_name]_query, i.e. method "parts_query" for relationship "parts".
|
451
|
-
# @param [String] The name of the relationship defined in the model
|
452
|
-
# @return [String]
|
453
|
-
# @example
|
454
|
-
# Class SampleAFObjRelationshipQueryParam < ActiveFedora::Base
|
455
|
-
# #points to all parents linked via is_member_of
|
456
|
-
# has_relationship "parents", :is_member_of
|
457
|
-
# #returns only parents that have a level value set to "series"
|
458
|
-
# has_relationship "series_parents", :is_member_of, :query_params=>{:q=>{"level_t"=>"series"}}
|
459
|
-
# end
|
460
|
-
# s = SampleAFObjRelationshipQueryParam.new
|
461
|
-
# obj = ActiveFedora::Base.new
|
462
|
-
# s.parents_append(obj)
|
463
|
-
# s.series_parents_query
|
464
|
-
# #=> "(id:changeme\\:13020 AND level_t:series)"
|
465
|
-
# SampleAFObjRelationshipQueryParam.named_relationship_query("series_parents")
|
466
|
-
# #=> "(id:changeme\\:13020 AND level_t:series)"
|
467
|
-
def named_relationship_query(relationship_name)
|
468
|
-
query = ""
|
469
|
-
if self.class.is_bidirectional_relationship?(relationship_name)
|
470
|
-
id_array = []
|
471
|
-
predicate = outbound_named_relationship_predicates["#{relationship_name}_outbound"]
|
472
|
-
if !outbound_relationships[predicate].nil?
|
473
|
-
outbound_relationships[predicate].each do |rel|
|
474
|
-
id_array << rel.gsub("info:fedora/", "")
|
475
|
-
end
|
476
|
-
end
|
477
|
-
query = self.class.bidirectional_named_relationship_query(pid,relationship_name,id_array)
|
478
|
-
elsif outbound_relationship_names.include?(relationship_name)
|
479
|
-
id_array = []
|
480
|
-
predicate = outbound_named_relationship_predicates[relationship_name]
|
481
|
-
if !outbound_relationships[predicate].nil?
|
482
|
-
outbound_relationships[predicate].each do |rel|
|
483
|
-
id_array << rel.gsub("info:fedora/", "")
|
484
|
-
end
|
485
|
-
end
|
486
|
-
query = self.class.outbound_named_relationship_query(relationship_name,id_array)
|
487
|
-
elsif inbound_relationship_names.include?(relationship_name)
|
488
|
-
query = self.class.inbound_named_relationship_query(pid,relationship_name)
|
489
|
-
end
|
490
|
-
query
|
491
|
-
end
|
492
|
-
|
445
|
+
|
493
446
|
module ClassMethods
|
494
447
|
|
495
448
|
# Allows for a relationship to be treated like any other attribute of a model class. You define
|
@@ -499,10 +452,7 @@ module ActiveFedora
|
|
499
452
|
# class AudioRecord < ActiveFedora::Base
|
500
453
|
#
|
501
454
|
# has_relationship "oral_history", :has_part, :inbound=>true, :type=>OralHistory
|
502
|
-
# # returns all similar audio
|
503
455
|
# has_relationship "similar_audio", :has_part, :type=>AudioRecord
|
504
|
-
# #returns only similar audio with format wav
|
505
|
-
# has_relationship "similar_audio_wav", :has_part, :query_params=>{:q=>"format_t"=>"wav"}
|
506
456
|
#
|
507
457
|
# The first two parameters are required:
|
508
458
|
# name: relationship name
|
@@ -511,7 +461,6 @@ module ActiveFedora
|
|
511
461
|
# possible parameters
|
512
462
|
# :inbound => if true loads an external relationship via Solr (defaults to false)
|
513
463
|
# :type => The type of model to use when instantiated an object from the pid in this relationship (defaults to ActiveFedora::Base)
|
514
|
-
# :query_params => Additional filters to be attached via a solr query (currently only :q implemented)
|
515
464
|
#
|
516
465
|
# If inbound is true it expects the relationship to be defined by another object's RELS-EXT
|
517
466
|
# and to load that relationship from Solr. Otherwise, if inbound is true the relationship is stored in
|
@@ -523,24 +472,22 @@ module ActiveFedora
|
|
523
472
|
# For the oral_history relationship in the example above the following helper methods are created:
|
524
473
|
# oral_history: returns array of OralHistory objects that have this AudioRecord with predicate :has_part
|
525
474
|
# oral_history_ids: Return array of pids for OralHistory objects that have this AudioRecord with predicate :has_part
|
526
|
-
# oral_history_query: Return solr query that can be used to retrieve related objects as solr documents
|
527
475
|
#
|
528
476
|
# For the outbound relationship "similar_audio" there are two additional methods to append and remove objects from that relationship
|
529
477
|
# since it is managed internally:
|
530
478
|
# similar_audio: Return array of AudioRecord objects that have been added to similar_audio relationship
|
531
479
|
# similar_audio_ids: Return array of AudioRecord object pids that have been added to similar_audio relationship
|
532
|
-
# similar_audio_query: Return solr query that can be used to retrieve related objects as solr documents
|
533
480
|
# similar_audio_append: Add an AudioRecord object to the similar_audio relationship
|
534
481
|
# similar_audio_remove: Remove an AudioRecord from the similar_audio relationship
|
535
482
|
def has_relationship(name, predicate, opts = {})
|
536
483
|
opts = {:singular => nil, :inbound => false}.merge(opts)
|
537
484
|
if opts[:inbound] == true
|
538
|
-
|
485
|
+
raise "Duplicate use of predicate for named inbound relationship not allowed" if named_predicate_exists_with_different_name?(:inbound,name,predicate)
|
539
486
|
register_named_relationship(:inbound, name, predicate, opts)
|
540
487
|
register_predicate(:inbound, predicate)
|
541
488
|
create_inbound_relationship_finders(name, predicate, opts)
|
542
489
|
else
|
543
|
-
|
490
|
+
raise "Duplicate use of predicate for named outbound relationship not allowed" if named_predicate_exists_with_different_name?(:self,name,predicate)
|
544
491
|
register_named_relationship(:self, name, predicate, opts)
|
545
492
|
register_predicate(:self, predicate)
|
546
493
|
create_named_relationship_methods(name)
|
@@ -615,160 +562,6 @@ module ActiveFedora
|
|
615
562
|
opts.merge!({:predicate=>predicate})
|
616
563
|
named_relationships_desc[subject][name] = opts
|
617
564
|
end
|
618
|
-
|
619
|
-
# Returns a solr query for retrieving objects specified in an outbound relationship.
|
620
|
-
# This method is mostly used by internal method calls.
|
621
|
-
# It enables the use of query_params defined within a relationship to attach a query filter
|
622
|
-
# on top of just the predicate being used. Because it is static it
|
623
|
-
# needs the pids defined within RELS-EXT for this relationship to be passed in.
|
624
|
-
# If you are calling this method directly to get the query you should use the
|
625
|
-
# ActiveFedora::SemanticNode.named_relationship_query instead or use the helper method
|
626
|
-
# [relationship_name]_query, i.e. method "parts_query" for relationship "parts". This
|
627
|
-
# method would only be called directly if you had something like an array of outbound pids
|
628
|
-
# already in something like a solr document for object that has these relationships.
|
629
|
-
# @param [String] The name of the relationship defined in the model
|
630
|
-
# @param [Array] An array of pids to include in the query
|
631
|
-
# @return [String]
|
632
|
-
# @example
|
633
|
-
# Class SampleAFObjRelationshipQueryParam < ActiveFedora::Base
|
634
|
-
# #points to all parents linked via is_member_of
|
635
|
-
# has_relationship "parents", :is_member_of
|
636
|
-
# #returns only parents that have a level value set to "series"
|
637
|
-
# has_relationship "series_parents", :is_member_of, :query_params=>{:q=>{"level_t"=>"series"}}
|
638
|
-
# end
|
639
|
-
# s = SampleAFObjRelationshipQueryParam.new
|
640
|
-
# obj = ActiveFedora::Base.new
|
641
|
-
# s.series_parents_append(obj)
|
642
|
-
# s.series_parents_query
|
643
|
-
# #=> "(id:changeme\\:13020 AND level_t:series)"
|
644
|
-
# SampleAFObjRelationshipQueryParam.outbound_named_relationship_query("series_parents",["id:changeme:13020"])
|
645
|
-
# #=> "(id:changeme\\:13020 AND level_t:series)"
|
646
|
-
def outbound_named_relationship_query(relationship_name,outbound_pids)
|
647
|
-
query = ActiveFedora::SolrService.construct_query_for_pids(outbound_pids)
|
648
|
-
subject = :self
|
649
|
-
if named_relationships_desc.has_key?(subject) && named_relationships_desc[subject].has_key?(relationship_name) && named_relationships_desc[subject][relationship_name].has_key?(:query_params)
|
650
|
-
query_params = format_query_params(named_relationships_desc[subject][relationship_name][:query_params])
|
651
|
-
if query_params[:q]
|
652
|
-
unless query.empty?
|
653
|
-
#substitute in the filter query for each pid so that it is applied to each in the query
|
654
|
-
query.sub!(/OR /,"AND #{query_params[:q]}) OR (")
|
655
|
-
#add opening parenthesis for first case
|
656
|
-
query = "(" + query
|
657
|
-
#add AND filter case for last element as well since no 'OR' following it
|
658
|
-
query << " AND #{query_params[:q]})"
|
659
|
-
else
|
660
|
-
query = query_params[:q]
|
661
|
-
end
|
662
|
-
end
|
663
|
-
end
|
664
|
-
query
|
665
|
-
end
|
666
|
-
|
667
|
-
# Returns a solr query for retrieving objects specified in an inbound relationship.
|
668
|
-
# This method is mostly used by internal method calls.
|
669
|
-
# It enables the use of query_params defined within a relationship to attach a query filter
|
670
|
-
# on top of just the predicate being used. Because it is static it
|
671
|
-
# needs the pid of the object that has the inbound relationships passed in.
|
672
|
-
# If you are calling this method directly to get the query you should use the
|
673
|
-
# ActiveFedora::SemanticNode.named_relationship_query instead or use the helper method
|
674
|
-
# [relationship_name]_query, i.e. method "parts_query" for relationship "parts". This
|
675
|
-
# method would only be called directly if you were working only with Solr and already
|
676
|
-
# had the pid for the object in something like a solr document.
|
677
|
-
# @param [String] The pid for the object that has these inbound relationships
|
678
|
-
# @param [String] The name of the relationship defined in the model
|
679
|
-
# @return [String]
|
680
|
-
# @example
|
681
|
-
# Class SampleAFObjRelationshipQueryParam < ActiveFedora::Base
|
682
|
-
# #returns all parts
|
683
|
-
# has_relationship "parts", :is_part_of, :inbound=>true
|
684
|
-
# #returns only parts that have level to "series"
|
685
|
-
# has_relationship "series_parts", :is_part_of, :inbound=>true, :query_params=>{:q=>{"level_t"=>"series"}}
|
686
|
-
# end
|
687
|
-
# s = SampleAFObjRelationshipQueryParam.new
|
688
|
-
# s.pid
|
689
|
-
# #=> id:changeme:13020
|
690
|
-
# s.series_parts_query
|
691
|
-
# #=> "is_part_of_s:info\\:fedora/changeme\\:13021 AND level_t:series"
|
692
|
-
# SampleAFObjRelationshipQueryParam.inbound_named_relationship_query(s.pid,"series_parts")
|
693
|
-
# #=> "is_part_of_s:info\\:fedora/changeme\\:13021 AND level_t:series"
|
694
|
-
def inbound_named_relationship_query(pid,relationship_name)
|
695
|
-
query = ""
|
696
|
-
subject = :inbound
|
697
|
-
if named_relationships_desc.has_key?(subject) && named_relationships_desc[subject].has_key?(relationship_name)
|
698
|
-
predicate = named_relationships_desc[subject][relationship_name][:predicate]
|
699
|
-
internal_uri = "info:fedora/#{pid}"
|
700
|
-
escaped_uri = internal_uri.gsub(/(:)/, '\\:')
|
701
|
-
query = "#{predicate}_s:#{escaped_uri}"
|
702
|
-
if named_relationships_desc.has_key?(subject) && named_relationships_desc[subject].has_key?(relationship_name) && named_relationships_desc[subject][relationship_name].has_key?(:query_params)
|
703
|
-
query_params = format_query_params(named_relationships_desc[subject][relationship_name][:query_params])
|
704
|
-
if query_params[:q]
|
705
|
-
query << " AND " unless query.empty?
|
706
|
-
query << query_params[:q]
|
707
|
-
end
|
708
|
-
end
|
709
|
-
end
|
710
|
-
query
|
711
|
-
end
|
712
|
-
|
713
|
-
# Returns a solr query for retrieving objects specified in a bidirectional relationship.
|
714
|
-
# This method is mostly used by internal method calls.
|
715
|
-
# It enables the use of query_params defined within a relationship to attach a query filter
|
716
|
-
# on top of just the predicate being used. Because it is static it
|
717
|
-
# needs the pids defined within RELS-EXT for the outbound relationship as well as the pid of the
|
718
|
-
# object for the inbound portion of the relationship.
|
719
|
-
# If you are calling this method directly to get the query you should use the
|
720
|
-
# ActiveFedora::SemanticNode.named_relationship_query instead or use the helper method
|
721
|
-
# [relationship_name]_query, i.e. method "bi_parts_query" for relationship "bi_parts". This
|
722
|
-
# method would only be called directly if you had something like an array of outbound pids
|
723
|
-
# already in something like a solr document for object that has these relationships.
|
724
|
-
# @param [String] The pid for the object that has these inbound relationships
|
725
|
-
# @param [String] The name of the relationship defined in the model
|
726
|
-
# @param [Array] An array of pids to include in the query
|
727
|
-
# @return [String]
|
728
|
-
# @example
|
729
|
-
# Class SampleAFObjRelationshipQueryParam < ActiveFedora::Base
|
730
|
-
# has_bidirectional_relationship "bi_series_parts", :has_part, :is_part_of, :query_params=>{:q=>{"level_t"=>"series"}}
|
731
|
-
# end
|
732
|
-
# s = SampleAFObjRelationshipQueryParam.new
|
733
|
-
# obj = ActiveFedora::Base.new
|
734
|
-
# s.bi_series_parts_append(obj)
|
735
|
-
# s.pid
|
736
|
-
# #=> "changeme:13025"
|
737
|
-
# obj.pid
|
738
|
-
# #=> id:changeme:13026
|
739
|
-
# s.bi_series_parts_query
|
740
|
-
# #=> "(id:changeme\\:13026 AND level_t:series) OR (is_part_of_s:info\\:fedora/changeme\\:13025 AND level_t:series)"
|
741
|
-
# SampleAFObjRelationshipQueryParam.bidirectional_named_relationship_query(s.pid,"series_parents",["id:changeme:13026"])
|
742
|
-
# #=> "(id:changeme\\:13026 AND level_t:series) OR (is_part_of_s:info\\:fedora/changeme\\:13025 AND level_t:series)"
|
743
|
-
def bidirectional_named_relationship_query(pid,relationship_name,outbound_pids)
|
744
|
-
outbound_named_relationship_query("#{relationship_name}_outbound",outbound_pids) + " OR (" + inbound_named_relationship_query(pid,"#{relationship_name}_inbound") + ")"
|
745
|
-
end
|
746
|
-
|
747
|
-
# This will transform and encode any query_params defined in a relationship method to properly escape special characters
|
748
|
-
# and format strings such as query string properly for a solr query
|
749
|
-
# @param [Hash] The has of expected query params (including at least :q)
|
750
|
-
# @return [String]
|
751
|
-
def format_query_params(query_params)
|
752
|
-
if query_params && query_params[:q]
|
753
|
-
add_query = ""
|
754
|
-
if query_params[:q].is_a? Hash
|
755
|
-
query_params[:q].keys.each_with_index do |key,index|
|
756
|
-
add_query << " AND " if index > 0
|
757
|
-
add_query << "#{key}:#{query_params[:q][key].gsub(/:/, '\\\\:')}"
|
758
|
-
end
|
759
|
-
elsif !query_params[:q].empty?
|
760
|
-
add_query = "#{query_params[:q]}"
|
761
|
-
end
|
762
|
-
query_params[:q] = add_query unless add_query.empty?
|
763
|
-
query_params
|
764
|
-
end
|
765
|
-
end
|
766
|
-
|
767
|
-
#Tests if the relationship name passed is in bidirectional
|
768
|
-
# @return [Boolean]
|
769
|
-
def is_bidirectional_relationship?(relationship_name)
|
770
|
-
named_relationships_desc[:self]["#{relationship_name}_outbound"] && named_relationships_desc[:inbound]["#{relationship_name}_inbound"]
|
771
|
-
end
|
772
565
|
|
773
566
|
# ** EXPERIMENTAL **
|
774
567
|
#
|
@@ -808,8 +601,8 @@ module ActiveFedora
|
|
808
601
|
class_eval <<-END
|
809
602
|
def #{name}(opts={})
|
810
603
|
opts = {:rows=>25}.merge(opts)
|
811
|
-
|
812
|
-
solr_result = SolrService.instance.conn.query(
|
604
|
+
escaped_uri = self.internal_uri.gsub(/(:)/, '\\:')
|
605
|
+
solr_result = SolrService.instance.conn.query("#{predicate}_s:\#{escaped_uri}", :rows=>opts[:rows])
|
813
606
|
if opts[:response_format] == :solr
|
814
607
|
return solr_result
|
815
608
|
else
|
@@ -832,18 +625,8 @@ module ActiveFedora
|
|
832
625
|
def #{name}_from_solr
|
833
626
|
#{name}(:response_format => :load_from_solr)
|
834
627
|
end
|
835
|
-
def #{name}_solr_docs
|
836
|
-
#{name}(:response_format => :solr)
|
837
|
-
end
|
838
|
-
def #{name}_query
|
839
|
-
named_relationship_query("#{name}")
|
840
|
-
end
|
841
628
|
END
|
842
629
|
end
|
843
|
-
|
844
|
-
def relationship_has_query_params?(subject, relationship_name)
|
845
|
-
named_relationships_desc.has_key?(subject) && named_relationships_desc[subject].has_key?(relationship_name) && named_relationships_desc[subject][relationship_name].has_key?(:query_params)
|
846
|
-
end
|
847
630
|
|
848
631
|
def create_outbound_relationship_finders(name, predicate, opts = {})
|
849
632
|
class_eval <<-END
|
@@ -854,20 +637,13 @@ module ActiveFedora
|
|
854
637
|
id_array << rel.gsub("info:fedora/", "")
|
855
638
|
end
|
856
639
|
end
|
857
|
-
|
858
|
-
if opts[:response_format] == :id_array && !self.class.relationship_has_query_params?(:self,"#{name}")
|
640
|
+
if opts[:response_format] == :id_array
|
859
641
|
return id_array
|
860
642
|
else
|
861
|
-
query =
|
643
|
+
query = ActiveFedora::SolrService.construct_query_for_pids(id_array)
|
862
644
|
solr_result = SolrService.instance.conn.query(query)
|
863
645
|
if opts[:response_format] == :solr
|
864
646
|
return solr_result
|
865
|
-
elsif opts[:response_format] == :id_array
|
866
|
-
id_array = []
|
867
|
-
solr_result.hits.each do |hit|
|
868
|
-
id_array << hit[SOLR_DOCUMENT_ID]
|
869
|
-
end
|
870
|
-
return id_array
|
871
647
|
elsif opts[:response_format] == :load_from_solr || self.load_from_solr
|
872
648
|
return ActiveFedora::SolrService.reify_solr_results(solr_result,{:load_from_solr=>true})
|
873
649
|
else
|
@@ -881,15 +657,9 @@ module ActiveFedora
|
|
881
657
|
def #{name}_from_solr
|
882
658
|
#{name}(:response_format => :load_from_solr)
|
883
659
|
end
|
884
|
-
def #{name}_solr_docs
|
885
|
-
#{name}(:response_format => :solr)
|
886
|
-
end
|
887
|
-
def #{name}_query
|
888
|
-
named_relationship_query("#{name}")
|
889
|
-
end
|
890
660
|
END
|
891
661
|
end
|
892
|
-
|
662
|
+
|
893
663
|
# Generates relationship finders for predicates that point in both directions
|
894
664
|
# and registers predicate relationships for each direction.
|
895
665
|
#
|
@@ -910,15 +680,12 @@ module ActiveFedora
|
|
910
680
|
def #{name}(opts={})
|
911
681
|
opts = {:rows=>25}.merge(opts)
|
912
682
|
if opts[:response_format] == :solr || opts[:response_format] == :load_from_solr
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
end
|
920
|
-
#outbound_id_array = #{outbound_method_name}(:response_format=>:id_array)
|
921
|
-
query = self.class.bidirectional_named_relationship_query(self.pid,"#{name}",outbound_id_array)
|
683
|
+
escaped_uri = self.internal_uri.gsub(/(:)/, '\\:')
|
684
|
+
query = "#{inbound_predicate}_s:\#{escaped_uri}"
|
685
|
+
|
686
|
+
outbound_id_array = #{outbound_method_name}(:response_format=>:id_array)
|
687
|
+
query = query + " OR " + ActiveFedora::SolrService.construct_query_for_pids(outbound_id_array)
|
688
|
+
|
922
689
|
solr_result = SolrService.instance.conn.query(query, :rows=>opts[:rows])
|
923
690
|
|
924
691
|
if opts[:response_format] == :solr
|
@@ -939,12 +706,6 @@ module ActiveFedora
|
|
939
706
|
def #{name}_from_solr
|
940
707
|
#{name}(:response_format => :load_from_solr)
|
941
708
|
end
|
942
|
-
def #{name}_solr_docs
|
943
|
-
#{name}(:response_format => :solr)
|
944
|
-
end
|
945
|
-
def #{name}_query
|
946
|
-
named_relationship_query("#{name}")
|
947
|
-
end
|
948
709
|
END
|
949
710
|
end
|
950
711
|
|