active-fedora 9.1.2 → 9.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Gemfile +1 -0
- data/History.txt +90 -0
- data/active-fedora.gemspec +2 -2
- data/lib/active_fedora.rb +17 -3
- data/lib/active_fedora/associations.rb +77 -0
- data/lib/active_fedora/associations/association.rb +2 -2
- data/lib/active_fedora/associations/basic_contains_association.rb +52 -0
- data/lib/active_fedora/associations/builder/directly_contains.rb +23 -0
- data/lib/active_fedora/associations/builder/directly_contains_one.rb +44 -0
- data/lib/active_fedora/associations/builder/has_and_belongs_to_many.rb +2 -23
- data/lib/active_fedora/associations/builder/indirectly_contains.rb +26 -0
- data/lib/active_fedora/associations/builder/property.rb +10 -0
- data/lib/active_fedora/associations/collection_association.rb +42 -45
- data/lib/active_fedora/associations/collection_proxy.rb +6 -0
- data/lib/active_fedora/associations/contained_finder.rb +41 -0
- data/lib/active_fedora/associations/container_proxy.rb +9 -0
- data/lib/active_fedora/associations/contains_association.rb +20 -38
- data/lib/active_fedora/associations/delete_proxy.rb +28 -0
- data/lib/active_fedora/associations/directly_contains_association.rb +56 -0
- data/lib/active_fedora/associations/directly_contains_one_association.rb +113 -0
- data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +6 -14
- data/lib/active_fedora/associations/has_many_association.rb +0 -3
- data/lib/active_fedora/associations/id_composite.rb +30 -0
- data/lib/active_fedora/associations/indirectly_contains_association.rb +90 -0
- data/lib/active_fedora/associations/rdf.rb +8 -4
- data/lib/active_fedora/associations/record_composite.rb +39 -0
- data/lib/active_fedora/attached_files.rb +1 -1
- data/lib/active_fedora/attributes.rb +28 -10
- data/lib/active_fedora/attributes/active_triple_attribute.rb +17 -0
- data/lib/active_fedora/attributes/om_attribute.rb +29 -0
- data/lib/active_fedora/attributes/rdf_datastream_attribute.rb +47 -0
- data/lib/active_fedora/attributes/stream_attribute.rb +46 -0
- data/lib/active_fedora/autosave_association.rb +2 -2
- data/lib/active_fedora/base.rb +3 -0
- data/lib/active_fedora/containers/container.rb +38 -0
- data/lib/active_fedora/containers/direct_container.rb +5 -0
- data/lib/active_fedora/containers/indirect_container.rb +7 -0
- data/lib/active_fedora/core.rb +4 -48
- data/lib/active_fedora/delegated_attribute.rb +5 -98
- data/lib/active_fedora/fedora.rb +1 -1
- data/lib/active_fedora/fedora_attributes.rb +4 -26
- data/lib/active_fedora/file.rb +87 -159
- data/lib/active_fedora/file/attributes.rb +63 -0
- data/lib/active_fedora/file/streaming.rb +46 -0
- data/lib/active_fedora/file_relation.rb +7 -0
- data/lib/active_fedora/identifiable.rb +87 -0
- data/lib/active_fedora/inbound_relation_connection.rb +21 -0
- data/lib/active_fedora/indexers.rb +10 -0
- data/lib/active_fedora/indexers/global_indexer.rb +30 -0
- data/lib/active_fedora/indexers/null_indexer.rb +12 -0
- data/lib/active_fedora/indexing/map.rb +4 -5
- data/lib/active_fedora/indexing_service.rb +3 -22
- data/lib/active_fedora/loadable_from_json.rb +8 -0
- data/lib/active_fedora/pathing.rb +24 -0
- data/lib/active_fedora/persistence.rb +15 -8
- data/lib/active_fedora/rdf.rb +2 -0
- data/lib/active_fedora/rdf/fcrepo4.rb +1 -0
- data/lib/active_fedora/rdf/field_map.rb +90 -0
- data/lib/active_fedora/rdf/field_map_entry.rb +28 -0
- data/lib/active_fedora/rdf/indexing_service.rb +9 -23
- data/lib/active_fedora/rdf/rdf_datastream.rb +1 -2
- data/lib/active_fedora/reflection.rb +16 -15
- data/lib/active_fedora/relation/delegation.rb +15 -4
- data/lib/active_fedora/relation/finder_methods.rb +4 -4
- data/lib/active_fedora/schema.rb +26 -0
- data/lib/active_fedora/schema_indexing_strategy.rb +25 -0
- data/lib/active_fedora/simple_datastream.rb +2 -2
- data/lib/active_fedora/solr_query_builder.rb +3 -2
- data/lib/active_fedora/version.rb +1 -1
- data/lib/active_fedora/with_metadata.rb +1 -1
- data/spec/integration/associations/rdf_spec.rb +49 -0
- data/spec/integration/base_spec.rb +19 -0
- data/spec/integration/belongs_to_association_spec.rb +6 -6
- data/spec/integration/collection_association_spec.rb +4 -4
- data/spec/integration/complex_rdf_datastream_spec.rb +12 -12
- data/spec/integration/datastream_rdf_nested_attributes_spec.rb +1 -1
- data/spec/integration/direct_container_spec.rb +254 -0
- data/spec/integration/directly_contains_one_association_spec.rb +102 -0
- data/spec/integration/file_spec.rb +16 -5
- data/spec/integration/has_many_associations_spec.rb +93 -58
- data/spec/integration/indirect_container_spec.rb +251 -0
- data/spec/integration/rdf_nested_attributes_spec.rb +1 -1
- data/spec/integration/relation_spec.rb +43 -27
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/attributes_spec.rb +6 -6
- data/spec/unit/collection_proxy_spec.rb +28 -0
- data/spec/unit/file_spec.rb +1 -1
- data/spec/unit/files_hash_spec.rb +4 -4
- data/spec/unit/has_and_belongs_to_many_association_spec.rb +11 -9
- data/spec/unit/indexers/global_indexer_spec.rb +41 -0
- data/spec/unit/indexing_service_spec.rb +0 -21
- data/spec/unit/loadable_from_json_spec.rb +31 -0
- data/spec/unit/pathing_spec.rb +37 -0
- data/spec/unit/rdf/indexing_service_spec.rb +3 -3
- data/spec/unit/rdf_resource_datastream_spec.rb +26 -7
- data/spec/unit/schema_indexing_strategy_spec.rb +68 -0
- data/spec/unit/solr_query_builder_spec.rb +1 -1
- data/spec/unit/solr_service_spec.rb +1 -1
- metadata +49 -8
@@ -0,0 +1,113 @@
|
|
1
|
+
module ActiveFedora
|
2
|
+
module Associations
|
3
|
+
# Filters a DirectContainer relationship, returning the first item that matches the given :type
|
4
|
+
class DirectlyContainsOneAssociation < SingularAssociation #:nodoc:
|
5
|
+
|
6
|
+
# Finds objects contained by the container predicate (either the configured has_member_relation or ldp:contains)
|
7
|
+
# TODO: Refactor this to use solr (for efficiency) instead of parsing the RDF graph. Requires indexing ActiveFedora::File objects into solr, including their RDF.type and, if possible, the id of their container
|
8
|
+
def find_target
|
9
|
+
# filtered_objects = container_association_proxy.to_a.select { |o| o.metadata_node.type.include?(options[:type]) }
|
10
|
+
query_node = if container_predicate = options[:has_member_relation]
|
11
|
+
owner
|
12
|
+
else
|
13
|
+
container_predicate = ::RDF::Vocab::LDP.contains
|
14
|
+
container_association.container # Use the :through association's container
|
15
|
+
end
|
16
|
+
|
17
|
+
contained_uris = query_node.resource.query(predicate: container_predicate).map { |r| r.object.to_s }
|
18
|
+
contained_uris.each do |object_uri|
|
19
|
+
contained_object = klass.find(klass.uri_to_id(object_uri))
|
20
|
+
return contained_object if get_type_from_record(contained_object).include?(options[:type])
|
21
|
+
end
|
22
|
+
return nil # if nothing was found & returned while iterating on contained_uris, return nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# Adds record to the DirectContainer identified by the container_association
|
26
|
+
# Relies on container_association.initialize_attributes to appropriately set things like record.uri
|
27
|
+
def add_to_container(record)
|
28
|
+
container_association.add_to_target(record) # adds record to corresponding Container
|
29
|
+
# TODO is send necessary?
|
30
|
+
container_association.send(:initialize_attributes, record) # Uses the :through association initialize the record with things like the correct URI for a direclty contained object
|
31
|
+
end
|
32
|
+
|
33
|
+
# Replaces association +target+ with +record+
|
34
|
+
# Ensures that this association's +type+ is set on the record and adds the record to the association's DirectContainer
|
35
|
+
def replace(record, *)
|
36
|
+
if record
|
37
|
+
raise_on_type_mismatch(record)
|
38
|
+
remove_existing_target
|
39
|
+
add_type_to_record(record, options[:type])
|
40
|
+
add_to_container(record)
|
41
|
+
else
|
42
|
+
remove_existing_target
|
43
|
+
end
|
44
|
+
|
45
|
+
self.target = record
|
46
|
+
end
|
47
|
+
|
48
|
+
def updated?
|
49
|
+
@updated
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def remove_existing_target
|
55
|
+
@target ||= find_target
|
56
|
+
if @target
|
57
|
+
container_association_proxy.delete @target
|
58
|
+
@updated = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Overrides initialize_attributes to ensure that record is initialized with attributes from the corresponding container
|
63
|
+
def initialize_attributes(record)
|
64
|
+
super
|
65
|
+
container_association.initialize_attributes(record)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the Reflection corresponding to the direct container association that's being filtered
|
69
|
+
def container_reflection
|
70
|
+
@container_reflection ||= @owner.class.reflect_on_association(@reflection.options[:through])
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the DirectContainerAssociation corresponding to the direct container that's being filtered
|
74
|
+
def container_association
|
75
|
+
container_association_proxy.proxy_association
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns the ContainerAssociationProxy corresponding to the direct container that's being filtered
|
79
|
+
def container_association_proxy
|
80
|
+
@owner.send(@reflection.options[:through])
|
81
|
+
end
|
82
|
+
|
83
|
+
# Adds type_uri to the RDF.type assertions on record
|
84
|
+
def add_type_to_record(record, type_uri)
|
85
|
+
metadata_node = metadata_node_for_record(record)
|
86
|
+
types = metadata_node.type
|
87
|
+
unless types.include?(type_uri)
|
88
|
+
types << type_uri
|
89
|
+
metadata_node.set_value(:type, types)
|
90
|
+
end
|
91
|
+
return record
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the RDF.type assertions for the record
|
95
|
+
def get_type_from_record(record)
|
96
|
+
metadata_node_for_record(record).type
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the RDF node that contains metadata like RDF.type assertions for the record
|
100
|
+
# Sometimes this is the record, other times it's record.metadata_node
|
101
|
+
def metadata_node_for_record(record)
|
102
|
+
if record.respond_to?(:type) && record.respond_to?(:set_value)
|
103
|
+
return record
|
104
|
+
elsif record.respond_to?(:metadata_node)
|
105
|
+
return record.metadata_node
|
106
|
+
else
|
107
|
+
raise ArgumentError, "record must either have a metadata node or must respond to .type"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -46,20 +46,6 @@ module ActiveFedora
|
|
46
46
|
result && records
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
def find_target
|
51
|
-
page_size = @reflection.options[:solr_page_size]
|
52
|
-
page_size ||= 200
|
53
|
-
ids = owner[reflection.foreign_key]
|
54
|
-
return [] if ids.blank?
|
55
|
-
solr_result = []
|
56
|
-
0.step(ids.size,page_size) do |startIdx|
|
57
|
-
query = ActiveFedora::SolrQueryBuilder.construct_query_for_ids(ids.slice(startIdx,page_size))
|
58
|
-
solr_result += ActiveFedora::SolrService.query(query, rows: page_size)
|
59
|
-
end
|
60
|
-
return ActiveFedora::QueryResultBuilder.reify_solr_results(solr_result)
|
61
|
-
end
|
62
|
-
|
63
49
|
# In a HABTM, just look in the RDF, no need to run a count query from solr.
|
64
50
|
def count(options = {})
|
65
51
|
owner[reflection.foreign_key].size
|
@@ -96,6 +82,12 @@ module ActiveFedora
|
|
96
82
|
owner[reflection.foreign_key]
|
97
83
|
end
|
98
84
|
|
85
|
+
def find_target
|
86
|
+
ids = owner[reflection.foreign_key]
|
87
|
+
return [] if ids.blank?
|
88
|
+
ActiveFedora::Base.find(ids)
|
89
|
+
end
|
90
|
+
|
99
91
|
end
|
100
92
|
end
|
101
93
|
end
|
@@ -35,19 +35,16 @@ module ActiveFedora
|
|
35
35
|
record[inverse.foreign_key] = owner.id
|
36
36
|
else # HABTM
|
37
37
|
record[inverse.foreign_key] ||= []
|
38
|
-
#TODO use primary_key instead of `owner.id`
|
39
38
|
record[inverse.foreign_key] += [owner.id]
|
40
39
|
end
|
41
40
|
elsif owner.persisted?
|
42
41
|
inverse = reflection.inverse_of
|
43
42
|
if inverse && inverse.collection?
|
44
43
|
record[inverse.foreign_key] ||= []
|
45
|
-
#TODO use primary_key instead of `owner.id`
|
46
44
|
record[inverse.foreign_key] += [owner.id]
|
47
45
|
elsif inverse && inverse.klass == ActiveFedora::Base
|
48
46
|
record[inverse.foreign_key] = owner.id
|
49
47
|
else
|
50
|
-
#TODO use primary_key instead of `owner.id`
|
51
48
|
record[reflection.foreign_key] = owner.id
|
52
49
|
end
|
53
50
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveFedora::Associations
|
2
|
+
##
|
3
|
+
# A composite object for an array of IDs. This abstracts away the fact that an
|
4
|
+
# ID might be either a relative ID or a URI to a resource.
|
5
|
+
class IDComposite
|
6
|
+
attr_reader :ids, :id_translator
|
7
|
+
include Enumerable
|
8
|
+
def initialize(ids, id_translator)
|
9
|
+
@ids = ids
|
10
|
+
@id_translator = id_translator
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Array<relative_id>]
|
14
|
+
def each
|
15
|
+
ids.each do |id|
|
16
|
+
yield convert(id)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def convert(id)
|
23
|
+
if id.start_with?("http")
|
24
|
+
id_translator.call(id)
|
25
|
+
else
|
26
|
+
id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ActiveFedora
|
2
|
+
module Associations
|
3
|
+
class IndirectlyContainsAssociation < ContainsAssociation #:nodoc:
|
4
|
+
|
5
|
+
# TODO we may want to split this into two subclasses, one for has_member_relation
|
6
|
+
# and the other for is_member_of_relation
|
7
|
+
|
8
|
+
def insert_record(record, force = true, validate = true)
|
9
|
+
container.save!
|
10
|
+
if force
|
11
|
+
record.save!
|
12
|
+
else
|
13
|
+
return false unless record.save(validate: validate)
|
14
|
+
end
|
15
|
+
|
16
|
+
save_through_record(record)
|
17
|
+
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_target
|
22
|
+
if container_predicate = options[:has_member_relation]
|
23
|
+
uris = owner.resource.query(predicate: container_predicate).map { |r| r.object.to_s }
|
24
|
+
uris.map { |object_uri| klass.find(klass.uri_to_id(object_uri)) }
|
25
|
+
else # is_member_of_relation
|
26
|
+
# TODO this is a lot of reads. Avoid this path
|
27
|
+
container_predicate = ::RDF::Vocab::LDP.contains
|
28
|
+
proxy_uris = container.resource.query(predicate: container_predicate).map { |r| r.object.to_s }
|
29
|
+
proxy_uris.map { |uri| proxy_class.find(proxy_class.uri_to_id(uri))[options[:foreign_key]] }
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def container
|
36
|
+
@container ||= begin
|
37
|
+
IndirectContainer.find_or_initialize(ActiveFedora::Base.uri_to_id(uri)).tap do |container|
|
38
|
+
container.parent = @owner
|
39
|
+
container.has_member_relation = Array(options[:has_member_relation])
|
40
|
+
container.is_member_of_relation = Array(options[:is_member_of_relation])
|
41
|
+
container.inserted_content_relation = Array(options[:inserted_content_relation])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def initialize_attributes(record) #:nodoc:
|
49
|
+
#record.uri = ActiveFedora::Base.id_to_uri(container.mint_id)
|
50
|
+
# set_inverse_instance(record)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def delete_records(records, method)
|
56
|
+
container.reload # Reload container to get updated LDP.contains
|
57
|
+
records.each do |record|
|
58
|
+
delete_record(record)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def delete_record(record)
|
63
|
+
record_proxy_finder.find(record).delete
|
64
|
+
end
|
65
|
+
|
66
|
+
def record_proxy_finder
|
67
|
+
ContainedFinder.new(container: container, repository: composite_proxy_repository)
|
68
|
+
end
|
69
|
+
|
70
|
+
def composite_proxy_repository
|
71
|
+
RecordComposite::Repository.new(base_repository: proxy_class)
|
72
|
+
end
|
73
|
+
|
74
|
+
def save_through_record(record)
|
75
|
+
build_proxy_node({}) do |node|
|
76
|
+
node[options[:foreign_key]] = record
|
77
|
+
node.save
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_proxy_node(attributes, &block)
|
82
|
+
proxy_class.new({ id: container.mint_id }.merge(attributes), &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
def proxy_class
|
86
|
+
@proxy_class ||= options[:through].constantize
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -33,9 +33,15 @@ module ActiveFedora
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
# TODO Detect when this is the only relationship for this predicate, then skip the filtering.
|
37
36
|
def filtering_required?
|
38
|
-
reflection.klass
|
37
|
+
return false if reflection.klass == ActiveFedora::Base
|
38
|
+
reflections_with_same_predicate.count > 1
|
39
|
+
end
|
40
|
+
|
41
|
+
# Count the number of reflections that have the same predicate as the reflection
|
42
|
+
# for this association.
|
43
|
+
def reflections_with_same_predicate
|
44
|
+
owner.class.outgoing_reflections.select { |k, v| v.options[:predicate] == reflection.predicate }
|
39
45
|
end
|
40
46
|
|
41
47
|
# @return [Array<RDF::URI>]
|
@@ -48,8 +54,6 @@ module ActiveFedora
|
|
48
54
|
owner.resource.query(subject: owner.rdf_subject, predicate: reflection.predicate).enum_statement
|
49
55
|
end
|
50
56
|
|
51
|
-
|
52
|
-
# TODO this is a huge waste of time that can be completely avoided if the attributes aren't sharing predicates.
|
53
57
|
# @return [Array<RDF::URI>]
|
54
58
|
def filter_by_class(candidate_uris)
|
55
59
|
return [] if candidate_uris.empty?
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActiveFedora::Associations
|
2
|
+
##
|
3
|
+
# A Composite for records - currently only supports delete interface.
|
4
|
+
# The goal is to push commands down to the containing records.
|
5
|
+
class RecordComposite
|
6
|
+
attr_reader :records
|
7
|
+
include Enumerable
|
8
|
+
def initialize(records:)
|
9
|
+
@records = records
|
10
|
+
end
|
11
|
+
|
12
|
+
def each
|
13
|
+
records.each do |record|
|
14
|
+
yield record
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete
|
19
|
+
self.each(&:delete)
|
20
|
+
end
|
21
|
+
##
|
22
|
+
# A Repository which returns a composite from #find instead of a single
|
23
|
+
# record. Delegates find to a base repository.
|
24
|
+
class Repository
|
25
|
+
attr_reader :base_repository
|
26
|
+
delegate :translate_uri_to_id, to: :base_repository
|
27
|
+
def initialize(base_repository:)
|
28
|
+
@base_repository = base_repository
|
29
|
+
end
|
30
|
+
|
31
|
+
def find(ids)
|
32
|
+
records = ids.map do |id|
|
33
|
+
base_repository.find(id)
|
34
|
+
end
|
35
|
+
RecordComposite.new(records: records)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -124,7 +124,7 @@ module ActiveFedora
|
|
124
124
|
private
|
125
125
|
def create_singleton_association(file_path)
|
126
126
|
self.undeclared_files << file_path.to_sym
|
127
|
-
association = Associations::
|
127
|
+
association = Associations::BasicContainsAssociation.new(self, Reflection::AssociationReflection.new(:contains, file_path, {class_name: 'ActiveFedora::File'}, self.class))
|
128
128
|
@association_cache[file_path.to_sym] = association
|
129
129
|
|
130
130
|
self.singleton_class.send :define_method, accessor_name(file_path) do
|
@@ -177,7 +177,7 @@ module ActiveFedora
|
|
177
177
|
elsif properties.key?(:delegate_to)
|
178
178
|
define_delegated_accessor([name], properties.delete(:delegate_to), properties.reverse_merge(multiple: true), &block)
|
179
179
|
else
|
180
|
-
raise "You must provide `:
|
180
|
+
raise "You must provide `:delegate_to' or `:predicate' options to property"
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
@@ -186,7 +186,7 @@ module ActiveFedora
|
|
186
186
|
def define_active_triple_accessor(name, properties, &block)
|
187
187
|
warn_duplicate_predicates name, properties
|
188
188
|
properties = { multiple: true }.merge(properties)
|
189
|
-
find_or_create_defined_attribute(name,
|
189
|
+
find_or_create_defined_attribute(name, ActiveTripleAttribute, properties)
|
190
190
|
raise ArgumentError, "#{name} is a keyword and not an acceptable property name." if protected_property_name? name
|
191
191
|
reflection = ActiveFedora::Attributes::PropertyBuilder.build(self, name, properties, &block)
|
192
192
|
ActiveTriples::Reflection.add_reflection self, name, reflection
|
@@ -197,6 +197,10 @@ module ActiveFedora
|
|
197
197
|
def define_delegated_accessor(fields, delegate_target, options, &block)
|
198
198
|
define_attribute_methods fields
|
199
199
|
fields.each do |f|
|
200
|
+
klass = datastream_class_for_name(delegate_target)
|
201
|
+
attribute_properties = options.merge(delegate_target: delegate_target, klass: klass)
|
202
|
+
find_or_create_defined_attribute f, attribute_class(klass), attribute_properties
|
203
|
+
|
200
204
|
create_attribute_reader(f, delegate_target, options)
|
201
205
|
create_attribute_setter(f, delegate_target, options)
|
202
206
|
add_attribute_indexing_config(f, &block) if block_given?
|
@@ -204,8 +208,7 @@ module ActiveFedora
|
|
204
208
|
end
|
205
209
|
|
206
210
|
def add_attribute_indexing_config(name, &block)
|
207
|
-
|
208
|
-
index_config[name] ||= ActiveFedora::Indexing::Map::IndexObject.new &block
|
211
|
+
index_config[name] ||= ActiveFedora::Indexing::Map::IndexObject.new(name, &block)
|
209
212
|
end
|
210
213
|
|
211
214
|
def warn_duplicate_predicates new_name, new_properties
|
@@ -215,31 +218,46 @@ module ActiveFedora
|
|
215
218
|
end
|
216
219
|
end
|
217
220
|
|
218
|
-
|
219
|
-
|
221
|
+
# @param [Symbol] field the field to find or create
|
222
|
+
# @param [Class] klass the class to use to delegate the attribute (e.g.
|
223
|
+
# ActiveTripleAttribute, OmAttribute, or RdfDatastreamAttribute)
|
224
|
+
# @param [Hash] args
|
225
|
+
# @option args [String] :delegate_target the path to the delegate
|
226
|
+
# @option args [Class] :klass the class to create
|
227
|
+
# @option args [true,false] :multiple (false) true for multi-value fields
|
228
|
+
# @option args [Array<Symbol>] :at path to a deep node
|
229
|
+
# @return [DelegatedAttribute] the found or created attribute
|
230
|
+
def find_or_create_defined_attribute(field, klass, args)
|
231
|
+
delegated_attributes[field] ||= klass.new(field, args)
|
220
232
|
end
|
221
233
|
|
222
234
|
# @param [String] dsid the datastream id
|
223
235
|
# @return [Class] the class of the datastream
|
224
236
|
def datastream_class_for_name(dsid)
|
225
|
-
reflection = reflect_on_association(dsid)
|
237
|
+
reflection = reflect_on_association(dsid.to_sym)
|
226
238
|
reflection ? reflection.klass : ActiveFedora::File
|
227
239
|
end
|
228
240
|
|
229
241
|
def create_attribute_reader(field, dsid, args)
|
230
|
-
find_or_create_defined_attribute(field, dsid, args)
|
231
|
-
|
232
242
|
define_method field do |*opts|
|
233
243
|
array_reader(field, *opts)
|
234
244
|
end
|
235
245
|
end
|
236
246
|
|
237
247
|
def create_attribute_setter(field, dsid, args)
|
238
|
-
find_or_create_defined_attribute(field, dsid, args)
|
239
248
|
define_method "#{field}=".to_sym do |v|
|
240
249
|
self[field]=v
|
241
250
|
end
|
242
251
|
end
|
252
|
+
|
253
|
+
def attribute_class(klass)
|
254
|
+
if klass < ActiveFedora::RDFDatastream
|
255
|
+
RdfDatastreamAttribute
|
256
|
+
else
|
257
|
+
OmAttribute
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
243
261
|
end
|
244
262
|
end
|
245
263
|
end
|