activefedora-aggregation 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|