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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +1 -1
  3. data/.travis.yml +16 -15
  4. data/CHANGELOG.md +16 -0
  5. data/GOALS.md +8 -0
  6. data/Guardfile +4 -0
  7. data/README.md +21 -81
  8. data/guacamole.gemspec +3 -3
  9. data/lib/guacamole.rb +1 -0
  10. data/lib/guacamole/aql_query.rb +6 -1
  11. data/lib/guacamole/collection.rb +34 -66
  12. data/lib/guacamole/configuration.rb +53 -25
  13. data/lib/guacamole/document_model_mapper.rb +149 -38
  14. data/lib/guacamole/edge.rb +74 -0
  15. data/lib/guacamole/edge_collection.rb +91 -0
  16. data/lib/guacamole/exceptions.rb +0 -5
  17. data/lib/guacamole/graph_query.rb +31 -0
  18. data/lib/guacamole/model.rb +4 -0
  19. data/lib/guacamole/proxies/proxy.rb +7 -3
  20. data/lib/guacamole/proxies/relation.rb +22 -0
  21. data/lib/guacamole/railtie.rb +1 -1
  22. data/lib/guacamole/transaction.rb +177 -0
  23. data/lib/guacamole/version.rb +1 -1
  24. data/shared/transaction.js +66 -0
  25. data/spec/acceptance/aql_spec.rb +32 -40
  26. data/spec/acceptance/relations_spec.rb +239 -0
  27. data/spec/acceptance/spec_helper.rb +2 -2
  28. data/spec/fabricators/author_fabricator.rb +2 -0
  29. data/spec/setup/arangodb.sh +2 -2
  30. data/spec/unit/collection_spec.rb +20 -97
  31. data/spec/unit/configuration_spec.rb +73 -50
  32. data/spec/unit/document_model_mapper_spec.rb +84 -77
  33. data/spec/unit/edge_collection_spec.rb +174 -0
  34. data/spec/unit/edge_spec.rb +57 -0
  35. data/spec/unit/proxies/relation_spec.rb +35 -0
  36. metadata +22 -14
  37. data/lib/guacamole/proxies/referenced_by.rb +0 -15
  38. data/lib/guacamole/proxies/references.rb +0 -15
  39. data/spec/acceptance/association_spec.rb +0 -40
  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
- it 'should create a struct with password' do
107
- expect(config_struct.password).to eq 'password'
108
- end
149
+ subject { Guacamole::Configuration.build_config(config_hash) }
109
150
 
110
- it 'should create a struct with database' do
111
- expect(config_struct.database).to eq 'awesome_db'
112
- end
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
- it 'should create a struct with password' do
128
- expect(config_struct.password).to eq 'password'
129
- end
161
+ subject { Guacamole::Configuration.build_config(database_url) }
130
162
 
131
- it 'should create a struct with database' do
132
- expect(config_struct.database).to eq 'awesome_db'
133
- end
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 receive(:[]).with('development').and_return(env_config)
182
- allow(YAML).to receive(:load).and_return(config)
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 referenced_by models' do
56
- let(:referenced_by_model_name) { :cupcakes }
57
- let(:referenced_by_models) { [referenced_by_model_name] }
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
- it 'should initialize the association proxy with referenced_by model and its name' do
69
- expect(association_proxy).to receive(:new)
70
- .with(referenced_by_model_name, model_instance)
71
- .and_return(association_proxy_instance)
72
-
73
- subject.document_to_model document
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 set an association proxy' do
77
- expect(model_instance).to receive("#{referenced_by_model_name}=").with(association_proxy_instance)
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
- context 'with referenced models' do
84
- let(:referenced_model_name) { :pony }
85
- let(:referenced_models) { [referenced_model_name] }
86
- let(:association_proxy) { Guacamole::Proxies::References }
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 set an association proxy' do
105
- expect(model_instance).to receive("#{referenced_model_name}=").with(association_proxy_instance)
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 referenced_by models' do
175
- let(:referenced_by_model_name) { :cupcakes }
176
- let(:referenced_by_models) { [referenced_by_model_name] }
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(:referenced_models).and_return referenced_models
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 referenced attribute from the document' do
200
- expect(model_attributes).to receive(:delete).with(referenced_model_name)
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 'referenced_by' do
224
- subject { Guacamole::DocumentModelMapper.new FancyModel, FakeIdentityMap }
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
- it 'should remember which models holding references' do
227
- subject.referenced_by :ponies
210
+ context 'attributes for relations' do
211
+ let(:edge_class) { double('SomeEdgeClass') }
228
212
 
229
- expect(subject.referenced_by_models).to include :ponies
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 remember which models are referenced' do
237
- subject.references :pony
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.referenced_models).to include :pony
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