rdf-serializers 0.0.5 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/rdf/serializers/config.rb +47 -0
- data/lib/rdf/serializers/data_type_helper.rb +35 -0
- data/lib/rdf/serializers/hdnjson_parser.rb +70 -0
- data/lib/rdf/serializers/hextuple_serializer.rb +71 -0
- data/lib/rdf/serializers/list_serializer.rb +19 -0
- data/lib/rdf/serializers/lookup_chain.rb +61 -0
- data/lib/rdf/serializers/nil_serializer.rb +13 -0
- data/lib/rdf/serializers/object_serializer.rb +170 -0
- data/lib/rdf/serializers/relationship.rb +65 -0
- data/lib/rdf/serializers/renderers.rb +33 -6
- data/lib/rdf/serializers/scalar.rb +50 -0
- data/lib/rdf/serializers/serialization_core.rb +130 -0
- data/lib/rdf/serializers/statements.rb +27 -0
- data/lib/rdf/serializers/version.rb +1 -1
- data/lib/rdf/serializers.rb +86 -2
- metadata +41 -18
- data/lib/active_model_serializers/adapter/rdf/relationship.rb +0 -60
- data/lib/active_model_serializers/adapter/rdf.rb +0 -126
- data/lib/active_model_serializers/serializer.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0be7947d0024e7f830b59b3a3a54ee24ba41f577abab0e85d31f332b5e992e01
|
4
|
+
data.tar.gz: 63ac5d819554a72e03e2ab66b1420fd956c29db46d40031b107cdfd0e775f957
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec6636a77e6799e8aae8f2c623081b45b22fe0e291f51370eaee3aea16e6f34557bcef3aae4496fc3c0b087cc765d499ee58fcfe222208b24650a44b86fe6afd
|
7
|
+
data.tar.gz: 6bc906962033ad39c23efa768c111cfa0a7d52ed6727f6786dc78592f5165ee34bf2b783ddf7438a005ea1a2a48ad65a632889715eaaca12f84965a895a8d1c9
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
def self.configure
|
6
|
+
yield @config ||= RDF::Serializers::Configuration.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.config
|
10
|
+
@config
|
11
|
+
end
|
12
|
+
|
13
|
+
class Configuration
|
14
|
+
include ActiveSupport::Configurable
|
15
|
+
config_accessor :always_include_named_graphs
|
16
|
+
config_accessor :default_graph
|
17
|
+
config_accessor :serializer_lookup_chain
|
18
|
+
config_accessor :serializer_lookup_enabled
|
19
|
+
end
|
20
|
+
|
21
|
+
configure do |config|
|
22
|
+
config.always_include_named_graphs = true
|
23
|
+
|
24
|
+
config.serializer_lookup_enabled = true
|
25
|
+
|
26
|
+
# For configuring how serializers are found.
|
27
|
+
# This should be an array of procs.
|
28
|
+
#
|
29
|
+
# The priority of the output is that the first item
|
30
|
+
# in the evaluated result array will take precedence
|
31
|
+
# over other possible serializer paths.
|
32
|
+
#
|
33
|
+
# i.e.: First match wins.
|
34
|
+
#
|
35
|
+
# @example output
|
36
|
+
# => [
|
37
|
+
# "CustomNamespace::ResourceSerializer",
|
38
|
+
# "ParentSerializer::ResourceSerializer",
|
39
|
+
# "ResourceNamespace::ResourceSerializer" ,
|
40
|
+
# "ResourceSerializer"]
|
41
|
+
#
|
42
|
+
# If CustomNamespace::ResourceSerializer exists, it will be used
|
43
|
+
# for serialization
|
44
|
+
config.serializer_lookup_chain = RDF::Serializers::LookupChain::DEFAULT.dup
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
module DataTypeHelper
|
6
|
+
def xsd_to_rdf(xsd, value, opts = {}) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
7
|
+
klass =
|
8
|
+
case xsd
|
9
|
+
when RDF::XSD[:anyURI]
|
10
|
+
RDF::URI
|
11
|
+
when RDF::XSD[:integer]
|
12
|
+
RDF::Literal::Integer
|
13
|
+
when RDF::XSD[:dateTime]
|
14
|
+
RDF::Literal::DateTime
|
15
|
+
when RDF::XSD[:date]
|
16
|
+
RDF::Literal::Date
|
17
|
+
when RDF::XSD[:boolean]
|
18
|
+
RDF::Literal::Boolean
|
19
|
+
when RDF::XSD[:time]
|
20
|
+
RDF::Literal::Time
|
21
|
+
when RDF::XSD[:long], RDF::XSD[:double]
|
22
|
+
RDF::Literal::Double
|
23
|
+
when RDF::XSD[:decimal]
|
24
|
+
RDF::Literal::Decimal
|
25
|
+
when RDF::XSD[:token]
|
26
|
+
RDF::Literal::Token
|
27
|
+
else
|
28
|
+
RDF::Literal
|
29
|
+
end
|
30
|
+
|
31
|
+
klass.new(value, opts)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
class HndJSONParser
|
6
|
+
include DataTypeHelper
|
7
|
+
|
8
|
+
HEX_SUBJECT = 0
|
9
|
+
HEX_PREDICATE = 1
|
10
|
+
HEX_OBJECT = 2
|
11
|
+
HEX_DATATYPE = 3
|
12
|
+
HEX_LANGUAGE = 4
|
13
|
+
HEX_GRAPH = 5
|
14
|
+
|
15
|
+
def parse_body(body)
|
16
|
+
body.split("\n").map { |line| parse_hex(JSON.parse(line)) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_hex(hex)
|
20
|
+
subject = parse_subject(hex[HEX_SUBJECT])
|
21
|
+
predicate = RDF::URI(hex[HEX_PREDICATE])
|
22
|
+
object = parse_object(hex[HEX_OBJECT], hex[HEX_DATATYPE], hex[HEX_LANGUAGE])
|
23
|
+
graph = hex[HEX_GRAPH].present? ? RDF::URI(hex[HEX_GRAPH]) : RDF::Serializers.config.default_graph
|
24
|
+
|
25
|
+
RDF::Statement.new(
|
26
|
+
subject,
|
27
|
+
predicate,
|
28
|
+
object,
|
29
|
+
graph_name: graph
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def blank_node(id)
|
36
|
+
@blank_nodes ||= {}
|
37
|
+
@blank_nodes[id] ||= RDF::Node(id)
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_object(value, datatype, language)
|
41
|
+
case datatype
|
42
|
+
when 'http://www.w3.org/1999/02/22-rdf-syntax-ns#namedNode'
|
43
|
+
RDF::URI(value)
|
44
|
+
when 'http://www.w3.org/1999/02/22-rdf-syntax-ns#blankNode'
|
45
|
+
blank_node(value.sub('_:', ''))
|
46
|
+
when language
|
47
|
+
RDF::Literal(value, datatype: RDF.langString, language: language)
|
48
|
+
else
|
49
|
+
xsd_to_rdf(datatype, value, language: language.presence)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_subject(subject)
|
54
|
+
if subject.is_a?(RDF::Resource)
|
55
|
+
subject
|
56
|
+
elsif subject.start_with?('_')
|
57
|
+
blank_node(subject.sub('_:', ''))
|
58
|
+
else
|
59
|
+
RDF::URI(subject)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
def parse(body)
|
65
|
+
new.parse_body(body)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
module HextupleSerializer
|
6
|
+
def iri_from_record(record)
|
7
|
+
return record if record.try(:uri?)
|
8
|
+
|
9
|
+
raise FastJsonapi::MandatoryField, 'record has no iri' unless record.respond_to?(:iri)
|
10
|
+
|
11
|
+
record.iri
|
12
|
+
end
|
13
|
+
|
14
|
+
def normalized_object(object)
|
15
|
+
case object
|
16
|
+
when ::RDF::Term
|
17
|
+
object
|
18
|
+
when ActiveSupport::TimeWithZone
|
19
|
+
::RDF::Literal(object.to_datetime)
|
20
|
+
else
|
21
|
+
::RDF::Literal(object)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def object_value(obj)
|
26
|
+
if obj.is_a?(::RDF::URI)
|
27
|
+
obj.value
|
28
|
+
elsif obj.is_a?(::RDF::Node)
|
29
|
+
obj.to_s
|
30
|
+
else
|
31
|
+
obj.value.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def object_datatype(obj)
|
36
|
+
if obj.is_a?(::RDF::URI)
|
37
|
+
'http://www.w3.org/1999/02/22-rdf-syntax-ns#namedNode'
|
38
|
+
elsif obj.is_a?(::RDF::Node)
|
39
|
+
'http://www.w3.org/1999/02/22-rdf-syntax-ns#blankNode'
|
40
|
+
elsif obj.try(:datatype?)
|
41
|
+
obj.datatype
|
42
|
+
else
|
43
|
+
lit = RDF::Literal(obj)
|
44
|
+
lit.datatype.to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def value_to_hex(iri, predicate, object, graph = nil, serialization_params = {})
|
49
|
+
return if object.nil?
|
50
|
+
|
51
|
+
obj = normalized_object(object)
|
52
|
+
|
53
|
+
[
|
54
|
+
iri.to_s,
|
55
|
+
predicate.to_s,
|
56
|
+
object_value(obj),
|
57
|
+
object_datatype(obj),
|
58
|
+
obj.try(:language) || '',
|
59
|
+
operation((graph || ::RDF::Serializers.config.default_graph)&.value, serialization_params[:context])
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
def operation(operation, graph_name)
|
64
|
+
return nil if operation.blank?
|
65
|
+
return operation if graph_name.blank?
|
66
|
+
|
67
|
+
"#{operation}?graph=#{WEBrick::HTTPUtils.escape_form(graph_name.to_s)}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
class ListSerializer
|
6
|
+
include RDF::Serializers::ObjectSerializer
|
7
|
+
|
8
|
+
def hextuples_for_collection
|
9
|
+
@resource.map do |resource|
|
10
|
+
RDF::Serializers.serializer_for(resource).record_hextuples(resource, nil, @includes, @params)
|
11
|
+
end.flatten(1)
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def validate_includes!(_includes); end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
# Extracted from active_model_serializers
|
6
|
+
module LookupChain
|
7
|
+
# Standard appending of Serializer to the resource name.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
# Author => AuthorSerializer
|
11
|
+
BY_RESOURCE = lambda do |resource_class, _namespace|
|
12
|
+
serializer_from(resource_class)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Uses the namespace of the resource to find the serializer
|
16
|
+
#
|
17
|
+
# Example:
|
18
|
+
# British::Author => British::AuthorSerializer
|
19
|
+
BY_RESOURCE_NAMESPACE = lambda do |resource_class, _namespace|
|
20
|
+
resource_namespace = namespace_for(resource_class)
|
21
|
+
serializer_name = serializer_from(resource_class)
|
22
|
+
|
23
|
+
"#{resource_namespace}::#{serializer_name}"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Uses the controller namespace of the resource to find the serializer
|
27
|
+
#
|
28
|
+
# Example:
|
29
|
+
# Api::V3::AuthorsController => Api::V3::AuthorSerializer
|
30
|
+
BY_NAMESPACE = lambda do |resource_class, namespace|
|
31
|
+
resource_name = resource_class_name(resource_class)
|
32
|
+
namespace ? "#{namespace}::#{resource_name}Serializer" : nil
|
33
|
+
end
|
34
|
+
|
35
|
+
DEFAULT = [
|
36
|
+
BY_NAMESPACE,
|
37
|
+
BY_RESOURCE_NAMESPACE,
|
38
|
+
BY_RESOURCE
|
39
|
+
].freeze
|
40
|
+
|
41
|
+
module_function
|
42
|
+
|
43
|
+
def namespace_for(klass)
|
44
|
+
klass.name.deconstantize
|
45
|
+
end
|
46
|
+
|
47
|
+
def resource_class_name(klass)
|
48
|
+
klass.name.demodulize
|
49
|
+
end
|
50
|
+
|
51
|
+
def serializer_from_resource_name(name)
|
52
|
+
"#{name}Serializer"
|
53
|
+
end
|
54
|
+
|
55
|
+
def serializer_from(klass)
|
56
|
+
name = resource_class_name(klass)
|
57
|
+
serializer_from_resource_name(name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'oj'
|
4
|
+
|
5
|
+
module RDF
|
6
|
+
module Serializers
|
7
|
+
module ObjectSerializer
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
include FastJsonapi::ObjectSerializer
|
10
|
+
include SerializationCore
|
11
|
+
|
12
|
+
def dump(*args, **options)
|
13
|
+
case args.first
|
14
|
+
when :hndjson
|
15
|
+
render_hndjson
|
16
|
+
else
|
17
|
+
render_repository(*args, options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def triples(*args, **options)
|
22
|
+
if include_named_graphs?(*args)
|
23
|
+
repository.triples(*args, options)
|
24
|
+
else
|
25
|
+
repository.project_graph(nil).triples(*args, options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def blank_node(id)
|
32
|
+
@blank_nodes ||= {}
|
33
|
+
@blank_nodes[id] ||= RDF::Node(id)
|
34
|
+
end
|
35
|
+
|
36
|
+
def hextuples_for_collection
|
37
|
+
data = []
|
38
|
+
fieldset = @fieldsets[self.class.record_type.to_sym]
|
39
|
+
@resource.each do |record|
|
40
|
+
data.concat self.class.record_hextuples(record, fieldset, @includes, @params)
|
41
|
+
next unless @includes.present?
|
42
|
+
|
43
|
+
data.concat(
|
44
|
+
self.class.get_included_records_hex(record, @includes, @known_included_objects, @fieldsets, @params)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
data
|
49
|
+
end
|
50
|
+
|
51
|
+
def hextuples_for_one_record
|
52
|
+
serializable_hextuples = []
|
53
|
+
|
54
|
+
serializable_hextuples.concat self.class.record_hextuples(
|
55
|
+
@resource,
|
56
|
+
@fieldsets[self.class.record_type.to_sym],
|
57
|
+
@includes,
|
58
|
+
@params
|
59
|
+
)
|
60
|
+
|
61
|
+
if @includes.present?
|
62
|
+
serializable_hextuples.concat self.class.get_included_records_hex(
|
63
|
+
@resource,
|
64
|
+
@includes,
|
65
|
+
@known_included_objects,
|
66
|
+
@fieldsets,
|
67
|
+
@params
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
serializable_hextuples
|
72
|
+
end
|
73
|
+
|
74
|
+
def include_named_graphs?(*args)
|
75
|
+
::RDF::Serializers.config.always_include_named_graphs ||
|
76
|
+
::RDF::Writer.for(*args.presence || :nquads).instance_methods.include?(:write_quad)
|
77
|
+
end
|
78
|
+
|
79
|
+
def meta_hextuples
|
80
|
+
return [] unless @meta.is_a?(Array)
|
81
|
+
|
82
|
+
@meta.map do |statement|
|
83
|
+
if statement.is_a?(Array)
|
84
|
+
value_to_hex(statement[0], statement[1], statement[2], statement[3], @params)
|
85
|
+
else
|
86
|
+
value_to_hex(statement.subject.to_s, statement.predicate, statement.object, statement.graph_name, @params)
|
87
|
+
end
|
88
|
+
end.compact
|
89
|
+
end
|
90
|
+
|
91
|
+
def repository
|
92
|
+
return @repository if @repository.present?
|
93
|
+
|
94
|
+
@repository = ::RDF::Repository.new
|
95
|
+
parser = HndJSONParser.new
|
96
|
+
|
97
|
+
serializable_hextuples.compact.each do |hextuple|
|
98
|
+
@repository << parser.parse_hex(hextuple)
|
99
|
+
end
|
100
|
+
|
101
|
+
@repository
|
102
|
+
end
|
103
|
+
|
104
|
+
def render_hndjson
|
105
|
+
serializable_hextuples
|
106
|
+
.map { |s| Oj.fast_generate(s) }
|
107
|
+
.join("\n")
|
108
|
+
end
|
109
|
+
|
110
|
+
def render_repository(*args, options)
|
111
|
+
if include_named_graphs?(*args)
|
112
|
+
repository.dump(*args, options)
|
113
|
+
else
|
114
|
+
repository.project_graph(nil).dump(*args, options)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def serializable_hextuples
|
119
|
+
if is_collection?(@resource, @is_collection)
|
120
|
+
hextuples_for_collection + meta_hextuples
|
121
|
+
elsif !@resource
|
122
|
+
[]
|
123
|
+
else
|
124
|
+
hextuples_for_one_record + meta_hextuples
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class_methods do
|
129
|
+
def create_relationship(base_key, relationship_type, options, block)
|
130
|
+
association = options.delete(:association)
|
131
|
+
image = options.delete(:image)
|
132
|
+
predicate = options.delete(:predicate)
|
133
|
+
sequence = options.delete(:sequence)
|
134
|
+
relation = super
|
135
|
+
relation.association = association
|
136
|
+
relation.image = image
|
137
|
+
relation.predicate = predicate
|
138
|
+
relation.sequence = sequence
|
139
|
+
|
140
|
+
relation
|
141
|
+
end
|
142
|
+
|
143
|
+
# Checks for the `class_name` property on the Model's association to
|
144
|
+
# determine a serializer.
|
145
|
+
def association_serializer_for(name)
|
146
|
+
model_class_name = self.name.to_s.demodulize.classify.gsub(/Serializer$/, '')
|
147
|
+
model_class = model_class_name.safe_constantize
|
148
|
+
|
149
|
+
association_class_name = model_class.try(:reflect_on_association, name)&.class_name
|
150
|
+
|
151
|
+
return nil unless association_class_name
|
152
|
+
|
153
|
+
serializer_for(association_class_name)
|
154
|
+
end
|
155
|
+
|
156
|
+
def serializer_for(name)
|
157
|
+
associatopm_serializer = association_serializer_for(name)
|
158
|
+
return associatopm_serializer if associatopm_serializer
|
159
|
+
|
160
|
+
begin
|
161
|
+
RDF::Serializers.serializer_for(const_get(name.to_s.classify))
|
162
|
+
rescue NameError
|
163
|
+
raise NameError, "#{self.name} cannot resolve a serializer class for '#{name}'. " \
|
164
|
+
'Consider specifying the serializer directly through options[:serializer].'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
module Relationship
|
6
|
+
include HextupleSerializer
|
7
|
+
|
8
|
+
attr_accessor :predicate, :image, :association, :sequence
|
9
|
+
|
10
|
+
def serialize_hex(record, included, serialization_params)
|
11
|
+
return [] unless include_relationship?(record, serialization_params, included) && predicate.present?
|
12
|
+
|
13
|
+
iris = iris_from_record_and_relationship(record, serialization_params)
|
14
|
+
|
15
|
+
sequence ? relationship_sequence(record, iris, serialization_params) : relationship_statements(record, iris, serialization_params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def relationship_sequence(record, iris, serialization_params)
|
19
|
+
sequence = RDF::Node.new
|
20
|
+
|
21
|
+
[
|
22
|
+
value_to_hex(iri_from_record(record).to_s, predicate, sequence, nil, serialization_params),
|
23
|
+
value_to_hex(sequence, RDF.type, RDF.Seq, nil, serialization_params)
|
24
|
+
] + iris.map.with_index do |iri, index|
|
25
|
+
value_to_hex(sequence, RDF["_#{index}"], iri, nil, serialization_params)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def relationship_statements(record, iris, serialization_params)
|
30
|
+
iris.map do |related_iri|
|
31
|
+
value_to_hex(
|
32
|
+
iri_from_record(record).to_s,
|
33
|
+
predicate,
|
34
|
+
related_iri,
|
35
|
+
nil,
|
36
|
+
serialization_params
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def include_relationship?(record, serialization_params, included = false)
|
42
|
+
return false if lazy_load_data && !included
|
43
|
+
|
44
|
+
super(record, serialization_params)
|
45
|
+
end
|
46
|
+
|
47
|
+
def iris_from_record_and_relationship(record, params = {})
|
48
|
+
initialize_static_serializer unless @initialized_static_serializer
|
49
|
+
|
50
|
+
associated_object = fetch_associated_object(record, params)
|
51
|
+
return [] unless associated_object
|
52
|
+
|
53
|
+
if associated_object.respond_to? :map
|
54
|
+
return associated_object.compact.map do |object|
|
55
|
+
iri_from_record(object)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
[iri_from_record(associated_object)]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
FastJsonapi::Relationship.prepend(RDF::Serializers::Relationship)
|
@@ -16,18 +16,45 @@ module RDF
|
|
16
16
|
symbols = [symbols] unless symbols.respond_to?(:each)
|
17
17
|
symbols.each do |symbol|
|
18
18
|
format = RDF::Format.for(symbol)
|
19
|
-
raise "#{symbol}
|
19
|
+
raise "#{symbol} is not a known rdf format" if format.nil?
|
20
|
+
|
20
21
|
Mime::Type.register format.content_type.first, format.file_extension.first
|
21
|
-
add_renderer(format, opts)
|
22
|
+
add_renderer(format.file_extension.first, format.content_type.first, format.symbols.first, opts)
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
|
-
def self.add_renderer(
|
26
|
-
ActionController::Renderers.add
|
27
|
-
self.content_type =
|
28
|
-
|
26
|
+
def self.add_renderer(ext, content_type, symbol, opts = {})
|
27
|
+
ActionController::Renderers.add ext do |resource, options|
|
28
|
+
self.content_type = content_type
|
29
|
+
serializer_opts = RDF::Serializers::Renderers.transform_opts(
|
30
|
+
options,
|
31
|
+
respond_to?(:serializer_params, true) ? serializer_params : {}
|
32
|
+
)
|
33
|
+
RDF::Serializers.serializer_for(resource)&.new(resource, serializer_opts)&.dump(symbol, opts)
|
29
34
|
end
|
30
35
|
end
|
36
|
+
|
37
|
+
def self.transform_include(include, root = nil)
|
38
|
+
return root if include.blank?
|
39
|
+
return [root, include].compact.join('.') if include.is_a?(Symbol) || include.is_a?(String)
|
40
|
+
|
41
|
+
if include.is_a?(Hash)
|
42
|
+
include.flat_map do |k, v|
|
43
|
+
transform_include(v, [root, k].compact.join('.'))
|
44
|
+
end
|
45
|
+
elsif include.is_a?(Array)
|
46
|
+
include.flat_map do |v|
|
47
|
+
transform_include(v, root)
|
48
|
+
end
|
49
|
+
end.compact
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.transform_opts(options, params)
|
53
|
+
(options || {}).merge(
|
54
|
+
include: transform_include(options[:include]),
|
55
|
+
params: params
|
56
|
+
)
|
57
|
+
end
|
31
58
|
end
|
32
59
|
end
|
33
60
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
module Scalar
|
6
|
+
include HextupleSerializer
|
7
|
+
|
8
|
+
attr_accessor :predicate, :image, :datatype
|
9
|
+
|
10
|
+
def initialize(key:, method:, options: {})
|
11
|
+
super
|
12
|
+
@predicate = options[:predicate]
|
13
|
+
@image = options[:image]
|
14
|
+
@datatype = options[:datatype]
|
15
|
+
end
|
16
|
+
|
17
|
+
def serialize_hex(record, serialization_params)
|
18
|
+
return [] unless conditionally_allowed?(record, serialization_params) && predicate.present?
|
19
|
+
|
20
|
+
value = value_from_record(record, method, serialization_params)
|
21
|
+
|
22
|
+
return [] if value.nil?
|
23
|
+
|
24
|
+
if value.is_a?(Array)
|
25
|
+
value.map { |arr_item| value_to_hex(iri_from_record(record).to_s, predicate, arr_item, nil, serialization_params) }
|
26
|
+
elsif value.is_a?(::RDF::List)
|
27
|
+
first = value.statements.first&.subject || RDF.nil
|
28
|
+
value.statements.map do |statement|
|
29
|
+
value_to_hex(statement.subject.to_s, statement.predicate, statement.object, statement.graph_name, serialization_params)
|
30
|
+
end + [
|
31
|
+
value_to_hex(iri_from_record(record).to_s, predicate, first, nil, serialization_params)
|
32
|
+
]
|
33
|
+
else
|
34
|
+
[value_to_hex(iri_from_record(record).to_s, predicate, value, nil, serialization_params)]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def value_from_record(record, method, serialization_params)
|
39
|
+
if method.is_a?(Proc)
|
40
|
+
FastJsonapi.call_proc(method, record, serialization_params)
|
41
|
+
else
|
42
|
+
v = record.public_send(method)
|
43
|
+
v.is_a?('ActiveRecord'.safe_constantize&.const_get('Relation') || NilClass) ? v.to_a : v
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
FastJsonapi::Scalar.prepend(RDF::Serializers::Scalar)
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
module SerializationCore
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include HextupleSerializer
|
10
|
+
extend HextupleSerializer
|
11
|
+
end
|
12
|
+
|
13
|
+
class_methods do
|
14
|
+
def relationships_hextuples(record, relationships = nil, fieldset = nil, includes_list = [], params = {})
|
15
|
+
relationships = relationships_to_serialize if relationships.nil?
|
16
|
+
relationships = relationships.slice(*fieldset) if fieldset.present?
|
17
|
+
relationships = [] if fieldset == []
|
18
|
+
|
19
|
+
statements = []
|
20
|
+
relationships.each do |key, relationship|
|
21
|
+
included = includes_list.present? && includes_list.include?(key)
|
22
|
+
statements.concat relationship.serialize_hex(record, included, params)
|
23
|
+
end
|
24
|
+
|
25
|
+
statements
|
26
|
+
end
|
27
|
+
|
28
|
+
def attributes_hextuples(record, fieldset = nil, params = {})
|
29
|
+
attributes = attributes_to_serialize
|
30
|
+
attributes = attributes.slice(*fieldset) if fieldset.present?
|
31
|
+
attributes = {} if fieldset == []
|
32
|
+
|
33
|
+
statements = attributes.flat_map do |_k, attr|
|
34
|
+
attr.serialize_hex(record, params)
|
35
|
+
end
|
36
|
+
|
37
|
+
statements.compact
|
38
|
+
end
|
39
|
+
|
40
|
+
def statements_hextuples(record, params = {})
|
41
|
+
statements = []
|
42
|
+
|
43
|
+
_statements&.map do |key|
|
44
|
+
send(key, record, params).each do |statement|
|
45
|
+
statements << if statement.is_a?(Array)
|
46
|
+
value_to_hex(statement[0], statement[1], statement[2], statement[3], params)
|
47
|
+
else
|
48
|
+
value_to_hex(statement.subject.to_s, statement.predicate, statement.object, statement.graph_name, params)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
statements.compact
|
54
|
+
end
|
55
|
+
|
56
|
+
def record_hextuples(record, fieldset, includes_list, params = {})
|
57
|
+
if cache_store_instance
|
58
|
+
record_hex = Rails.cache.fetch(record.cache_key, expires_in: cache_length, race_condition_ttl: race_condition_ttl) do
|
59
|
+
temp_hex = []
|
60
|
+
temp_hex.concat attributes_hextuples(record, fieldset, params) if attributes_to_serialize.present?
|
61
|
+
temp_hex.concat statements_hextuples(record, params)
|
62
|
+
if cachable_relationships_to_serialize.present?
|
63
|
+
temp_hex.concat relationships_hextuples(record, cachable_relationships_to_serialize, fieldset, includes_list, params)
|
64
|
+
end
|
65
|
+
temp_hex
|
66
|
+
end
|
67
|
+
if uncachable_relationships_to_serialize.present?
|
68
|
+
record_hex.concat relationships_hextuples(record, uncachable_relationships_to_serialize, fieldset, includes_list, params)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
record_hex = []
|
72
|
+
record_hex.concat attributes_hextuples(record, fieldset, params) if attributes_to_serialize.present?
|
73
|
+
record_hex.concat statements_hextuples(record, params)
|
74
|
+
if relationships_to_serialize.present?
|
75
|
+
record_hex.concat relationships_hextuples(record, nil, fieldset, includes_list, params)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
record_hex
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_included_records_hex(record, includes_list, known_included_objects, fieldsets, params = {})
|
82
|
+
return unless includes_list.present?
|
83
|
+
|
84
|
+
includes_list.sort.each_with_object([]) do |include_item, included_records|
|
85
|
+
items = parse_include_item(include_item)
|
86
|
+
remaining_items = remaining_items(items)
|
87
|
+
|
88
|
+
items.each do |item|
|
89
|
+
next unless relationships_to_serialize && relationships_to_serialize[item]
|
90
|
+
|
91
|
+
relationship_item = relationships_to_serialize[item]
|
92
|
+
next unless relationship_item.include_relationship?(record, params)
|
93
|
+
|
94
|
+
relationship_type = relationship_item.relationship_type
|
95
|
+
|
96
|
+
included_objects = relationship_item.fetch_associated_object(record, params)
|
97
|
+
next if included_objects.blank?
|
98
|
+
|
99
|
+
included_objects = [included_objects] unless relationship_type == :has_many
|
100
|
+
|
101
|
+
static_serializer = relationship_item.static_serializer
|
102
|
+
static_record_type = relationship_item.static_record_type
|
103
|
+
|
104
|
+
included_objects.each do |inc_obj|
|
105
|
+
serializer = static_serializer || relationship_item.serializer_for(inc_obj, params)
|
106
|
+
record_type = static_record_type || serializer.record_type
|
107
|
+
|
108
|
+
if remaining_items.present?
|
109
|
+
serializer_records =
|
110
|
+
serializer
|
111
|
+
.get_included_records_hex(inc_obj, remaining_items, known_included_objects, fieldsets, params)
|
112
|
+
included_records.concat(serializer_records) unless serializer_records.empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
code = "#{record_type}_#{serializer.iri_from_record(inc_obj)}"
|
116
|
+
next if known_included_objects.key?(code)
|
117
|
+
|
118
|
+
known_included_objects[code] = inc_obj
|
119
|
+
|
120
|
+
included_records.concat(
|
121
|
+
serializer.record_hextuples(inc_obj, fieldsets[record_type], includes_list, params)
|
122
|
+
)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
module Serializers
|
5
|
+
module Statements
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :_statements
|
10
|
+
self._statements ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def inherited(base)
|
15
|
+
super
|
16
|
+
base._statements = _statements.dup
|
17
|
+
end
|
18
|
+
|
19
|
+
def statements(attribute)
|
20
|
+
self._statements << attribute
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
FastJsonapi::ObjectSerializer.include(RDF::Serializers::Statements)
|
data/lib/rdf/serializers.rb
CHANGED
@@ -1,4 +1,88 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
3
|
+
require 'fast_jsonapi'
|
4
|
+
|
5
|
+
require 'rdf/serializers/lookup_chain'
|
6
|
+
require 'rdf/serializers/config'
|
7
|
+
require 'rdf/serializers/statements'
|
8
|
+
require 'rdf/serializers/hextuple_serializer'
|
9
|
+
require 'rdf/serializers/data_type_helper'
|
10
|
+
require 'rdf/serializers/hdnjson_parser'
|
11
|
+
require 'rdf/serializers/serialization_core'
|
12
|
+
require 'rdf/serializers/object_serializer'
|
13
|
+
require 'rdf/serializers/scalar'
|
14
|
+
require 'rdf/serializers/relationship'
|
15
|
+
require 'rdf/serializers/nil_serializer'
|
16
|
+
require 'rdf/serializers/list_serializer'
|
17
|
+
|
18
|
+
module RDF
|
19
|
+
module Serializers
|
20
|
+
class << self
|
21
|
+
# Extracted from active_model_serializers
|
22
|
+
# @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
|
23
|
+
# @return [ActiveModel::Serializer]
|
24
|
+
# Preferentially returns
|
25
|
+
# 1. resource.serializer_class
|
26
|
+
# 2. ArraySerializer when resource is a collection
|
27
|
+
# 3. options[:serializer]
|
28
|
+
# 4. lookup serializer when resource is a Class
|
29
|
+
def serializer_for(resource_or_class, options = {})
|
30
|
+
if resource_or_class.respond_to?(:serializer_class)
|
31
|
+
resource_or_class.serializer_class
|
32
|
+
elsif resource_or_class.respond_to?(:to_ary)
|
33
|
+
unless resource_or_class.all? { |resource| resource.is_a?(resource_or_class.first.class) }
|
34
|
+
return ListSerializer
|
35
|
+
end
|
36
|
+
|
37
|
+
serializer_for(resource_or_class.first)
|
38
|
+
else
|
39
|
+
resource_class = resource_or_class.class == Class ? resource_or_class : resource_or_class.class
|
40
|
+
options.fetch(:serializer) { get_serializer_for(resource_class, options[:namespace]) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Extracted from active_model_serializers
|
47
|
+
# Find a serializer from a class and caches the lookup.
|
48
|
+
# Preferentially returns:
|
49
|
+
# 1. class name appended with "Serializer"
|
50
|
+
# 2. try again with superclass, if present
|
51
|
+
# 3. nil
|
52
|
+
def get_serializer_for(klass, namespace = nil)
|
53
|
+
return nil unless config.serializer_lookup_enabled
|
54
|
+
|
55
|
+
return NilSerializer if klass == NilClass
|
56
|
+
|
57
|
+
cache_key = ActiveSupport::Cache.expand_cache_key(klass, namespace)
|
58
|
+
serializers_cache.fetch_or_store(cache_key) do
|
59
|
+
# NOTE(beauby): When we drop 1.9.3 support we can lazify the map for perfs.
|
60
|
+
lookup_chain = serializer_lookup_chain_for(klass, namespace)
|
61
|
+
serializer_class = lookup_chain.map(&:safe_constantize).find do |x|
|
62
|
+
x&.include?(FastJsonapi::SerializationCore)
|
63
|
+
end
|
64
|
+
|
65
|
+
if serializer_class
|
66
|
+
serializer_class
|
67
|
+
elsif klass.superclass
|
68
|
+
get_serializer_for(klass.superclass, namespace)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Extracted from active_model_serializers
|
74
|
+
# Used to cache serializer name => serializer class
|
75
|
+
# when looked up by Serializer.get_serializer_for.
|
76
|
+
def serializers_cache
|
77
|
+
@serializers_cache ||= Concurrent::Map.new
|
78
|
+
end
|
79
|
+
|
80
|
+
def serializer_lookup_chain_for(klass, namespace = nil)
|
81
|
+
lookups = config.serializer_lookup_chain
|
82
|
+
Array[*lookups].flat_map do |lookup|
|
83
|
+
lookup.call(klass, namespace)
|
84
|
+
end.compact
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
metadata
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdf-serializers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arthur Dingemans
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: jsonapi-serializer
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: oj
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: railties
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -33,7 +47,7 @@ dependencies:
|
|
33
47
|
version: 4.2.0
|
34
48
|
- - "<"
|
35
49
|
- !ruby/object:Gem::Version
|
36
|
-
version: '
|
50
|
+
version: '7'
|
37
51
|
type: :runtime
|
38
52
|
prerelease: false
|
39
53
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -43,7 +57,7 @@ dependencies:
|
|
43
57
|
version: 4.2.0
|
44
58
|
- - "<"
|
45
59
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
60
|
+
version: '7'
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: rdf
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,22 +72,32 @@ dependencies:
|
|
58
72
|
- - "~>"
|
59
73
|
- !ruby/object:Gem::Version
|
60
74
|
version: '3.0'
|
61
|
-
description:
|
75
|
+
description:
|
62
76
|
email: arthur@argu.co
|
63
77
|
executables: []
|
64
78
|
extensions: []
|
65
79
|
extra_rdoc_files: []
|
66
80
|
files:
|
67
|
-
- lib/active_model_serializers/adapter/rdf.rb
|
68
|
-
- lib/active_model_serializers/adapter/rdf/relationship.rb
|
69
|
-
- lib/active_model_serializers/serializer.rb
|
70
81
|
- lib/rdf/serializers.rb
|
82
|
+
- lib/rdf/serializers/config.rb
|
83
|
+
- lib/rdf/serializers/data_type_helper.rb
|
84
|
+
- lib/rdf/serializers/hdnjson_parser.rb
|
85
|
+
- lib/rdf/serializers/hextuple_serializer.rb
|
86
|
+
- lib/rdf/serializers/list_serializer.rb
|
87
|
+
- lib/rdf/serializers/lookup_chain.rb
|
88
|
+
- lib/rdf/serializers/nil_serializer.rb
|
89
|
+
- lib/rdf/serializers/object_serializer.rb
|
90
|
+
- lib/rdf/serializers/relationship.rb
|
71
91
|
- lib/rdf/serializers/renderers.rb
|
92
|
+
- lib/rdf/serializers/scalar.rb
|
93
|
+
- lib/rdf/serializers/serialization_core.rb
|
94
|
+
- lib/rdf/serializers/statements.rb
|
72
95
|
- lib/rdf/serializers/version.rb
|
73
|
-
homepage: https://github.com/
|
74
|
-
licenses:
|
96
|
+
homepage: https://github.com/ontola/rdf-serializers
|
97
|
+
licenses:
|
98
|
+
- MIT
|
75
99
|
metadata: {}
|
76
|
-
post_install_message:
|
100
|
+
post_install_message:
|
77
101
|
rdoc_options: []
|
78
102
|
require_paths:
|
79
103
|
- lib
|
@@ -88,9 +112,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
112
|
- !ruby/object:Gem::Version
|
89
113
|
version: '0'
|
90
114
|
requirements: []
|
91
|
-
|
92
|
-
|
93
|
-
signing_key:
|
115
|
+
rubygems_version: 3.1.2
|
116
|
+
signing_key:
|
94
117
|
specification_version: 4
|
95
118
|
summary: Adds RDF serialization, like n-triples or turtle, to active model serializers
|
96
119
|
test_files: []
|
@@ -1,60 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveModelSerializers
|
4
|
-
module Adapter
|
5
|
-
class RDF
|
6
|
-
class Relationship < JsonApi::Relationship
|
7
|
-
def triples
|
8
|
-
return [] if subject.blank? || predicate.blank? || data.empty?
|
9
|
-
data.map do |object|
|
10
|
-
raise "#{object} is not a RDF::Resource but a #{object.class}" unless object.is_a?(::RDF::Resource)
|
11
|
-
::RDF::Statement.new(subject, predicate, object)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def data
|
18
|
-
@data ||=
|
19
|
-
if association.collection?
|
20
|
-
objects_for_many(association).compact
|
21
|
-
else
|
22
|
-
[object_for_one(association)].compact
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def objects_for_many(association)
|
27
|
-
collection_serializer = association.lazy_association.serializer
|
28
|
-
if collection_serializer.respond_to?(:each)
|
29
|
-
collection_serializer.map do |serializer|
|
30
|
-
serializer.read_attribute_for_serialization(:rdf_subject)
|
31
|
-
end
|
32
|
-
else
|
33
|
-
[]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def object_for_one(association)
|
38
|
-
if belongs_to_id_on_self?(association)
|
39
|
-
parent_serializer.read_attribute_for_serialization(:rdf_subject)
|
40
|
-
else
|
41
|
-
serializer = association.lazy_association.serializer
|
42
|
-
if (virtual_value = association.virtual_value)
|
43
|
-
virtual_value[:id]
|
44
|
-
elsif serializer && association.object
|
45
|
-
serializer.read_attribute_for_serialization(:rdf_subject)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def predicate
|
51
|
-
@predicate ||= association.reflection.options[:predicate]
|
52
|
-
end
|
53
|
-
|
54
|
-
def subject
|
55
|
-
@subject ||= parent_serializer.read_attribute_for_serialization(:rdf_subject)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveModelSerializers
|
4
|
-
module Adapter
|
5
|
-
class RDF < Base
|
6
|
-
extend ActiveSupport::Autoload
|
7
|
-
autoload :Relationship
|
8
|
-
|
9
|
-
delegate :object, to: :serializer
|
10
|
-
delegate :dump, :triples, to: :graph
|
11
|
-
|
12
|
-
def initialize(serializer, options = {})
|
13
|
-
super
|
14
|
-
@include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
|
15
|
-
@fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
|
16
|
-
@resource_identifiers = Set.new
|
17
|
-
end
|
18
|
-
|
19
|
-
protected
|
20
|
-
|
21
|
-
attr_reader :fieldset
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def add_attribute(subject, predicate, value)
|
26
|
-
return unless predicate
|
27
|
-
value = value.respond_to?(:each) ? value : [value]
|
28
|
-
value.compact.map { |v| add_triple(subject, predicate, v) }
|
29
|
-
end
|
30
|
-
|
31
|
-
def add_triple(subject, predicate, object)
|
32
|
-
obj =
|
33
|
-
case object
|
34
|
-
when ::RDF::Term
|
35
|
-
object
|
36
|
-
when ActiveSupport::TimeWithZone
|
37
|
-
::RDF::Literal(object.to_datetime)
|
38
|
-
else
|
39
|
-
::RDF::Literal(object)
|
40
|
-
end
|
41
|
-
@graph << ::RDF::Statement.new(subject, ::RDF::URI(predicate), obj)
|
42
|
-
end
|
43
|
-
|
44
|
-
def attributes_for(serializer, fields)
|
45
|
-
serializer.attributes(fields).each do |key, value|
|
46
|
-
add_attribute(
|
47
|
-
serializer.read_attribute_for_serialization(:rdf_subject),
|
48
|
-
serializer.class._attributes_data[key].try(:options).try(:[], :predicate),
|
49
|
-
value
|
50
|
-
)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def custom_triples_for(serializer)
|
55
|
-
serializer.class.try(:_triples)&.map do |key|
|
56
|
-
serializer.read_attribute_for_serialization(key).each do |triple|
|
57
|
-
@graph << triple
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def graph
|
63
|
-
return @graph if @graph.present?
|
64
|
-
@graph = ::RDF::Graph.new
|
65
|
-
|
66
|
-
serializers.each { |serializer| process_resource(serializer, @include_directive) }
|
67
|
-
serializers.each { |serializer| process_relationships(serializer, @include_directive) }
|
68
|
-
instance_options[:meta]&.each { |meta| add_triple(*meta) }
|
69
|
-
|
70
|
-
@graph
|
71
|
-
end
|
72
|
-
|
73
|
-
def process_relationship(serializer, include_slice)
|
74
|
-
return serializer.each { |s| process_relationship(s, include_slice) } if serializer.respond_to?(:each)
|
75
|
-
return unless serializer&.object && process_resource(serializer, include_slice)
|
76
|
-
process_relationships(serializer, include_slice)
|
77
|
-
end
|
78
|
-
|
79
|
-
def process_relationships(serializer, include_slice)
|
80
|
-
return unless serializer.respond_to?(:associations)
|
81
|
-
serializer.associations(include_slice).each do |association|
|
82
|
-
process_relationship(association.lazy_association.serializer, include_slice[association.key])
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def process_resource(serializer, include_slice = {})
|
87
|
-
if serializer.is_a?(ActiveModel::Serializer::CollectionSerializer)
|
88
|
-
return serializer.map { |child| process_resource(child, include_slice) }
|
89
|
-
end
|
90
|
-
return unless serializer.respond_to?(:rdf_subject) || serializer.object.respond_to?(:rdf_subject)
|
91
|
-
return false unless @resource_identifiers.add?(serializer.read_attribute_for_serialization(:rdf_subject))
|
92
|
-
resource_object_for(serializer, include_slice)
|
93
|
-
true
|
94
|
-
end
|
95
|
-
|
96
|
-
def relationships_for(serializer, requested_associations, include_slice)
|
97
|
-
include_directive = JSONAPI::IncludeDirective.new(requested_associations, allow_wildcard: true)
|
98
|
-
serializer.associations(include_directive, include_slice).each do |association|
|
99
|
-
Relationship.new(serializer, instance_options, association).triples.each do |triple|
|
100
|
-
@graph << triple
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def resource_object_for(serializer, include_slice = {})
|
106
|
-
type = type_for(serializer, instance_options).to_s
|
107
|
-
serializer.fetch(self) do
|
108
|
-
break nil if serializer.read_attribute_for_serialization(:rdf_subject).nil?
|
109
|
-
requested_fields = fieldset&.fields_for(type)
|
110
|
-
attributes_for(serializer, requested_fields)
|
111
|
-
custom_triples_for(serializer)
|
112
|
-
end
|
113
|
-
requested_associations = fieldset.fields_for(type) || '*'
|
114
|
-
relationships_for(serializer, requested_associations, include_slice)
|
115
|
-
end
|
116
|
-
|
117
|
-
def serializers
|
118
|
-
serializer.respond_to?(:each) ? serializer : [serializer]
|
119
|
-
end
|
120
|
-
|
121
|
-
def type_for(serializer, instance_options)
|
122
|
-
JsonApi::ResourceIdentifier.new(serializer, instance_options).as_json[:type]
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|