ladder 0.0.3 → 0.0.4
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/.gitignore +14 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +202 -22
- data/README.md +315 -6
- data/Rakefile +2 -0
- data/ladder.gemspec +33 -0
- data/lib/ladder/resource.rb +80 -0
- data/lib/ladder/searchable.rb +53 -0
- data/lib/ladder/version.rb +3 -0
- data/lib/ladder.rb +6 -0
- data/mongoid.yml +6 -0
- data/spec/ladder/resource_spec.rb +305 -0
- data/spec/ladder/searchable_spec.rb +179 -0
- data/spec/spec_helper.rb +15 -0
- metadata +80 -6
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
require 'active_triples'
|
3
|
+
require 'json/ld'
|
4
|
+
|
5
|
+
module Ladder::Resource
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
include Mongoid::Document
|
9
|
+
include ActiveTriples::Identifiable
|
10
|
+
|
11
|
+
included do
|
12
|
+
configure base_uri: RDF::URI.new(LADDER_BASE_URI) / name.underscore.pluralize if defined? LADDER_BASE_URI
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Convenience method to return JSON-LD representation
|
17
|
+
#
|
18
|
+
def as_jsonld(opts = {})
|
19
|
+
update_resource(opts.slice :related).dump(:jsonld, {standard_prefixes: true}.merge(opts))
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Overload ActiveTriples #update_resource
|
24
|
+
#
|
25
|
+
# @see ActiveTriples::Identifiable
|
26
|
+
def update_resource(opts = {})
|
27
|
+
relation_hash = opts[:related] ? relations : embedded_relations
|
28
|
+
|
29
|
+
super() do |name, prop|
|
30
|
+
object = self.send(prop.term)
|
31
|
+
next if object.nil?
|
32
|
+
|
33
|
+
objects = object.is_a?(Enumerable) ? object : [object]
|
34
|
+
|
35
|
+
values = objects.map do |obj|
|
36
|
+
if obj.is_a?(ActiveTriples::Identifiable)
|
37
|
+
if relation_hash.keys.include? name
|
38
|
+
obj.update_resource
|
39
|
+
obj.resource.set_value(relation_hash[name].inverse, self.rdf_subject) if relation_hash[name].inverse
|
40
|
+
obj
|
41
|
+
else
|
42
|
+
resource.delete [obj.rdf_subject] if resource.enum_subjects.include? obj.rdf_subject and ! opts[:related]
|
43
|
+
obj.rdf_subject
|
44
|
+
end
|
45
|
+
else
|
46
|
+
if fields[name].localized?
|
47
|
+
read_attribute(name).map { |lang, val| RDF::Literal.new(val, language: lang) }
|
48
|
+
else
|
49
|
+
obj
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
resource.set_value(prop.predicate, values.flatten)
|
55
|
+
end
|
56
|
+
|
57
|
+
resource
|
58
|
+
end
|
59
|
+
|
60
|
+
module ClassMethods
|
61
|
+
|
62
|
+
##
|
63
|
+
# Overload ActiveTriples #property
|
64
|
+
#
|
65
|
+
# @see ActiveTriples::Properties
|
66
|
+
def property(name, opts={})
|
67
|
+
if class_name = opts[:class_name]
|
68
|
+
mongoid_opts = opts.except(:predicate, :multivalue).merge(autosave: true)
|
69
|
+
opts.except! *mongoid_opts.keys
|
70
|
+
|
71
|
+
has_and_belongs_to_many(name, mongoid_opts) unless relations.keys.include? name.to_s
|
72
|
+
else
|
73
|
+
field(name, localize: true)
|
74
|
+
end
|
75
|
+
|
76
|
+
super
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'ladder/resource'
|
2
|
+
require 'elasticsearch/model'
|
3
|
+
require 'elasticsearch/model/callbacks'
|
4
|
+
|
5
|
+
module Ladder::Searchable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include Elasticsearch::Model
|
10
|
+
include Elasticsearch::Model::Callbacks
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Generate a qname-based JSON representation
|
15
|
+
#
|
16
|
+
def as_qname
|
17
|
+
qname_hash = type.empty? ? {} : {rdf: {type: type.first.pname }}
|
18
|
+
|
19
|
+
resource_class.properties.each do |field_name, property|
|
20
|
+
ns, name = property.predicate.qname
|
21
|
+
qname_hash[ns] ||= Hash.new
|
22
|
+
|
23
|
+
object = self.send(field_name)
|
24
|
+
|
25
|
+
if relations.keys.include? field_name
|
26
|
+
qname_hash[ns][name] = object.to_a.map { |obj| "#{obj.class.name.underscore.pluralize}:#{obj.id}" }
|
27
|
+
elsif fields.keys.include? field_name
|
28
|
+
qname_hash[ns][name] = read_attribute(field_name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
qname_hash
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
|
37
|
+
##
|
38
|
+
# Specify type of serialization to use for indexing
|
39
|
+
#
|
40
|
+
def index(opts={})
|
41
|
+
case opts[:as]
|
42
|
+
when :jsonld
|
43
|
+
define_method(:as_indexed_json) { |opts = {}| as_jsonld }
|
44
|
+
when :qname
|
45
|
+
define_method(:as_indexed_json) { |opts = {}| as_qname }
|
46
|
+
else
|
47
|
+
define_method(:as_indexed_json) { |opts = {}| as_json(except: ['id', '_id']) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/lib/ladder.rb
ADDED
data/mongoid.yml
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
describe Ladder::Resource do
|
5
|
+
before do
|
6
|
+
Mongoid.load!('mongoid.yml', :development)
|
7
|
+
Mongoid.logger.level = Moped.logger.level = Logger::DEBUG
|
8
|
+
Mongoid.purge!
|
9
|
+
|
10
|
+
LADDER_BASE_URI = 'http://example.org'
|
11
|
+
|
12
|
+
class Thing
|
13
|
+
include Ladder::Resource
|
14
|
+
end
|
15
|
+
|
16
|
+
class Person
|
17
|
+
include Ladder::Resource
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
after do
|
22
|
+
Object.send(:remove_const, :LADDER_BASE_URI) if Object
|
23
|
+
Object.send(:remove_const, "Thing") if Object
|
24
|
+
Object.send(:remove_const, "Person") if Object
|
25
|
+
end
|
26
|
+
|
27
|
+
subject { Thing.new }
|
28
|
+
let(:person) { Person.new }
|
29
|
+
|
30
|
+
shared_context 'with data' do
|
31
|
+
let(:concept) { Concept.new }
|
32
|
+
let(:part) { Part.new }
|
33
|
+
|
34
|
+
before do
|
35
|
+
class Concept
|
36
|
+
include Ladder::Resource
|
37
|
+
end
|
38
|
+
|
39
|
+
class Part
|
40
|
+
include Ladder::Resource
|
41
|
+
embedded_in :thing
|
42
|
+
property :thing, :predicate => RDF::DC.relation, :class_name => 'Thing'
|
43
|
+
end
|
44
|
+
|
45
|
+
# localized literal
|
46
|
+
subject.class.property :title, :predicate => RDF::DC.title
|
47
|
+
subject.title = 'Comet in Moominland'
|
48
|
+
|
49
|
+
# many-to-many
|
50
|
+
person.class.property :things, :predicate => RDF::DC.relation, :class_name => 'Thing'
|
51
|
+
subject.class.property :people, :predicate => RDF::DC.creator, :class_name => 'Person'
|
52
|
+
subject.people << person
|
53
|
+
|
54
|
+
# one-sided has-many
|
55
|
+
subject.class.has_and_belongs_to_many :concepts, inverse_of: nil
|
56
|
+
subject.class.property :concepts, :predicate => RDF::DC.subject, :class_name => 'Concept'
|
57
|
+
subject.concepts << concept
|
58
|
+
|
59
|
+
# embedded many
|
60
|
+
subject.class.embeds_many :parts, cascade_callbacks: true
|
61
|
+
subject.class.property :parts, :predicate => RDF::DC.hasPart, :class_name => 'Part'
|
62
|
+
subject.parts << part
|
63
|
+
subject.save
|
64
|
+
end
|
65
|
+
|
66
|
+
after do
|
67
|
+
Object.send(:remove_const, 'Concept')
|
68
|
+
Object.send(:remove_const, 'Part')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should have relations' do
|
72
|
+
expect(subject.title).to eq 'Comet in Moominland'
|
73
|
+
expect(subject.people.to_a).to include person
|
74
|
+
expect(subject.concepts.to_a).to include concept
|
75
|
+
expect(subject.parts.to_a).to include part
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should have reverse relations' do
|
79
|
+
expect(person.things.to_a).to include subject
|
80
|
+
expect(concept.relations).to be_empty
|
81
|
+
expect(part.thing).to eq subject
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'LADDER_BASE_URI' do
|
86
|
+
it 'should automatically have a base URI' do
|
87
|
+
expect(subject.rdf_subject.parent).to eq RDF::URI('http://example.org/things/')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#property' do
|
92
|
+
context 'with localized literal' do
|
93
|
+
before do
|
94
|
+
subject.class.property :title, :predicate => RDF::DC.title
|
95
|
+
subject.title = 'Comet in Moominland'
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should return localized value' do
|
99
|
+
expect(subject.title).to eq 'Comet in Moominland'
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should return all locales' do
|
103
|
+
expect(subject.attributes['title']).to eq Hash({'en' => 'Comet in Moominland'})
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should have a valid predicate' do
|
107
|
+
expect(subject.class.properties).to include 'title'
|
108
|
+
expect(t = subject.class.properties['title']).to be_a ActiveTriples::NodeConfig
|
109
|
+
expect(t.predicate).to eq RDF::DC.title
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'with many-to-many' do
|
114
|
+
before do
|
115
|
+
subject.class.property :people, :predicate => RDF::DC.creator, :class_name => 'Person'
|
116
|
+
person.class.property :things, :predicate => RDF::DC.relation, :class_name => 'Thing'
|
117
|
+
subject.people << person
|
118
|
+
subject.save
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should have a relation' do
|
122
|
+
expect(subject.relations).to include 'people'
|
123
|
+
expect(subject.relations['people'].relation).to eq (Mongoid::Relations::Referenced::ManyToMany)
|
124
|
+
expect(subject.people.to_a).to include person
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should have an inverse relation' do
|
128
|
+
expect(person.relations).to include 'things'
|
129
|
+
expect(person.relations['things'].relation).to eq (Mongoid::Relations::Referenced::ManyToMany)
|
130
|
+
expect(person.things.to_a).to include subject
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should have a valid predicate' do
|
134
|
+
expect(subject.class.properties).to include 'people'
|
135
|
+
expect(t = subject.class.properties['people']).to be_a ActiveTriples::NodeConfig
|
136
|
+
expect(t.predicate).to eq RDF::DC.creator
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should have a valid inverse predicate' do
|
140
|
+
expect(person.class.properties).to include 'things'
|
141
|
+
expect(t = person.class.properties['things']).to be_a ActiveTriples::NodeConfig
|
142
|
+
expect(t.predicate).to eq RDF::DC.relation
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'with one-sided has-many' do
|
147
|
+
before do
|
148
|
+
subject.class.has_and_belongs_to_many :people, inverse_of: nil
|
149
|
+
subject.class.property :people, :predicate => RDF::DC.creator, :class_name => 'Person'
|
150
|
+
subject.people << person
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should have a relation' do
|
154
|
+
expect(subject.relations).to include 'people'
|
155
|
+
expect(subject.relations['people'].relation).to eq (Mongoid::Relations::Referenced::ManyToMany)
|
156
|
+
expect(subject.people.to_a).to include person
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should not have an inverse relation' do
|
160
|
+
expect(subject.relations['people'].inverse_of).to be nil
|
161
|
+
expect(person.relations).to be_empty
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should have a valid predicate' do
|
165
|
+
expect(subject.class.properties).to include 'people'
|
166
|
+
expect(t = subject.class.properties['people']).to be_a ActiveTriples::NodeConfig
|
167
|
+
expect(t.predicate).to eq RDF::DC.creator
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should not have an inverse predicate' do
|
171
|
+
expect(person.class.properties).to be_empty
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'with embeds-many' do
|
176
|
+
before do
|
177
|
+
subject.class.embeds_many :people
|
178
|
+
subject.class.property :people, :predicate => RDF::DC.creator, :class_name => 'Person'
|
179
|
+
|
180
|
+
person.class.embedded_in :thing
|
181
|
+
person.class.property :thing, :predicate => RDF::DC.relation, :class_name => 'Thing'
|
182
|
+
|
183
|
+
subject.people << person
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should have a relation' do
|
187
|
+
expect(subject.relations).to include 'people'
|
188
|
+
expect(subject.relations['people'].relation).to eq (Mongoid::Relations::Embedded::Many)
|
189
|
+
expect(subject.people.to_a).to include person
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should have an inverse relation' do
|
193
|
+
expect(person.relations).to include 'thing'
|
194
|
+
expect(person.relations['thing'].relation).to eq (Mongoid::Relations::Embedded::In)
|
195
|
+
expect(person.thing).to eq subject
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should have a valid predicate' do
|
199
|
+
expect(subject.class.properties).to include 'people'
|
200
|
+
expect(t = subject.class.properties['people']).to be_a ActiveTriples::NodeConfig
|
201
|
+
expect(t.predicate).to eq RDF::DC.creator
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should have a valid inverse predicate' do
|
205
|
+
expect(person.class.properties).to include 'thing'
|
206
|
+
expect(t = person.class.properties['thing']).to be_a ActiveTriples::NodeConfig
|
207
|
+
expect(t.predicate).to eq RDF::DC.relation
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#update_resource' do
|
213
|
+
|
214
|
+
context 'without related: true' do
|
215
|
+
include_context 'with data'
|
216
|
+
|
217
|
+
before do
|
218
|
+
subject.update_resource
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should have a literal object' do
|
222
|
+
subject.resource.query(:subject => subject.rdf_subject, :predicate => RDF::DC.title).each_statement do |s|
|
223
|
+
expect(s.object.to_s).to eq 'Comet in Moominland'
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'should have an embedded object' do
|
228
|
+
subject.resource.query(:subject => part.rdf_subject, :predicate => RDF::DC.relation).each_statement do |s|
|
229
|
+
expect(s.object).to eq subject.rdf_subject
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'should have an embedded object relation' do
|
234
|
+
subject.resource.query(:subject => subject.rdf_subject, :predicate => RDF::DC.hasPart).each_statement do |s|
|
235
|
+
expect(s.object).to eq part.rdf_subject
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'should not have related objects' do
|
240
|
+
expect(subject.resource.query(:subject => person.rdf_subject)).to be_empty
|
241
|
+
expect(subject.resource.query(:subject => concept.rdf_subject)).to be_empty
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should not have related object relations' do
|
245
|
+
expect(person.resource.statements).to be_empty
|
246
|
+
expect(concept.resource.statements).to be_empty
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'with related: true' do
|
251
|
+
include_context 'with data'
|
252
|
+
|
253
|
+
before do
|
254
|
+
subject.update_resource(:related => true)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'should have a literal object' do
|
258
|
+
subject.resource.query(:subject => subject.rdf_subject, :predicate => RDF::DC.title).each_statement do |s|
|
259
|
+
expect(s.object.to_s).to eq 'Comet in Moominland'
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'should have an embedded object' do
|
264
|
+
subject.resource.query(:subject => part.rdf_subject, :predicate => RDF::DC.relation).each_statement do |s|
|
265
|
+
expect(s.object).to eq subject.rdf_subject
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'should have an embedded object relation' do
|
270
|
+
subject.resource.query(:subject => subject.rdf_subject, :predicate => RDF::DC.hasPart).each_statement do |s|
|
271
|
+
expect(s.object).to eq part.rdf_subject
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'should have related objects' do
|
276
|
+
subject.resource.query(:subject => subject.rdf_subject, :predicate => RDF::DC.subject).each_statement do |s|
|
277
|
+
expect(s.object).to eq concept.rdf_subject
|
278
|
+
end
|
279
|
+
subject.resource.query(:subject => subject.rdf_subject, :predicate => RDF::DC.creator).each_statement do |s|
|
280
|
+
expect(s.object).to eq person.rdf_subject
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'should have related object relations' do
|
285
|
+
person.resource.query(:subject => person.rdf_subject, :predicate => RDF::DC.relation).each_statement do |s|
|
286
|
+
expect(s.object).to eq subject.rdf_subject
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
describe '#as_jsonld' do
|
293
|
+
include_context 'with data'
|
294
|
+
|
295
|
+
before do
|
296
|
+
subject.update_resource
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'should output a valid jsonld representation of itself' do
|
300
|
+
g = RDF::Graph.new << JSON::LD::API.toRdf(JSON.parse subject.as_jsonld)
|
301
|
+
expect(subject.resource.to_hash == g.to_hash).to be true
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
describe Ladder::Searchable do
|
5
|
+
before do
|
6
|
+
Mongoid.load!('mongoid.yml', :development)
|
7
|
+
Mongoid.logger.level = Moped.logger.level = Logger::DEBUG
|
8
|
+
Mongoid.purge!
|
9
|
+
|
10
|
+
Elasticsearch::Model.client = Elasticsearch::Client.new host: 'localhost:9200', log: true
|
11
|
+
Elasticsearch::Model.client.indices.delete index: '_all'
|
12
|
+
|
13
|
+
LADDER_BASE_URI = 'http://example.org'
|
14
|
+
|
15
|
+
class Thing
|
16
|
+
include Ladder::Resource
|
17
|
+
include Ladder::Searchable
|
18
|
+
end
|
19
|
+
|
20
|
+
class Person
|
21
|
+
include Ladder::Resource
|
22
|
+
include Ladder::Searchable
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
after do
|
27
|
+
Object.send(:remove_const, "Thing") if Object
|
28
|
+
Object.send(:remove_const, "Person") if Object
|
29
|
+
end
|
30
|
+
|
31
|
+
subject { Thing.new }
|
32
|
+
let(:person) { Person.new }
|
33
|
+
|
34
|
+
shared_context 'with data' do
|
35
|
+
before do
|
36
|
+
subject.class.configure type: RDF::DC.BibliographicResource
|
37
|
+
subject.class.property :title, :predicate => RDF::DC.title
|
38
|
+
subject.title = 'Comet in Moominland'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#index' do
|
43
|
+
include_context 'with data'
|
44
|
+
|
45
|
+
context 'with default' do
|
46
|
+
before do
|
47
|
+
subject.class.index
|
48
|
+
subject.save
|
49
|
+
Elasticsearch::Model.client.indices.flush
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should exist in the index' do
|
53
|
+
results = subject.class.search('title:moomin*')
|
54
|
+
expect(results.count).to eq 1
|
55
|
+
expect(results.first._source.to_hash).to eq JSON.parse(subject.as_indexed_json.to_json)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with as qname' do
|
60
|
+
before do
|
61
|
+
subject.class.index as: :qname
|
62
|
+
subject.save
|
63
|
+
Elasticsearch::Model.client.indices.flush
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should exist in the index' do
|
67
|
+
results = subject.class.search('dc.title.en:moomin*')
|
68
|
+
expect(results.count).to eq 1
|
69
|
+
expect(results.first._source.to_hash).to eq JSON.parse(subject.as_qname.to_json)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with as jsonld' do
|
74
|
+
before do
|
75
|
+
subject.class.index as: :jsonld
|
76
|
+
subject.save
|
77
|
+
Elasticsearch::Model.client.indices.flush
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should exist in the index' do
|
81
|
+
results = subject.class.search('dc\:title.@value:moomin*')
|
82
|
+
expect(results.count).to eq 1
|
83
|
+
expect(results.first._source.to_hash).to eq JSON.parse(subject.as_jsonld)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#index with related' do
|
89
|
+
include_context 'with data'
|
90
|
+
|
91
|
+
before do
|
92
|
+
# related object
|
93
|
+
person.class.configure type: RDF::FOAF.Person
|
94
|
+
person.class.property :name, :predicate => RDF::FOAF.name
|
95
|
+
person.class.property :things, :predicate => RDF::DC.relation, :class_name => 'Thing'
|
96
|
+
person.name = 'Tove Jansson'
|
97
|
+
|
98
|
+
# many-to-many relation
|
99
|
+
subject.class.property :people, :predicate => RDF::DC.creator, :class_name => 'Person'
|
100
|
+
subject.people << person
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'with default' do
|
104
|
+
before do
|
105
|
+
person.class.index
|
106
|
+
subject.class.index
|
107
|
+
subject.save
|
108
|
+
Elasticsearch::Model.client.indices.flush
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should contain an ID for the related object' do
|
112
|
+
results = subject.class.search('person_ids.$oid:' + person.id)
|
113
|
+
expect(results.count).to eq 1
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should include the related object in the index' do
|
117
|
+
results = person.class.search('name:tove')
|
118
|
+
expect(results.count).to eq 1
|
119
|
+
expect(results.first._source.to_hash).to eq JSON.parse(person.as_indexed_json.to_json)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should contain an ID for the subject' do
|
123
|
+
results = person.class.search('thing_ids.$oid:' + subject.id)
|
124
|
+
expect(results.count).to eq 1
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'with as qname' do
|
129
|
+
before do
|
130
|
+
person.class.index as: :qname
|
131
|
+
subject.class.index as: :qname
|
132
|
+
subject.save
|
133
|
+
Elasticsearch::Model.client.indices.flush
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should contain an ID for the related object' do
|
137
|
+
results = subject.class.search('dc.creator:' + person.id)
|
138
|
+
expect(results.count).to eq 1
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should include the related object in the index' do
|
142
|
+
results = person.class.search('foaf.name.en:tove')
|
143
|
+
expect(results.count).to eq 1
|
144
|
+
expect(results.first._source.to_hash).to eq JSON.parse(person.as_qname.to_json)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should contain an ID for the subject' do
|
148
|
+
results = person.class.search('dc.relation:' + subject.id)
|
149
|
+
expect(results.count).to eq 1
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'with as_jsonld' do
|
154
|
+
before do
|
155
|
+
person.class.index as: :jsonld
|
156
|
+
subject.class.index as: :jsonld
|
157
|
+
subject.save
|
158
|
+
Elasticsearch::Model.client.indices.flush
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should contain an ID for the related object' do
|
162
|
+
results = subject.class.search('dc\:creator.@id:' + person.id)
|
163
|
+
expect(results.count).to eq 1
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should include the related object in the index' do
|
167
|
+
results = person.class.search('foaf\:name.@value:tove')
|
168
|
+
expect(results.count).to eq 1
|
169
|
+
expect(results.first._source.to_hash).to eq JSON.parse(person.as_jsonld)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'should contain an ID for the subject' do
|
173
|
+
results = person.class.search('dc\:relation.@id:' + subject.id)
|
174
|
+
expect(results.count).to eq 1
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
require 'ladder'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.color = true
|
8
|
+
config.tty = true
|
9
|
+
|
10
|
+
# Uncomment the following line to get errors and backtrace for deprecation warnings
|
11
|
+
# config.raise_errors_for_deprecations!
|
12
|
+
|
13
|
+
# Use the specified formatter
|
14
|
+
config.formatter = :documentation
|
15
|
+
end
|