neography-batch 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- neography-batch (1.0.3)
4
+ neography-batch (1.0.4)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ neography-batch makes neography-batches better composable
2
+ Copyright (C) 2013 Jorg Jenni
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
data/README.md CHANGED
@@ -1,25 +1,96 @@
1
- # neography-batch
2
-
3
1
  ## Introduction
4
- makes neography-batches better composable
2
+ Makes [neography-batches](https://github.com/maxdemarzi/neography/wiki/Batch "Neography Batch") better composable. By composing batches you can
3
+ * reduce the number of calls to the neo4j-server and therefore reducing network latency
4
+ * implement transactions by aggregating the results of smaller calculations into one large transactional batch
5
5
 
6
- TODO: writing something nice here
6
+ ```ruby
7
+ batch_1 = Neography::Composable::Batch.new
8
+ john = batch_1 << [:create_node, {'name' => 'john'}]
7
9
 
8
- ## Installation
9
- TODO: Test & Describe installation
10
+ batch_2 = Neography::Composable::Batch.new
11
+ lucy = batch_2 << [:create_node, {'name' => 'lucy'}]
12
+
13
+ batch_3 = Neography::Composable::Batch.new
14
+ batch_3 << [:create_relationship, 'friend_of', john, lucy]
10
15
 
16
+ super_batch = batch_1 << batch_2 << batch_3
17
+ super_batch.submit()
18
+ ```
19
+ Batches might be the foundation to more advanced concepts like [UnitOfWork](http://www.martinfowler.com/eaaCatalog/unitOfWork.html) or [Aggregates](http://en.wikipedia.org/wiki/Domain-driven_design).
20
+ ## Installation
21
+ ### Gemfile:
22
+ Add `neography-batch` to your Gemfile:
23
+ ```ruby
24
+ gem 'neography-batch'
25
+ ```
26
+ And run Bundler:
27
+ ```sh
28
+ $ bundle install
29
+ ```
30
+ ### Manually:
31
+ Or install `neography-batch` manually:
32
+ ```sh
33
+ $ gem install 'neography-batch'
34
+ ```
35
+ And require the gem in your Ruby code:
36
+ ```ruby
37
+ require 'neography-batch'
38
+ ```
11
39
  ## Usage
12
- TODO: Describe usage
40
+ ### Creating a batch
41
+ A batch is be created by
42
+ ```ruby
43
+ batch = Neography::Composable::Batch.new
44
+ # add commands to the batch here
45
+ ```
46
+ or
47
+ ```ruby
48
+ batch = Neography::Composable::Batch.new do |b|
49
+ # add commands to the batch here
50
+ end
51
+ ```
52
+ See also [read and write examples](https://github.com/Enceradeira/neography-batch/blob/master/spec/examples/read_and_write_examples_spec.rb).
53
+ ### Adding commands & submitting
54
+ ```ruby
55
+ batch << [:create_node, {'name' => 'john'}]
56
+ batch << [:create_node, {'name' => 'lucy'}]
57
+ batch.submit()
58
+ ```
59
+ You can add everything that is supported by neography's-batch. See [here](https://github.com/maxdemarzi/neography/wiki/Batch) for details.
60
+ ### Aggregating & submitting
61
+ ```ruby
62
+ super_batch = persons_batch << employee_batch << wages_batch
63
+ super_batch.submit()
64
+ ```
65
+ See also [reference and notification examples](https://github.com/Enceradeira/neography-batch/blob/master/spec/examples/references_and_notification_examples_spec.rb).
66
+ ### Referencing & submitting
67
+ ```ruby
68
+ ibm = company_batch << [:create_node, {'name' => 'IBM'}]
69
+ john = persons_batch << [:create_node, {'name' => 'john'}]
70
+ lucy = persons_batch << [:create_node, {'name' => 'lucy'}]
71
+ employee_batch << [:create_relationship, 'employee', ibm, john]
72
+ employee_batch << [:create_relationship, 'employee', ibm, lucy]
13
73
 
14
- # Running tests
74
+ super_batch = company_batch << persons_batch << employee_batch
75
+ super_batch.submit()
76
+ ```
77
+ See also [reference and notification examples](https://github.com/Enceradeira/neography-batch/blob/master/spec/examples/references_and_notification_examples_spec.rb).
78
+ ## Running tests
79
+ ### Installing & starting neo4j
15
80
  A few tests run against a neo4j-instance. This instance can be installed and run using following rake commands:
16
81
  ```sh
17
82
  rake neo4j:install # Install Neo4j to the neo4j directory under your project
18
83
  rake neo4j:start # Start Neo4j
19
84
  rake neo4j:stop # Stop Neo4j
20
85
  ```
86
+ For a complete documentation see [neography's rake tasks](https://github.com/maxdemarzi/neography/wiki/Rake-tasks "Rake tasks").
87
+ ### Tests
88
+ Tests can best be executed with:
89
+ ```sh
90
+ rake spec
91
+ ```
92
+ ## License
93
+ This work is licensed under [GNU General Public License (v3 or later)](http://www.gnu.org/licenses/gpl-3.0.html)
21
94
 
22
- For a complete documentation see [neography's rake tasks](https://github.com/maxdemarzi/neography/wiki/Rake-tasks "Rake tasks")
23
-
24
- # License
25
- TODO: Think hard about it
95
+ ### 3-party licenses
96
+ * Neography - MIT, see the LICENSE file http://github.com/maxdemarzi/neography/tree/master/LICENSE.
@@ -1,3 +1,5 @@
1
+ require_relative 'neography_context.rb'
2
+
1
3
  module Neography
2
4
  module Composable
3
5
  class BatchReference
@@ -21,7 +23,7 @@ module Neography
21
23
 
22
24
  def notify_after_submit(result)
23
25
  unless @after_submit_action.nil?
24
- @after_submit_action.call(result)
26
+ NeographyContext.new(&@after_submit_action).eval(result)
25
27
  end
26
28
  end
27
29
 
@@ -0,0 +1,16 @@
1
+ module Neography
2
+ module Composable
3
+ class NeographyContext
4
+ include Neography::Rest::Helpers
5
+
6
+ def initialize(&block)
7
+ @block = block
8
+ end
9
+
10
+ public
11
+ def eval(result)
12
+ instance_exec(result, &@block)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "neography-batch"
6
- s.version = "1.0.3"
6
+ s.version = "1.0.4"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = "Jorg Jenni"
9
9
  s.email = "jorg.jenni@jennius.co.uk"
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'read and write examples' do
4
+ describe 'simple write and read' do
5
+ it 'writes to neo4j and reads from neo4j' do
6
+
7
+ # write some data
8
+ batch = Neography::Composable::Batch.new
9
+ batch << [:create_unique_node, 'person', 'name', 'john', {'age' => 33}]
10
+ batch.submit()
11
+
12
+ # read data
13
+ read_batch = Neography::Composable::Batch.new
14
+ read_batch << [:get_node_index, 'person', 'name', 'john']
15
+ result = read_batch.submit()
16
+
17
+ # test if it worked?
18
+ expect(result).to have(1).item
19
+ expect(result.first.first['data']).to eq({'age' => 33})
20
+ end
21
+ end
22
+ describe 'simple write and read using a block for initialization' do
23
+ it 'writes to neo4j and reads from neo4j' do
24
+
25
+ # write & submit some data
26
+ Neography::Composable::Batch.new do |b|
27
+ b << [:create_unique_node, 'person', 'name', 'john', {'age' => 33}]
28
+ end.submit()
29
+
30
+ # read & submit
31
+ result = Neography::Composable::Batch.new do |b|
32
+ b << [:get_node_index, 'person', 'name', 'john']
33
+ end.submit()
34
+
35
+ # test if it worked?
36
+ expect(result).to have(1).item
37
+ expect(result.first.first['data']).to eq({'age' => 33})
38
+ end
39
+ end
40
+ describe 'aggregating two batches into one' do
41
+ it 'writes all data in one batch/transaction' do
42
+
43
+ batch1 = Neography::Composable::Batch.new do |b|
44
+ b << [:create_unique_node, 'person', 'name', 'john', {'age' => 33}]
45
+ b << [:create_unique_node, 'person', 'name', 'carl', {'age' => 45}]
46
+ end
47
+
48
+ batch2 = Neography::Composable::Batch.new do |b|
49
+ b << [:create_unique_node, 'salary', 'employee', 'john', {'wage' => 1200}]
50
+ b << [:create_unique_node, 'salary', 'employee', 'carl', {'wage' => 1055}]
51
+ end
52
+
53
+ # combining the two batches and submitting it in one transfer/transaction
54
+ super_batch = batch1 << batch2
55
+ super_batch.submit()
56
+
57
+ # test if it worked?
58
+ result = Neography::Composable::Batch.new do |b|
59
+ b << [:get_node_index, 'person', 'name', 'john']
60
+ b << [:get_node_index, 'person', 'name', 'carl']
61
+ b << [:get_node_index, 'salary', 'employee', 'john']
62
+ b << [:get_node_index, 'salary', 'employee', 'carl']
63
+ end.submit()
64
+
65
+ expect(result).to have(4).items
66
+ expect(result[0][0]['data']).to eq({'age' => 33})
67
+ expect(result[1][0]['data']).to eq({'age' => 45})
68
+ expect(result[2][0]['data']).to eq({'wage' => 1200})
69
+ expect(result[3][0]['data']).to eq({'wage' => 1055})
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'references and notification examples' do
4
+ let(:neo) { Neography::Rest.new }
5
+ let(:root) { neo.get_root }
6
+
7
+ describe 'referencing nodes from different batches' do
8
+ it 'works perfectly' do
9
+ # creating a company
10
+ company_batch = Neography::Composable::Batch.new
11
+ ibm = company_batch << [:create_node, {'name' => 'IBM'}]
12
+ company_batch << [:create_relationship, 'company', root, ibm]
13
+
14
+ # create some persons
15
+ persons_batch = Neography::Composable::Batch.new
16
+ john = persons_batch << [:create_node, {'name' => 'john'}]
17
+ lucy = persons_batch << [:create_node, {'name' => 'lucy'}]
18
+
19
+ # connect persons with company
20
+ hr_batch = Neography::Composable::Batch.new
21
+ hr_batch << [:create_relationship, 'employee', ibm, john]
22
+ hr_batch << [:create_relationship, 'employee', ibm, lucy]
23
+
24
+ # query the inserted nodes
25
+ query_batch = Neography::Composable::Batch.new
26
+ query_batch << [:execute_query, 'start r=node(0) match r-[:company]->c-[:employee]->e return e.name']
27
+
28
+ # join batches and execute all in one go
29
+ super_batch = company_batch << persons_batch << hr_batch << query_batch
30
+ result = super_batch.submit()
31
+
32
+ # test if it worked?
33
+ query_result = result.last['data'].map { |r| r.first }
34
+ expect(query_result).to include('john')
35
+ expect(query_result).to include('lucy')
36
+ end
37
+ end
38
+
39
+ describe 'notification after submitting a command' do
40
+ it 'notifies reference with result returned from server' do
41
+ johns_id = nil
42
+
43
+ batch = Neography::Composable::Batch.new
44
+ john = batch << [:create_node, {'name' => 'john'}]
45
+
46
+ # ask for being notified after submit
47
+ john.after_submit do |n|
48
+ johns_id = get_id(n)
49
+ end
50
+
51
+ batch.submit()
52
+
53
+ # test if it worked?
54
+ johns_node = neo.get_node(johns_id)
55
+ expect(johns_node['data']['name']).to eq('john')
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'showcase' do
4
+ it 'shows essential features' do
5
+ batch_1 = Neography::Composable::Batch.new
6
+ john = batch_1 << [:create_node, {'name' => 'john'}]
7
+
8
+ batch_2 = Neography::Composable::Batch.new
9
+ lucy = batch_2 << [:create_node, {'name' => 'lucy'}]
10
+
11
+ batch_3 = Neography::Composable::Batch.new
12
+ batch_3 << [:create_relationship, 'friend_of', john, lucy]
13
+
14
+ super_batch = batch_1 << batch_2 << batch_3
15
+ super_batch.submit()
16
+ end
17
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ module Neography
4
+ module Composable
5
+ describe BatchReference do
6
+ describe '==' do
7
+ context 'different command-instances' do
8
+ let(:command1) { [:create, {"id" => 1}] }
9
+ let(:command2) { [:create, {"id" => 1}] }
10
+ let(:ref1) { BatchReference.new(command1) }
11
+ let(:ref2) { BatchReference.new(command2) }
12
+
13
+ it 'is not equal' do
14
+ expect(ref1).not_to eq(ref2)
15
+ end
16
+ end
17
+ context 'same command-instances' do
18
+ let(:command) { [:create, {"id" => 1}] }
19
+ let(:ref1) { BatchReference.new(command) }
20
+ let(:ref2) { BatchReference.new(command) }
21
+
22
+ it 'is equal' do
23
+ expect(ref1).to eq(ref2)
24
+ end
25
+ context 'same after_submit block' do
26
+ let(:block) { Proc.new { | |} }
27
+ before do
28
+ ref1.after_submit(&block)
29
+ ref2.after_submit(&block)
30
+ end
31
+
32
+ it 'is equal' do
33
+ expect(ref1).to eq(ref2)
34
+ end
35
+ end
36
+ context 'different after_submit block' do
37
+ let(:block1) { Proc.new { | |} }
38
+ let(:block2) { Proc.new { | |} }
39
+ before do
40
+ ref1.after_submit(&block1)
41
+ ref2.after_submit(&block2)
42
+ end
43
+
44
+ it 'is equal' do
45
+ expect(ref1).not_to eq(ref2)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,326 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ module Neography
5
+ module Composable
6
+ describe Batch do
7
+ let(:neo) { Neography::Rest.new }
8
+ describe '#new' do
9
+ context 'without block' do
10
+ let(:batch) { Batch.new(neo) }
11
+
12
+ it 'is equal unit' do
13
+ expect(batch).to eq(Batch.unit())
14
+ end
15
+ end
16
+ context 'with block containing one command' do
17
+ let(:command) { [:command] }
18
+ let(:batch) do
19
+ Batch.new(neo) do |b|
20
+ b << command
21
+ end
22
+
23
+ it 'is equal batch with one command added' do
24
+ other_batch = Batch.new(neo)
25
+ other_batch << command
26
+ expect(batch).to eq(other_batch)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ describe '==' do
32
+ context 'two empty batches' do
33
+ let(:empty_batch) { Batch.new(neo) }
34
+ let(:another_empty_batch) { Batch.new(neo) }
35
+
36
+ it 'are equal' do
37
+ expect(empty_batch).to eq(another_empty_batch)
38
+ end
39
+ end
40
+ context 'batch and something else' do
41
+ let(:batch) { Batch.new(neo) }
42
+ let(:something_different) { [] }
43
+
44
+ it 'are different' do
45
+ expect(batch).not_to eq(something_different)
46
+ end
47
+ end
48
+ context 'two batches with same command instances' do
49
+ let(:command) { [:command] }
50
+ let(:batch) { Batch.new(neo) { |b| b << command } }
51
+ let(:another_batch) { Batch.new(neo) { |b| b << command } }
52
+
53
+ it 'are equal' do
54
+ expect(batch).to eq(another_batch)
55
+ end
56
+ end
57
+ context 'two batches with different command instances' do
58
+ let(:batch) { Batch.new(neo) { |b| b << [:command] } }
59
+ let(:another_batch) { Batch.new(neo) { |b| b << [:command] } }
60
+
61
+ it 'are different' do
62
+ expect(batch).not_to eq(another_batch)
63
+ end
64
+ end
65
+ context 'batch with empty command and batch with none-empty command' do
66
+ let(:empty_cmd_batch) { Batch.new(neo) { |b| b << [] } }
67
+ let(:batch) { Batch.new(neo) { |b| b << [:command] } }
68
+
69
+ it 'are different' do
70
+ expect(batch).not_to eq(empty_cmd_batch)
71
+ expect(empty_cmd_batch).not_to eq(batch)
72
+ end
73
+ end
74
+ context 'empty batch and batch with one command' do
75
+ let(:empty_batch) { Batch.new(neo) }
76
+ let(:batch) { Batch.new(neo) { |b| b << [:command] } }
77
+
78
+ it 'are different' do
79
+ expect(batch).not_to eq(empty_batch)
80
+ expect(empty_batch).not_to eq(batch)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#bind' do
86
+ context "batch" do
87
+ let(:command) { [[:create_node, {'id' => 7}]] }
88
+ let(:batch) { Batch.new(neo) { |b| b << command } }
89
+ context 'with unit' do
90
+ let(:unit) { Batch.unit() }
91
+
92
+ it 'is equal batch' do
93
+ expect(unit.bind(batch)).to eq(batch)
94
+ end
95
+ end
96
+ end
97
+ context 'unit' do
98
+ let(:unit) { Batch.unit() }
99
+ context 'with batch' do
100
+ let(:command) { [[:create_node, {'id' => 7}]] }
101
+ let(:batch) { Batch.new(neo) { |b| b << command } }
102
+
103
+ it 'is equal batch' do
104
+ expect(unit.bind(batch)).to eq(batch)
105
+ end
106
+ end
107
+ end
108
+ context 'three batches' do
109
+ let(:command1) { [:create_node, {'id' => 7}] }
110
+ let(:command2) { [:create_unique_node, {'id' => 8}] }
111
+ let(:command3) { [:create_node, {'id' => 9}] }
112
+ let(:batch1) { Batch.new(neo) { |b| b << command1 } }
113
+ let(:batch2) { Batch.new(neo) { |b| b << command2 } }
114
+ let(:batch3) { Batch.new(neo) { |b| b << command3 } }
115
+
116
+ context 'once chained and once inner bound' do
117
+ let(:chained_batch) { batch3.bind(batch1).bind(batch2) }
118
+ let(:inner_bound_batch) { batch3.bind(batch1.bind(batch2)) }
119
+
120
+ it "are equal" do
121
+ expect(chained_batch).to eq(inner_bound_batch)
122
+ end
123
+ end
124
+ end
125
+ context 'two batches containing commands that reference into other batch' do
126
+ let(:two_batches) do
127
+ batch1 = Batch.new(neo)
128
+ batch2 = Batch.new(neo)
129
+
130
+ ref11 = batch1 << [:create_node, {'id' => 1}]
131
+ ref12 = batch1 << [:create_node, {'id' => 2}]
132
+ ref21 = batch2 << [:create_node, {'id' => 3}]
133
+ ref22 = batch2 << [:create_node, {'id' => 4}]
134
+
135
+ batch1 << [:create_relationship, ref11, ref22, {}]
136
+ batch2 << [:create_relationship, ref21, ref22, {}]
137
+ [batch1, batch2]
138
+ end
139
+ let(:super_batch) { two_batches[1].bind(two_batches[0]) }
140
+
141
+ describe "#submit" do
142
+
143
+ it "updates references" do
144
+ neo.should_receive(:batch).with do |*commands|
145
+ commands[0].should == [:create_node, {'id' => 3}]
146
+ commands[1].should == [:create_node, {'id' => 4}]
147
+ commands[2].should == [:create_relationship, "{0}", "{1}", {}]
148
+ commands[3].should == [:create_node, {'id' => 1}]
149
+ commands[4].should == [:create_node, {'id' => 2}]
150
+ commands[5].should == [:create_relationship, "{3}", "{1}", {}]
151
+ end.and_return([])
152
+
153
+ super_batch.submit()
154
+ end
155
+ end
156
+ end
157
+ end
158
+ describe '#find_reference' do
159
+ let(:batch) { Batch.new(neo) }
160
+ context 'with three commands' do
161
+ let(:command1) { [:create_node, {'id' => 7}] }
162
+ let(:command2) { [:create_node, {'id' => 8}] }
163
+ let(:command3) { [:create_relationship, ref1, ref2, {}] }
164
+ let!(:ref1) { batch << command1 }
165
+ let!(:ref2) { batch << command2 }
166
+ let!(:ref3) { batch << command3 }
167
+
168
+ context 'when predicate matches one command' do
169
+ let!(:result) { batch.find_reference { |c| c == command2 } }
170
+
171
+ it 'returns one reference' do
172
+ expect(result).to have(1).item
173
+ end
174
+ it 'returns matching reference' do
175
+ expect(result).to include(ref2)
176
+ end
177
+ end
178
+
179
+ context 'when predicate does not match' do
180
+ let!(:result) { batch.find_reference { |c| false } }
181
+ it 'returns no reference' do
182
+ expect(result).to be_empty
183
+ end
184
+ end
185
+
186
+ context 'when no predicate specified' do
187
+ let!(:result) { batch.find_reference }
188
+ it 'returns all references' do
189
+ expect(result).to have(3).items
190
+ end
191
+ end
192
+ end
193
+ end
194
+ describe '<<' do
195
+ context 'with command' do
196
+ let(:command) { [:create_node] }
197
+ it 'behaves like add command' do
198
+ batch_with_add = Batch.new(neo)
199
+ batch = Batch.new(neo)
200
+
201
+ batch_with_add.add(command)
202
+ batch << command
203
+
204
+ expect(batch).to eq(batch_with_add)
205
+ end
206
+ end
207
+ context 'with batch' do
208
+ let(:another_batch) { Batch.new(neo) { |b| b << [:create_node] } }
209
+ it 'behaves like bind batch' do
210
+ batch_with_bind = Batch.new(neo)
211
+ batch = Batch.new(neo)
212
+
213
+ batch_with_bind.bind(another_batch)
214
+ batch << another_batch
215
+
216
+ expect(batch).to eq(batch_with_bind)
217
+ end
218
+ end
219
+ end
220
+
221
+ describe '#add' do
222
+ context "subclassed batch class" do
223
+ class SubclassedBatch < Batch
224
+ end
225
+ let(:command1) { [:create_node] }
226
+ let(:command2) { [:create_relationship] }
227
+ let(:batch) { Batch.new { |b| b << command1 } }
228
+ let(:subclassed_batch) { SubclassedBatch.new(neo) { |b| b << command2 } }
229
+
230
+ it "combines batches" do
231
+ expected_batch = Batch.new(neo) do |b|
232
+ b << command1
233
+ b << command2
234
+ end
235
+
236
+ result = batch.add(subclassed_batch)
237
+ expect(result).to eq(expected_batch)
238
+ end
239
+ end
240
+ context 'element that does not respond to :each' do
241
+ it 'raises StandardError' do
242
+ -> { subject.add(1) }.should raise_exception(StandardError)
243
+ end
244
+ end
245
+ end
246
+
247
+ describe '#submit' do
248
+ let(:batch) { Batch.new(neo) }
249
+ context 'with one added command' do
250
+ let(:command) { [:create_node, {'id' => 1}] }
251
+ before { batch.add(command) }
252
+
253
+ it 'calls neography-batch with added command' do
254
+ neo.should_receive(:batch).with(command).and_return([])
255
+
256
+ batch.submit()
257
+ end
258
+ context '#submit' do
259
+ before { batch.submit() }
260
+
261
+ it 'does nothing the second time' do
262
+ neo.should_not_receive(:batch)
263
+
264
+ batch.submit()
265
+ end
266
+ end
267
+ end
268
+ context 'with a relationship between two commands' do
269
+ let!(:ref_1) { batch << [:create_node] }
270
+ let!(:ref_2) { batch << [:create_node] }
271
+ let!(:relation) { batch << [:create_relationship, ref_2, ref_1] }
272
+
273
+ it 'resolves references to preceding commands' do
274
+ neo.should_receive(:batch).with do |*commands|
275
+ relationship_cmd = commands.select { |r| r[0]==:create_relationship }.first
276
+ relationship_cmd[1].should == "{1}"
277
+ expect(relationship_cmd[1]).to eq("{1}")
278
+ expect(relationship_cmd[2]).to eq("{0}")
279
+ end.and_return([])
280
+
281
+ batch.submit()
282
+ end
283
+ end
284
+ context 'with commands that trigger a server error' do
285
+ before do
286
+ # this provokes a server error, because the second create_unique_node cannot be reference in create_relationship
287
+ batch << [:create_unique_node, "test", "id", "1", {}]
288
+ batch << [:create_unique_node, "test", "id", "2", {}]
289
+ batch << [:create_relationship, "test", "{0}", "{1}", {}]
290
+ end
291
+ it 'raises StandardError' do
292
+ ->() { batch.submit() }.should raise_error(StandardError)
293
+ end
294
+ end
295
+ context 'with two after_submit handlers' do
296
+ let(:command1) { [:create_node, {'id' => 1}] }
297
+ let!(:reference1) { batch << command1 }
298
+ let(:command2) { [:create_node, {'id' => 2}] }
299
+ let!(:reference2) { batch << command2 }
300
+ it 'notifies reference1' do
301
+ node = nil
302
+ reference1.after_submit do |n|
303
+ node = n
304
+ end
305
+
306
+ batch.submit()
307
+
308
+ expect(node).not_to be_nil
309
+ expect(node['data']['id']).to be(command1[1]['id'])
310
+ end
311
+ it 'notifies reference2' do
312
+ node = nil
313
+ reference2.after_submit do |n|
314
+ node = n
315
+ end
316
+
317
+ batch.submit()
318
+
319
+ expect(node).not_to be_nil
320
+ expect(node['data']['id']).to be(command2[1]['id'])
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
@@ -1 +1,10 @@
1
- require_relative '../lib/neography-batch'
1
+ require_relative '../lib/neography-batch'
2
+
3
+ RSpec.configure do |config|
4
+ config.before(:each) do
5
+ neo = Neography::Rest.new
6
+ neo.batch(
7
+ [:execute_query, "START n = node(*) MATCH n-[r]-() WHERE ID(n) > 0 DELETE r"],
8
+ [:execute_query, "START n = node(*) WHERE ID(n) > 0 DELETE n"])
9
+ end
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neography-batch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-22 00:00:00.000000000 Z
12
+ date: 2013-06-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: neography
@@ -69,15 +69,20 @@ files:
69
69
  - .gitignore
70
70
  - Gemfile
71
71
  - Gemfile.lock
72
+ - LICENSE
72
73
  - README.md
73
74
  - Rakefile
74
75
  - lib/neography-batch.rb
75
76
  - lib/neography-batch/batch.rb
76
77
  - lib/neography-batch/batch_reference.rb
78
+ - lib/neography-batch/neography_context.rb
77
79
  - neography-batch.gemspec
78
80
  - publish.sh
79
- - spec/batch_reference_spec.rb
80
- - spec/batch_spec.rb
81
+ - spec/examples/read_and_write_examples_spec.rb
82
+ - spec/examples/references_and_notification_examples_spec.rb
83
+ - spec/examples/showcase_spec.rb
84
+ - spec/lib/batch_reference_spec.rb
85
+ - spec/lib/batch_spec.rb
81
86
  - spec/spec_helper.rb
82
87
  homepage: https://github.com/Enceradeira/neography-batch
83
88
  licenses: []
@@ -1,33 +0,0 @@
1
- require "spec_helper"
2
-
3
- module Neography
4
- module Composable
5
- describe BatchReference do
6
- describe "==" do
7
- specify do
8
- ref1 = BatchReference.new([:create, {"id" => 1}])
9
- ref2 = BatchReference.new([:create, {"id" => 1}])
10
- (ref1==ref2).should be_false
11
- end
12
- specify do
13
- command = [:create, {"id" => 1}]
14
- ref1 = BatchReference.new(command)
15
- ref2 = BatchReference.new(command)
16
- (ref1==ref2).should be_true
17
- end
18
- specify do
19
- command = [:create, {"id" => 1}]
20
- ref1 = BatchReference.new(command)
21
- ref1.after_submit do
22
- puts "Do this"
23
- end
24
- ref2 = BatchReference.new(command)
25
- ref2.after_submit do
26
- puts "Do something else"
27
- end
28
- (ref1==ref2).should be_false
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,336 +0,0 @@
1
- require_relative 'spec_helper'
2
-
3
-
4
- module Neography
5
- module Composable
6
- describe Batch do
7
-
8
- def create_batches(command1, command2, command3)
9
- batch1 = Batch.new do |b|
10
- b<<command1
11
- end
12
-
13
- batch2 = Batch.new do |b|
14
- b<<command2
15
- end
16
-
17
- batch3 = Batch.new do |b|
18
- b<<command3
19
- end
20
- return batch1, batch2, batch3
21
- end
22
-
23
- let(:db) { Neography::Rest.new }
24
- subject { Batch.new(db) }
25
-
26
- describe "new" do
27
- it "should create unit when no block provided" do
28
- Batch.new.should == Batch.unit()
29
- end
30
- it "should call block with itself when block is provided" do
31
- command = [:command]
32
- batch_configured_without_block = Batch.new
33
- batch_configured_without_block << command
34
-
35
- batch_with_block = Batch.new do |b|
36
- b << command
37
- end
38
-
39
- batch_with_block.should == batch_configured_without_block
40
- end
41
- end
42
-
43
- describe "==" do
44
- specify { (Batch.new==Batch.new).should be_true }
45
- specify { (Batch.new==[]).should be_false }
46
- specify do
47
- command1 = [:command_1]
48
- command2 = [:command_2]
49
- batch1 = Batch.new do |b|
50
- b << command1
51
- b << command2
52
- end
53
- batch2 = Batch.new do |b|
54
- b << command1
55
- b << command2
56
- end
57
- (batch1==batch2).should be_true
58
- end
59
- specify do
60
- batch1 = Batch.new do |b|
61
- b << [:command_1]
62
- b << [:command_2]
63
- end
64
- batch2 = Batch.new do |b|
65
- b << [:command_2]
66
- b << [:command_1]
67
- end
68
- (batch1==batch2).should be_false
69
- end
70
- specify do
71
- batch1 = Batch.new do |b|
72
- b << [:command_1, {:id => 7}]
73
- b << [:command_2, {:id => 9}]
74
- end
75
- batch2 = Batch.new do |b|
76
- b << [:command_1, {:id => 7}]
77
- b << [:command_2, {:id => 8}]
78
- end
79
- (batch1==batch2).should be_false
80
- end
81
- specify do
82
- batch1 = Batch.new { |b| b << [:command_1] }
83
- batch2 = Batch.new { |b| b << [:command_2] }
84
- (batch1==batch2).should be_false
85
- end
86
- specify do
87
- batch1 = Batch.new { |b| b << [] }
88
- batch2 = Batch.new { |b| b << [:command_2] }
89
- (batch1==batch2).should be_false
90
- end
91
- specify do
92
- batch1 = Batch.new
93
- batch2 = Batch.new { |b| b << [:command_2] }
94
- (batch1==batch2).should be_false
95
- end
96
- specify do
97
- batch1 = Batch.new { |b| b << [:command_1] }
98
- batch2 = Batch.new { |b| b << [] }
99
- (batch1==batch2).should be_false
100
- end
101
- end
102
-
103
- describe "bind" do
104
- let(:command1) { [:create_node, {"id" => 7}] }
105
- let(:command2) { [:create_unique_node, {"id" => 8}] }
106
- let(:command3) { [:create_node, {"id" => 9}] }
107
- it "on unit with f should be equal f" do
108
- batch1, _, _ = create_batches(command1, command2, command3)
109
-
110
- Batch.unit().bind(batch1).should == batch1
111
- end
112
-
113
- it "with unit should be equal Batch" do
114
- batch1, _, _ = create_batches(command1, command2, command3)
115
-
116
- batch1.bind(Batch.unit()).should == batch1
117
- end
118
-
119
- it "chained should be equal to bind with inner binds" do
120
- batch1, batch2, batch3 = create_batches(command1, command2, command3)
121
- result1 = batch3.bind(batch1).bind(batch2)
122
-
123
- batch1, batch2, batch3 = create_batches(command1, command2, command3)
124
- f = ->() { batch1 }
125
- g = ->() { batch2 }
126
- result2 = batch3.bind(batch1.bind(batch2))
127
-
128
- result1.should == result2
129
- end
130
- describe "and submit" do
131
- it "should combine separate batches into one batch" do
132
- batch1 = Batch.new(db)
133
- ref11 = batch1 << [:create_node, {"id" => 1}]
134
- ref12 = batch1 << [:create_node, {"id" => 2}]
135
- batch1 << [:create_relationship, ref11, ref12, {}]
136
-
137
- batch2 = Batch.new(db)
138
- ref21 = batch2 << [:create_node, {"id" => 3}]
139
- ref22 = batch2 << [:create_node, {"id" => 4}]
140
- batch2 << [:create_relationship, ref21, ref22, {}]
141
-
142
- batch = batch2.bind(batch1)
143
-
144
- db.should_receive(:batch).with do |*commands|
145
- commands[0].should == [:create_node, {"id" => 3}]
146
- commands[1].should == [:create_node, {"id" => 4}]
147
- commands[2].should == [:create_relationship, "{0}", "{1}", {}]
148
- commands[3].should == [:create_node, {"id" => 1}]
149
- commands[4].should == [:create_node, {"id" => 2}]
150
- commands[5].should == [:create_relationship, "{3}", "{4}", {}]
151
- end.and_return([])
152
-
153
- batch.submit()
154
- end
155
- end
156
- end
157
- describe "find_reference" do
158
- it "should return reference when command is found" do
159
- ref1 = subject << [:create_node, {"id" => 7}]
160
- ref2 = subject << [:create_node, {"id" => 8}]
161
- subject << [:create_relationship, ref2, ref1, {}]
162
-
163
- result = subject.find_reference { |c| c[0] == :create_node && c[1]["id"] == 8 }
164
- result.should have(1).item
165
- result.should include(ref2)
166
- end
167
-
168
- it "should return empty when command is not found" do
169
- result = subject.find_reference { |c| c[0] == :create_node && c[1]["id"] == 8 }
170
- result.should be_empty
171
- end
172
-
173
- it "should return all reference when no predicate specified" do
174
- ref1 = subject << [:create_node, {"id" => 7}]
175
- ref2 = subject << [:create_node, {"id" => 8}]
176
-
177
- result = subject.find_reference()
178
- result.should have(2).item
179
- end
180
- end
181
- describe "<<" do
182
- it "should be the same as add when command is argument" do
183
- command = [:create_node]
184
- batch_used_with_add = Batch.new
185
- batch_used_with_add.add command
186
-
187
- subject << command
188
-
189
- subject.should == batch_used_with_add
190
- end
191
- it "should be the same as bind when command is Batch" do
192
- another_batch = Batch.new do |b|
193
- b << [:create_node]
194
- end
195
- subject << [:create_node]
196
-
197
- subject << another_batch
198
-
199
- db.should_receive(:batch) do |*commands|
200
- commands.should have(2).items
201
- end.and_return([])
202
- subject.submit()
203
- end
204
- end
205
- describe "add" do
206
- context "with subclassed batch class" do
207
- class SubclassedBatch < Batch
208
- end
209
- let(:batch) { Batch.new }
210
- let(:subclassed_batch) { SubclassedBatch.new }
211
-
212
- context "combines commands" do
213
- before do
214
- batch << [:create_node, {"id" => 2}]
215
- subclassed_batch << [:create_node, {"id" => 45}]
216
- end
217
- it "combines commands" do
218
- batch.add(subclassed_batch)
219
- batch.should have(2).commands
220
- end
221
- end
222
-
223
- end
224
- end
225
- describe "add and submit" do
226
- it "should raise exception when added element doesn't respond to :each" do
227
- -> { subject.add(1) }.should raise_exception(StandardError)
228
- end
229
-
230
- it "should add command to be submitted later" do
231
- command = [:create_node]
232
- subject.add(command)
233
-
234
- db.should_receive(:batch).with(command).and_return([])
235
-
236
- subject.submit()
237
- end
238
-
239
- it "should resolve references to preceding commands" do
240
- jim = subject << [:create_node]
241
- john = subject << [:create_node]
242
- subject << [:create_relationship, john, jim]
243
-
244
- db.should_receive(:batch).with do |*commands|
245
- relationship_cmd = commands.last
246
- relationship_cmd[1].should == "{1}" # john was resolved to index where john was created
247
- relationship_cmd[2].should == "{0}" # jim was resolved to index where john was created
248
- end.and_return([])
249
-
250
- subject.submit()
251
- end
252
-
253
- context "list contains 2 commands" do
254
- before do
255
- @john = subject.add [:create_node]
256
- @markus = subject.add [:create_node]
257
- end
258
- context "and another command is added" do
259
- let(:another_command) { [:create_relationship] }
260
- before do
261
- subject.add(another_command)
262
- end
263
- it "should contain 3 commands" do
264
- db.should_receive(:batch).with do |*commands|
265
- commands.should have(3).items
266
- end.and_return([])
267
-
268
- subject.submit()
269
- end
270
- it "should append command" do
271
- db.should_receive(:batch).with do |*commands|
272
- commands.last.should == another_command
273
- end.and_return([])
274
-
275
- subject.submit()
276
- end
277
- end
278
- end
279
- end
280
- describe "submit" do
281
- it "should raise exception when server returns error" do
282
- # this provokes a server error, because the second create_unique_node cannot be reference in create_relationship
283
- subject << [:create_unique_node, "test", "id", "1", {}]
284
- subject << [:create_unique_node, "test", "id", "2", {}]
285
- subject << [:create_relationship, "test", "{0}", "{1}", {}]
286
-
287
- ->() { subject.submit() }.should raise_error(StandardError)
288
- end
289
- it "should notify reference handler" do
290
- node_1_result = nil
291
- node_2_result = nil
292
- ref1 = subject << [:create_node, {"id" => 1}]
293
- ref2 = subject << [:create_node, {"id" => 2}]
294
- ref1.after_submit do |node|
295
- node_1_result = node
296
- end
297
- ref2.after_submit do |node|
298
- node_2_result = node
299
- end
300
-
301
- subject.submit()
302
-
303
- node_1_result.should_not be_nil
304
- node_2_result.should_not be_nil
305
- node_1_result["data"]["id"].should == 1
306
- node_2_result["data"]["id"].should == 2
307
- end
308
-
309
- it "should reset state of batch" do
310
- subject << [:create_node, {"id" => 1}]
311
- subject.submit()
312
-
313
- db.should_not_receive(:batch)
314
- result = subject.submit()
315
- result.should be_empty
316
- end
317
-
318
- context "one create_node added" do
319
- before { subject << [:create_node, {}] }
320
- it "should return created node" do
321
- result = subject.submit()
322
- result.should have(1).items
323
- end
324
- it "should create-node on Db" do
325
- result = subject.submit()
326
-
327
- node = result.first
328
- node_id = db.get_id(node)
329
- count = db.execute_query("start s=node(#{node_id}) return count(*)")
330
- count["data"][0][0].should == 1
331
- end
332
- end
333
- end
334
- end
335
- end
336
- end