ashikawa-core 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +0 -1
- data/.travis.yml +2 -0
- data/CONTRIBUTING.md +14 -29
- data/Gemfile.devtools +9 -10
- data/README.md +30 -9
- data/Rakefile +1 -1
- data/ashikawa-core.gemspec +9 -8
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/roodi.yml +4 -5
- data/config/site.reek +40 -16
- data/config/yardstick.yml +1 -1
- data/lib/ashikawa-core/collection.rb +109 -22
- data/lib/ashikawa-core/connection.rb +42 -110
- data/lib/ashikawa-core/cursor.rb +13 -6
- data/lib/ashikawa-core/database.rb +67 -17
- data/lib/ashikawa-core/document.rb +41 -10
- data/lib/ashikawa-core/edge.rb +50 -0
- data/lib/ashikawa-core/exceptions/client_error/bad_syntax.rb +24 -0
- data/lib/ashikawa-core/exceptions/{collection_not_found.rb → client_error/resource_not_found/collection_not_found.rb} +3 -1
- data/lib/ashikawa-core/exceptions/{document_not_found.rb → client_error/resource_not_found/document_not_found.rb} +3 -1
- data/lib/ashikawa-core/exceptions/{index_not_found.rb → client_error/resource_not_found/index_not_found.rb} +3 -1
- data/lib/ashikawa-core/exceptions/client_error/resource_not_found.rb +25 -0
- data/lib/ashikawa-core/exceptions/client_error.rb +23 -0
- data/lib/ashikawa-core/exceptions/server_error/json_error.rb +25 -0
- data/lib/ashikawa-core/exceptions/server_error.rb +23 -0
- data/lib/ashikawa-core/figure.rb +59 -2
- data/lib/ashikawa-core/index.rb +23 -7
- data/lib/ashikawa-core/query.rb +10 -10
- data/lib/ashikawa-core/request_preprocessor.rb +49 -0
- data/lib/ashikawa-core/response_preprocessor.rb +111 -0
- data/lib/ashikawa-core/version.rb +1 -1
- data/lib/ashikawa-core.rb +0 -1
- data/spec/acceptance/basic_spec.rb +61 -22
- data/spec/acceptance/index_spec.rb +11 -4
- data/spec/acceptance/query_spec.rb +4 -1
- data/spec/acceptance/spec_helper.rb +0 -2
- data/spec/acceptance_auth/spec_helper.rb +0 -2
- data/spec/fixtures/collections/60768679-count.json +13 -0
- data/spec/fixtures/collections/60768679-figures.json +35 -0
- data/spec/fixtures/collections/60768679-properties-volatile.json +12 -0
- data/spec/fixtures/collections/60768679-properties.json +12 -0
- data/spec/fixtures/collections/{4588.json → 60768679.json} +2 -2
- data/spec/fixtures/collections/all.json +5 -5
- data/spec/fixtures/cursor/26011191-2.json +1 -1
- data/spec/fixtures/cursor/26011191.json +1 -1
- data/spec/fixtures/documents/example_1-137249191.json +6 -0
- data/spec/fixtures/documents/new-example_1-137249191.json +6 -0
- data/spec/setup/arangodb.sh +1 -1
- data/spec/unit/collection_spec.rb +117 -42
- data/spec/unit/connection_spec.rb +161 -61
- data/spec/unit/cursor_spec.rb +39 -12
- data/spec/unit/database_spec.rb +119 -19
- data/spec/unit/document_spec.rb +4 -2
- data/spec/unit/edge_spec.rb +54 -0
- data/spec/unit/exception_spec.rb +36 -8
- data/spec/unit/figure_spec.rb +37 -11
- data/spec/unit/index_spec.rb +1 -1
- data/spec/unit/query_spec.rb +18 -18
- data/spec/unit/spec_helper.rb +4 -13
- data/tasks/adjustments.rake +3 -2
- metadata +59 -32
- data/lib/ashikawa-core/exceptions/unknown_path.rb +0 -15
- data/spec/fixtures/collections/4590-properties.json +0 -9
- data/spec/fixtures/collections/4590.json +0 -8
- data/spec/fixtures/collections/73482-figures.json +0 -23
- data/spec/fixtures/documents/4590-333.json +0 -5
- data/spec/fixtures/documents/new-4590-333.json +0 -5
@@ -0,0 +1,49 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "multi_json"
|
3
|
+
|
4
|
+
module Ashikawa
|
5
|
+
module Core
|
6
|
+
# Preprocessor for Faraday Requests
|
7
|
+
class RequestPreprocessor < Faraday::Middleware
|
8
|
+
# Create a new Request Preprocessor
|
9
|
+
#
|
10
|
+
# @param [Object] app Faraday internal
|
11
|
+
# @param [Object] logger The object you want to log to
|
12
|
+
# @return [RequestPreprocessor]
|
13
|
+
# @api private
|
14
|
+
def initialize(app, logger)
|
15
|
+
@app = app
|
16
|
+
@logger = logger
|
17
|
+
end
|
18
|
+
|
19
|
+
# Process a Request
|
20
|
+
#
|
21
|
+
# @param [Hash] env Environment info
|
22
|
+
# @return [Object]
|
23
|
+
# @api private
|
24
|
+
def call(env)
|
25
|
+
body = env[:body]
|
26
|
+
env[:body] = MultiJson.dump(body) if body
|
27
|
+
log(env[:method], env[:url], body)
|
28
|
+
@app.call(env)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Log a Request
|
34
|
+
#
|
35
|
+
# @param [Symbol] method
|
36
|
+
# @param [String] url
|
37
|
+
# @param [String] body
|
38
|
+
# @return [nil]
|
39
|
+
# @api private
|
40
|
+
def log(method, url, body)
|
41
|
+
@logger.info("#{method.upcase} #{url} #{body}")
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Faraday.register_middleware :request,
|
47
|
+
:ashikawa_request => lambda { RequestPreprocessor}
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "multi_json"
|
3
|
+
require "ashikawa-core/exceptions/client_error"
|
4
|
+
require "ashikawa-core/exceptions/client_error/resource_not_found"
|
5
|
+
require "ashikawa-core/exceptions/client_error/resource_not_found/index_not_found"
|
6
|
+
require "ashikawa-core/exceptions/client_error/resource_not_found/document_not_found"
|
7
|
+
require "ashikawa-core/exceptions/client_error/resource_not_found/collection_not_found"
|
8
|
+
require "ashikawa-core/exceptions/client_error/bad_syntax"
|
9
|
+
require "ashikawa-core/exceptions/server_error"
|
10
|
+
require "ashikawa-core/exceptions/server_error/json_error"
|
11
|
+
|
12
|
+
module Ashikawa
|
13
|
+
module Core
|
14
|
+
# Preprocessor for Faraday Requests
|
15
|
+
class ResponsePreprocessor < Faraday::Middleware
|
16
|
+
ClientErrorStatuses = 400...499
|
17
|
+
ServerErrorStatuses = 500...599
|
18
|
+
BadSyntaxStatus = 400
|
19
|
+
ResourceNotFoundErrorError = 404
|
20
|
+
|
21
|
+
# Create a new Response Preprocessor
|
22
|
+
#
|
23
|
+
# @param [Object] app Faraday internal
|
24
|
+
# @param [Object] logger The object you want to log to
|
25
|
+
# @return [ResponsePreprocessor]
|
26
|
+
# @api private
|
27
|
+
def initialize(app, logger)
|
28
|
+
@app = app
|
29
|
+
@logger = logger
|
30
|
+
end
|
31
|
+
|
32
|
+
# Process a Response
|
33
|
+
#
|
34
|
+
# @param [Hash] env Environment info
|
35
|
+
# @return [Object]
|
36
|
+
# @api private
|
37
|
+
def call(env)
|
38
|
+
@app.call(env).on_complete do
|
39
|
+
log(env)
|
40
|
+
handle_status(env)
|
41
|
+
env[:body] = parse_json(env)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Raise the fitting ResourceNotFoundException
|
48
|
+
#
|
49
|
+
# @raise [DocumentNotFoundException, CollectionNotFoundException, IndexNotFoundException]
|
50
|
+
# @return nil
|
51
|
+
# @api private
|
52
|
+
def resource_not_found_for(env)
|
53
|
+
raise case env[:url].path
|
54
|
+
when /\A\/_api\/document/ then Ashikawa::Core::DocumentNotFoundException
|
55
|
+
when /\A\/_api\/collection/ then Ashikawa::Core::CollectionNotFoundException
|
56
|
+
when /\A\/_api\/index/ then Ashikawa::Core::IndexNotFoundException
|
57
|
+
else Ashikawa::Core::ResourceNotFound
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Parse the JSON
|
62
|
+
#
|
63
|
+
# @param [Hash] env Environment info
|
64
|
+
# @return [Hash] The parsed body
|
65
|
+
# @api private
|
66
|
+
def parse_json(env)
|
67
|
+
raise MultiJson::LoadError unless json_content_type?(env[:response_headers]["content-type"])
|
68
|
+
MultiJson.load(env[:body])
|
69
|
+
rescue MultiJson::LoadError
|
70
|
+
raise Ashikawa::Core::JsonError
|
71
|
+
end
|
72
|
+
|
73
|
+
# Check if the Content Type is JSON
|
74
|
+
#
|
75
|
+
# @param [String] content_type
|
76
|
+
# @return [Boolean]
|
77
|
+
# @api private
|
78
|
+
def json_content_type?(content_type)
|
79
|
+
content_type == "application/json; charset=utf-8"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Handle the status code
|
83
|
+
#
|
84
|
+
# @param [Hash] env Environment info
|
85
|
+
# @return [nil]
|
86
|
+
# @api private
|
87
|
+
def handle_status(env)
|
88
|
+
status = env[:status]
|
89
|
+
case status
|
90
|
+
when BadSyntaxStatus then raise Ashikawa::Core::BadSyntax
|
91
|
+
when ResourceNotFoundErrorError then raise resource_not_found_for(env)
|
92
|
+
when ClientErrorStatuses then raise Ashikawa::Core::ClientError, status
|
93
|
+
when ServerErrorStatuses then raise Ashikawa::Core::ServerError, status
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Log a Request
|
98
|
+
#
|
99
|
+
# @param [Hash] env Environment info
|
100
|
+
# @return [nil]
|
101
|
+
# @api private
|
102
|
+
def log(env)
|
103
|
+
@logger.info("#{env[:status]} #{env[:body]}")
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
Faraday.register_middleware :response,
|
109
|
+
:ashikawa_response => lambda { ResponsePreprocessor}
|
110
|
+
end
|
111
|
+
end
|
data/lib/ashikawa-core.rb
CHANGED
@@ -3,7 +3,6 @@ require "ashikawa-core/connection"
|
|
3
3
|
require "ashikawa-core/database"
|
4
4
|
require "ashikawa-core/document"
|
5
5
|
require "ashikawa-core/version"
|
6
|
-
require "ashikawa-core/exceptions/document_not_found"
|
7
6
|
|
8
7
|
# Ashikawa is a project dedicated to connect Ruby and ArangoDB
|
9
8
|
module Ashikawa
|
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'acceptance/spec_helper'
|
2
2
|
|
3
3
|
describe "Basics" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
describe "for an initialized database" do
|
5
|
+
subject {
|
6
|
+
Ashikawa::Core::Database.new do |config|
|
7
|
+
config.url = ARANGO_HOST
|
8
|
+
end
|
9
|
+
}
|
8
10
|
|
9
11
|
after :each do
|
10
12
|
subject.collections.each { |collection| collection.delete }
|
@@ -17,7 +19,7 @@ describe "Basics" do
|
|
17
19
|
end
|
18
20
|
|
19
21
|
it "should create and delete collections" do
|
20
|
-
subject.collections.
|
22
|
+
subject.collections.each { |collection| collection.delete }
|
21
23
|
subject["collection_1"]
|
22
24
|
subject["collection_2"]
|
23
25
|
subject["collection_3"]
|
@@ -26,6 +28,21 @@ describe "Basics" do
|
|
26
28
|
subject.collections.length.should == 2
|
27
29
|
end
|
28
30
|
|
31
|
+
it "should create a non-volatile collection by default" do
|
32
|
+
subject.create_collection("nonvolatile_collection")
|
33
|
+
subject["nonvolatile_collection"].volatile?.should be_false
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should create a volatile collection" do
|
37
|
+
subject.create_collection("volatile_collection", :is_volatile => true)
|
38
|
+
subject["volatile_collection"].volatile?.should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should be possible to create an edge collection" do
|
42
|
+
subject.create_collection("edge_collection", :content_type => :edge)
|
43
|
+
subject["edge_collection"].content_type.should == :edge
|
44
|
+
end
|
45
|
+
|
29
46
|
it "should be possible to change the name of a collection" do
|
30
47
|
my_collection = subject["test_collection"]
|
31
48
|
my_collection.name.should == "test_collection"
|
@@ -49,11 +66,16 @@ describe "Basics" do
|
|
49
66
|
|
50
67
|
it "should be possible to get figures" do
|
51
68
|
my_collection = subject["test_collection"]
|
52
|
-
my_collection.figure.datafiles_count.class.should == Fixnum
|
53
69
|
my_collection.figure.alive_size.class.should == Fixnum
|
54
70
|
my_collection.figure.alive_count.class.should == Fixnum
|
55
71
|
my_collection.figure.dead_size.class.should == Fixnum
|
56
72
|
my_collection.figure.dead_count.class.should == Fixnum
|
73
|
+
my_collection.figure.dead_deletion.class.should == Fixnum
|
74
|
+
my_collection.figure.datafiles_count.class.should == Fixnum
|
75
|
+
my_collection.figure.datafiles_file_size.class.should == Fixnum
|
76
|
+
my_collection.figure.journals_count.class.should == Fixnum
|
77
|
+
my_collection.figure.journals_file_size.class.should == Fixnum
|
78
|
+
my_collection.figure.shapes_count.class.should == Fixnum
|
57
79
|
end
|
58
80
|
|
59
81
|
it "should change and receive information about waiting for sync" do
|
@@ -77,44 +99,61 @@ describe "Basics" do
|
|
77
99
|
it "should be possible to update the attributes of a document" do
|
78
100
|
collection = subject["documenttests"]
|
79
101
|
|
80
|
-
document = collection.
|
81
|
-
|
102
|
+
document = collection.create_document(:name => "The Dude", :bowling => true)
|
103
|
+
document_key = document.key
|
82
104
|
document["name"] = "Other Dude"
|
83
105
|
document.save
|
84
106
|
|
85
|
-
collection[
|
107
|
+
collection[document_key]["name"].should == "Other Dude"
|
86
108
|
end
|
87
109
|
|
88
110
|
it "should be possible to access and create documents from a collection" do
|
89
111
|
collection = subject["documenttests"]
|
90
112
|
|
91
|
-
document = collection.
|
92
|
-
|
93
|
-
collection[
|
113
|
+
document = collection.create_document(:name => "The Dude", :bowling => true)
|
114
|
+
document_key = document.key
|
115
|
+
collection[document_key]["name"].should == "The Dude"
|
116
|
+
|
117
|
+
collection[document_key] = { :name => "Other Dude", :bowling => true }
|
118
|
+
collection[document_key]["name"].should == "Other Dude"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should be possible to create an edge between two documents" do
|
122
|
+
nodes = subject.create_collection("nodecollection")
|
123
|
+
edges = subject.create_collection("edgecollection", :content_type => :edge)
|
124
|
+
|
125
|
+
a = nodes.create_document({:name => "a"})
|
126
|
+
b = nodes.create_document({:name => "b"})
|
127
|
+
e = edges.create_edge(a, b, {:name => "fance_edge"})
|
94
128
|
|
95
|
-
|
96
|
-
|
129
|
+
e = edges[e.key]
|
130
|
+
e.from_id.should == a.id
|
131
|
+
e.to_id.should == b.id
|
97
132
|
end
|
98
133
|
end
|
99
134
|
|
100
|
-
describe "created document" do
|
101
|
-
let(:database) {
|
135
|
+
describe "for a created document" do
|
136
|
+
let(:database) {
|
137
|
+
Ashikawa::Core::Database.new do |config|
|
138
|
+
config.url = ARANGO_HOST
|
139
|
+
end
|
140
|
+
}
|
102
141
|
let(:collection) { database["documenttests"] }
|
103
|
-
subject { collection.
|
104
|
-
let(:
|
142
|
+
subject { collection.create_document(:name => "The Dude") }
|
143
|
+
let(:document_key) { subject.key }
|
105
144
|
|
106
145
|
it "should be possible to manipulate documents and save them" do
|
107
146
|
subject["name"] = "Jeffrey Lebowski"
|
108
147
|
subject["name"].should == "Jeffrey Lebowski"
|
109
|
-
collection[
|
148
|
+
collection[document_key]["name"].should == "The Dude"
|
110
149
|
subject.save
|
111
|
-
collection[
|
150
|
+
collection[document_key]["name"].should == "Jeffrey Lebowski"
|
112
151
|
end
|
113
152
|
|
114
153
|
it "should be possible to delete a document" do
|
115
|
-
collection[
|
154
|
+
collection[document_key].delete
|
116
155
|
expect {
|
117
|
-
collection[
|
156
|
+
collection[document_key]
|
118
157
|
}.to raise_exception Ashikawa::Core::DocumentNotFoundException
|
119
158
|
end
|
120
159
|
|
@@ -1,9 +1,12 @@
|
|
1
1
|
require 'acceptance/spec_helper'
|
2
2
|
|
3
3
|
describe "Indices" do
|
4
|
-
let(:database) { Ashikawa::Core::Database.new
|
4
|
+
let(:database) { Ashikawa::Core::Database.new do |config|
|
5
|
+
config.url = ARANGO_HOST
|
6
|
+
end
|
7
|
+
}
|
5
8
|
subject { database["documenttest"] }
|
6
|
-
let(:index) { subject.add_index
|
9
|
+
let(:index) { subject.add_index(:skiplist, :on => [:identifier]) }
|
7
10
|
|
8
11
|
it "should be possible to set indices" do
|
9
12
|
index.delete
|
@@ -14,15 +17,19 @@ describe "Indices" do
|
|
14
17
|
end
|
15
18
|
|
16
19
|
it "should be possible to get an index by ID" do
|
17
|
-
|
20
|
+
# This is temporary until Index has a key
|
21
|
+
index_key = index.id.split('/')[1]
|
22
|
+
|
23
|
+
subject.index(index_key).id.should == index.id
|
18
24
|
subject.indices[0].class.should == Ashikawa::Core::Index
|
19
25
|
end
|
20
26
|
|
21
27
|
it "should be possible to remove indices" do
|
22
|
-
pending "
|
28
|
+
pending "See Bug #34"
|
23
29
|
|
24
30
|
expect {
|
25
31
|
index.delete
|
32
|
+
sleep(1) # from time to time it may fail because of threading
|
26
33
|
}.to change { subject.indices.length }.by(-1)
|
27
34
|
end
|
28
35
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'acceptance/spec_helper'
|
2
2
|
|
3
3
|
describe "Queries" do
|
4
|
-
let(:database) { Ashikawa::Core::Database.new
|
4
|
+
let(:database) { Ashikawa::Core::Database.new do |config|
|
5
|
+
config.url = ARANGO_HOST
|
6
|
+
end
|
7
|
+
}
|
5
8
|
let(:collection) { database["my_collection"] }
|
6
9
|
|
7
10
|
describe "AQL query via the database" do
|
@@ -0,0 +1,35 @@
|
|
1
|
+
{
|
2
|
+
"id": "60768679",
|
3
|
+
"name": "example_1",
|
4
|
+
"waitForSync": true,
|
5
|
+
"journalSize": 134217728,
|
6
|
+
"isVolatile": false,
|
7
|
+
"isSystem": false,
|
8
|
+
"count": 0,
|
9
|
+
"figures": {
|
10
|
+
"alive": {
|
11
|
+
"count": 0,
|
12
|
+
"size": 0
|
13
|
+
},
|
14
|
+
"dead": {
|
15
|
+
"count": 149,
|
16
|
+
"size": 2384,
|
17
|
+
"deletion": 0
|
18
|
+
},
|
19
|
+
"datafiles": {
|
20
|
+
"count": 1,
|
21
|
+
"fileSize": 0
|
22
|
+
},
|
23
|
+
"journals": {
|
24
|
+
"count": 1,
|
25
|
+
"fileSize": 33554432
|
26
|
+
},
|
27
|
+
"shapes": {
|
28
|
+
"count": 6
|
29
|
+
}
|
30
|
+
},
|
31
|
+
"status": 3,
|
32
|
+
"type": 2,
|
33
|
+
"error": false,
|
34
|
+
"code": 200
|
35
|
+
}
|