active-fedora 2.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CONSOLE_GETTING_STARTED.textile +92 -59
- data/Gemfile.lock +1 -2
- data/README.textile +2 -2
- data/config/fedora.yml +1 -1
- data/config/predicate_mappings.yml +17 -20
- data/lib/active_fedora.rb +2 -5
- data/lib/active_fedora/samples/hydra-mods_article_datastream.rb +3 -3
- data/lib/active_fedora/samples/sample_af_obj_relationship_query_param.rb +11 -0
- data/lib/active_fedora/samples/special_thing.rb +4 -2
- data/lib/active_fedora/semantic_node.rb +254 -15
- data/lib/active_fedora/version.rb +1 -1
- data/spec/fixtures/rails_root/config/fedora.yml +4 -4
- data/spec/integration/nokogiri_datastream_spec.rb +2 -1
- data/spec/integration/semantic_node_spec.rb +259 -2
- data/spec/unit/active_fedora_spec.rb +2 -2
- data/spec/unit/semantic_node_spec.rb +13 -6
- metadata +8 -6
@@ -0,0 +1,11 @@
|
|
1
|
+
class SampleAFObjRelationshipQueryParam < ActiveFedora::Base
|
2
|
+
#points to all parents linked via is_member_of
|
3
|
+
has_relationship "parents", :is_member_of
|
4
|
+
#returns only parents that have a level value set to "series"
|
5
|
+
has_relationship "series_parents", :is_member_of, :query_params=>{:q=>{"level_t"=>"series"}}
|
6
|
+
#returns all parts
|
7
|
+
has_relationship "parts", :is_part_of, :inbound=>true
|
8
|
+
#returns only parts that have level to "series"
|
9
|
+
has_relationship "series_parts", :is_part_of, :inbound=>true, :query_params=>{:q=>{"level_t"=>"series"}}
|
10
|
+
has_bidirectional_relationship "bi_series_parts", :has_part, :is_part_of, :query_params=>{:q=>{"level_t"=>"series"}}
|
11
|
+
end
|
@@ -5,10 +5,12 @@ require "active_fedora/samples/marpa-dc_datastream.rb"
|
|
5
5
|
|
6
6
|
# This is an example of an ActiveFedora Model
|
7
7
|
#
|
8
|
-
# Some of the datastream ids were chosen based on the Hydra modeling conventions. You don't have to follow them in your work.
|
8
|
+
# Some of the datastream ids were chosen based on the Hydra modeling conventions. You don't have to follow them in your work.
|
9
|
+
# ActiveFedora itself has no notion of those conventions, but we do encourage you to use them.
|
9
10
|
#
|
10
11
|
# The Hydra conventions encourage you to have a datastream with this dsid whose contents are descriptive metadata like MODS or Dublin Core. They especially encourage MODS.
|
11
|
-
# The
|
12
|
+
# The descMetadata dsid is a Hydra convention for a datastream with descriptive metadata contents, like MODS or Dublin Core. They especially encourage MODS.
|
13
|
+
# The rightsMetadata dsid is also a convention provided by the Hydra Common Metadata "content model"
|
12
14
|
#
|
13
15
|
# For more info on the Hydra conventions, see the documentation on "Common Metadata content model" in https://wiki.duraspace.org/display/hydra/Hydra+content+models+and+disseminators
|
14
16
|
# Note that on the wiki, "content model" is often used to refer to Fedora CModels and/or abstract/notional models. The Common Metadata content model is an example of this.
|
@@ -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
|
5
5
|
|
6
6
|
attr_accessor :internal_uri, :named_relationship_desc, :relationships_are_dirty, :load_from_solr
|
7
7
|
|
@@ -442,7 +442,54 @@ module ActiveFedora
|
|
442
442
|
end
|
443
443
|
xml.to_s
|
444
444
|
end
|
445
|
-
|
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
|
+
|
446
493
|
module ClassMethods
|
447
494
|
|
448
495
|
# Allows for a relationship to be treated like any other attribute of a model class. You define
|
@@ -452,7 +499,10 @@ module ActiveFedora
|
|
452
499
|
# class AudioRecord < ActiveFedora::Base
|
453
500
|
#
|
454
501
|
# has_relationship "oral_history", :has_part, :inbound=>true, :type=>OralHistory
|
502
|
+
# # returns all similar audio
|
455
503
|
# 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"}
|
456
506
|
#
|
457
507
|
# The first two parameters are required:
|
458
508
|
# name: relationship name
|
@@ -461,6 +511,7 @@ module ActiveFedora
|
|
461
511
|
# possible parameters
|
462
512
|
# :inbound => if true loads an external relationship via Solr (defaults to false)
|
463
513
|
# :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)
|
464
515
|
#
|
465
516
|
# If inbound is true it expects the relationship to be defined by another object's RELS-EXT
|
466
517
|
# and to load that relationship from Solr. Otherwise, if inbound is true the relationship is stored in
|
@@ -472,22 +523,24 @@ module ActiveFedora
|
|
472
523
|
# For the oral_history relationship in the example above the following helper methods are created:
|
473
524
|
# oral_history: returns array of OralHistory objects that have this AudioRecord with predicate :has_part
|
474
525
|
# 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
|
475
527
|
#
|
476
528
|
# For the outbound relationship "similar_audio" there are two additional methods to append and remove objects from that relationship
|
477
529
|
# since it is managed internally:
|
478
530
|
# similar_audio: Return array of AudioRecord objects that have been added to similar_audio relationship
|
479
531
|
# 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
|
480
533
|
# similar_audio_append: Add an AudioRecord object to the similar_audio relationship
|
481
534
|
# similar_audio_remove: Remove an AudioRecord from the similar_audio relationship
|
482
535
|
def has_relationship(name, predicate, opts = {})
|
483
536
|
opts = {:singular => nil, :inbound => false}.merge(opts)
|
484
537
|
if opts[:inbound] == true
|
485
|
-
raise "Duplicate use of predicate for named inbound relationship not allowed" if named_predicate_exists_with_different_name?(:inbound,name,predicate)
|
538
|
+
#raise "Duplicate use of predicate for named inbound relationship not allowed" if named_predicate_exists_with_different_name?(:inbound,name,predicate)
|
486
539
|
register_named_relationship(:inbound, name, predicate, opts)
|
487
540
|
register_predicate(:inbound, predicate)
|
488
541
|
create_inbound_relationship_finders(name, predicate, opts)
|
489
542
|
else
|
490
|
-
raise "Duplicate use of predicate for named outbound relationship not allowed" if named_predicate_exists_with_different_name?(:self,name,predicate)
|
543
|
+
#raise "Duplicate use of predicate for named outbound relationship not allowed" if named_predicate_exists_with_different_name?(:self,name,predicate)
|
491
544
|
register_named_relationship(:self, name, predicate, opts)
|
492
545
|
register_predicate(:self, predicate)
|
493
546
|
create_named_relationship_methods(name)
|
@@ -562,6 +615,160 @@ module ActiveFedora
|
|
562
615
|
opts.merge!({:predicate=>predicate})
|
563
616
|
named_relationships_desc[subject][name] = opts
|
564
617
|
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
|
565
772
|
|
566
773
|
# ** EXPERIMENTAL **
|
567
774
|
#
|
@@ -601,8 +808,8 @@ module ActiveFedora
|
|
601
808
|
class_eval <<-END
|
602
809
|
def #{name}(opts={})
|
603
810
|
opts = {:rows=>25}.merge(opts)
|
604
|
-
|
605
|
-
solr_result = SolrService.instance.conn.query(
|
811
|
+
query = self.class.inbound_named_relationship_query(self.pid,"#{name}")
|
812
|
+
solr_result = SolrService.instance.conn.query(query, :rows=>opts[:rows])
|
606
813
|
if opts[:response_format] == :solr
|
607
814
|
return solr_result
|
608
815
|
else
|
@@ -625,8 +832,18 @@ module ActiveFedora
|
|
625
832
|
def #{name}_from_solr
|
626
833
|
#{name}(:response_format => :load_from_solr)
|
627
834
|
end
|
835
|
+
def #{name}_solr_docs
|
836
|
+
#{name}(:response_format => :solr)
|
837
|
+
end
|
838
|
+
def #{name}_query
|
839
|
+
named_relationship_query("#{name}")
|
840
|
+
end
|
628
841
|
END
|
629
842
|
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
|
630
847
|
|
631
848
|
def create_outbound_relationship_finders(name, predicate, opts = {})
|
632
849
|
class_eval <<-END
|
@@ -637,13 +854,20 @@ module ActiveFedora
|
|
637
854
|
id_array << rel.gsub("info:fedora/", "")
|
638
855
|
end
|
639
856
|
end
|
640
|
-
|
857
|
+
|
858
|
+
if opts[:response_format] == :id_array && !self.class.relationship_has_query_params?(:self,"#{name}")
|
641
859
|
return id_array
|
642
860
|
else
|
643
|
-
query =
|
861
|
+
query = self.class.outbound_named_relationship_query("#{name}",id_array)
|
644
862
|
solr_result = SolrService.instance.conn.query(query)
|
645
863
|
if opts[:response_format] == :solr
|
646
864
|
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
|
647
871
|
elsif opts[:response_format] == :load_from_solr || self.load_from_solr
|
648
872
|
return ActiveFedora::SolrService.reify_solr_results(solr_result,{:load_from_solr=>true})
|
649
873
|
else
|
@@ -657,9 +881,15 @@ module ActiveFedora
|
|
657
881
|
def #{name}_from_solr
|
658
882
|
#{name}(:response_format => :load_from_solr)
|
659
883
|
end
|
884
|
+
def #{name}_solr_docs
|
885
|
+
#{name}(:response_format => :solr)
|
886
|
+
end
|
887
|
+
def #{name}_query
|
888
|
+
named_relationship_query("#{name}")
|
889
|
+
end
|
660
890
|
END
|
661
891
|
end
|
662
|
-
|
892
|
+
|
663
893
|
# Generates relationship finders for predicates that point in both directions
|
664
894
|
# and registers predicate relationships for each direction.
|
665
895
|
#
|
@@ -680,12 +910,15 @@ module ActiveFedora
|
|
680
910
|
def #{name}(opts={})
|
681
911
|
opts = {:rows=>25}.merge(opts)
|
682
912
|
if opts[:response_format] == :solr || opts[:response_format] == :load_from_solr
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
913
|
+
outbound_id_array = []
|
914
|
+
predicate = outbound_named_relationship_predicates["#{name}_outbound"]
|
915
|
+
if !outbound_relationships[predicate].nil?
|
916
|
+
outbound_relationships[predicate].each do |rel|
|
917
|
+
outbound_id_array << rel.gsub("info:fedora/", "")
|
918
|
+
end
|
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)
|
689
922
|
solr_result = SolrService.instance.conn.query(query, :rows=>opts[:rows])
|
690
923
|
|
691
924
|
if opts[:response_format] == :solr
|
@@ -706,6 +939,12 @@ module ActiveFedora
|
|
706
939
|
def #{name}_from_solr
|
707
940
|
#{name}(:response_format => :load_from_solr)
|
708
941
|
end
|
942
|
+
def #{name}_solr_docs
|
943
|
+
#{name}(:response_format => :solr)
|
944
|
+
end
|
945
|
+
def #{name}_query
|
946
|
+
named_relationship_query("#{name}")
|
947
|
+
end
|
709
948
|
END
|
710
949
|
end
|
711
950
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
development:
|
2
2
|
fedora:
|
3
|
-
url: http://fedoraAdmin:fedoraAdmin@
|
3
|
+
url: http://fedoraAdmin:fedoraAdmin@localhost:8983/fedora
|
4
4
|
solr:
|
5
|
-
url: http://
|
5
|
+
url: http://localhost:8983/solr/development
|
6
6
|
test:
|
7
7
|
fedora:
|
8
|
-
url: http://fedoraAdmin:fedoraAdmin@
|
8
|
+
url: http://fedoraAdmin:fedoraAdmin@localhost:8983/fedora
|
9
9
|
solr:
|
10
|
-
url: http://
|
10
|
+
url: http://localhost:8983/solr/development
|
11
11
|
production:
|
12
12
|
fedora:
|
13
13
|
url: http://fedoraAdmin:fedoraAdmin@testhost.com:8080/fedora
|
@@ -20,7 +20,8 @@ describe ActiveFedora::NokogiriDatastream do
|
|
20
20
|
m.field 'collection', :string
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
|
+
RAILS_ENV='development'
|
24
25
|
@pid = "hydrangea:fixture_mods_article1"
|
25
26
|
@test_solr_object = HydrangeaArticle2.load_instance_from_solr(@pid)
|
26
27
|
@test_object = HydrangeaArticle2.load_instance(@pid)
|
@@ -13,6 +13,15 @@ describe ActiveFedora::SemanticNode do
|
|
13
13
|
class SNSpecModel < ActiveFedora::Base
|
14
14
|
has_relationship("parts", :is_part_of, :inbound => true)
|
15
15
|
has_relationship("containers", :is_member_of)
|
16
|
+
has_bidirectional_relationship("bi_containers", :is_member_of, :has_member)
|
17
|
+
end
|
18
|
+
class SpecNodeQueryParam < ActiveFedora::Base
|
19
|
+
has_relationship("parts", :is_part_of, :inbound => true)
|
20
|
+
has_relationship("special_parts", :is_part_of, :inbound => true, :query_params=>{:q=>{"has_model_s"=>"info:fedora/SpecialPart"}})
|
21
|
+
has_relationship("containers", :is_member_of)
|
22
|
+
has_relationship("special_containers", :is_member_of, :query_params=>{:q=>{"has_model_s"=>"info:fedora/SpecialContainer"}})
|
23
|
+
has_bidirectional_relationship("bi_containers", :is_member_of, :has_member)
|
24
|
+
has_bidirectional_relationship("bi_special_containers", :is_member_of, :has_member, :query_params=>{:q=>{"has_model_s"=>"info:fedora/SpecialContainer"}})
|
16
25
|
end
|
17
26
|
|
18
27
|
@test_object = SNSpecModel.new
|
@@ -25,24 +34,89 @@ describe ActiveFedora::SemanticNode do
|
|
25
34
|
@part2.add_relationship(:is_part_of, @test_object)
|
26
35
|
@part2.save
|
27
36
|
|
28
|
-
|
29
37
|
@container1 = ActiveFedora::Base.new()
|
30
38
|
@container1.save
|
31
39
|
@container2 = ActiveFedora::Base.new()
|
32
40
|
@container2.save
|
41
|
+
@container3 = ActiveFedora::Base.new()
|
42
|
+
@container3.save
|
33
43
|
|
34
44
|
@test_object.add_relationship(:is_member_of, @container1)
|
35
45
|
@test_object.add_relationship(:is_member_of, @container2)
|
36
46
|
@test_object.save
|
47
|
+
|
48
|
+
@special_container = ActiveFedora::Base.new()
|
49
|
+
@special_container.add_relationship(:has_model,"SpecialContainer")
|
50
|
+
@special_container.save
|
51
|
+
|
52
|
+
#even though adding container3 and special container, it should only include special_container when returning via named finder methods
|
53
|
+
#also should only return special part similarly
|
54
|
+
@test_object_query = SpecNodeQueryParam.new
|
55
|
+
@test_object_query.add_relationship(:is_member_of, @container3)
|
56
|
+
@test_object_query.add_relationship(:is_member_of, @special_container)
|
57
|
+
@test_object_query.save
|
58
|
+
|
59
|
+
@special_container2 = ActiveFedora::Base.new()
|
60
|
+
@special_container2.add_relationship(:has_model,"SpecialContainer")
|
61
|
+
@special_container2.add_relationship(:has_member,@test_object_query.pid)
|
62
|
+
@special_container2.save
|
63
|
+
|
64
|
+
@part3 = ActiveFedora::Base.new()
|
65
|
+
@part3.add_relationship(:is_part_of, @test_object_query)
|
66
|
+
@part3.save
|
67
|
+
|
68
|
+
@special_part = ActiveFedora::Base.new()
|
69
|
+
@special_part.add_relationship(:has_model,"SpecialPart")
|
70
|
+
@special_part.add_relationship(:is_part_of, @test_object_query)
|
71
|
+
@special_part.save
|
72
|
+
|
37
73
|
end
|
38
74
|
|
39
75
|
after(:all) do
|
76
|
+
begin
|
40
77
|
@part1.delete
|
78
|
+
rescue
|
79
|
+
end
|
80
|
+
begin
|
41
81
|
@part2.delete
|
82
|
+
rescue
|
83
|
+
end
|
84
|
+
begin
|
85
|
+
@part3.delete
|
86
|
+
rescue
|
87
|
+
end
|
88
|
+
begin
|
42
89
|
@container1.delete
|
90
|
+
rescue
|
91
|
+
end
|
92
|
+
begin
|
43
93
|
@container2.delete
|
94
|
+
rescue
|
95
|
+
end
|
96
|
+
begin
|
97
|
+
@container3.delete
|
98
|
+
rescue
|
99
|
+
end
|
100
|
+
begin
|
44
101
|
@test_object.delete
|
45
|
-
|
102
|
+
rescue
|
103
|
+
end
|
104
|
+
begin
|
105
|
+
@test_object_query.delete
|
106
|
+
rescue
|
107
|
+
end
|
108
|
+
begin
|
109
|
+
@special_part.delete
|
110
|
+
rescue
|
111
|
+
end
|
112
|
+
begin
|
113
|
+
@special_container.delete
|
114
|
+
rescue
|
115
|
+
end
|
116
|
+
begin
|
117
|
+
@special_container2.delete
|
118
|
+
rescue
|
119
|
+
end
|
46
120
|
Object.send(:remove_const, :SNSpecModel)
|
47
121
|
|
48
122
|
end
|
@@ -74,6 +148,73 @@ describe ActiveFedora::SemanticNode do
|
|
74
148
|
id.should satisfy {|id| id == @part1.pid || @part2.pid}
|
75
149
|
end
|
76
150
|
end
|
151
|
+
it "should return an array of Base objects with some filtered out if using query params" do
|
152
|
+
@test_object_query.special_parts_ids.should == [@special_part.pid]
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should return an array of all Base objects with relationship if not using query params" do
|
156
|
+
@test_object_query.parts_ids.size.should == 2
|
157
|
+
@test_object_query.parts_ids.include?(@special_part.pid).should == true
|
158
|
+
@test_object_query.parts_ids.include?(@part3.pid).should == true
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should return a solr query for an inbound relationship" do
|
162
|
+
@test_object_query.special_parts_query.should == "#{@test_object_query.named_relationship_predicates[:inbound]['special_parts']}_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')} AND has_model_s:info\\:fedora/SpecialPart"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "inbound named relationship query" do
|
167
|
+
it "should return a properly formatted query for a relationship that has a query param defined" do
|
168
|
+
SpecNodeQueryParam.inbound_named_relationship_query(@test_object_query.pid,"special_parts").should == "#{@test_object_query.named_relationship_predicates[:inbound]['special_parts']}_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')} AND has_model_s:info\\:fedora/SpecialPart"
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should return a properly formatted query for a relationship that does not have a query param defined" do
|
172
|
+
SpecNodeQueryParam.inbound_named_relationship_query(@test_object_query.pid,"parts").should == "is_part_of_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "outbound named relationship query" do
|
177
|
+
it "should return a properly formatted query for a relationship that has a query param defined" do
|
178
|
+
expected_string = ""
|
179
|
+
@test_object_query.containers_ids.each_with_index do |id,index|
|
180
|
+
expected_string << " OR " if index > 0
|
181
|
+
expected_string << "(id:" + id.gsub(/(:)/, '\\:') + " AND has_model_s:info\\:fedora/SpecialContainer)"
|
182
|
+
end
|
183
|
+
SpecNodeQueryParam.outbound_named_relationship_query("special_containers",@test_object_query.containers_ids).should == expected_string
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should return a properly formatted query for a relationship that does not have a query param defined" do
|
187
|
+
expected_string = ""
|
188
|
+
@test_object_query.containers_ids.each_with_index do |id,index|
|
189
|
+
expected_string << " OR " if index > 0
|
190
|
+
expected_string << "id:" + id.gsub(/(:)/, '\\:')
|
191
|
+
end
|
192
|
+
SpecNodeQueryParam.outbound_named_relationship_query("containers",@test_object_query.containers_ids).should == expected_string
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe "bidirectional named relationship query" do
|
197
|
+
it "should return a properly formatted query for a relationship that has a query param defined" do
|
198
|
+
expected_string = ""
|
199
|
+
@test_object_query.bi_containers_outbound_ids.each_with_index do |id,index|
|
200
|
+
expected_string << " OR " if index > 0
|
201
|
+
expected_string << "(id:" + id.gsub(/(:)/, '\\:') + " AND has_model_s:info\\:fedora/SpecialContainer)"
|
202
|
+
end
|
203
|
+
expected_string << " OR "
|
204
|
+
expected_string << "(#{@test_object_query.named_relationship_predicates[:inbound]['bi_special_containers_inbound']}_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')} AND has_model_s:info\\:fedora/SpecialContainer)"
|
205
|
+
SpecNodeQueryParam.bidirectional_named_relationship_query(@test_object_query.pid,"bi_special_containers",@test_object_query.bi_containers_outbound_ids).should == expected_string
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should return a properly formatted query for a relationship that does not have a query param defined" do
|
209
|
+
expected_string = ""
|
210
|
+
@test_object_query.bi_containers_outbound_ids.each_with_index do |id,index|
|
211
|
+
expected_string << " OR " if index > 0
|
212
|
+
expected_string << "id:" + id.gsub(/(:)/, '\\:')
|
213
|
+
end
|
214
|
+
expected_string << " OR "
|
215
|
+
expected_string << "(#{@test_object_query.named_relationship_predicates[:inbound]['bi_special_containers_inbound']}_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')})"
|
216
|
+
SpecNodeQueryParam.bidirectional_named_relationship_query(@test_object_query.pid,"bi_containers",@test_object_query.bi_containers_outbound_ids).should == expected_string
|
217
|
+
end
|
77
218
|
end
|
78
219
|
|
79
220
|
describe "outbound relationship finders" do
|
@@ -90,5 +231,121 @@ describe ActiveFedora::SemanticNode do
|
|
90
231
|
id.should satisfy {|id| id == @container1.pid || @container2.pid}
|
91
232
|
end
|
92
233
|
end
|
234
|
+
|
235
|
+
it "should return an array of Base objects with some filtered out if using query params" do
|
236
|
+
@test_object_query.special_containers_ids.size.should == 1
|
237
|
+
@test_object_query.special_containers_ids.include?(@container3.pid).should == false
|
238
|
+
@test_object_query.special_containers_ids.include?(@special_container.pid).should == true
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should return an array of all Base objects with relationship if not using query params" do
|
242
|
+
@test_object_query.containers_ids.size.should == 2
|
243
|
+
@test_object_query.containers_ids.include?(@special_container2.pid).should == false
|
244
|
+
@test_object_query.containers_ids.include?(@special_container.pid).should == true
|
245
|
+
@test_object_query.containers_ids.include?(@container3.pid).should == true
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should return a solr query for an outbound relationship" do
|
249
|
+
expected_string = ""
|
250
|
+
@test_object_query.containers_ids.each_with_index do |id,index|
|
251
|
+
expected_string << " OR " if index > 0
|
252
|
+
expected_string << "(id:" + id.gsub(/(:)/, '\\:') + " AND has_model_s:info\\:fedora/SpecialContainer)"
|
253
|
+
end
|
254
|
+
@test_object_query.special_containers_query.should == expected_string
|
255
|
+
end
|
93
256
|
end
|
257
|
+
|
258
|
+
describe "bidirectional relationship finders" do
|
259
|
+
it "should return an array of Base objects" do
|
260
|
+
containers = @test_object.bi_containers
|
261
|
+
containers.length.should > 0
|
262
|
+
containers.each do |container|
|
263
|
+
container.should be_kind_of(ActiveFedora::Base)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
it "_ids should return an array of pids" do
|
267
|
+
ids = @test_object.bi_containers_ids
|
268
|
+
ids.size.should == 2
|
269
|
+
ids.each do |id|
|
270
|
+
id.should satisfy {|id| id == @container1.pid || @container2.pid}
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should return an array of Base objects with some filtered out if using query params" do
|
275
|
+
ids = @test_object_query.bi_special_containers_ids
|
276
|
+
ids.size.should == 2
|
277
|
+
ids.each do |id|
|
278
|
+
id.should satisfy {|id| id == @special_container.pid || @special_container2.pid}
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should return an array of all Base objects with relationship if not using query params" do
|
283
|
+
ids = @test_object_query.bi_containers_ids
|
284
|
+
ids.size.should == 3
|
285
|
+
ids.each do |id|
|
286
|
+
id.should satisfy {|id| id == @special_container.pid || @special_container2.pid || @container3.pid}
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
it "should return a solr query for a bidirectional relationship" do
|
291
|
+
expected_string = ""
|
292
|
+
@test_object_query.bi_containers_outbound_ids.each_with_index do |id,index|
|
293
|
+
expected_string << " OR " if index > 0
|
294
|
+
expected_string << "(id:" + id.gsub(/(:)/, '\\:') + " AND has_model_s:info\\:fedora/SpecialContainer)"
|
295
|
+
end
|
296
|
+
expected_string << " OR "
|
297
|
+
expected_string << "(#{@test_object_query.named_relationship_predicates[:inbound]['bi_special_containers_inbound']}_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')} AND has_model_s:info\\:fedora/SpecialContainer)"
|
298
|
+
@test_object_query.bi_special_containers_query.should == expected_string
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe "named_relationship_query" do
|
303
|
+
it "should return correct query for a bidirectional relationship with query params" do
|
304
|
+
expected_string = ""
|
305
|
+
@test_object_query.bi_containers_outbound_ids.each_with_index do |id,index|
|
306
|
+
expected_string << " OR " if index > 0
|
307
|
+
expected_string << "(id:" + id.gsub(/(:)/, '\\:') + " AND has_model_s:info\\:fedora/SpecialContainer)"
|
308
|
+
end
|
309
|
+
expected_string << " OR "
|
310
|
+
expected_string << "(#{@test_object_query.named_relationship_predicates[:inbound]['bi_special_containers_inbound']}_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')} AND has_model_s:info\\:fedora/SpecialContainer)"
|
311
|
+
@test_object_query.named_relationship_query("bi_special_containers").should == expected_string
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should return correct query for a bidirectional relationship without query params" do
|
315
|
+
expected_string = ""
|
316
|
+
@test_object_query.bi_containers_outbound_ids.each_with_index do |id,index|
|
317
|
+
expected_string << " OR " if index > 0
|
318
|
+
expected_string << "id:" + id.gsub(/(:)/, '\\:')
|
319
|
+
end
|
320
|
+
expected_string << " OR "
|
321
|
+
expected_string << "(#{@test_object_query.named_relationship_predicates[:inbound]['bi_special_containers_inbound']}_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')})"
|
322
|
+
@test_object_query.named_relationship_query("bi_containers").should == expected_string
|
323
|
+
end
|
324
|
+
|
325
|
+
it "should return a properly formatted query for an outbound relationship that has a query param defined" do
|
326
|
+
expected_string = ""
|
327
|
+
@test_object_query.containers_ids.each_with_index do |id,index|
|
328
|
+
expected_string << " OR " if index > 0
|
329
|
+
expected_string << "(id:" + id.gsub(/(:)/, '\\:') + " AND has_model_s:info\\:fedora/SpecialContainer)"
|
330
|
+
end
|
331
|
+
@test_object_query.named_relationship_query("special_containers").should == expected_string
|
332
|
+
end
|
333
|
+
|
334
|
+
it "should return a properly formatted query for an outbound relationship that does not have a query param defined" do
|
335
|
+
expected_string = ""
|
336
|
+
@test_object_query.containers_ids.each_with_index do |id,index|
|
337
|
+
expected_string << " OR " if index > 0
|
338
|
+
expected_string << "id:" + id.gsub(/(:)/, '\\:')
|
339
|
+
end
|
340
|
+
@test_object_query.named_relationship_query("containers").should == expected_string
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should return a properly formatted query for an inbound relationship that has a query param defined" do
|
344
|
+
@test_object_query.named_relationship_query("special_parts").should == "#{@test_object_query.named_relationship_predicates[:inbound]['special_parts']}_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')} AND has_model_s:info\\:fedora/SpecialPart"
|
345
|
+
end
|
346
|
+
|
347
|
+
it "should return a properly formatted query for an inbound relationship that does not have a query param defined" do
|
348
|
+
@test_object_query.named_relationship_query("parts").should == "is_part_of_s:#{@test_object_query.internal_uri.gsub(/(:)/, '\\:')}"
|
349
|
+
end
|
350
|
+
end
|
94
351
|
end
|