activefedora-aggregation 0.9.0 → 0.10.0
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.
- checksums.yaml +4 -4
- data/activefedora-aggregation.gemspec +1 -1
- data/lib/active_fedora/aggregation.rb +0 -14
- data/lib/active_fedora/aggregation/base_extension.rb +0 -47
- data/lib/active_fedora/aggregation/version.rb +1 -1
- data/lib/active_fedora/filter/builder.rb +21 -2
- data/lib/active_fedora/filter/reflection.rb +1 -1
- data/lib/active_fedora/orders/aggregation_builder.rb +14 -16
- data/lib/active_fedora/orders/association.rb +4 -3
- data/lib/active_fedora/orders/builder.rb +36 -23
- data/lib/active_fedora/orders/reflection.rb +17 -2
- metadata +5 -20
- data/lib/active_fedora/aggregation/aggregation_extension.rb +0 -26
- data/lib/active_fedora/aggregation/appends_to_aggregation.rb +0 -31
- data/lib/active_fedora/aggregation/association.rb +0 -81
- data/lib/active_fedora/aggregation/builder.rb +0 -33
- data/lib/active_fedora/aggregation/decorating_repository.rb +0 -29
- data/lib/active_fedora/aggregation/decorator_list.rb +0 -15
- data/lib/active_fedora/aggregation/decorator_with_arguments.rb +0 -15
- data/lib/active_fedora/aggregation/link_inserter.rb +0 -56
- data/lib/active_fedora/aggregation/null_proxy.rb +0 -23
- data/lib/active_fedora/aggregation/ordered_proxy.rb +0 -57
- data/lib/active_fedora/aggregation/persist_links.rb +0 -9
- data/lib/active_fedora/aggregation/proxy_owner.rb +0 -24
- data/lib/active_fedora/aggregation/proxy_repository.rb +0 -38
- data/lib/active_fedora/aggregation/reflection.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f69090697f543089afbc0a5a0e83fd2deddb0b3a
|
4
|
+
data.tar.gz: 0d8775ae201b1ae026fca4d2ee0018079b0eb59d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be36c19a9bd67b2c73ebf9398ae1a0b9dc324db7ca664b957c41d4496e743a21e55ea747f4a06f59ea2c0bdc6458dd1e732380252b589741837a9433b736a567
|
7
|
+
data.tar.gz: 80e91cdac629e9b372f5c8938cd50580d52c80a8c5b40e917ef1f88633f148d633837877fc50fc4bf951a337239a161ae6a22d92a6bf768d6c56e2a3cf7122aa
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.require_paths = ["lib"]
|
18
18
|
|
19
19
|
spec.add_dependency 'activesupport'
|
20
|
-
spec.add_dependency 'active-fedora', '~> 9.
|
20
|
+
spec.add_dependency 'active-fedora', '~> 9.10.1'
|
21
21
|
spec.add_dependency 'rdf-vocab', '~> 0.8.1'
|
22
22
|
# Avoid RDF 1.1.17 because of a bug from ruby 2.2
|
23
23
|
# https://github.com/ruby-rdf/rdf/pull/213
|
@@ -9,23 +9,9 @@ module ActiveFedora
|
|
9
9
|
module Aggregation
|
10
10
|
extend ActiveSupport::Autoload
|
11
11
|
eager_autoload do
|
12
|
-
autoload :Association
|
13
|
-
autoload :AggregationExtension
|
14
12
|
autoload :Proxy
|
15
|
-
autoload :Builder
|
16
|
-
autoload :Reflection
|
17
13
|
autoload :BaseExtension
|
18
|
-
autoload :LinkInserter
|
19
14
|
autoload :OrderedReader
|
20
|
-
autoload :PersistLinks
|
21
|
-
autoload :OrderedProxy
|
22
|
-
autoload :AppendsToAggregation
|
23
|
-
autoload :ProxyOwner
|
24
|
-
autoload :NullProxy
|
25
|
-
autoload :DecoratingRepository
|
26
|
-
autoload :DecoratorWithArguments
|
27
|
-
autoload :DecoratorList
|
28
|
-
autoload :ProxyRepository
|
29
15
|
autoload :ListSource
|
30
16
|
end
|
31
17
|
|
@@ -2,20 +2,6 @@ module ActiveFedora::Aggregation
|
|
2
2
|
module BaseExtension
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
# Queries the RDF graph to find all records that include this object in their aggregations
|
6
|
-
# Since any class may be the target of an aggregation, this must be on every class extending
|
7
|
-
# from ActiveFedora::Base
|
8
|
-
# @return [Array] records that include this object in their aggregations
|
9
|
-
def aggregated_by
|
10
|
-
# In theory you should be able to find the aggregation predicate (ie ore:aggregates)
|
11
|
-
# but Fedora does not return that predicate due to this bug in FCREPO:
|
12
|
-
# https://jira.duraspace.org/browse/FCREPO-1497
|
13
|
-
# so we have to look up the proxies asserting RDF::Vocab::ORE.proxyFor
|
14
|
-
# and return their containers.
|
15
|
-
return [] unless id
|
16
|
-
proxy_class.where(proxyFor_ssim: id).map(&:container)
|
17
|
-
end
|
18
|
-
|
19
5
|
def ordered_by
|
20
6
|
ordered_by_ids.lazy.map{ |x| ActiveFedora::Base.find(x) }
|
21
7
|
end
|
@@ -31,21 +17,7 @@ module ActiveFedora::Aggregation
|
|
31
17
|
end
|
32
18
|
end
|
33
19
|
|
34
|
-
def proxy_class
|
35
|
-
ActiveFedora::Aggregation::Proxy
|
36
|
-
end
|
37
|
-
|
38
20
|
module ClassMethods
|
39
|
-
##
|
40
|
-
# Create an aggregation association on the class
|
41
|
-
# @example
|
42
|
-
# class Image < ActiveFedora::Base
|
43
|
-
# aggregates :generic_files
|
44
|
-
# end
|
45
|
-
def aggregates(name, options={})
|
46
|
-
Builder.build(self, name, options)
|
47
|
-
end
|
48
|
-
|
49
21
|
##
|
50
22
|
# Allows ordering of an association
|
51
23
|
# @example
|
@@ -79,25 +51,6 @@ module ActiveFedora::Aggregation
|
|
79
51
|
name = options.delete(:as)
|
80
52
|
ActiveFedora::Filter::Builder.build(self, name, options.merge(extending_from: extending_from))
|
81
53
|
end
|
82
|
-
|
83
|
-
def create_reflection(macro, name, options, active_fedora)
|
84
|
-
case macro
|
85
|
-
when :aggregation
|
86
|
-
Reflection.new(macro, name, options, active_fedora).tap do |reflection|
|
87
|
-
add_reflection name, reflection
|
88
|
-
end
|
89
|
-
when :filter
|
90
|
-
ActiveFedora::Filter::Reflection.new(macro, name, options, active_fedora).tap do |reflection|
|
91
|
-
add_reflection name, reflection
|
92
|
-
end
|
93
|
-
when :orders
|
94
|
-
ActiveFedora::Orders::Reflection.new(macro, name, options, active_fedora).tap do |reflection|
|
95
|
-
add_reflection name, reflection
|
96
|
-
end
|
97
|
-
else
|
98
|
-
super
|
99
|
-
end
|
100
|
-
end
|
101
54
|
end
|
102
55
|
end
|
103
56
|
end
|
@@ -1,7 +1,12 @@
|
|
1
1
|
module ActiveFedora::Filter
|
2
2
|
class Builder < ActiveFedora::Associations::Builder::CollectionAssociation
|
3
|
-
self.
|
4
|
-
|
3
|
+
def self.valid_options(options)
|
4
|
+
super + [:extending_from, :condition]
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.macro
|
8
|
+
:filter
|
9
|
+
end
|
5
10
|
|
6
11
|
def self.define_readers(mixin, name)
|
7
12
|
super
|
@@ -9,6 +14,20 @@ module ActiveFedora::Filter
|
|
9
14
|
association(name).ids_reader
|
10
15
|
end
|
11
16
|
end
|
17
|
+
|
18
|
+
def self.create_reflection(model, name, scope, options, extension = nil)
|
19
|
+
unless name.is_a?(Symbol)
|
20
|
+
name = name.to_sym
|
21
|
+
Deprecation.warn(ActiveFedora::Base, "association names must be a Symbol")
|
22
|
+
end
|
23
|
+
validate_options(options)
|
24
|
+
translate_property_to_predicate(options)
|
25
|
+
|
26
|
+
scope = build_scope(scope, extension)
|
27
|
+
name = better_name(name)
|
28
|
+
|
29
|
+
ActiveFedora::Orders::Reflection.create(macro, name, scope, options, model)
|
30
|
+
end
|
12
31
|
end
|
13
32
|
end
|
14
33
|
|
@@ -10,7 +10,7 @@ module ActiveFedora::Filter
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def extending_from
|
13
|
-
@extending_from ||= active_fedora.
|
13
|
+
@extending_from ||= active_fedora._reflect_on_association(options.fetch(:extending_from))
|
14
14
|
end
|
15
15
|
|
16
16
|
def collection?
|
@@ -1,47 +1,45 @@
|
|
1
1
|
module ActiveFedora::Orders
|
2
2
|
class AggregationBuilder < ActiveFedora::Associations::Builder::Association
|
3
|
-
self.valid_options
|
4
|
-
|
5
|
-
def self.build(model, name, options)
|
6
|
-
new(model, name, options).build
|
3
|
+
def self.valid_options(options)
|
4
|
+
[:through, :class_name, :has_member_relation, :type_validator]
|
7
5
|
end
|
8
6
|
|
9
|
-
def build
|
10
|
-
model.indirectly_contains name, {has_member_relation: has_member_relation, through: proxy_class, foreign_key: proxy_foreign_key, inserted_content_relation: inserted_content_relation}.merge(indirect_options)
|
11
|
-
model.contains contains_key, class_name: list_source_class
|
12
|
-
model.orders name, through: contains_key
|
7
|
+
def self.build(model, name, options)
|
8
|
+
model.indirectly_contains name, { has_member_relation: has_member_relation(options), through: proxy_class, foreign_key: proxy_foreign_key, inserted_content_relation: inserted_content_relation}.merge(indirect_options(options))
|
9
|
+
model.contains contains_key(options), class_name: list_source_class
|
10
|
+
model.orders name, through: contains_key(options)
|
13
11
|
end
|
14
12
|
|
15
13
|
private
|
16
14
|
|
17
|
-
def indirect_options
|
15
|
+
def self.indirect_options(options)
|
18
16
|
{
|
19
17
|
class_name: options[:class_name],
|
20
18
|
type_validator: options[:type_validator]
|
21
|
-
}.select{ |k, v| v.present? }
|
19
|
+
}.select { |k, v| v.present? }
|
22
20
|
end
|
23
21
|
|
24
|
-
def has_member_relation
|
22
|
+
def self.has_member_relation(options)
|
25
23
|
options[:has_member_relation] || ::RDF::DC.hasPart
|
26
24
|
end
|
27
25
|
|
28
|
-
def inserted_content_relation
|
26
|
+
def self.inserted_content_relation
|
29
27
|
::RDF::Vocab::ORE::proxyFor
|
30
28
|
end
|
31
29
|
|
32
|
-
def proxy_class
|
30
|
+
def self.proxy_class
|
33
31
|
"ActiveFedora::Aggregation::Proxy"
|
34
32
|
end
|
35
33
|
|
36
|
-
def proxy_foreign_key
|
34
|
+
def self.proxy_foreign_key
|
37
35
|
:target
|
38
36
|
end
|
39
37
|
|
40
|
-
def contains_key
|
38
|
+
def self.contains_key(options)
|
41
39
|
options[:through]
|
42
40
|
end
|
43
41
|
|
44
|
-
def list_source_class
|
42
|
+
def self.list_source_class
|
45
43
|
"ActiveFedora::Aggregation::ListSource"
|
46
44
|
end
|
47
45
|
end
|
@@ -12,6 +12,7 @@ module ActiveFedora::Orders
|
|
12
12
|
|
13
13
|
def reader(*args)
|
14
14
|
@proxy ||= ActiveFedora::Orders::CollectionProxy.new(self)
|
15
|
+
@null_proxy ||= ActiveFedora::Orders::CollectionProxy.new(self)
|
15
16
|
super
|
16
17
|
end
|
17
18
|
|
@@ -144,11 +145,11 @@ module ActiveFedora::Orders
|
|
144
145
|
end
|
145
146
|
|
146
147
|
def unordered_association
|
147
|
-
owner.association(
|
148
|
+
owner.association(unordered_reflection_name)
|
148
149
|
end
|
149
150
|
|
150
|
-
def
|
151
|
-
reflection.
|
151
|
+
def unordered_reflection_name
|
152
|
+
reflection.unordered_reflection.name
|
152
153
|
end
|
153
154
|
end
|
154
155
|
end
|
@@ -1,8 +1,13 @@
|
|
1
1
|
module ActiveFedora::Orders
|
2
2
|
class Builder < ActiveFedora::Associations::Builder::CollectionAssociation
|
3
3
|
include ActiveFedora::AutosaveAssociation::AssociationBuilderExtension
|
4
|
-
self.macro
|
5
|
-
|
4
|
+
def self.macro
|
5
|
+
:orders
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.valid_options(options)
|
9
|
+
super + [:through, :unordered_reflection]
|
10
|
+
end
|
6
11
|
|
7
12
|
def self.define_readers(mixin, name)
|
8
13
|
super
|
@@ -14,14 +19,37 @@ module ActiveFedora::Orders
|
|
14
19
|
end
|
15
20
|
end
|
16
21
|
|
17
|
-
def
|
18
|
-
|
19
|
-
@model = model
|
22
|
+
def self.build(model, name, options)
|
23
|
+
options = { unordered_reflection: unordered_reflection(model, name)}.merge(options)
|
20
24
|
name = :"ordered_#{name.to_s.singularize}_proxies"
|
21
|
-
|
25
|
+
model.property :head, predicate: ::RDF::Vocab::IANA['first']
|
26
|
+
model.property :tail, predicate: ::RDF::Vocab::IANA.last
|
27
|
+
model.send(:define_method, :apply_first_and_last) do
|
28
|
+
source = send(options[:through])
|
29
|
+
source.save
|
30
|
+
return if head.map(&:rdf_subject) == source.head_id && tail.map(&:rdf_subject) == source.tail_id
|
31
|
+
self.head = source.head_id
|
32
|
+
self.tail = source.tail_id
|
33
|
+
save! if changed?
|
34
|
+
end
|
35
|
+
model.include ActiveFedora::Orders::Builder::FixFirstLast
|
22
36
|
super
|
23
37
|
end
|
24
38
|
|
39
|
+
def self.create_reflection(model, name, scope, options, extension = nil)
|
40
|
+
unless name.is_a?(Symbol)
|
41
|
+
name = name.to_sym
|
42
|
+
Deprecation.warn(ActiveFedora::Base, "association names must be a Symbol")
|
43
|
+
end
|
44
|
+
validate_options(options)
|
45
|
+
translate_property_to_predicate(options)
|
46
|
+
|
47
|
+
scope = build_scope(scope, extension)
|
48
|
+
name = better_name(name)
|
49
|
+
|
50
|
+
ActiveFedora::Orders::Reflection.create(macro, name, scope, options, model)
|
51
|
+
end
|
52
|
+
|
25
53
|
module FixFirstLast
|
26
54
|
def save(*args)
|
27
55
|
super.tap do |result|
|
@@ -39,29 +67,14 @@ module ActiveFedora::Orders
|
|
39
67
|
end
|
40
68
|
end
|
41
69
|
|
42
|
-
def build
|
43
|
-
super.tap do |result|
|
44
|
-
model.property :head, predicate: ::RDF::Vocab::IANA['first']
|
45
|
-
model.property :tail, predicate: ::RDF::Vocab::IANA.last
|
46
|
-
model.send(:define_method, :apply_first_and_last) do
|
47
|
-
source = send(result.options[:through])
|
48
|
-
return if head.map(&:rdf_subject) == source.head_id && tail.map(&:rdf_subject) == source.tail_id
|
49
|
-
self.head = source.head_id
|
50
|
-
self.tail = source.tail_id
|
51
|
-
save! if changed?
|
52
|
-
end
|
53
|
-
model.include ActiveFedora::Orders::Builder::FixFirstLast
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
70
|
private
|
58
71
|
|
59
72
|
def self.target_accessor(name)
|
60
73
|
name.to_s.gsub("_proxies","").pluralize
|
61
74
|
end
|
62
75
|
|
63
|
-
def
|
64
|
-
model.
|
76
|
+
def self.unordered_reflection(model, original_name)
|
77
|
+
model._reflect_on_association(original_name)
|
65
78
|
end
|
66
79
|
end
|
67
80
|
end
|
@@ -1,5 +1,20 @@
|
|
1
1
|
module ActiveFedora::Orders
|
2
2
|
class Reflection < ActiveFedora::Reflection::AssociationReflection
|
3
|
+
class << self
|
4
|
+
def create(macro, name, scope, options, active_fedora)
|
5
|
+
klass = case macro
|
6
|
+
when :aggregation
|
7
|
+
Reflection
|
8
|
+
when :filter
|
9
|
+
ActiveFedora::Filter::Reflection
|
10
|
+
when :orders
|
11
|
+
ActiveFedora::Orders::Reflection
|
12
|
+
end
|
13
|
+
reflection = klass.new(macro, name, scope, options, active_fedora)
|
14
|
+
ActiveFedora::Reflection.add_reflection(active_fedora, name, reflection)
|
15
|
+
reflection
|
16
|
+
end
|
17
|
+
end
|
3
18
|
def association_class
|
4
19
|
Association
|
5
20
|
end
|
@@ -12,8 +27,8 @@ module ActiveFedora::Orders
|
|
12
27
|
klass.to_s
|
13
28
|
end
|
14
29
|
|
15
|
-
def
|
16
|
-
options[:
|
30
|
+
def unordered_reflection
|
31
|
+
options[:unordered_reflection]
|
17
32
|
end
|
18
33
|
|
19
34
|
def klass
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activefedora-aggregation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 9.
|
33
|
+
version: 9.10.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 9.
|
40
|
+
version: 9.10.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rdf-vocab
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,24 +177,10 @@ files:
|
|
177
177
|
- bin/setup
|
178
178
|
- circle.yml
|
179
179
|
- lib/active_fedora/aggregation.rb
|
180
|
-
- lib/active_fedora/aggregation/aggregation_extension.rb
|
181
|
-
- lib/active_fedora/aggregation/appends_to_aggregation.rb
|
182
|
-
- lib/active_fedora/aggregation/association.rb
|
183
180
|
- lib/active_fedora/aggregation/base_extension.rb
|
184
|
-
- lib/active_fedora/aggregation/builder.rb
|
185
|
-
- lib/active_fedora/aggregation/decorating_repository.rb
|
186
|
-
- lib/active_fedora/aggregation/decorator_list.rb
|
187
|
-
- lib/active_fedora/aggregation/decorator_with_arguments.rb
|
188
|
-
- lib/active_fedora/aggregation/link_inserter.rb
|
189
181
|
- lib/active_fedora/aggregation/list_source.rb
|
190
|
-
- lib/active_fedora/aggregation/null_proxy.rb
|
191
|
-
- lib/active_fedora/aggregation/ordered_proxy.rb
|
192
182
|
- lib/active_fedora/aggregation/ordered_reader.rb
|
193
|
-
- lib/active_fedora/aggregation/persist_links.rb
|
194
183
|
- lib/active_fedora/aggregation/proxy.rb
|
195
|
-
- lib/active_fedora/aggregation/proxy_owner.rb
|
196
|
-
- lib/active_fedora/aggregation/proxy_repository.rb
|
197
|
-
- lib/active_fedora/aggregation/reflection.rb
|
198
184
|
- lib/active_fedora/aggregation/version.rb
|
199
185
|
- lib/active_fedora/filter.rb
|
200
186
|
- lib/active_fedora/filter/association.rb
|
@@ -246,9 +232,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
246
232
|
version: '0'
|
247
233
|
requirements: []
|
248
234
|
rubyforge_project:
|
249
|
-
rubygems_version: 2.5.1
|
235
|
+
rubygems_version: 2.4.5.1
|
250
236
|
signing_key:
|
251
237
|
specification_version: 4
|
252
238
|
summary: Aggregations for active-fedora
|
253
239
|
test_files: []
|
254
|
-
has_rdoc:
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# This module is mixed into classes that declare 'aggregates ...'
|
2
|
-
#
|
3
|
-
module ActiveFedora::Aggregation
|
4
|
-
module AggregationExtension
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
include PersistLinks
|
7
|
-
|
8
|
-
included do
|
9
|
-
after_destroy :remove_aggregation_proxies_from_solr
|
10
|
-
|
11
|
-
# Doesn't use after_save because we need this callback to come after the autosave callback
|
12
|
-
after_create :persist_aggregation_links
|
13
|
-
after_update :persist_aggregation_links
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
# The proxies, being nested under the object, are automatically destroyed
|
19
|
-
# this cleans up their records from solr.
|
20
|
-
def remove_aggregation_proxies_from_solr
|
21
|
-
query = ActiveFedora::SolrQueryBuilder.construct_query_for_rel(proxyIn: id, has_model: Proxy.to_class_uri)
|
22
|
-
ActiveFedora::SolrService.instance.conn.delete_by_query(query, params: {'softCommit' => true})
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
class AppendsToAggregation < SimpleDelegator
|
3
|
-
attr_reader :parent_node
|
4
|
-
# @param [#next, #prev] proxy The proxy to add behavior to.
|
5
|
-
# @param [#head, #tail] parent_node The aggregation to append proxies to.
|
6
|
-
def initialize(proxy, parent_node)
|
7
|
-
@parent_node = parent_node
|
8
|
-
super(proxy)
|
9
|
-
end
|
10
|
-
|
11
|
-
def is_a?(klass)
|
12
|
-
__getobj__.is_a?(klass)
|
13
|
-
end
|
14
|
-
|
15
|
-
def save(*args)
|
16
|
-
insert_link do
|
17
|
-
super
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def insert_link
|
24
|
-
result = yield
|
25
|
-
if result
|
26
|
-
LinkInserter.new(parent_node, self).call
|
27
|
-
end
|
28
|
-
result
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
class Association < ::ActiveFedora::Associations::IndirectlyContainsAssociation
|
3
|
-
delegate :first, to: :ordered_reader
|
4
|
-
|
5
|
-
def ordered_reader
|
6
|
-
OrderedReader.new(owner).to_a.map(&:target)
|
7
|
-
end
|
8
|
-
|
9
|
-
def proxy_class
|
10
|
-
@proxy_class ||= ProxyRepository.new(owner, super)
|
11
|
-
end
|
12
|
-
|
13
|
-
def options
|
14
|
-
@all_options ||= default_options.merge(super)
|
15
|
-
end
|
16
|
-
|
17
|
-
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
|
18
|
-
def ids_reader
|
19
|
-
return [] if @owner.new_record?
|
20
|
-
if loaded?
|
21
|
-
load_target.map do |record|
|
22
|
-
record.id
|
23
|
-
end
|
24
|
-
else
|
25
|
-
proxies = load_proxies_from_solr(fl: 'id, next_ssim, proxyFor_ssim')
|
26
|
-
create_linked_list(@owner.head_id, proxies)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
# Write a query to find the proxies
|
33
|
-
def construct_proxy_query
|
34
|
-
raise "Owner must have an identifier" unless @owner.id
|
35
|
-
@proxy_query ||= begin
|
36
|
-
clauses = { 'proxyIn' => @owner.id }
|
37
|
-
clauses[:has_model] = ActiveFedora::Aggregation::Proxy.to_class_uri
|
38
|
-
ActiveFedora::SolrQueryBuilder.construct_query_for_rel(clauses)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Finds the proxies
|
43
|
-
# @param opts [Hash] Options that will be passed through to ActiveFedora::SolrService.query.
|
44
|
-
def load_proxies_from_solr(opts = Hash.new)
|
45
|
-
finder_query = construct_proxy_query
|
46
|
-
rows = 1000
|
47
|
-
ActiveFedora::SolrService.query(finder_query, { rows: rows }.merge(opts))
|
48
|
-
end
|
49
|
-
|
50
|
-
# @param [String, NilClass] first_id
|
51
|
-
# @param [Array<Hash>] remainder
|
52
|
-
# @param [Array] list
|
53
|
-
def create_linked_list(first_id, remainder, list=[])
|
54
|
-
return list if remainder.empty?
|
55
|
-
|
56
|
-
index = remainder.find_index { |n| n.fetch('id') == first_id }
|
57
|
-
first = remainder.delete_at(index)
|
58
|
-
next_id = first['next_ssim'].try(:first)
|
59
|
-
proxy_for = first.fetch('proxyFor_ssim', []).first
|
60
|
-
if proxy_for
|
61
|
-
create_linked_list(next_id, remainder, list + [proxy_for])
|
62
|
-
else
|
63
|
-
ActiveFedora::Base.logger.error("Found a proxy (id: #{first['id']}) that has no proxyFor_ssim") if ActiveFedora::Base.logger
|
64
|
-
create_linked_list(next_id, remainder, list)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def default_options
|
69
|
-
{ through: default_proxy_class, foreign_key: :target, has_member_relation: reflection.predicate, inserted_content_relation: content_relation }
|
70
|
-
end
|
71
|
-
|
72
|
-
def content_relation
|
73
|
-
default_proxy_class.constantize.reflect_on_association(:target).predicate
|
74
|
-
end
|
75
|
-
|
76
|
-
def default_proxy_class
|
77
|
-
'ActiveFedora::Aggregation::Proxy'
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
class Builder < ActiveFedora::Associations::Builder::CollectionAssociation
|
3
|
-
include ActiveFedora::AutosaveAssociation::AssociationBuilderExtension
|
4
|
-
self.macro = :aggregation
|
5
|
-
|
6
|
-
def build
|
7
|
-
reflection = super
|
8
|
-
model.belongs_to :head, predicate: ::RDF::Vocab::IANA['first'], class_name: 'ActiveFedora::Aggregation::Proxy'
|
9
|
-
model.belongs_to :tail, predicate: ::RDF::Vocab::IANA.last, class_name: 'ActiveFedora::Aggregation::Proxy'
|
10
|
-
|
11
|
-
model.include AggregationExtension
|
12
|
-
reflection
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.define_readers(mixin, name)
|
16
|
-
super
|
17
|
-
mixin.redefine_method("#{name.to_s.singularize}_ids") do
|
18
|
-
association(name).ids_reader
|
19
|
-
end
|
20
|
-
mixin.redefine_method("ordered_#{name.to_s.pluralize}") do
|
21
|
-
association(name).ordered_reader
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.define_writers(mixin, name)
|
26
|
-
super
|
27
|
-
mixin.redefine_method("#{name.to_s.singularize}_ids=") do |ids|
|
28
|
-
association(name).ids_writer(ids)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
##
|
3
|
-
# Decorates the results of a repository with the given decorator.
|
4
|
-
class DecoratingRepository < SimpleDelegator
|
5
|
-
attr_reader :decorator
|
6
|
-
# @param [#new] decorator A decorator.
|
7
|
-
# @param [#find, #new] base_repository A repository to decorate.
|
8
|
-
def initialize(decorator, base_repository)
|
9
|
-
@decorator = decorator
|
10
|
-
super(base_repository)
|
11
|
-
end
|
12
|
-
|
13
|
-
def find(id)
|
14
|
-
decorate(super(id))
|
15
|
-
end
|
16
|
-
|
17
|
-
def new(*args)
|
18
|
-
result = decorate(super(*args))
|
19
|
-
yield result if block_given?
|
20
|
-
result
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def decorate(obj)
|
26
|
-
decorator.new(obj)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
# A composite object to allow for a list of decorators to be treated like one.
|
3
|
-
class DecoratorList
|
4
|
-
attr_reader :decorators
|
5
|
-
def initialize(*decorators)
|
6
|
-
@decorators = decorators
|
7
|
-
end
|
8
|
-
|
9
|
-
def new(undecorated_object)
|
10
|
-
decorators.inject(undecorated_object) do |obj, decorator|
|
11
|
-
decorator.new(obj)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
# This is an Adapter to allow a Decorator to respond to the interface #new()
|
3
|
-
# but still require other arguments to instantiate.
|
4
|
-
class DecoratorWithArguments
|
5
|
-
attr_reader :decorator, :args
|
6
|
-
def initialize(decorator, *args)
|
7
|
-
@decorator = decorator
|
8
|
-
@args = args
|
9
|
-
end
|
10
|
-
|
11
|
-
def new(obj)
|
12
|
-
decorator.new(obj, *args)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
class LinkInserter
|
3
|
-
attr_reader :root, :proxy
|
4
|
-
# @param [ProxyOwner] root the node representing the aggregation
|
5
|
-
# @param [Proxy] proxy the proxy to add to the aggregation
|
6
|
-
def initialize(root, proxy)
|
7
|
-
@root = root
|
8
|
-
@proxy = proxy
|
9
|
-
end
|
10
|
-
|
11
|
-
def call
|
12
|
-
if root.head
|
13
|
-
append
|
14
|
-
else
|
15
|
-
set
|
16
|
-
end
|
17
|
-
proxy.container = root
|
18
|
-
persist_nodes!
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def append
|
24
|
-
Appender.new(root, proxy).call
|
25
|
-
end
|
26
|
-
|
27
|
-
def set
|
28
|
-
root.head = proxy
|
29
|
-
root.tail = proxy
|
30
|
-
end
|
31
|
-
|
32
|
-
def persist_nodes!
|
33
|
-
[proxy, proxy.prev].uniq.compact.each(&:save!)
|
34
|
-
end
|
35
|
-
|
36
|
-
class Appender
|
37
|
-
attr_reader :root, :proxy
|
38
|
-
def initialize(root, proxy)
|
39
|
-
@root = root
|
40
|
-
@proxy = proxy
|
41
|
-
end
|
42
|
-
|
43
|
-
def call
|
44
|
-
last_proxy.next = proxy
|
45
|
-
proxy.prev = last_proxy
|
46
|
-
root.tail = proxy
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def last_proxy
|
52
|
-
@last_proxy ||= root.tail
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
# A null proxy to simplify logic.
|
3
|
-
class NullProxy
|
4
|
-
include Singleton
|
5
|
-
|
6
|
-
attr_writer :prev, :next
|
7
|
-
def prev
|
8
|
-
self
|
9
|
-
end
|
10
|
-
|
11
|
-
def next
|
12
|
-
self
|
13
|
-
end
|
14
|
-
|
15
|
-
def reload
|
16
|
-
self
|
17
|
-
end
|
18
|
-
|
19
|
-
def changed?
|
20
|
-
false
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
# A proxy which knows how to delete itself from an aggregation.
|
3
|
-
class OrderedProxy < SimpleDelegator
|
4
|
-
attr_reader :parent_node
|
5
|
-
# @param [#next, #prev, #delete] proxy The proxy to add behavior to.
|
6
|
-
# @param [#delete_proxy!] parent_node The aggregation to delete proxies
|
7
|
-
# from.
|
8
|
-
def initialize(proxy, parent_node)
|
9
|
-
@parent_node = parent_node
|
10
|
-
super(proxy)
|
11
|
-
end
|
12
|
-
|
13
|
-
def is_a?(klass)
|
14
|
-
__getobj__.is_a?(klass)
|
15
|
-
end
|
16
|
-
|
17
|
-
def delete(*args)
|
18
|
-
link_node_if_true do
|
19
|
-
super
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
protected
|
24
|
-
|
25
|
-
def link_node_if_true
|
26
|
-
# Have to precache these or AF tries to access this node?
|
27
|
-
next_or_null
|
28
|
-
prev_or_null
|
29
|
-
yield.tap do |result|
|
30
|
-
if result
|
31
|
-
# Have to reload proxies because otherwise you persist them with bad
|
32
|
-
# referencing triples.
|
33
|
-
[next_or_null, prev_or_null, parent_node].each(&:reload)
|
34
|
-
prev_or_null.next = self.next
|
35
|
-
next_or_null.prev = prev
|
36
|
-
changed_nodes.each(&:save!)
|
37
|
-
parent_node.delete_proxy!(self)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def next_or_null
|
43
|
-
self.next || NullProxy.instance
|
44
|
-
end
|
45
|
-
|
46
|
-
def prev_or_null
|
47
|
-
self.prev || NullProxy.instance
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def changed_nodes
|
53
|
-
[self.prev, self.next].uniq.compact.select(&:changed?)
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
@@ -1,9 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
module PersistLinks
|
3
|
-
# If the head or tail pointer was updated (in an autosave callback), then persist them
|
4
|
-
def persist_aggregation_links
|
5
|
-
return true unless @new_record_before_save
|
6
|
-
save if changes.key?("head_id") or changes.key?("tail_id")
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
##
|
3
|
-
# Decorates a proxy owner such that it knows how to delete a proxy from its
|
4
|
-
# ordered list.
|
5
|
-
class ProxyOwner < SimpleDelegator
|
6
|
-
def is_a?(klass)
|
7
|
-
__getobj__.is_a?(klass)
|
8
|
-
end
|
9
|
-
|
10
|
-
# @param [#next, #prev] proxy A Proxy link to delete.
|
11
|
-
def delete_proxy!(proxy)
|
12
|
-
if proxy == head || head.nil? # Head is nil if proxy is now deleted.
|
13
|
-
self.head = proxy.next
|
14
|
-
end
|
15
|
-
if proxy == tail || tail.nil? # Head is nil if proxy is now deleted.
|
16
|
-
self.tail = proxy.prev
|
17
|
-
end
|
18
|
-
[head, tail].uniq.compact.each(&:reload)
|
19
|
-
if changed?
|
20
|
-
save!
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
##
|
3
|
-
# Repository for Proxies. This repository is responsible for decorating a
|
4
|
-
# proxy such that it's useful for aggregation and is an attempt at
|
5
|
-
# centralizing hard-coded dependencies without a dependency injection
|
6
|
-
# container.
|
7
|
-
class ProxyRepository < SimpleDelegator
|
8
|
-
attr_reader :owner, :base_proxy_factory
|
9
|
-
# @param [ActiveFedora::Base] owner The node which proxy will assert order
|
10
|
-
# on.
|
11
|
-
# @param [#find, #new] base_proxy_factory The base factory which returns proxies
|
12
|
-
# that will be decorated.
|
13
|
-
# @return [#find, #new] A repository which can return proxies useful for
|
14
|
-
# aggregation.
|
15
|
-
def initialize(owner, base_proxy_factory)
|
16
|
-
@owner = owner
|
17
|
-
@base_proxy_factory = base_proxy_factory
|
18
|
-
super(repository)
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def repository
|
24
|
-
DecoratingRepository.new(proxy_decorator, base_proxy_factory)
|
25
|
-
end
|
26
|
-
|
27
|
-
def proxy_decorator
|
28
|
-
DecoratorList.new(
|
29
|
-
DecoratorWithArguments.new(OrderedProxy, proxy_owner),
|
30
|
-
DecoratorWithArguments.new(AppendsToAggregation, proxy_owner)
|
31
|
-
)
|
32
|
-
end
|
33
|
-
|
34
|
-
def proxy_owner
|
35
|
-
@proxy_owner ||= ProxyOwner.new(owner)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module ActiveFedora::Aggregation
|
2
|
-
class Reflection < ActiveFedora::Reflection::AssociationReflection
|
3
|
-
def association_class
|
4
|
-
Association
|
5
|
-
end
|
6
|
-
|
7
|
-
def klass
|
8
|
-
@klass ||= begin
|
9
|
-
klass = class_name.constantize
|
10
|
-
klass.respond_to?(:uri_to_id) ? klass : ActiveFedora::Base
|
11
|
-
rescue NameError => e
|
12
|
-
# If the NameError is a result of the class having a
|
13
|
-
# NameError (e.g. NoMethodError) within it then raise the error.
|
14
|
-
raise e if Object.const_defined? class_name
|
15
|
-
# Otherwise the NameError was a result of not being able to find the class
|
16
|
-
ActiveFedora::Base
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def predicate
|
21
|
-
@options[:predicate] || ::RDF::Vocab::ORE.aggregates
|
22
|
-
end
|
23
|
-
|
24
|
-
def collection?
|
25
|
-
true
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|