ashikawa-core 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/Guardfile +18 -0
  2. data/README.md +10 -10
  3. data/Rakefile +5 -4
  4. data/ashikawa-core.gemspec +14 -6
  5. data/lib/ashikawa-core.rb +1 -0
  6. data/lib/ashikawa-core/collection.rb +189 -98
  7. data/lib/ashikawa-core/connection.rb +18 -20
  8. data/lib/ashikawa-core/cursor.rb +65 -0
  9. data/lib/ashikawa-core/database.rb +33 -46
  10. data/lib/ashikawa-core/document.rb +63 -22
  11. data/lib/ashikawa-core/exceptions/document_not_found.rb +8 -0
  12. data/lib/ashikawa-core/index.rb +47 -0
  13. data/lib/ashikawa-core/version.rb +1 -1
  14. data/spec/fixtures/cursor/26011191-2.json +19 -0
  15. data/spec/fixtures/cursor/26011191-3.json +13 -0
  16. data/spec/fixtures/cursor/26011191.json +19 -0
  17. data/spec/fixtures/cursor/query.json +18 -0
  18. data/spec/fixtures/documents/new-4590-333.json +5 -0
  19. data/spec/fixtures/indices/all.json +22 -0
  20. data/spec/fixtures/indices/hash-index.json +12 -0
  21. data/spec/fixtures/indices/new-hash-index.json +12 -0
  22. data/spec/fixtures/simple-queries/all.json +10 -4
  23. data/spec/fixtures/simple-queries/all_limit.json +9 -3
  24. data/spec/fixtures/simple-queries/all_skip.json +9 -3
  25. data/spec/fixtures/simple-queries/example.json +9 -3
  26. data/spec/fixtures/simple-queries/near.json +11 -5
  27. data/spec/fixtures/simple-queries/range.json +10 -0
  28. data/spec/fixtures/simple-queries/within.json +9 -3
  29. data/spec/integration/arango_helper.rb +27 -0
  30. data/spec/integration/basic_spec.rb +107 -28
  31. data/spec/integration/spec_helper.rb +0 -28
  32. data/spec/unit/collection_spec.rb +190 -83
  33. data/spec/unit/connection_spec.rb +17 -17
  34. data/spec/unit/cursor_spec.rb +75 -0
  35. data/spec/unit/database_spec.rb +34 -19
  36. data/spec/unit/document_spec.rb +77 -6
  37. data/spec/unit/index_spec.rb +39 -0
  38. metadata +98 -6
data/Guardfile ADDED
@@ -0,0 +1,18 @@
1
+ guard 'bundler' do
2
+ watch(/^.+\.gemspec/)
3
+ end
4
+
5
+ guard 'yard' do
6
+ watch(%r{lib/.+\.rb})
7
+ end
8
+
9
+ guard 'rspec', :version => 2, :spec_paths => "spec/unit" do
10
+ watch(%r{lib/.+\.rb})
11
+ watch(%r{spec/.+\.rb})
12
+ end
13
+
14
+ guard 'rspec', :version => 2, :spec_paths => "spec/integration" do
15
+ watch(%r{lib/.+\.rb})
16
+ watch(%r{spec/.+\.rb})
17
+ end
18
+
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Ashikawa Core
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/triAGENS/ashikawa-core.png?branch=master)](http://travis-ci.org/triAGENS/ashikawa-core)
4
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/triAGENS/ashikawa-core)
4
5
 
5
6
  Ashikawa Core is a Wrapper around the ArangoDB Rest API. It provides low level access and will be used in different ArangoDB ODMs.
6
7
 
@@ -39,6 +40,14 @@ Now you can run `rake` to see all tests passing (hopefully). Happy coding!
39
40
 
40
41
  You can also start up yard for documentation: `rake yard:server`
41
42
 
43
+ ### Guard
44
+
45
+ Guard is a tool for comfortable development. If you want to use it for development, you have to first start an instance of ArangoDB and then start guard with `guard`. This will:
46
+
47
+ * Run a documentation server on `http://localhost:8808`
48
+ * Run `bundle` whenever you change the dependencies
49
+ * Run the integration and unit tests whenever you change a file in the lib or spec directory
50
+
42
51
  ### Continuous Integration
43
52
 
44
53
  Our tests are run on Travis CI, the build status is displayed above. **Please note** that it only runs the unit tests and not the integration tests, because that would require ArangoDB to be installed on the Travis CI boxes. *Therefore green doesn't neccessarily mean green* (which is unfortunate).
@@ -50,14 +59,5 @@ When you want to write code for the project, please follow these guidelines:
50
59
  1. Claim the ticket: Tell us that you want to work on a certain ticket, we will assign it to you (We don't want two people to work on the same thing ;) )
51
60
  2. Write an Integration Test: Describe what you want to do (our integration tests touch the database)
52
61
  3. Implement it: Write a unit test, check that it fails, make the test pass – repeat (our unit tests don't touch the database)
53
- 4. Write Documentation for it: Check the compatibility with our rules via *yardstick*
62
+ 4. Write Documentation for it.
54
63
  5. Check with `rake` that everything is fine and send the Pull Request :)
55
-
56
- ## Documentation
57
-
58
- We want `Ashikawa::Core` to be a solid foundation for all Ruby Libraries connecting to ArangoDB. Therefore we want an excellent documentation. We created two rake tasks:
59
-
60
- * `rake yard:report`: Measure docs in lib/**/*.rb with yardstick
61
- * `rake yard:verify`: Verify that yardstick coverage is 100%
62
-
63
- The Yardstick coverage will be checked by our CI. Please make sure that the coverage is always at 100%.
data/Rakefile CHANGED
@@ -9,6 +9,7 @@ require "rspec/core/rake_task"
9
9
  namespace :spec do
10
10
  desc "Run the integration tests. Requires ArangoDB."
11
11
  RSpec::Core::RakeTask.new(:integration) do |spec|
12
+ spec.rspec_opts = "--require integration/arango_helper.rb"
12
13
  spec.pattern = "spec/integration/*_spec.rb"
13
14
  end
14
15
 
@@ -58,9 +59,9 @@ namespace :yard do
58
59
  end
59
60
 
60
61
  desc "Run Unit Tests and verify documentation - no ArangoDB required"
61
- # task :ci => ["spec:unit", "yard:verify", "dependencies"]
62
- task :ci => ["spec:unit", "dependencies"]
62
+ # task :ci => ["spec:unit", "yard:verify"]
63
+ task :ci => ["spec:unit"]
63
64
 
64
65
  desc "Run all tests and verify documentation - ArangoDB required"
65
- # task :default => ["spec:all", "yard:verify", "dependencies"]
66
- task :default => ["spec:all", "dependencies"]
66
+ # task :default => ["spec:all", "yard:verify"]
67
+ task :default => ["spec:all"]
@@ -7,13 +7,13 @@ Gem::Specification.new do |gem|
7
7
  gem.version = Ashikawa::Core::VERSION
8
8
  gem.authors = ["moonglum", "EinLama"]
9
9
  gem.email = ["me@moonglum.net", "tobias.eilert@me.com"]
10
- gem.homepage = ""
10
+ gem.homepage = "https://github.com/triAGENS/ashikawa-core"
11
11
  gem.summary = "Ashikawa Core is a Wrapper around the ArangoDB Rest API"
12
12
  gem.description = "Ashikawa Core is a Wrapper around the ArangoDB Rest API. It provides low level access and will be used in different ArangoDB ODMs."
13
-
13
+
14
14
  gem.required_ruby_version = '>= 1.9.2'
15
15
  gem.requirements << "ArangoDB"
16
-
16
+
17
17
  gem.rubyforge_project = "ashikawa-core"
18
18
 
19
19
  gem.files = `git ls-files`.split("\n")
@@ -23,18 +23,26 @@ Gem::Specification.new do |gem|
23
23
 
24
24
  # Runtime Dependencies
25
25
  gem.add_dependency "rest-client", "~> 1.6.7"
26
-
26
+
27
27
  # Runtime Dependencies (JRuby only)
28
28
  if defined? PLATFORM and PLATFORM == 'java'
29
29
  gem.add_dependency "json", "~> 1.6.6"
30
30
  gem.add_dependency "jruby-openssl", "~> 0.7.6.1"
31
+ else
32
+ # RedCarpet is not compatible with JRuby
33
+ # It is only needed to generate the YARD Documentation
34
+ gem.add_development_dependency "redcarpet", "~> 2.1.1"
31
35
  end
32
-
36
+
33
37
  # Development Dependencies
34
38
  gem.add_development_dependency "rake", "~> 0.9.2.2"
35
39
  gem.add_development_dependency "rspec", "~> 2.11.0"
36
40
  gem.add_development_dependency "yard", "~> 0.8.2.1"
37
41
  gem.add_development_dependency "webmock", "~> 1.8.9"
38
42
  # gem.add_development_dependency "yardstick", "~> 0.6.0"
39
- gem.add_development_dependency "redcarpet", "~> 2.1.1"
43
+
44
+ gem.add_development_dependency "guard", "~> 1.3.2"
45
+ gem.add_development_dependency "guard-rspec", "~> 1.2.1"
46
+ gem.add_development_dependency "guard-bundler", "~> 1.0.0"
47
+ gem.add_development_dependency "guard-yard", "~> 2.0.0"
40
48
  end
data/lib/ashikawa-core.rb CHANGED
@@ -3,6 +3,7 @@ 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"
6
7
 
7
8
  # Ashikawa is a project dedicated to connect Ruby and ArangoDB
8
9
  module Ashikawa
@@ -1,11 +1,16 @@
1
1
  require "ashikawa-core/document"
2
+ require "ashikawa-core/index"
3
+ require "ashikawa-core/cursor"
4
+ require "forwardable"
2
5
 
3
6
  module Ashikawa
4
7
  module Core
5
8
  # Represents a certain Collection within the Database
6
9
  class Collection
10
+ extend Forwardable
11
+
7
12
  # The name of the collection, must be unique
8
- #
13
+ #
9
14
  # @return [String]
10
15
  # @api public
11
16
  # @example Change the name of a collection
@@ -23,9 +28,9 @@ module Ashikawa
23
28
  # collection.name = "example_2"
24
29
  # collection.name # => "example_2"
25
30
  attr_reader :name
26
-
31
+
27
32
  # The ID of the collection. Is set by the database and unique
28
- #
33
+ #
29
34
  # @return [Fixnum]
30
35
  # @api public
31
36
  # @example Get the id of the collection
@@ -41,9 +46,12 @@ module Ashikawa
41
46
  # collection = Ashikawa::Core::Collection.new database, raw_collection
42
47
  # collection.id #=> 4588
43
48
  attr_reader :id
44
-
49
+
50
+ # Sending requests is delegated to the database
51
+ delegate send_request: :@database
52
+
45
53
  # Create a new Collection object with a name and an optional ID
46
- #
54
+ #
47
55
  # @param [Database] database The database the connection belongs to
48
56
  # @param [Hash] raw_collection The raw collection returned from the server
49
57
  # @api public
@@ -64,9 +72,9 @@ module Ashikawa
64
72
  @id = raw_collection['id'].to_i if raw_collection.has_key? 'id'
65
73
  @status = raw_collection['status'].to_i if raw_collection.has_key? 'status'
66
74
  end
67
-
75
+
68
76
  # Change the name of the collection
69
- #
77
+ #
70
78
  # @param [String] new_name New Name
71
79
  # @return [String] New Name
72
80
  # @api public
@@ -88,9 +96,9 @@ module Ashikawa
88
96
  send_request_for_this_collection "/rename", put: { "name" => new_name }
89
97
  @name = new_name
90
98
  end
91
-
99
+
92
100
  # Checks if the collection is new born
93
- #
101
+ #
94
102
  # @return [Boolean]
95
103
  # @api public
96
104
  # @example Is the collection new born?
@@ -108,9 +116,9 @@ module Ashikawa
108
116
  def new_born?
109
117
  @status == 1
110
118
  end
111
-
119
+
112
120
  # Checks if the collection is unloaded
113
- #
121
+ #
114
122
  # @return [Boolean]
115
123
  # @api public
116
124
  # @example Is the collection unloaded?
@@ -128,9 +136,9 @@ module Ashikawa
128
136
  def unloaded?
129
137
  @status == 2
130
138
  end
131
-
139
+
132
140
  # Checks if the collection is loaded
133
- #
141
+ #
134
142
  # @return [Boolean]
135
143
  # @api public
136
144
  # @example Is the collection loaded?
@@ -148,9 +156,9 @@ module Ashikawa
148
156
  def loaded?
149
157
  @status == 3
150
158
  end
151
-
159
+
152
160
  # Checks if the collection is in the process of being unloaded
153
- #
161
+ #
154
162
  # @return [Boolean]
155
163
  # @api public
156
164
  # @example Is the collection unloaded?
@@ -168,9 +176,9 @@ module Ashikawa
168
176
  def being_unloaded?
169
177
  @status == 4
170
178
  end
171
-
179
+
172
180
  # Checks if the collection is corrupted
173
- #
181
+ #
174
182
  # @return [Boolean]
175
183
  # @api public
176
184
  # @example Is the collection corrupted?
@@ -188,9 +196,9 @@ module Ashikawa
188
196
  def corrupted?
189
197
  @status > 5
190
198
  end
191
-
199
+
192
200
  # Does the document wait until the data has been synchronised to disk?
193
- #
201
+ #
194
202
  # @return [Boolean]
195
203
  # @api public
196
204
  # @example Does the collection wait for file synchronization?
@@ -209,9 +217,9 @@ module Ashikawa
209
217
  server_response = send_request_for_this_collection "/properties"
210
218
  server_response["waitForSync"]
211
219
  end
212
-
220
+
213
221
  # Change if the document will wait until the data has been synchronised to disk
214
- #
222
+ #
215
223
  # @return [String] Response from the server
216
224
  # @api public
217
225
  # @example Tell the collection to wait for file synchronization
@@ -227,11 +235,11 @@ module Ashikawa
227
235
  # collection = Ashikawa::Core::Collection.new database, raw_collection
228
236
  # collection.wait_for_sync = true
229
237
  def wait_for_sync=(new_value)
230
- server_response = send_request_for_this_collection "/properties", put: { "waitForSync" => new_value }
238
+ send_request_for_this_collection "/properties", put: { "waitForSync" => new_value }
231
239
  end
232
-
240
+
233
241
  # Returns the number of documents in the collection
234
- #
242
+ #
235
243
  # @return [Fixnum] Number of documents
236
244
  # @api public
237
245
  # @example How many documents are in the collection?
@@ -250,9 +258,9 @@ module Ashikawa
250
258
  server_response = send_request_for_this_collection "/count"
251
259
  server_response["count"]
252
260
  end
253
-
261
+
254
262
  # Return a figure for the collection
255
- #
263
+ #
256
264
  # @param [Symbol] figure_type The figure you want to know:
257
265
  # * :datafiles_count - the number of active datafiles
258
266
  # * :alive_size - the total size in bytes used by all living documents
@@ -275,13 +283,12 @@ module Ashikawa
275
283
  # collection.figure :datafiles_count #=> 0
276
284
  def figure(figure_type)
277
285
  server_response = send_request_for_this_collection "/figures"
278
-
279
286
  figure_area, figure_name = figure_type.to_s.split "_"
280
287
  server_response["figures"][figure_area][figure_name]
281
288
  end
282
-
289
+
283
290
  # Deletes the collection
284
- #
291
+ #
285
292
  # @return [String] Response from the server
286
293
  # @api public
287
294
  # @example Delete a collection
@@ -299,9 +306,9 @@ module Ashikawa
299
306
  def delete
300
307
  send_request_for_this_collection "", delete: {}
301
308
  end
302
-
309
+
303
310
  # Load the collection into memory
304
- #
311
+ #
305
312
  # @return [String] Response from the server
306
313
  # @api public
307
314
  # @example Load a collection into memory
@@ -319,9 +326,9 @@ module Ashikawa
319
326
  def load
320
327
  send_request_for_this_collection "/load", put: {}
321
328
  end
322
-
329
+
323
330
  # Load the collection into memory
324
- #
331
+ #
325
332
  # @return [String] Response from the server
326
333
  # @api public
327
334
  # @example Unload a collection into memory
@@ -339,9 +346,9 @@ module Ashikawa
339
346
  def unload
340
347
  send_request_for_this_collection "/unload", put: {}
341
348
  end
342
-
349
+
343
350
  # Delete all documents from the collection
344
- #
351
+ #
345
352
  # @return [String] Response from the server
346
353
  # @api public
347
354
  # @example Remove all documents from a collection
@@ -359,14 +366,13 @@ module Ashikawa
359
366
  def truncate!
360
367
  send_request_for_this_collection "/truncate", put: {}
361
368
  end
362
-
369
+
363
370
  # Retrieves all documents for this collection
364
- #
371
+ #
365
372
  # @note It is advised to NOT use this method due to possible HUGE data amounts requested
366
- # @param [Hash] options Additional options for this query.
367
373
  # @option options [Integer] :limit limit the maximum number of queried and returned elements.
368
374
  # @option options [Integer] :skip skip the first <n> documents of the query.
369
- # @return [Array<Document>]
375
+ # @return [Cursor]
370
376
  # @api public
371
377
  # @example Get an array with all documents
372
378
  # database = Ashikawa::Core::Database.new "http://localhost:8529"
@@ -379,25 +385,17 @@ module Ashikawa
379
385
  # "code" => 200
380
386
  # }
381
387
  # collection = Ashikawa::Core::Collection.new database, raw_collection
382
- # collection.all # => [#<Document id=43>]
388
+ # collection.all # => #<Cursor id=33>
383
389
  def all(options={})
384
- request_data = { "collection" => @name }
385
-
386
- request_data["limit"] = options[:limit] if options.has_key? :limit
387
- request_data["skip"] = options[:skip] if options.has_key? :skip
388
-
389
- server_response = @database.send_request "/simple/all", :put => request_data
390
-
391
- documents_from_response(server_response)
390
+ send_simple_query "/simple/all", options, [:limit, :skip]
392
391
  end
393
-
392
+
394
393
  # Looks for documents in the collection which match the given criteria
395
- #
396
- # @param [Hash] reference_data a Hash with data similar to the documents you are looking for.
397
- # @param [Hash] options Additional options for this query.
394
+ #
395
+ # @option options [Hash] :example a Hash with data matching the documents you are looking for.
398
396
  # @option options [Integer] :limit limit the maximum number of queried and returned elements.
399
397
  # @option options [Integer] :skip skip the first <n> documents of the query.
400
- # @return [Array<Document>]
398
+ # @return [Cursor]
401
399
  # @api public
402
400
  # @example Find all documents in the collection that are red
403
401
  # database = Ashikawa::Core::Database.new "http://localhost:8529"
@@ -410,26 +408,45 @@ module Ashikawa
410
408
  # "code" => 200
411
409
  # }
412
410
  # collection = Ashikawa::Core::Collection.new database, raw_collection
413
- # collection.by_example { "color" => "red"} # => [#<Document id=2444 color="red">]
414
- def by_example(reference_data, options={})
415
- request_data = { "collection" => @name, "example" => reference_data }
416
-
417
- request_data["limit"] = options[:limit] if options.has_key? :limit
418
- request_data["skip"] = options[:skip] if options.has_key? :skip
419
-
420
- server_response = @database.send_request "/simple/by-example", :put => request_data
421
-
422
- documents_from_response(server_response)
411
+ # collection.by_example example: { "color" => "red"} # => #<Cursor id=2444>
412
+ def by_example(options={})
413
+ send_simple_query "/simple/by-example", options, [:limit, :skip, :example]
423
414
  end
424
-
415
+
416
+ # Looks for one document in the collection which matches the given criteria
417
+ #
418
+ # @param [Hash] example a Hash with data matching the document you are looking for.
419
+ # @return [Document]
420
+ # @api public
421
+ # @example Find one document in the collection that is red
422
+ # database = Ashikawa::Core::Database.new "http://localhost:8529"
423
+ # raw_collection = {
424
+ # "name" => "example_1",
425
+ # "waitForSync" => true,
426
+ # "id" => 4588,
427
+ # "status" => 3,
428
+ # "error" => false,
429
+ # "code" => 200
430
+ # }
431
+ # collection = Ashikawa::Core::Collection.new database, raw_collection
432
+ # collection.first_example { "color" => "red"} # => #<Document id=2444 color="red">
433
+ def first_example(example)
434
+ server_response = send_request "/simple/first-example",
435
+ put: { "collection" => @name, "example" => example }
436
+ Document.new @database, server_response
437
+ end
438
+
425
439
  # Looks for documents in the collection based on location
426
440
  #
427
- # @param [Hash] options Options for this search.
428
441
  # @option options [Integer] :latitude Latitude location for your search.
429
442
  # @option options [Integer] :longitude Longitude location for your search.
430
- # @return [Array<Document>]
443
+ # @option options [Integer] :skip The documents to skip in the query.
444
+ # @option options [Integer] :distance If given, the attribute key used to store the distance.
445
+ # @option options [Integer] :limit The maximal amount of documents to return (default: 100).
446
+ # @option options [Integer] :geo If given, the identifier of the geo-index to use.
447
+ # @return [Cursor]
431
448
  # @api public
432
- # @example Find all documents at Infinite Loop
449
+ # @example Find all documents at Infinite Loop
433
450
  # database = Ashikawa::Core::Database.new "http://localhost:8529"
434
451
  # raw_collection = {
435
452
  # "name" => "example_1",
@@ -442,23 +459,19 @@ module Ashikawa
442
459
  # collection = Ashikawa::Core::Collection.new database, raw_collection
443
460
  # collection.near latitude: 37.331693, longitude: -122.030468
444
461
  def near(options={})
445
- request_data = { "collection" => @name }
446
-
447
- request_data["latitude"] = options[:latitude] if options.has_key? :latitude
448
- request_data["longitude"] = options[:longitude] if options.has_key? :longitude
449
-
450
- server_response = @database.send_request "/simple/near", :put => request_data
451
-
452
- documents_from_response(server_response)
462
+ send_simple_query "/simple/near", options, [:latitude, :longitude, :distance, :skip, :limit, :geo]
453
463
  end
454
464
 
455
465
  # Looks for documents in the collection within a certain radius
456
466
  #
457
- # @param [Hash] options Options for this search.
458
467
  # @option options [Integer] :latitude Latitude location for your search.
459
468
  # @option options [Integer] :longitude Longitude location for your search.
460
469
  # @option options [Integer] :radius Radius around the given location you want to search in.
461
- # @return [Array<Document>]
470
+ # @option options [Integer] :skip The documents to skip in the query.
471
+ # @option options [Integer] :distance If given, the attribute key used to store the distance.
472
+ # @option options [Integer] :limit The maximal amount of documents to return (default: 100).
473
+ # @option options [Integer] :geo If given, the identifier of the geo-index to use.
474
+ # @return [Cursor]
462
475
  # @api public
463
476
  # @example Find all documents within a radius of 100 to Infinite Loop
464
477
  # database = Ashikawa::Core::Database.new "http://localhost:8529"
@@ -473,26 +486,101 @@ module Ashikawa
473
486
  # collection = Ashikawa::Core::Collection.new database, raw_collection
474
487
  # collection.within latitude: 37.331693, longitude: -122.030468, radius: 100
475
488
  def within(options={})
476
- request_data = { "collection" => @name }
477
-
478
- request_data["latitude"] = options[:latitude] if options.has_key? :latitude
479
- request_data["longitude"] = options[:longitude] if options.has_key? :longitude
480
- request_data["radius"] = options[:radius] if options.has_key? :radius
489
+ send_simple_query "/simple/within", options, [:latitude, :longitude, :radius, :distance, :skip, :limit, :geo]
490
+ end
481
491
 
482
- server_response = @database.send_request "/simple/within", :put => request_data
483
492
 
484
- documents_from_response(server_response)
493
+ # Looks for documents in the collection with an attribute between two values
494
+ #
495
+ # @option options [Integer] :attribute The attribute path to check.
496
+ # @option options [Integer] :left The lower bound
497
+ # @option options [Integer] :right The upper bound
498
+ # @option options [Integer] :closed If true, use intervall including left and right, otherwise exclude right, but include left.
499
+ # @option options [Integer] :skip The documents to skip in the query (optional).
500
+ # @option options [Integer] :limit The maximal amount of documents to return (optional).
501
+ # @return [Cursor]
502
+ # @api public
503
+ def in_range(options={})
504
+ send_simple_query "/simple/range", options, [:attribute, :left, :right, :closed, :limit, :skip]
485
505
  end
486
506
 
487
507
  # Fetch a certain document by its ID
488
- #
508
+ #
489
509
  # @param [Integer] document_id the id of the document
510
+ # @raise [DocumentNotFoundException] If the requested document was not found
490
511
  # @return Document
491
512
  # @api public
492
513
  # @example Fetch a document with the ID 12345
493
514
  # document = collection[12345]
494
515
  def [](document_id)
495
- Ashikawa::Core::Document.new "#{@id}/#{document_id}"
516
+ begin
517
+ server_response = send_request "/document/#{@id}/#{document_id}"
518
+ rescue RestClient::ResourceNotFound
519
+ raise DocumentNotFoundException
520
+ end
521
+
522
+ Document.new @database, server_response
523
+ end
524
+
525
+ # Replace a certain document by its ID
526
+ #
527
+ # @param [Integer] document_id the id of the document
528
+ # @param [Hash] raw_document the data you want to replace it with
529
+ # @api public
530
+ def []=(document_id, raw_document)
531
+ send_request "/document/#{@id}/#{document_id}", put: raw_document
532
+ end
533
+
534
+ # Create a document with given raw data
535
+ #
536
+ # @param [Hash] raw_document
537
+ # @return DocumentHash
538
+ # @api public
539
+ def create(raw_document)
540
+ server_response = send_request "/document?collection=#{@id}",
541
+ post: raw_document
542
+
543
+ Document.new @database, server_response
544
+ end
545
+
546
+ alias :<< :create
547
+
548
+ # Add an index to the collection
549
+ #
550
+ # @param [Symbol] type What kind of index?
551
+ # @option opts [Array<Symbol>] on On which fields?
552
+ # @return Index
553
+ # @api public
554
+ def add_index(type, opts)
555
+ server_response = send_request "/index?collection=#{@id}", post: {
556
+ "type" => type.to_s,
557
+ "fields" => opts[:on].map { |field| field.to_s }
558
+ }
559
+
560
+ Index.new self, server_response
561
+ end
562
+
563
+ # Get an index by ID
564
+ #
565
+ # @param [Int] id
566
+ # @return Index
567
+ # @api public
568
+ def index(id)
569
+ server_response = send_request "/index/#{@id}/#{id}"
570
+
571
+ Index.new self, server_response
572
+ end
573
+
574
+ # Get all indices
575
+ #
576
+ # @return [Array<Index>]
577
+ # @api public
578
+ def indices
579
+ server_response = send_request "/index?collection=#{@id}"
580
+
581
+ server_response["indexes"].map do |raw_index|
582
+ Index.new self, raw_index
583
+ end
496
584
  end
497
585
 
498
586
  private
@@ -502,22 +590,25 @@ module Ashikawa
502
590
  # @return [String] Response from the server
503
591
  # @api private
504
592
  def send_request_for_this_collection(path, method={})
505
- if method == {}
506
- @database.send_request "/collection/#{id}#{path}"
507
- else
508
- @database.send_request "/collection/#{id}#{path}", method
509
- end
593
+ send_request "/collection/#{id}#{path}", method
510
594
  end
511
595
 
512
- # Takes JSON returned by the database and collects Documents from the data
513
- #
514
- # @param [Array<Hash>] parsed_server_response parsed JSON response from the server. Should contain document-hashes.
515
- # @return [Array<Document>]
596
+ # Send a simple query to the server
597
+ #
598
+ # @param [String] path The path for the request
599
+ # @param [Hash] options The options given to the method
600
+ # @param [Array<Symbol>] keys The required keys
601
+ # @return [Hash] The parsed hash for the request
516
602
  # @api private
517
- def documents_from_response(parsed_server_response)
518
- parsed_server_response.collect do |document|
519
- Ashikawa::Core::Document.new(document["_id"], document["_rev"])
603
+ def send_simple_query(path, options, keys)
604
+ request_data = { "collection" => @name }
605
+
606
+ keys.each do |key|
607
+ request_data[key.to_s] = options[key] if options.has_key? key
520
608
  end
609
+
610
+ server_response = send_request path, :put => request_data
611
+ Cursor.new @database, server_response
521
612
  end
522
613
  end
523
614
  end