ashikawa-core 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Guardfile +18 -0
- data/README.md +10 -10
- data/Rakefile +5 -4
- data/ashikawa-core.gemspec +14 -6
- data/lib/ashikawa-core.rb +1 -0
- data/lib/ashikawa-core/collection.rb +189 -98
- data/lib/ashikawa-core/connection.rb +18 -20
- data/lib/ashikawa-core/cursor.rb +65 -0
- data/lib/ashikawa-core/database.rb +33 -46
- data/lib/ashikawa-core/document.rb +63 -22
- data/lib/ashikawa-core/exceptions/document_not_found.rb +8 -0
- data/lib/ashikawa-core/index.rb +47 -0
- data/lib/ashikawa-core/version.rb +1 -1
- data/spec/fixtures/cursor/26011191-2.json +19 -0
- data/spec/fixtures/cursor/26011191-3.json +13 -0
- data/spec/fixtures/cursor/26011191.json +19 -0
- data/spec/fixtures/cursor/query.json +18 -0
- data/spec/fixtures/documents/new-4590-333.json +5 -0
- data/spec/fixtures/indices/all.json +22 -0
- data/spec/fixtures/indices/hash-index.json +12 -0
- data/spec/fixtures/indices/new-hash-index.json +12 -0
- data/spec/fixtures/simple-queries/all.json +10 -4
- data/spec/fixtures/simple-queries/all_limit.json +9 -3
- data/spec/fixtures/simple-queries/all_skip.json +9 -3
- data/spec/fixtures/simple-queries/example.json +9 -3
- data/spec/fixtures/simple-queries/near.json +11 -5
- data/spec/fixtures/simple-queries/range.json +10 -0
- data/spec/fixtures/simple-queries/within.json +9 -3
- data/spec/integration/arango_helper.rb +27 -0
- data/spec/integration/basic_spec.rb +107 -28
- data/spec/integration/spec_helper.rb +0 -28
- data/spec/unit/collection_spec.rb +190 -83
- data/spec/unit/connection_spec.rb +17 -17
- data/spec/unit/cursor_spec.rb +75 -0
- data/spec/unit/database_spec.rb +34 -19
- data/spec/unit/document_spec.rb +77 -6
- data/spec/unit/index_spec.rb +39 -0
- metadata +98 -6
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"hasMore": true,
|
3
|
+
"error": false,
|
4
|
+
"id": 26011191,
|
5
|
+
"result": [
|
6
|
+
{
|
7
|
+
"n": 0,
|
8
|
+
"_rev": 25880119,
|
9
|
+
"_id": "23914039/25880119"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"n": 1,
|
13
|
+
"_rev": 25880119,
|
14
|
+
"_id": "23914039/25880119"
|
15
|
+
}
|
16
|
+
],
|
17
|
+
"code": 201,
|
18
|
+
"count": 5
|
19
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"code": 200,
|
3
|
+
"indexes": [
|
4
|
+
{
|
5
|
+
"fields": [
|
6
|
+
"_id"
|
7
|
+
],
|
8
|
+
"id": "4590/0",
|
9
|
+
"type": "primary"
|
10
|
+
}
|
11
|
+
],
|
12
|
+
"error": false,
|
13
|
+
"identifiers": {
|
14
|
+
"176836793/0": {
|
15
|
+
"fields": [
|
16
|
+
"_id"
|
17
|
+
],
|
18
|
+
"id": "4590/0",
|
19
|
+
"type": "primary"
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
@@ -1,4 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
{
|
2
|
+
"code": 201,
|
3
|
+
"hasMore": false,
|
4
|
+
"count": 1,
|
5
|
+
"error": false,
|
6
|
+
"result": [
|
7
|
+
{ "_id" : "12345/57463", "_rev" : 57463, "hello" : "world" },
|
8
|
+
{ "_id" : "12346/3872", "_rev" : 3872, "key" : "value" }
|
9
|
+
]
|
10
|
+
}
|
@@ -1,5 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
{
|
2
|
+
"code": 201,
|
3
|
+
"hasMore": false,
|
4
|
+
"count": 3,
|
5
|
+
"error": false,
|
6
|
+
"result": [
|
7
|
+
{ "_id" : "12345/57463", "_rev" : 57463, "name" : "world/0/0", "loc" : [0, 0] },
|
8
|
+
{ "_id" : "12346/2938", "_rev" : 2938, "name" : "world/0/10", "loc" : [0, 10] },
|
9
|
+
{ "_id" : "12347/23737", "_rev" : 23737, "name" : "world/-10/0", "loc" : [-10, 0] }
|
10
|
+
]
|
11
|
+
}
|
@@ -1,3 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
{
|
2
|
+
"code": 201,
|
3
|
+
"hasMore": false,
|
4
|
+
"count": 1,
|
5
|
+
"error": false,
|
6
|
+
"result": [
|
7
|
+
{ "_id" : "12345/57463", "_rev" : 57463, "name" : "world/0/0", "loc" : [0, 0] }
|
8
|
+
]
|
9
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
RSpec.configure do |config|
|
2
|
+
raise "Could not find arangod. Please install it or check if it is in your path." if `which arangod` == ""
|
3
|
+
|
4
|
+
database_directory = "/tmp/ashikawa-integration"
|
5
|
+
arango_process = false
|
6
|
+
|
7
|
+
config.before(:suite) do
|
8
|
+
puts "Starting ArangoDB"
|
9
|
+
process_id = $$
|
10
|
+
|
11
|
+
Dir.mkdir database_directory unless Dir.exists? database_directory
|
12
|
+
arango_process = IO.popen("arangod #{database_directory} --watch-process #{process_id}")
|
13
|
+
|
14
|
+
sleep 2 # Wait for Arango to start up
|
15
|
+
end
|
16
|
+
|
17
|
+
config.after(:suite) do
|
18
|
+
puts
|
19
|
+
puts "Shutting down ArangoDB"
|
20
|
+
|
21
|
+
Process.kill "INT", arango_process.pid
|
22
|
+
sleep 2 # Wait for Arango to shut down
|
23
|
+
arango_process.close
|
24
|
+
|
25
|
+
`rm -r #{database_directory}/*`
|
26
|
+
end
|
27
|
+
end
|
@@ -1,14 +1,20 @@
|
|
1
1
|
require 'integration/spec_helper'
|
2
2
|
|
3
|
+
ARANGO_HOST = "http://localhost:8529"
|
4
|
+
|
3
5
|
describe "Basics" do
|
4
|
-
subject {
|
6
|
+
subject { ARANGO_HOST }
|
5
7
|
|
6
8
|
it "should have booted up an ArangoDB instance" do
|
7
|
-
expect {
|
9
|
+
expect { RestClient.get(subject) }.to_not raise_error
|
8
10
|
end
|
9
11
|
|
10
12
|
describe "initialized database" do
|
11
|
-
subject { Ashikawa::Core::Database.new
|
13
|
+
subject { Ashikawa::Core::Database.new ARANGO_HOST }
|
14
|
+
|
15
|
+
after :each do
|
16
|
+
subject.collections.each { |collection| collection.delete }
|
17
|
+
end
|
12
18
|
|
13
19
|
it "should do what the README describes" do
|
14
20
|
subject["my_collection"]
|
@@ -33,12 +39,12 @@ describe "Basics" do
|
|
33
39
|
my_collection.name.should == "my_new_name"
|
34
40
|
end
|
35
41
|
|
36
|
-
it "should be possible to find a collection by ID" do
|
42
|
+
it "should be possible to find a collection by ID" do
|
37
43
|
my_collection = subject["test_collection"]
|
38
44
|
subject[my_collection.id].name.should == "test_collection"
|
39
45
|
end
|
40
46
|
|
41
|
-
it "should be possible to load and unload collections" do
|
47
|
+
it "should be possible to load and unload collections" do
|
42
48
|
my_collection = subject["test_collection"]
|
43
49
|
my_collection.loaded?.should be_true
|
44
50
|
my_collection.unload
|
@@ -47,7 +53,7 @@ describe "Basics" do
|
|
47
53
|
subject[my_id].loaded?.should be_false
|
48
54
|
end
|
49
55
|
|
50
|
-
it "should be possible to get figures" do
|
56
|
+
it "should be possible to get figures" do
|
51
57
|
my_collection = subject["test_collection"]
|
52
58
|
my_collection.figure(:datafiles_count).class.should == Fixnum
|
53
59
|
my_collection.figure(:alive_size).class.should == Fixnum
|
@@ -58,13 +64,13 @@ describe "Basics" do
|
|
58
64
|
|
59
65
|
it "should change and receive information about waiting for sync" do
|
60
66
|
my_collection = subject["my_collection"]
|
67
|
+
my_collection.wait_for_sync = false
|
61
68
|
my_collection.wait_for_sync?.should be_false
|
62
69
|
my_collection.wait_for_sync = true
|
63
70
|
my_collection.wait_for_sync?.should be_true
|
64
71
|
end
|
65
72
|
|
66
73
|
it "should be possible to get information about the number of documents" do
|
67
|
-
pending("`<<` not implemented yet")
|
68
74
|
empty_collection = subject["empty_collection"]
|
69
75
|
empty_collection.length.should == 0
|
70
76
|
empty_collection << { name: "testname", age: 27}
|
@@ -75,14 +81,12 @@ describe "Basics" do
|
|
75
81
|
end
|
76
82
|
|
77
83
|
it "should return all documents of a collection" do
|
78
|
-
pending("`<<` not implemented yet")
|
79
84
|
empty_collection = subject["empty_collection"]
|
80
85
|
empty_collection << { name: "testname", age: 27}
|
81
86
|
empty_collection.all.first["name"].should == "testname"
|
82
87
|
end
|
83
88
|
|
84
89
|
it "should be possible to limit and skip results" do
|
85
|
-
pending("`<<` not implemented yet")
|
86
90
|
empty_collection = subject["empty_collection"]
|
87
91
|
empty_collection.truncate!
|
88
92
|
|
@@ -94,11 +98,20 @@ describe "Basics" do
|
|
94
98
|
empty_collection.all(skip: 2).length.should == 1
|
95
99
|
end
|
96
100
|
|
101
|
+
it "should be possible to update the attributes of a document" do
|
102
|
+
collection = subject["documenttests"]
|
103
|
+
|
104
|
+
document = collection.create name: "The Dude", bowling: true
|
105
|
+
document_id = document.id
|
106
|
+
document["name"] = "Other Dude"
|
107
|
+
document.save
|
108
|
+
|
109
|
+
collection[document_id]["name"].should == "Other Dude"
|
110
|
+
end
|
97
111
|
|
98
112
|
it "should be possible to access and create documents from a collection" do
|
99
113
|
collection = subject["documenttests"]
|
100
114
|
|
101
|
-
pending("`create` not implemented yet")
|
102
115
|
document = collection.create name: "The Dude", bowling: true
|
103
116
|
document_id = document.id
|
104
117
|
collection[document_id]["name"].should == "The Dude"
|
@@ -112,37 +125,53 @@ describe "Basics" do
|
|
112
125
|
@places = subject['geo_collection']
|
113
126
|
@places.truncate!
|
114
127
|
|
115
|
-
|
116
|
-
@places << { name
|
117
|
-
@places << { name
|
128
|
+
@places.add_index :geo, on: [:latitude, :longitude]
|
129
|
+
@places << { "name" => "cologne", "latitude" => 50.948045, "longitude" => 6.961212 }
|
130
|
+
@places << { "name" => "san francisco", "latitude" => -122.395899, "longitude" => 37.793621 }
|
118
131
|
end
|
119
132
|
|
120
133
|
it "should be possible to query documents near a certain location" do
|
121
|
-
|
122
|
-
|
123
|
-
near_places.first.name.should == "san francisco"
|
134
|
+
found_places = @places.near latitude: 50, longitude: 6
|
135
|
+
found_places.first["name"].should == "cologne"
|
124
136
|
end
|
125
137
|
|
126
138
|
it "should be possible to query documents within a certain range" do
|
127
|
-
|
128
|
-
|
129
|
-
|
139
|
+
found_places = @places.within latitude: 50.948040, longitude: 6.961210, radius: 2
|
140
|
+
found_places.length.should == 1
|
141
|
+
found_places.first["name"].should == "cologne"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "ranges" do
|
146
|
+
before :each do
|
147
|
+
@people = subject['range_collection']
|
148
|
+
@people.truncate!
|
149
|
+
|
150
|
+
@people.add_index :skiplist, on: [:age]
|
151
|
+
@people << { "name" => "Georg", "age" => 12 }
|
152
|
+
@people << { "name" => "Anne", "age" => 21 }
|
153
|
+
@people << { "name" => "Jens", "age" => 49 }
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should be possible to query documents for numbers in a certain range" do
|
157
|
+
found_people = @people.in_range attribute: "age", left: 20, right: 30, closed: true
|
158
|
+
found_people.length.should == 1
|
159
|
+
found_people.first["name"].should == "Anne"
|
130
160
|
end
|
131
161
|
end
|
132
162
|
|
133
163
|
describe "created document" do
|
134
164
|
before :each do
|
135
|
-
pending("`create` not implemented yet")
|
136
165
|
@collection = subject["documenttests"]
|
137
166
|
@document = @collection.create name: "The Dude"
|
138
167
|
@document_id = @document.id
|
139
168
|
end
|
140
169
|
|
141
170
|
it "should be possible to manipulate documents and save them" do
|
142
|
-
@document = @collection[document_id]
|
171
|
+
@document = @collection[@document_id]
|
143
172
|
@document["name"] = "Jeffrey Lebowski"
|
144
173
|
@document["name"].should == "Jeffrey Lebowski"
|
145
|
-
@collection[@document_id].should == "The Dude"
|
174
|
+
@collection[@document_id]["name"].should == "The Dude"
|
146
175
|
@document.save
|
147
176
|
@collection[@document_id]["name"].should == "Jeffrey Lebowski"
|
148
177
|
end
|
@@ -152,16 +181,66 @@ describe "Basics" do
|
|
152
181
|
@document = @collection.create name: "The Dude"
|
153
182
|
@document_id = @document.id
|
154
183
|
@collection[@document_id].delete
|
155
|
-
expect { @collection[@document_id] }.to raise_exception Ashikawa::DocumentNotFoundException
|
184
|
+
expect { @collection[@document_id] }.to raise_exception Ashikawa::Core::DocumentNotFoundException
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should not be possible to delete a document that doesn't exist" do
|
188
|
+
@collection = subject["documenttests"]
|
189
|
+
expect { @collection[123].delete }.to raise_exception Ashikawa::Core::DocumentNotFoundException
|
156
190
|
end
|
157
191
|
end
|
158
192
|
|
159
|
-
|
160
|
-
|
193
|
+
describe "setting and deleting indices" do
|
194
|
+
before :each do
|
195
|
+
@collection = subject["documenttests"]
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should be possible to set indices" do
|
199
|
+
@collection.add_index :geo, on: [:latitude, :longitude]
|
200
|
+
@collection.add_index :skiplist, on: [:identifier]
|
201
|
+
@collection.indices.length.should == 3 # primary index is always set
|
202
|
+
@collection.indices[0].class.should == Ashikawa::Core::Index
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should be possible to get an index by ID" do
|
206
|
+
index = @collection.add_index :skiplist, on: [:identifier]
|
207
|
+
@collection.index(index.id).id.should == index.id
|
208
|
+
end
|
161
209
|
|
162
|
-
|
163
|
-
|
164
|
-
|
210
|
+
it "should be possible to remove indices" do
|
211
|
+
index = @collection.add_index :skiplist, on: [:identifier]
|
212
|
+
index.delete
|
213
|
+
@collection.indices.length.should == 1 # primary index is always set
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "querying for documents" do
|
218
|
+
it "should be possible to query documents by example" do
|
219
|
+
collection = subject["documenttests"]
|
220
|
+
|
221
|
+
collection << { "name" => "Random Collection" }
|
222
|
+
result = collection.by_example example: {"name" => "Random Collection"}
|
223
|
+
result.length.should == 1
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should be possible to query documents with AQL" do
|
227
|
+
collection = subject["aqltest"]
|
228
|
+
|
229
|
+
collection << { "name" => "Jeff Lebowski", "bowling" => true }
|
230
|
+
collection << { "name" => "Walter Sobchak", "bowling" => true }
|
231
|
+
collection << { "name" => "Donny Kerabatsos", "bowling" => true }
|
232
|
+
collection << { "name" => "Jeffrey Lebowski", "bowling" => false }
|
233
|
+
|
234
|
+
results = subject.query "FOR u IN aqltest FILTER u.bowling == true RETURN u",
|
235
|
+
batch_size: 2,
|
236
|
+
count: true
|
237
|
+
|
238
|
+
results.length.should == 3
|
239
|
+
|
240
|
+
results = results.map { |person| person["name"] }
|
241
|
+
results.should include "Jeff Lebowski"
|
242
|
+
results.should_not include "Jeffrey Lebowski"
|
243
|
+
end
|
165
244
|
end
|
166
245
|
end
|
167
246
|
end
|