guacamole 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.hound.yml +1 -1
- data/.travis.yml +16 -15
- data/CHANGELOG.md +16 -0
- data/GOALS.md +8 -0
- data/Guardfile +4 -0
- data/README.md +21 -81
- data/guacamole.gemspec +3 -3
- data/lib/guacamole.rb +1 -0
- data/lib/guacamole/aql_query.rb +6 -1
- data/lib/guacamole/collection.rb +34 -66
- data/lib/guacamole/configuration.rb +53 -25
- data/lib/guacamole/document_model_mapper.rb +149 -38
- data/lib/guacamole/edge.rb +74 -0
- data/lib/guacamole/edge_collection.rb +91 -0
- data/lib/guacamole/exceptions.rb +0 -5
- data/lib/guacamole/graph_query.rb +31 -0
- data/lib/guacamole/model.rb +4 -0
- data/lib/guacamole/proxies/proxy.rb +7 -3
- data/lib/guacamole/proxies/relation.rb +22 -0
- data/lib/guacamole/railtie.rb +1 -1
- data/lib/guacamole/transaction.rb +177 -0
- data/lib/guacamole/version.rb +1 -1
- data/shared/transaction.js +66 -0
- data/spec/acceptance/aql_spec.rb +32 -40
- data/spec/acceptance/relations_spec.rb +239 -0
- data/spec/acceptance/spec_helper.rb +2 -2
- data/spec/fabricators/author_fabricator.rb +2 -0
- data/spec/setup/arangodb.sh +2 -2
- data/spec/unit/collection_spec.rb +20 -97
- data/spec/unit/configuration_spec.rb +73 -50
- data/spec/unit/document_model_mapper_spec.rb +84 -77
- data/spec/unit/edge_collection_spec.rb +174 -0
- data/spec/unit/edge_spec.rb +57 -0
- data/spec/unit/proxies/relation_spec.rb +35 -0
- metadata +22 -14
- data/lib/guacamole/proxies/referenced_by.rb +0 -15
- data/lib/guacamole/proxies/references.rb +0 -15
- data/spec/acceptance/association_spec.rb +0 -40
- data/spec/unit/example_spec.rb +0 -8
@@ -81,6 +81,57 @@ describe Guacamole::Configuration do
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
describe 'graph' do
|
85
|
+
let(:database) { instance_double('Ashikawa::Core::Database') }
|
86
|
+
let(:graph) { instance_double('Ashikawa::Core::Graph') }
|
87
|
+
let(:graph_name) { 'my-amazing-graph' }
|
88
|
+
|
89
|
+
before do
|
90
|
+
subject.graph_name = nil
|
91
|
+
allow(subject).to receive(:database).and_return(database)
|
92
|
+
allow(database).to receive(:graph).with(graph_name).and_return(graph)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should allow access to the associated graph based on the graph_name attribute' do
|
96
|
+
allow(subject).to receive(:graph_name).and_return(graph_name)
|
97
|
+
|
98
|
+
expect(subject.graph).to eq graph
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'configure the graph name' do
|
102
|
+
context 'within a Rails application' do
|
103
|
+
let(:rails_module) { double('Rails') }
|
104
|
+
let(:application_class) { double('ApplicationClass', name: 'MyAwesomeApp::Application') }
|
105
|
+
let(:rails_application) { double('MyAwesomeApp::Application', class: application_class) }
|
106
|
+
|
107
|
+
before do
|
108
|
+
allow(rails_module).to receive(:application).and_return(rails_application)
|
109
|
+
stub_const('Rails', rails_module)
|
110
|
+
end
|
111
|
+
|
112
|
+
its(:graph_name) { should eq 'my_awesome_app_graph' }
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should be generated based on the current database name' do
|
116
|
+
allow(database).to receive(:name).and_return('my_database')
|
117
|
+
|
118
|
+
expect(subject.graph_name).to eq 'my_database_graph'
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should use a custom set graph name' do
|
122
|
+
subject.graph_name = 'fabulous_graph'
|
123
|
+
|
124
|
+
expect(subject.graph_name).to eq 'fabulous_graph'
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should take the graph name from the ENV' do
|
128
|
+
allow(ENV).to receive(:[]).with('GUACAMOLE_GRAPH').and_return('graph_from_env')
|
129
|
+
|
130
|
+
expect(subject.graph_name).to eq 'graph_from_env'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
84
135
|
describe 'build_config' do
|
85
136
|
context 'from a hash' do
|
86
137
|
let(:config_hash) do
|
@@ -90,47 +141,29 @@ describe Guacamole::Configuration do
|
|
90
141
|
'port' => 8529,
|
91
142
|
'username' => 'username',
|
92
143
|
'password' => 'password',
|
93
|
-
'database' => 'awesome_db'
|
144
|
+
'database' => 'awesome_db',
|
145
|
+
'graph' => 'custom_graph'
|
94
146
|
}
|
95
147
|
end
|
96
|
-
let(:config_struct) { subject.build_config(config_hash) }
|
97
|
-
|
98
|
-
it 'should create a struct with a database URL' do
|
99
|
-
expect(config_struct.url).to eq 'http://localhost:8529'
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'should create a struct with a username' do
|
103
|
-
expect(config_struct.username).to eq 'username'
|
104
|
-
end
|
105
148
|
|
106
|
-
|
107
|
-
expect(config_struct.password).to eq 'password'
|
108
|
-
end
|
149
|
+
subject { Guacamole::Configuration.build_config(config_hash) }
|
109
150
|
|
110
|
-
|
111
|
-
|
112
|
-
|
151
|
+
its(:url) { should eq 'http://localhost:8529' }
|
152
|
+
its(:username) { should eq 'username' }
|
153
|
+
its(:password) { should eq 'password' }
|
154
|
+
its(:database) { should eq 'awesome_db' }
|
155
|
+
its(:graph) { should eq 'custom_graph' }
|
113
156
|
end
|
114
157
|
|
115
158
|
context 'from a URL' do
|
116
159
|
let(:database_url) { 'http://username:password@localhost:8529/_db/awesome_db' }
|
117
|
-
let(:config_struct) { subject.build_config(database_url) }
|
118
|
-
|
119
|
-
it 'should create a struct with a database URL' do
|
120
|
-
expect(config_struct.url).to eq 'http://localhost:8529'
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'should create a struct with a username' do
|
124
|
-
expect(config_struct.username).to eq 'username'
|
125
|
-
end
|
126
160
|
|
127
|
-
|
128
|
-
expect(config_struct.password).to eq 'password'
|
129
|
-
end
|
161
|
+
subject { Guacamole::Configuration.build_config(database_url) }
|
130
162
|
|
131
|
-
|
132
|
-
|
133
|
-
|
163
|
+
its(:url) { should eq 'http://localhost:8529' }
|
164
|
+
its(:username) { should eq 'username' }
|
165
|
+
its(:password) { should eq 'password' }
|
166
|
+
its(:database) { should eq 'awesome_db' }
|
134
167
|
end
|
135
168
|
end
|
136
169
|
|
@@ -178,8 +211,9 @@ describe Guacamole::Configuration do
|
|
178
211
|
allow(subject).to receive(:create_database_connection)
|
179
212
|
allow(subject).to receive(:process_file_with_erb).with('config_file.yml')
|
180
213
|
allow(subject).to receive(:build_config).and_return(config_struct)
|
181
|
-
allow(config).to
|
182
|
-
allow(
|
214
|
+
allow(config).to receive(:[]).with('development').and_return(env_config)
|
215
|
+
allow(config_struct).to receive(:graph).and_return('custom_graph_name')
|
216
|
+
allow(YAML).to receive(:load).and_return(config)
|
183
217
|
end
|
184
218
|
|
185
219
|
it 'should parse a YAML configuration' do
|
@@ -206,6 +240,12 @@ describe Guacamole::Configuration do
|
|
206
240
|
subject.load 'config_file.yml'
|
207
241
|
end
|
208
242
|
|
243
|
+
it 'should set the graph name as read from the YAML file' do
|
244
|
+
expect(subject).to receive(:graph_name=).with('custom_graph_name')
|
245
|
+
|
246
|
+
subject.load 'config_file.yml'
|
247
|
+
end
|
248
|
+
|
209
249
|
it 'should warn if the database was not found' do
|
210
250
|
allow(subject).to receive(:database).and_return(double('Database'))
|
211
251
|
allow(subject.database).to receive(:name)
|
@@ -270,21 +310,4 @@ development:
|
|
270
310
|
subject.configure_with_uri(connection_uri)
|
271
311
|
end
|
272
312
|
end
|
273
|
-
|
274
|
-
describe 'experimental_features' do
|
275
|
-
let(:fresh_config) { Guacamole::Configuration.new }
|
276
|
-
|
277
|
-
after do
|
278
|
-
subject.experimental_features = []
|
279
|
-
end
|
280
|
-
|
281
|
-
it 'should default to none' do
|
282
|
-
expect(fresh_config.experimental_features).to be_empty
|
283
|
-
end
|
284
|
-
|
285
|
-
it 'should accept a list of features to activate' do
|
286
|
-
subject.experimental_features = [:aql_support]
|
287
|
-
expect(subject.experimental_features).to include :aql_support
|
288
|
-
end
|
289
|
-
end
|
290
313
|
end
|
@@ -22,6 +22,22 @@ describe Guacamole::DocumentModelMapper do
|
|
22
22
|
expect(mapper.model_class).to eq FancyModel
|
23
23
|
end
|
24
24
|
|
25
|
+
context 'document mapper instance' do
|
26
|
+
subject { Guacamole::DocumentModelMapper.new FancyModel, FakeIdentityMap }
|
27
|
+
|
28
|
+
let(:model) { double('Model') }
|
29
|
+
let(:model_class) { double('ModelClass') }
|
30
|
+
|
31
|
+
before do
|
32
|
+
allow(subject).to receive(:model_class).and_return(model_class)
|
33
|
+
allow(model).to receive(:instance_of?).with(model_class).and_return(true)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should know if it responsible for a certain model' do
|
37
|
+
expect(subject.responsible_for?(model)).to be_truthy
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
25
41
|
describe 'document_to_model' do
|
26
42
|
subject { Guacamole::DocumentModelMapper.new FancyModel, FakeIdentityMap }
|
27
43
|
|
@@ -52,57 +68,41 @@ describe Guacamole::DocumentModelMapper do
|
|
52
68
|
subject.document_to_model document
|
53
69
|
end
|
54
70
|
|
55
|
-
context 'with
|
56
|
-
let(:
|
57
|
-
|
58
|
-
let(:association_proxy) { Guacamole::Proxies::ReferencedBy }
|
59
|
-
let(:association_proxy_instance) { double('AssociationProxy') }
|
60
|
-
|
61
|
-
before do
|
62
|
-
allow(subject).to receive(:referenced_by_models).and_return referenced_by_models
|
63
|
-
allow(association_proxy).to receive(:new)
|
64
|
-
.with(referenced_by_model_name, model_instance)
|
65
|
-
.and_return(association_proxy_instance)
|
71
|
+
context 'with attributes as edge relations' do
|
72
|
+
let(:attribute_with_edge_relation) do
|
73
|
+
instance_double('Guacamole::DocumentModelMapper::Attribute', name: 'my_relation')
|
66
74
|
end
|
75
|
+
let(:related_edge_class) { instance_double('Guacamole::Edge') }
|
76
|
+
let(:relation_proxy_class) { Guacamole::Proxies::Relation }
|
77
|
+
let(:relation_proxy) { instance_double('Guacamole::Proxies::Relation') }
|
67
78
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
79
|
+
before do
|
80
|
+
allow(attribute_with_edge_relation).to receive(:setter).and_return('my_relation=')
|
81
|
+
allow(attribute_with_edge_relation).to receive(:edge_class).and_return(related_edge_class)
|
82
|
+
allow(subject).to receive(:edge_attributes).and_return([attribute_with_edge_relation])
|
83
|
+
allow(relation_proxy_class).to receive(:new).
|
84
|
+
with(model_instance, related_edge_class).
|
85
|
+
and_return(relation_proxy)
|
74
86
|
end
|
75
87
|
|
76
|
-
it 'should
|
77
|
-
expect(
|
88
|
+
it 'should initialize a relation proxy with the model and the appropriate edge class' do
|
89
|
+
expect(relation_proxy_class).to receive(:new).
|
90
|
+
with(model_instance, related_edge_class).
|
91
|
+
and_return(relation_proxy)
|
78
92
|
|
79
93
|
subject.document_to_model document
|
80
94
|
end
|
81
|
-
end
|
82
95
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
let(:association_proxy_instance) { double('AssociationProxy') }
|
88
|
-
|
89
|
-
before do
|
90
|
-
allow(subject).to receive(:referenced_models).and_return referenced_models
|
91
|
-
allow(association_proxy).to receive(:new)
|
92
|
-
.with(referenced_model_name, document)
|
93
|
-
.and_return(association_proxy_instance)
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'should initialize the association proxy with the document and the referenced model name' do
|
97
|
-
expect(association_proxy).to receive(:new)
|
98
|
-
.with(referenced_model_name, document)
|
99
|
-
.and_return(association_proxy_instance)
|
96
|
+
it 'should set first the key and rev and after that the proxy' do
|
97
|
+
expect(model_instance).to receive(:key=).ordered
|
98
|
+
expect(model_instance).to receive(:rev=).ordered
|
99
|
+
expect(subject).to receive(:handle_related_documents).ordered
|
100
100
|
|
101
101
|
subject.document_to_model document
|
102
102
|
end
|
103
103
|
|
104
|
-
it 'should
|
105
|
-
expect(model_instance).to receive(
|
104
|
+
it 'should assign the relation proxy for the appropriate attribute' do
|
105
|
+
expect(model_instance).to receive(:my_relation=).with(relation_proxy)
|
106
106
|
|
107
107
|
subject.document_to_model document
|
108
108
|
end
|
@@ -171,39 +171,17 @@ describe Guacamole::DocumentModelMapper do
|
|
171
171
|
end
|
172
172
|
end
|
173
173
|
|
174
|
-
context 'with
|
175
|
-
let(:
|
176
|
-
|
177
|
-
|
178
|
-
before do
|
179
|
-
allow(subject).to receive(:referenced_by_models).and_return referenced_by_models
|
174
|
+
context 'with attributes as edge relations' do
|
175
|
+
let(:attribute_with_edge_relation) do
|
176
|
+
instance_double('Guacamole::DocumentModelMapper::Attribute', name: 'my_relation')
|
180
177
|
end
|
181
178
|
|
182
|
-
it 'should remove the referenced_by attribute from the document' do
|
183
|
-
expect(model_attributes).to receive(:delete).with(referenced_by_model_name)
|
184
|
-
|
185
|
-
subject.model_to_document(model)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
context 'with referenced models' do
|
190
|
-
let(:referenced_model) { double('ReferencedModel', key: 23) }
|
191
|
-
let(:referenced_model_name) { :pony }
|
192
|
-
let(:referenced_models) { [referenced_model_name] }
|
193
|
-
|
194
179
|
before do
|
195
|
-
allow(subject).to receive(:
|
196
|
-
allow(model).to receive(:send).with(referenced_model_name).and_return referenced_model
|
180
|
+
allow(subject).to receive(:edge_attributes).and_return([attribute_with_edge_relation])
|
197
181
|
end
|
198
182
|
|
199
|
-
it 'should remove the
|
200
|
-
expect(model_attributes).to receive(:delete).with(
|
201
|
-
|
202
|
-
subject.model_to_document(model)
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'should add the key of the referenced model to the document' do
|
206
|
-
expect(model_attributes).to receive(:[]=).with(:"#{referenced_model_name}_id", referenced_model.key)
|
183
|
+
it 'should remove the attributes from the document' do
|
184
|
+
expect(model_attributes).to receive(:delete).with('my_relation')
|
207
185
|
|
208
186
|
subject.model_to_document(model)
|
209
187
|
end
|
@@ -220,23 +198,52 @@ describe Guacamole::DocumentModelMapper do
|
|
220
198
|
end
|
221
199
|
end
|
222
200
|
|
223
|
-
describe '
|
224
|
-
|
201
|
+
describe 'attribute' do
|
202
|
+
describe Guacamole::DocumentModelMapper::Attribute do
|
203
|
+
subject { Guacamole::DocumentModelMapper::Attribute.new(:attribute_name) }
|
204
|
+
|
205
|
+
its(:name) { should eq :attribute_name }
|
206
|
+
its(:options) { should eq({}) }
|
207
|
+
its(:getter) { should eq :attribute_name }
|
208
|
+
its(:setter) { should eq 'attribute_name=' }
|
225
209
|
|
226
|
-
|
227
|
-
|
210
|
+
context 'attributes for relations' do
|
211
|
+
let(:edge_class) { double('SomeEdgeClass') }
|
228
212
|
|
229
|
-
|
213
|
+
before do
|
214
|
+
subject.options[:via] = edge_class
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should know if the attribute must be mapped via an edge' do
|
218
|
+
expect(subject.map_via_edge?).to be_truthy
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should hold a reference to the edge class' do
|
222
|
+
expect(subject.edge_class).to eq edge_class
|
223
|
+
end
|
224
|
+
end
|
230
225
|
end
|
231
|
-
end
|
232
226
|
|
233
|
-
describe 'references' do
|
234
227
|
subject { Guacamole::DocumentModelMapper.new FancyModel, FakeIdentityMap }
|
235
228
|
|
236
|
-
it 'should
|
237
|
-
subject.
|
229
|
+
it 'should add an attribute to be handled differently during the mapping' do
|
230
|
+
subject.attribute :special_one
|
231
|
+
|
232
|
+
expect(subject.attributes).to include Guacamole::DocumentModelMapper::Attribute.new(:special_one)
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should hold a list of all attributes to be considered during the mapping' do
|
236
|
+
subject.attribute :some_attribute
|
237
|
+
subject.attribute :another_attribute
|
238
|
+
|
239
|
+
expect(subject.attributes.count).to eq 2
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'should hold a list of all attributes to be mapped via Edges' do
|
243
|
+
subject.attribute :normal_attribute
|
244
|
+
subject.attribute :related_model, via: double('EdgeClass')
|
238
245
|
|
239
|
-
expect(subject.
|
246
|
+
expect(subject.edge_attributes).to include(an_object_having_attributes(name: :related_model))
|
240
247
|
end
|
241
248
|
end
|
242
249
|
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'guacamole/edge_collection'
|
5
|
+
|
6
|
+
describe Guacamole::EdgeCollection do
|
7
|
+
let(:graph) { double('Graph') }
|
8
|
+
let(:config) { double('Configuration') }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(Guacamole).to receive(:configuration).and_return(config)
|
12
|
+
allow(config).to receive(:graph).and_return(graph)
|
13
|
+
allow(graph).to receive(:add_edge_definition)
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'the edge collection module' do
|
17
|
+
subject { Guacamole::EdgeCollection }
|
18
|
+
|
19
|
+
context 'with user defined edge collection class' do
|
20
|
+
let(:edge_class) { double('EdgeClass', name: 'MyEdge') }
|
21
|
+
let(:user_defined_edge_collection) { double('EdgeCollection') }
|
22
|
+
|
23
|
+
before do
|
24
|
+
stub_const('MyEdgesCollection', user_defined_edge_collection)
|
25
|
+
allow(user_defined_edge_collection).to receive(:add_edge_definition_to_graph)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should return the edge collection for a given edge class' do
|
29
|
+
expect(subject.for(edge_class)).to eq user_defined_edge_collection
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'without user defined edge collection class' do
|
34
|
+
let(:edge_class) { double('EdgeClass', name: 'AmazingEdge') }
|
35
|
+
let(:auto_defined_edge_collection) { double('EdgeCollection') }
|
36
|
+
|
37
|
+
before do
|
38
|
+
stub_const('ExampleEdge', double('Edge').as_null_object)
|
39
|
+
allow(auto_defined_edge_collection).to receive(:add_edge_definition_to_graph)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should create an edge collection class' do
|
43
|
+
edge_collection = subject.create_edge_collection('ExampleEdgesCollection')
|
44
|
+
|
45
|
+
expect(edge_collection.name).to eq 'ExampleEdgesCollection'
|
46
|
+
expect(edge_collection.ancestors).to include Guacamole::EdgeCollection
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should return the edge collection for a givene edge class' do
|
50
|
+
allow(subject).to receive(:create_edge_collection).
|
51
|
+
with('AmazingEdgesCollection').
|
52
|
+
and_return(auto_defined_edge_collection)
|
53
|
+
|
54
|
+
expect(subject.for(edge_class)).to eq auto_defined_edge_collection
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'concrete edge collections' do
|
60
|
+
subject do
|
61
|
+
class SomeEdgesCollection
|
62
|
+
include Guacamole::EdgeCollection
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
let(:database) { double('Database') }
|
67
|
+
let(:edge_collection_name) { 'some_edges' }
|
68
|
+
let(:raw_edge_collection) { double('Ashikawa::Core::EdgeCollection') }
|
69
|
+
let(:collection_a) { :a }
|
70
|
+
let(:collection_b) { :b }
|
71
|
+
let(:edge_class) { double('EdgeClass', name: 'SomeEdge', from: collection_a, to: collection_b) }
|
72
|
+
let(:model) { double('Model') }
|
73
|
+
|
74
|
+
before do
|
75
|
+
stub_const('SomeEdge', edge_class)
|
76
|
+
allow(graph).to receive(:edge_collection).with(edge_collection_name).and_return(raw_edge_collection)
|
77
|
+
allow(subject).to receive(:database).and_return(database)
|
78
|
+
allow(graph).to receive(:add_edge_definition)
|
79
|
+
end
|
80
|
+
|
81
|
+
after do
|
82
|
+
# This stunt is required to have a fresh subject each time and not running into problems
|
83
|
+
# with cached mock doubles that will raise errors upon test execution.
|
84
|
+
Object.send(:remove_const, subject.name)
|
85
|
+
end
|
86
|
+
|
87
|
+
its(:edge_class) { should eq edge_class }
|
88
|
+
|
89
|
+
it 'should be a specialized Guacamole::Collection' do
|
90
|
+
expect(subject).to include Guacamole::Collection
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should map the #connectino to the underlying edge_connection' do
|
94
|
+
allow(subject).to receive(:graph).and_return(graph)
|
95
|
+
|
96
|
+
expect(subject.connection).to eq raw_edge_collection
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'initialize the edge definition' do
|
100
|
+
it 'should add the edge definition as soon as the module is included' do
|
101
|
+
just_another_edge_collection = Class.new
|
102
|
+
expect(just_another_edge_collection).to receive(:add_edge_definition_to_graph)
|
103
|
+
|
104
|
+
just_another_edge_collection.send(:include, Guacamole::EdgeCollection)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should ignore if the the edge definition was already added' do
|
108
|
+
expect(graph).to receive(:add_edge_definition).and_raise(Ashikawa::Core::ResourceNotFound)
|
109
|
+
|
110
|
+
expect { subject.add_edge_definition_to_graph }.not_to raise_error
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should create the edge definition based on the edge class' do
|
114
|
+
expect(graph).to receive(:add_edge_definition).with(edge_collection_name,
|
115
|
+
from: [collection_a], to: [collection_b])
|
116
|
+
|
117
|
+
subject.add_edge_definition_to_graph
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'accessing the mapper' do
|
122
|
+
let(:collection_a) { double('Collection') }
|
123
|
+
let(:collection_b) { double('Collection') }
|
124
|
+
let(:mapper_a) { double('DocumentModelMapper') }
|
125
|
+
let(:mapper_b) { double('DocumentModelMapper') }
|
126
|
+
|
127
|
+
before do
|
128
|
+
allow(collection_a).to receive(:mapper).and_return(mapper_a)
|
129
|
+
allow(collection_b).to receive(:mapper).and_return(mapper_b)
|
130
|
+
allow(edge_class).to receive(:from_collection).and_return(collection_a)
|
131
|
+
allow(edge_class).to receive(:to_collection).and_return(collection_b)
|
132
|
+
allow(mapper_a).to receive(:responsible_for?).with(model).and_return(true)
|
133
|
+
allow(mapper_b).to receive(:responsible_for?).with(model).and_return(false)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should provide a method to get the mapper for the :to collection' do
|
137
|
+
expect(subject.mapper_for_target(model)).to eq mapper_b
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should provide a method to get the mapper for the :from collection' do
|
141
|
+
expect(subject.mapper_for_start(model)).to eq mapper_a
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'getting neighbors' do
|
146
|
+
let(:graph_query) { instance_double('Guacamole::GraphQuery') }
|
147
|
+
let(:target_mapper) { double('DocumentModelMapper') }
|
148
|
+
|
149
|
+
before do
|
150
|
+
allow(Guacamole::GraphQuery).to receive(:new).and_return(graph_query)
|
151
|
+
allow(subject).to receive(:mapper_for_target).with(model).and_return(target_mapper)
|
152
|
+
allow(graph_query).to receive(:neighbors).and_return(graph_query)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should return a query object' do
|
156
|
+
query = subject.neighbors(model)
|
157
|
+
|
158
|
+
expect(query).to eq graph_query
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should initialize the query object with the graph an the appropriate mapper' do
|
162
|
+
expect(Guacamole::GraphQuery).to receive(:new).with(graph, target_mapper).and_return(graph_query)
|
163
|
+
|
164
|
+
subject.neighbors(model)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should provide a #neighbors function' do
|
168
|
+
expect(graph_query).to receive(:neighbors).with(model, 'some_edges')
|
169
|
+
|
170
|
+
subject.neighbors(model)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|