ashikawa-core 0.1 → 0.2

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 (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