ashikawa-core 0.6.0 → 0.7.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 (68) hide show
  1. data/.rspec +0 -1
  2. data/.travis.yml +2 -0
  3. data/CONTRIBUTING.md +14 -29
  4. data/Gemfile.devtools +9 -10
  5. data/README.md +30 -9
  6. data/Rakefile +1 -1
  7. data/ashikawa-core.gemspec +9 -8
  8. data/config/flay.yml +2 -2
  9. data/config/flog.yml +1 -1
  10. data/config/roodi.yml +4 -5
  11. data/config/site.reek +40 -16
  12. data/config/yardstick.yml +1 -1
  13. data/lib/ashikawa-core/collection.rb +109 -22
  14. data/lib/ashikawa-core/connection.rb +42 -110
  15. data/lib/ashikawa-core/cursor.rb +13 -6
  16. data/lib/ashikawa-core/database.rb +67 -17
  17. data/lib/ashikawa-core/document.rb +41 -10
  18. data/lib/ashikawa-core/edge.rb +50 -0
  19. data/lib/ashikawa-core/exceptions/client_error/bad_syntax.rb +24 -0
  20. data/lib/ashikawa-core/exceptions/{collection_not_found.rb → client_error/resource_not_found/collection_not_found.rb} +3 -1
  21. data/lib/ashikawa-core/exceptions/{document_not_found.rb → client_error/resource_not_found/document_not_found.rb} +3 -1
  22. data/lib/ashikawa-core/exceptions/{index_not_found.rb → client_error/resource_not_found/index_not_found.rb} +3 -1
  23. data/lib/ashikawa-core/exceptions/client_error/resource_not_found.rb +25 -0
  24. data/lib/ashikawa-core/exceptions/client_error.rb +23 -0
  25. data/lib/ashikawa-core/exceptions/server_error/json_error.rb +25 -0
  26. data/lib/ashikawa-core/exceptions/server_error.rb +23 -0
  27. data/lib/ashikawa-core/figure.rb +59 -2
  28. data/lib/ashikawa-core/index.rb +23 -7
  29. data/lib/ashikawa-core/query.rb +10 -10
  30. data/lib/ashikawa-core/request_preprocessor.rb +49 -0
  31. data/lib/ashikawa-core/response_preprocessor.rb +111 -0
  32. data/lib/ashikawa-core/version.rb +1 -1
  33. data/lib/ashikawa-core.rb +0 -1
  34. data/spec/acceptance/basic_spec.rb +61 -22
  35. data/spec/acceptance/index_spec.rb +11 -4
  36. data/spec/acceptance/query_spec.rb +4 -1
  37. data/spec/acceptance/spec_helper.rb +0 -2
  38. data/spec/acceptance_auth/spec_helper.rb +0 -2
  39. data/spec/fixtures/collections/60768679-count.json +13 -0
  40. data/spec/fixtures/collections/60768679-figures.json +35 -0
  41. data/spec/fixtures/collections/60768679-properties-volatile.json +12 -0
  42. data/spec/fixtures/collections/60768679-properties.json +12 -0
  43. data/spec/fixtures/collections/{4588.json → 60768679.json} +2 -2
  44. data/spec/fixtures/collections/all.json +5 -5
  45. data/spec/fixtures/cursor/26011191-2.json +1 -1
  46. data/spec/fixtures/cursor/26011191.json +1 -1
  47. data/spec/fixtures/documents/example_1-137249191.json +6 -0
  48. data/spec/fixtures/documents/new-example_1-137249191.json +6 -0
  49. data/spec/setup/arangodb.sh +1 -1
  50. data/spec/unit/collection_spec.rb +117 -42
  51. data/spec/unit/connection_spec.rb +161 -61
  52. data/spec/unit/cursor_spec.rb +39 -12
  53. data/spec/unit/database_spec.rb +119 -19
  54. data/spec/unit/document_spec.rb +4 -2
  55. data/spec/unit/edge_spec.rb +54 -0
  56. data/spec/unit/exception_spec.rb +36 -8
  57. data/spec/unit/figure_spec.rb +37 -11
  58. data/spec/unit/index_spec.rb +1 -1
  59. data/spec/unit/query_spec.rb +18 -18
  60. data/spec/unit/spec_helper.rb +4 -13
  61. data/tasks/adjustments.rake +3 -2
  62. metadata +59 -32
  63. data/lib/ashikawa-core/exceptions/unknown_path.rb +0 -15
  64. data/spec/fixtures/collections/4590-properties.json +0 -9
  65. data/spec/fixtures/collections/4590.json +0 -8
  66. data/spec/fixtures/collections/73482-figures.json +0 -23
  67. data/spec/fixtures/documents/4590-333.json +0 -5
  68. data/spec/fixtures/documents/new-4590-333.json +0 -5
@@ -10,31 +10,31 @@ describe Ashikawa::Core::Cursor do
10
10
  end
11
11
 
12
12
  it "should create a cursor for a non-complete batch" do
13
- my_cursor = subject.new @database, server_response("/cursor/26011191")
14
- my_cursor.id.should == 26011191
13
+ my_cursor = subject.new @database, server_response("cursor/26011191")
14
+ my_cursor.id.should == "26011191"
15
15
  my_cursor.length.should == 5
16
16
  end
17
17
 
18
18
  it "should create a cursor for the last batch" do
19
- my_cursor = subject.new @database, server_response("/cursor/26011191-3")
19
+ my_cursor = subject.new @database, server_response("cursor/26011191-3")
20
20
  my_cursor.id.should be_nil
21
21
  my_cursor.length.should == 5
22
22
  end
23
23
 
24
24
  describe "existing cursor" do
25
25
  subject { Ashikawa::Core::Cursor.new @database,
26
- server_response("/cursor/26011191")
26
+ server_response("cursor/26011191")
27
27
  }
28
28
 
29
- it "should iterate over all documents of a cursor" do
29
+ it "should iterate over all documents of a cursor when given a block" do
30
30
  first = true
31
31
 
32
- @database.stub(:send_request).with("/cursor/26011191", :put => {}) do
32
+ @database.stub(:send_request).with("cursor/26011191", :put => {}) do
33
33
  if first
34
34
  first = false
35
- server_response("/cursor/26011191-2")
35
+ server_response("cursor/26011191-2")
36
36
  else
37
- server_response("/cursor/26011191-3")
37
+ server_response("cursor/26011191-3")
38
38
  end
39
39
  end
40
40
  @database.should_receive(:send_request).twice
@@ -45,9 +45,36 @@ describe Ashikawa::Core::Cursor do
45
45
  subject.each { |document| }
46
46
  end
47
47
 
48
+ it "should return an enumerator to go over all documents of a cursor when given no block" do
49
+ pending "This fails on 1.8.7 because of an old backports version" if RUBY_VERSION == "1.8.7"
50
+
51
+ first = true
52
+
53
+ @database.stub(:send_request).with("cursor/26011191", :put => {}) do
54
+ if first
55
+ first = false
56
+ server_response("cursor/26011191-2")
57
+ else
58
+ server_response("cursor/26011191-3")
59
+ end
60
+ end
61
+ @database.should_receive(:send_request).twice
62
+
63
+ Ashikawa::Core::Document.stub(:new)
64
+ Ashikawa::Core::Document.should_receive(:new).exactly(5).times
65
+
66
+ enumerator = subject.each
67
+ enumerator.next
68
+ enumerator.next
69
+ enumerator.next
70
+ enumerator.next
71
+ enumerator.next
72
+ expect { enumerator.next }.to raise_exception(StopIteration)
73
+ end
74
+
48
75
  it "should be deletable" do
49
76
  @database.stub(:send_request)
50
- @database.should_receive(:send_request).with("/cursor/26011191",
77
+ @database.should_receive(:send_request).with("cursor/26011191",
51
78
  :delete => {})
52
79
 
53
80
  subject.delete
@@ -56,12 +83,12 @@ describe Ashikawa::Core::Cursor do
56
83
  it "should be enumerable" do
57
84
  first = true
58
85
 
59
- @database.stub(:send_request).with("/cursor/26011191", :put => {}) do
86
+ @database.stub(:send_request).with("cursor/26011191", :put => {}) do
60
87
  if first
61
88
  first = false
62
- server_response("/cursor/26011191-2")
89
+ server_response("cursor/26011191-2")
63
90
  else
64
- server_response("/cursor/26011191-3")
91
+ server_response("cursor/26011191-3")
65
92
  end
66
93
  end
67
94
  @database.should_receive(:send_request).twice
@@ -15,20 +15,78 @@ describe Ashikawa::Core::Database do
15
15
  @connection.stub(:host) { "localhost" }
16
16
  @connection.stub(:port) { 8529 }
17
17
 
18
- database = subject.new @connection
18
+ database = subject.new do |config|
19
+ config.connection = @connection
20
+ end
19
21
  database.host.should == "localhost"
20
22
  database.port.should == 8529
21
23
  end
22
24
 
23
25
  it "should initialize with a connection string" do
24
- Ashikawa::Core::Connection.stub(:new).with("http://localhost:8529").and_return(double())
25
- Ashikawa::Core::Connection.should_receive(:new).with("http://localhost:8529")
26
+ Ashikawa::Core::Connection.stub(:new).with("http://localhost:8529", {
27
+ :logger => nil,
28
+ :adapter => nil
29
+ }).and_return(double())
30
+ Ashikawa::Core::Connection.should_receive(:new).with("http://localhost:8529", {
31
+ :logger => nil,
32
+ :adapter => nil
33
+ })
34
+
35
+ database = subject.new do |config|
36
+ config.url = "http://localhost:8529"
37
+ end
38
+ end
39
+
40
+ it "should initialize with a connection string and logger" do
41
+ logger = double
42
+ Ashikawa::Core::Connection.stub(:new).with("http://localhost:8529", {
43
+ :logger => logger,
44
+ :adapter => nil
45
+ }).and_return(double())
46
+ Ashikawa::Core::Connection.should_receive(:new).with("http://localhost:8529", {
47
+ :logger => logger,
48
+ :adapter => nil
49
+ })
50
+
51
+ database = subject.new do |config|
52
+ config.url = "http://localhost:8529"
53
+ config.logger = logger
54
+ end
55
+ end
26
56
 
27
- database = subject.new "http://localhost:8529"
57
+ it "should initialize with a connection string and adapter" do
58
+ adapter = double
59
+ Ashikawa::Core::Connection.stub(:new).with("http://localhost:8529", {
60
+ :logger => nil,
61
+ :adapter => adapter
62
+ }).and_return(double())
63
+ Ashikawa::Core::Connection.should_receive(:new).with("http://localhost:8529", {
64
+ :logger => nil,
65
+ :adapter => adapter
66
+ })
67
+
68
+ database = subject.new do |config|
69
+ config.url = "http://localhost:8529"
70
+ config.adapter = adapter
71
+ end
72
+ end
73
+
74
+ it "should throw an argument error when neither url nor connection was provided" do
75
+ adapter = double
76
+ logger = double
77
+
78
+ expect {
79
+ database = subject.new do |config|
80
+ config.adapter = adapter
81
+ config.logger = logger
82
+ end
83
+ }.to raise_error(ArgumentError, /either an url or a connection/)
28
84
  end
29
85
 
30
86
  it "should create a query" do
31
- database = subject.new @connection
87
+ database = subject.new do |config|
88
+ config.connection = @connection
89
+ end
32
90
 
33
91
  mock Ashikawa::Core::Query
34
92
  Ashikawa::Core::Query.stub(:new)
@@ -38,7 +96,10 @@ describe Ashikawa::Core::Database do
38
96
  end
39
97
 
40
98
  describe "initialized database" do
41
- subject { Ashikawa::Core::Database.new @connection }
99
+ subject { Ashikawa::Core::Database.new do |config|
100
+ config.connection = @connection
101
+ end
102
+ }
42
103
 
43
104
  it "should delegate authentication to the connection" do
44
105
  @connection.should_receive(:authenticate_with).with({ :username => "user", :password => "password" })
@@ -48,44 +109,83 @@ describe Ashikawa::Core::Database do
48
109
 
49
110
  it "should fetch all available collections" do
50
111
  @connection.stub(:send_request) {|path| server_response("collections/all") }
51
- @connection.should_receive(:send_request).with("/collection")
112
+ @connection.should_receive(:send_request).with("collection")
52
113
 
53
- Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("/collections/all")["collections"][0])
54
- Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("/collections/all")["collections"][1])
114
+ Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/all")["collections"][0])
115
+ Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/all")["collections"][1])
55
116
 
56
117
  subject.collections.length.should == 2
57
118
  end
58
119
 
120
+ it "should create a non volatile collection by default" do
121
+ @connection.stub(:send_request) { |path| server_response("collections/60768679") }
122
+ @connection.should_receive(:send_request).with("collection",
123
+ :post => { :name => "volatile_collection"})
124
+
125
+ Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/60768679"))
126
+
127
+ subject.create_collection("volatile_collection")
128
+ end
129
+
130
+ it "should create a volatile collection when asked" do
131
+ @connection.stub(:send_request) { |path| server_response("collections/60768679") }
132
+ @connection.should_receive(:send_request).with("collection",
133
+ :post => { :name => "volatile_collection", :isVolatile => true})
134
+
135
+ Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/60768679"))
136
+
137
+ subject.create_collection("volatile_collection", :is_volatile => true)
138
+ end
139
+
140
+ it "should create an edge collection when asked" do
141
+ @connection.stub(:send_request) { |path| server_response("collections/60768679") }
142
+ @connection.should_receive(:send_request).with("collection",
143
+ :post => { :name => "volatile_collection", :type => 3})
144
+
145
+ Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/60768679"))
146
+
147
+ subject.create_collection("volatile_collection", :content_type => :edge)
148
+ end
149
+
59
150
  it "should fetch a single collection if it exists" do
60
- @connection.stub(:send_request) { |path| server_response("collections/4588") }
61
- @connection.should_receive(:send_request).with("/collection/4588")
151
+ @connection.stub(:send_request) { |path| server_response("collections/60768679") }
152
+ @connection.should_receive(:send_request).with("collection/60768679")
153
+
154
+ Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/60768679"))
155
+
156
+ subject.collection(60768679)
157
+ end
158
+
159
+ it "should fetch a single collection with the array syntax" do
160
+ @connection.stub(:send_request) { |path| server_response("collections/60768679") }
161
+ @connection.should_receive(:send_request).with("collection/60768679")
62
162
 
63
- Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("/collections/4588"))
163
+ Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/60768679"))
64
164
 
65
- subject[4588]
165
+ subject[60768679]
66
166
  end
67
167
 
68
168
  it "should create a single collection if it doesn't exist" do
69
169
  @connection.stub :send_request do |path, method|
70
170
  method ||= {}
71
171
  if method.has_key? :post
72
- server_response("collections/4590")
172
+ server_response("collections/60768679")
73
173
  else
74
174
  raise Ashikawa::Core::CollectionNotFoundException
75
175
  end
76
176
  end
77
- @connection.should_receive(:send_request).with("/collection/new_collection")
78
- @connection.should_receive(:send_request).with("/collection", :post => { :name => "new_collection"} )
177
+ @connection.should_receive(:send_request).with("collection/new_collection")
178
+ @connection.should_receive(:send_request).with("collection", :post => { :name => "new_collection"} )
79
179
 
80
- Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/4590"))
180
+ Ashikawa::Core::Collection.should_receive(:new).with(subject, server_response("collections/60768679"))
81
181
 
82
182
  subject['new_collection']
83
183
  end
84
184
 
85
185
  it "should send a request via the connection object" do
86
- @connection.should_receive(:send_request).with("/my/path", :post => { :data => "mydata" })
186
+ @connection.should_receive(:send_request).with("my/path", :post => { :data => "mydata" })
87
187
 
88
- subject.send_request "/my/path", :post => { :data => "mydata" }
188
+ subject.send_request "my/path", :post => { :data => "mydata" }
89
189
  end
90
190
  end
91
191
  end
@@ -6,6 +6,7 @@ describe Ashikawa::Core::Document do
6
6
  let(:raw_data) {
7
7
  {
8
8
  "_id" => "1234567/2345678",
9
+ "_key" => "2345678",
9
10
  "_rev" => "3456789",
10
11
  "first_name" => "The",
11
12
  "last_name" => "Dude"
@@ -21,8 +22,9 @@ describe Ashikawa::Core::Document do
21
22
 
22
23
  it "should initialize data with ID" do
23
24
  document = subject.new database, raw_data
24
- document.id.should == 2345678
25
- document.revision.should == 3456789
25
+ document.id.should == "1234567/2345678"
26
+ document.key.should == "2345678"
27
+ document.revision.should == "3456789"
26
28
  end
27
29
 
28
30
  it "should initialize data without ID" do
@@ -0,0 +1,54 @@
1
+ require 'unit/spec_helper'
2
+ require 'ashikawa-core/edge'
3
+
4
+ describe Ashikawa::Core::Edge do
5
+ let(:database) { double() }
6
+ let(:raw_data) {
7
+ {
8
+ "_id" => "1234567/2345678",
9
+ "_key" => "2345678",
10
+ "_rev" => "3456789",
11
+ "_from" => "7848004/9289796",
12
+ "_to" => "7848004/9355332",
13
+ "first_name" => "The",
14
+ "last_name" => "Dude"
15
+ }
16
+ }
17
+ subject { Ashikawa::Core::Edge }
18
+
19
+ it "should initialize data" do
20
+ document = subject.new(database, raw_data)
21
+ document.id.should == "1234567/2345678"
22
+ document.key.should == "2345678"
23
+ document.revision.should == "3456789"
24
+ end
25
+
26
+ describe "initialized edge" do
27
+ subject { Ashikawa::Core::Edge.new(database, raw_data)}
28
+
29
+ it "should be deletable" do
30
+ database.should_receive(:send_request).with("edge/#{raw_data['_id']}",
31
+ { :delete => {} }
32
+ )
33
+
34
+ subject.delete
35
+ end
36
+
37
+ it "should store changes to the database" do
38
+ database.should_receive(:send_request).with("edge/#{raw_data['_id']}",
39
+ { :put => { "first_name" => "The", "last_name" => "Other" } }
40
+ )
41
+
42
+ subject["last_name"] = "Other"
43
+ subject.save
44
+ end
45
+
46
+ it "should know the ID of the 'from' document" do
47
+ subject.from_id.should == "7848004/9289796"
48
+ end
49
+
50
+ it "should know the ID of the 'to' document" do
51
+ subject.to_id.should == "7848004/9355332"
52
+ end
53
+ end
54
+ end
@@ -1,8 +1,36 @@
1
- require "ashikawa-core/exceptions/document_not_found"
2
- require "ashikawa-core/exceptions/collection_not_found"
3
- require "ashikawa-core/exceptions/index_not_found"
4
1
  require "ashikawa-core/exceptions/no_collection_provided"
5
- require "ashikawa-core/exceptions/unknown_path"
2
+ require "ashikawa-core/exceptions/client_error"
3
+ require "ashikawa-core/exceptions/client_error/bad_syntax"
4
+ require "ashikawa-core/exceptions/client_error/resource_not_found"
5
+ require "ashikawa-core/exceptions/client_error/resource_not_found/document_not_found"
6
+ require "ashikawa-core/exceptions/client_error/resource_not_found/collection_not_found"
7
+ require "ashikawa-core/exceptions/client_error/resource_not_found/index_not_found"
8
+ require "ashikawa-core/exceptions/server_error"
9
+ require "ashikawa-core/exceptions/server_error/json_error"
10
+
11
+ describe Ashikawa::Core::NoCollectionProvidedException do
12
+ it "should have a good explanation" do
13
+ subject.to_s.should include "without a collection"
14
+ end
15
+ end
16
+
17
+ describe Ashikawa::Core::ClientError do
18
+ it "should have a good explanation" do
19
+ Ashikawa::Core::ClientError.new(411).to_s.should include "client"
20
+ end
21
+ end
22
+
23
+ describe Ashikawa::Core::BadSyntax do
24
+ it "should have a good explanation" do
25
+ subject.to_s.should include "syntax"
26
+ end
27
+ end
28
+
29
+ describe Ashikawa::Core::ResourceNotFound do
30
+ it "should have a good explanation" do
31
+ subject.to_s.should include "was not found"
32
+ end
33
+ end
6
34
 
7
35
  describe Ashikawa::Core::DocumentNotFoundException do
8
36
  it "should have a good explanation" do
@@ -22,14 +50,14 @@ describe Ashikawa::Core::IndexNotFoundException do
22
50
  end
23
51
  end
24
52
 
25
- describe Ashikawa::Core::NoCollectionProvidedException do
53
+ describe Ashikawa::Core::ServerError do
26
54
  it "should have a good explanation" do
27
- subject.to_s.should include "without a collection"
55
+ Ashikawa::Core::ServerError.new(511).to_s.should include "server"
28
56
  end
29
57
  end
30
58
 
31
- describe Ashikawa::Core::UnknownPath do
59
+ describe Ashikawa::Core::JsonError do
32
60
  it "should have a good explanation" do
33
- subject.to_s.should include "path is unknown"
61
+ subject.to_s.should include "JSON from the server"
34
62
  end
35
63
  end
@@ -3,26 +3,52 @@ require "ashikawa-core/figure"
3
3
  describe Ashikawa::Core::Figure do
4
4
  let(:raw_figures) {
5
5
  {
6
- "datafiles" => {
7
- "count" => 1
8
- },
9
6
  "alive" => {
10
7
  "size" => 0,
11
8
  "count" => 0
12
9
  },
13
10
  "dead" => {
14
11
  "size" => 2384,
15
- "count" => 149
12
+ "count" => 149,
13
+ "deletion" => 0
14
+ },
15
+ "datafiles" => {
16
+ "count" => 1,
17
+ "fileSize" => 124
18
+ },
19
+ "journals" => {
20
+ "count" => 1,
21
+ "fileSize" => 124
22
+ },
23
+ "shapes" => {
24
+ "count" => 2
16
25
  }
17
26
  }
18
27
  }
19
- subject { Ashikawa::Core::Figure.new raw_figures }
28
+ subject { Ashikawa::Core::Figure.new(raw_figures) }
29
+
30
+ it "should check for the alive figures" do
31
+ subject.alive_size.should == 0
32
+ subject.alive_count.should == 0
33
+ end
34
+
35
+ it "should check for the dead figures" do
36
+ subject.dead_size.should == 2384
37
+ subject.dead_count.should == 149
38
+ subject.dead_deletion.should == 0
39
+ end
40
+
41
+ it "should check for the datafiles figures" do
42
+ subject.datafiles_count.should == 1
43
+ subject.datafiles_file_size.should == 124
44
+ end
45
+
46
+ it "should check for the journal figures" do
47
+ subject.journals_count.should == 1
48
+ subject.journals_file_size.should == 124
49
+ end
20
50
 
21
- it "should check for the figures" do
22
- subject.datafiles_count.should == 1
23
- subject.alive_size.should == 0
24
- subject.alive_count.should == 0
25
- subject.dead_size.should == 2384
26
- subject.dead_count.should == 149
51
+ it "should check for the shapes figure" do
52
+ subject.shapes_count.should == 2
27
53
  end
28
54
  end