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.
- 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
|
+
}
|