neography-batch 1.0.3 → 1.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.
@@ -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