ashikawa-core 0.4.1 → 0.5.1
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/.gitignore +2 -0
- data/.travis.yml +2 -0
- data/CONTRIBUTING.md +5 -8
- data/Guardfile +1 -1
- data/README.md +15 -1
- data/Rakefile +45 -12
- data/ashikawa-core.gemspec +13 -6
- data/lib/ashikawa-core/collection.rb +24 -160
- data/lib/ashikawa-core/connection.rb +64 -38
- data/lib/ashikawa-core/cursor.rb +15 -9
- data/lib/ashikawa-core/database.rb +5 -12
- data/lib/ashikawa-core/document.rb +13 -10
- data/lib/ashikawa-core/exceptions/document_not_found.rb +4 -1
- data/lib/ashikawa-core/exceptions/no_collection_provided.rb +11 -0
- data/lib/ashikawa-core/index.rb +6 -6
- data/lib/ashikawa-core/query.rb +251 -0
- data/lib/ashikawa-core/version.rb +1 -1
- data/spec/{integration → acceptance}/arango_helper.rb +1 -1
- data/spec/{integration → acceptance}/basic_spec.rb +4 -4
- data/spec/{integration → acceptance}/index_spec.rb +1 -1
- data/spec/acceptance/query_spec.rb +90 -0
- data/spec/{integration → acceptance}/spec_helper.rb +0 -0
- data/spec/{integration_auth → acceptance_auth}/arango_helper.rb +1 -1
- data/spec/{integration_auth → acceptance_auth}/auth_spec.rb +1 -1
- data/spec/{integration_auth → acceptance_auth}/spec_helper.rb +0 -0
- data/spec/fixtures/query/valid.json +5 -0
- data/spec/setup/arangodb.sh +68 -0
- data/spec/unit/collection_spec.rb +43 -143
- data/spec/unit/database_spec.rb +10 -14
- data/spec/unit/exception_spec.rb +14 -0
- data/spec/unit/query_spec.rb +215 -0
- data/spec/unit/spec_helper.rb +7 -1
- metadata +107 -30
- data/spec/integration/query_spec.rb +0 -78
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CONTRIBUTING.md
CHANGED
@@ -3,10 +3,11 @@
|
|
3
3
|
When you want to write code for the project, please follow these guidelines:
|
4
4
|
|
5
5
|
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 ;) )
|
6
|
-
2.
|
7
|
-
3.
|
8
|
-
4. Write
|
9
|
-
5.
|
6
|
+
2. Fork your feature branch from the `development` branch (not the `master` branch)
|
7
|
+
3. Write an acceptance test: Describe what you want to do (our integration tests touch the database)
|
8
|
+
4. Implement it: Write a unit test, check that it fails, make the test pass – repeat (our unit tests don't touch the database)
|
9
|
+
5. Write documentation for it.
|
10
|
+
6. Check with `rake` that everything is fine and send the pull request to the `development` branch :)
|
10
11
|
|
11
12
|
## How to get started developing
|
12
13
|
|
@@ -38,7 +39,3 @@ Guard is a tool for comfortable development. If you want to use it for developme
|
|
38
39
|
* Run a documentation server on `http://localhost:8808`
|
39
40
|
* Run `bundle` whenever you change the dependencies
|
40
41
|
* Run the integration and unit tests whenever you change a file in the lib or spec directory
|
41
|
-
|
42
|
-
### Continuous Integration
|
43
|
-
|
44
|
-
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). Therefore it is important that you run the integration tests on your local machine before sending the pull requests.
|
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -6,6 +6,16 @@
|
|
6
6
|
|
7
7
|
Ashikawa Core is a Wrapper around the ArangoDB Rest API. It provides low level access and will be used in different ArangoDB ODMs.
|
8
8
|
|
9
|
+
All tests run on Travis CI for the following versions of Ruby:
|
10
|
+
|
11
|
+
* MRI 1.9.2 and 1.9.3
|
12
|
+
* Rubinius 1.9 mode
|
13
|
+
* JRuby 1.9 mode
|
14
|
+
|
15
|
+
We also run on JRuby and MRI Head. MRI-head is currently not passing, because some dependencies are not compatible.
|
16
|
+
|
17
|
+
Please note that the `master` branch is always the stable version released on Ruby Gems (*This is actually a lie, but we are currently converting to this model ;) The next release will implement this*). If you want the most recent version, please refer to the `development` branch.
|
18
|
+
|
9
19
|
## How to use it
|
10
20
|
|
11
21
|
For a detailed description of Ashikawa::Core please refer to the [documentation](http://rdoc.info/github/triAGENS/ashikawa-core/master/frames). An example:
|
@@ -18,6 +28,10 @@ database["my_collection"].name = "new_name"
|
|
18
28
|
database["new_name"].delete
|
19
29
|
```
|
20
30
|
|
31
|
+
# Issues or Questions
|
32
|
+
|
33
|
+
If you find a bug in this gem, please report it on [our tracker](https://github.com/triAGENS/ashikawa-core/issues). If you have a question, just contact us via the [mailing list](https://groups.google.com/forum/?fromgroups#!forum/ashikawa) – we are happy to help you :)
|
34
|
+
|
21
35
|
# Contributing
|
22
36
|
|
23
|
-
If you want to contribute to the project, see CONTRIBUTING.md for details.
|
37
|
+
If you want to contribute to the project, see CONTRIBUTING.md for details. It contains information on our process and how to set up everything.
|
data/Rakefile
CHANGED
@@ -2,21 +2,28 @@
|
|
2
2
|
require "bundler/gem_tasks"
|
3
3
|
require "rspec"
|
4
4
|
require "rspec/core/rake_task"
|
5
|
+
require "roodi"
|
6
|
+
require "roodi_task"
|
5
7
|
# require 'yardstick/rake/measurement'
|
6
8
|
# require 'yardstick/rake/verify'
|
7
9
|
|
8
10
|
|
9
11
|
namespace :spec do
|
10
|
-
desc "Run the
|
11
|
-
RSpec::Core::RakeTask.new(:
|
12
|
-
spec.
|
13
|
-
spec.pattern = "spec/integration/*_spec.rb"
|
12
|
+
desc "Run the acceptance tests. Requires ArangoDB to be running."
|
13
|
+
RSpec::Core::RakeTask.new(:acceptance_with_running_arangodb) do |spec|
|
14
|
+
spec.pattern = "spec/acceptance/*_spec.rb"
|
14
15
|
end
|
15
16
|
|
16
|
-
desc "Run the
|
17
|
-
RSpec::Core::RakeTask.new(:
|
18
|
-
spec.rspec_opts = "--require
|
19
|
-
spec.pattern = "spec/
|
17
|
+
desc "Run the acceptance tests. Requires ArangoDB."
|
18
|
+
RSpec::Core::RakeTask.new(:acceptance) do |spec|
|
19
|
+
spec.rspec_opts = "--require acceptance/arango_helper.rb"
|
20
|
+
spec.pattern = "spec/acceptance/*_spec.rb"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Run the authentication acceptance tests. Requires ArangoDB."
|
24
|
+
RSpec::Core::RakeTask.new(:acceptance_auth) do |spec|
|
25
|
+
spec.rspec_opts = "--require acceptance_auth/arango_helper.rb"
|
26
|
+
spec.pattern = "spec/acceptance_auth/*_spec.rb"
|
20
27
|
end
|
21
28
|
|
22
29
|
desc "Run the unit tests"
|
@@ -25,7 +32,7 @@ namespace :spec do
|
|
25
32
|
end
|
26
33
|
|
27
34
|
desc "Run all tests. Requires ArangoDB"
|
28
|
-
task :all => [:
|
35
|
+
task :all => [:acceptance, :unit]
|
29
36
|
end
|
30
37
|
|
31
38
|
desc "check if gems are up to date"
|
@@ -64,10 +71,36 @@ namespace :yard do
|
|
64
71
|
end
|
65
72
|
end
|
66
73
|
|
67
|
-
|
74
|
+
namespace :metrics do
|
75
|
+
metric_tasks = []
|
76
|
+
|
77
|
+
begin
|
78
|
+
require 'cane/rake_task'
|
79
|
+
|
80
|
+
desc "Run cane to check quality metrics"
|
81
|
+
Cane::RakeTask.new(:cane) do |cane|
|
82
|
+
cane.abc_max = 10
|
83
|
+
cane.style_measure = 140
|
84
|
+
cane.style_glob = "{app,lib}/**/*.rb"
|
85
|
+
end
|
86
|
+
|
87
|
+
metric_tasks << :cane
|
88
|
+
rescue LoadError
|
89
|
+
warn "cane not available, quality task not provided."
|
90
|
+
end
|
91
|
+
|
92
|
+
RoodiTask.new do |roodi|
|
93
|
+
roodi.patterns = %w(lib/**/*.rb spec/**/*.rb)
|
94
|
+
end
|
95
|
+
metric_tasks << :roodi
|
96
|
+
|
97
|
+
task :all => metric_tasks
|
98
|
+
end
|
99
|
+
|
100
|
+
desc "Run Unit Tests - no ArangoDB required"
|
68
101
|
# task :ci => ["spec:unit", "yard:verify"]
|
69
|
-
task :ci => ["spec:unit"]
|
102
|
+
task :ci => ["spec:unit", "spec:acceptance_with_running_arangodb", "metrics:all"]
|
70
103
|
|
71
104
|
desc "Run all tests and verify documentation - ArangoDB required"
|
72
105
|
# task :default => ["spec:all", "yard:verify"]
|
73
|
-
task :default => ["spec:all"]
|
106
|
+
task :default => ["spec:all", "metrics:all"]
|
data/ashikawa-core.gemspec
CHANGED
@@ -31,19 +31,26 @@ Gem::Specification.new do |gem|
|
|
31
31
|
else
|
32
32
|
# RedCarpet is not compatible with JRuby
|
33
33
|
# It is only needed to generate the YARD Documentation
|
34
|
-
gem.add_development_dependency "redcarpet", "~> 2.2.
|
34
|
+
gem.add_development_dependency "redcarpet", "~> 2.2.2"
|
35
35
|
end
|
36
36
|
|
37
37
|
# Development Dependencies
|
38
38
|
gem.add_development_dependency "rake", "~> 0.9.2.2"
|
39
39
|
gem.add_development_dependency "rspec", "~> 2.11.0"
|
40
40
|
gem.add_development_dependency "yard", "~> 0.8.3"
|
41
|
-
gem.add_development_dependency "webmock", "~> 1.
|
41
|
+
gem.add_development_dependency "webmock", "~> 1.9.0"
|
42
42
|
# gem.add_development_dependency "yardstick", "~> 0.6.0"
|
43
|
+
gem.add_development_dependency "simplecov", "~> 0.7.1"
|
44
|
+
gem.add_development_dependency "cane", "~> 2.4.0"
|
45
|
+
gem.add_development_dependency "roodi1.9", "~> 2.0.1"
|
43
46
|
|
44
|
-
|
45
|
-
|
47
|
+
# Do not update to version 3, it is currently not compatible with roodi1.9
|
48
|
+
# see grsmv/roodi1.9#1
|
49
|
+
gem.add_development_dependency "ruby_parser", "~> 2.3.1"
|
50
|
+
|
51
|
+
gem.add_development_dependency "guard", "~> 1.5.3"
|
52
|
+
gem.add_development_dependency "guard-rspec", "~> 2.1.1"
|
46
53
|
gem.add_development_dependency "guard-bundler", "~> 1.0.0"
|
47
|
-
gem.add_development_dependency "guard-yard", "~> 2.0.
|
48
|
-
gem.add_development_dependency "rb-fsevent", "~> 0.9.
|
54
|
+
gem.add_development_dependency "guard-yard", "~> 2.0.1"
|
55
|
+
gem.add_development_dependency "rb-fsevent", "~> 0.9.2"
|
49
56
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require "ashikawa-core/document"
|
2
2
|
require "ashikawa-core/index"
|
3
3
|
require "ashikawa-core/cursor"
|
4
|
+
require "ashikawa-core/query"
|
5
|
+
require "restclient/exceptions"
|
4
6
|
require "forwardable"
|
5
7
|
|
6
8
|
module Ashikawa
|
@@ -47,6 +49,12 @@ module Ashikawa
|
|
47
49
|
# collection.id #=> 4588
|
48
50
|
attr_reader :id
|
49
51
|
|
52
|
+
# The database the collection belongs to
|
53
|
+
#
|
54
|
+
# @return [Database]
|
55
|
+
# @api public
|
56
|
+
attr_reader :database
|
57
|
+
|
50
58
|
# Sending requests is delegated to the database
|
51
59
|
delegate send_request: :@database
|
52
60
|
|
@@ -367,143 +375,6 @@ module Ashikawa
|
|
367
375
|
send_request_for_this_collection "/truncate", put: {}
|
368
376
|
end
|
369
377
|
|
370
|
-
# Retrieves all documents for this collection
|
371
|
-
#
|
372
|
-
# @note It is advised to NOT use this method due to possible HUGE data amounts requested
|
373
|
-
# @option options [Integer] :limit limit the maximum number of queried and returned elements.
|
374
|
-
# @option options [Integer] :skip skip the first <n> documents of the query.
|
375
|
-
# @return [Cursor]
|
376
|
-
# @api public
|
377
|
-
# @example Get an array with all documents
|
378
|
-
# database = Ashikawa::Core::Database.new "http://localhost:8529"
|
379
|
-
# raw_collection = {
|
380
|
-
# "name" => "example_1",
|
381
|
-
# "waitForSync" => true,
|
382
|
-
# "id" => 4588,
|
383
|
-
# "status" => 3,
|
384
|
-
# "error" => false,
|
385
|
-
# "code" => 200
|
386
|
-
# }
|
387
|
-
# collection = Ashikawa::Core::Collection.new database, raw_collection
|
388
|
-
# collection.all # => #<Cursor id=33>
|
389
|
-
def all(options={})
|
390
|
-
send_simple_query "/simple/all", options, [:limit, :skip]
|
391
|
-
end
|
392
|
-
|
393
|
-
# Looks for documents in the collection which match the given criteria
|
394
|
-
#
|
395
|
-
# @option options [Hash] :example a Hash with data matching the documents you are looking for.
|
396
|
-
# @option options [Integer] :limit limit the maximum number of queried and returned elements.
|
397
|
-
# @option options [Integer] :skip skip the first <n> documents of the query.
|
398
|
-
# @return [Cursor]
|
399
|
-
# @api public
|
400
|
-
# @example Find all documents in the collection that are red
|
401
|
-
# database = Ashikawa::Core::Database.new "http://localhost:8529"
|
402
|
-
# raw_collection = {
|
403
|
-
# "name" => "example_1",
|
404
|
-
# "waitForSync" => true,
|
405
|
-
# "id" => 4588,
|
406
|
-
# "status" => 3,
|
407
|
-
# "error" => false,
|
408
|
-
# "code" => 200
|
409
|
-
# }
|
410
|
-
# collection = Ashikawa::Core::Collection.new database, raw_collection
|
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]
|
414
|
-
end
|
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
|
-
|
439
|
-
# Looks for documents in the collection based on location
|
440
|
-
#
|
441
|
-
# @option options [Integer] :latitude Latitude location for your search.
|
442
|
-
# @option options [Integer] :longitude Longitude location for your search.
|
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]
|
448
|
-
# @api public
|
449
|
-
# @example Find all documents at Infinite Loop
|
450
|
-
# database = Ashikawa::Core::Database.new "http://localhost:8529"
|
451
|
-
# raw_collection = {
|
452
|
-
# "name" => "example_1",
|
453
|
-
# "waitForSync" => true,
|
454
|
-
# "id" => 4588,
|
455
|
-
# "status" => 3,
|
456
|
-
# "error" => false,
|
457
|
-
# "code" => 200
|
458
|
-
# }
|
459
|
-
# collection = Ashikawa::Core::Collection.new database, raw_collection
|
460
|
-
# collection.near latitude: 37.331693, longitude: -122.030468
|
461
|
-
def near(options={})
|
462
|
-
send_simple_query "/simple/near", options, [:latitude, :longitude, :distance, :skip, :limit, :geo]
|
463
|
-
end
|
464
|
-
|
465
|
-
# Looks for documents in the collection within a certain radius
|
466
|
-
#
|
467
|
-
# @option options [Integer] :latitude Latitude location for your search.
|
468
|
-
# @option options [Integer] :longitude Longitude location for your search.
|
469
|
-
# @option options [Integer] :radius Radius around the given location you want to search in.
|
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]
|
475
|
-
# @api public
|
476
|
-
# @example Find all documents within a radius of 100 to Infinite Loop
|
477
|
-
# database = Ashikawa::Core::Database.new "http://localhost:8529"
|
478
|
-
# raw_collection = {
|
479
|
-
# "name" => "example_1",
|
480
|
-
# "waitForSync" => true,
|
481
|
-
# "id" => 4588,
|
482
|
-
# "status" => 3,
|
483
|
-
# "error" => false,
|
484
|
-
# "code" => 200
|
485
|
-
# }
|
486
|
-
# collection = Ashikawa::Core::Collection.new database, raw_collection
|
487
|
-
# collection.within latitude: 37.331693, longitude: -122.030468, radius: 100
|
488
|
-
def within(options={})
|
489
|
-
send_simple_query "/simple/within", options, [:latitude, :longitude, :radius, :distance, :skip, :limit, :geo]
|
490
|
-
end
|
491
|
-
|
492
|
-
|
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]
|
505
|
-
end
|
506
|
-
|
507
378
|
# Fetch a certain document by its ID
|
508
379
|
#
|
509
380
|
# @param [Integer] document_id the id of the document
|
@@ -522,7 +393,7 @@ module Ashikawa
|
|
522
393
|
Document.new @database, server_response
|
523
394
|
end
|
524
395
|
|
525
|
-
# Replace a
|
396
|
+
# Replace a document by its ID
|
526
397
|
#
|
527
398
|
# @param [Integer] document_id the id of the document
|
528
399
|
# @param [Hash] raw_document the data you want to replace it with
|
@@ -531,7 +402,7 @@ module Ashikawa
|
|
531
402
|
send_request "/document/#{@id}/#{document_id}", put: raw_document
|
532
403
|
end
|
533
404
|
|
534
|
-
# Create a document
|
405
|
+
# Create a new document from raw data
|
535
406
|
#
|
536
407
|
# @param [Hash] raw_document
|
537
408
|
# @return DocumentHash
|
@@ -547,10 +418,13 @@ module Ashikawa
|
|
547
418
|
|
548
419
|
# Add an index to the collection
|
549
420
|
#
|
550
|
-
# @param [Symbol] type
|
551
|
-
# @option opts [Array<Symbol>] on
|
421
|
+
# @param [Symbol] type specify the type of the index, for example `:hash`
|
422
|
+
# @option opts [Array<Symbol>] on fields on which to apply the index
|
552
423
|
# @return Index
|
553
424
|
# @api public
|
425
|
+
# @example Add a hash-index to the fields :name and :profession of a collection
|
426
|
+
# people = database['people']
|
427
|
+
# people.add_index :hash, :on => [:name, :profession]
|
554
428
|
def add_index(type, opts)
|
555
429
|
server_response = send_request "/index?collection=#{@id}", post: {
|
556
430
|
"type" => type.to_s,
|
@@ -562,7 +436,7 @@ module Ashikawa
|
|
562
436
|
|
563
437
|
# Get an index by ID
|
564
438
|
#
|
565
|
-
# @param [
|
439
|
+
# @param [Integer] id
|
566
440
|
# @return Index
|
567
441
|
# @api public
|
568
442
|
def index(id)
|
@@ -583,6 +457,14 @@ module Ashikawa
|
|
583
457
|
end
|
584
458
|
end
|
585
459
|
|
460
|
+
# Return a Query initialized with this collection
|
461
|
+
#
|
462
|
+
# @return [Query]
|
463
|
+
# @api public
|
464
|
+
def query
|
465
|
+
Query.new self
|
466
|
+
end
|
467
|
+
|
586
468
|
private
|
587
469
|
|
588
470
|
# Send a request to the server with the name of the collection prepended
|
@@ -592,24 +474,6 @@ module Ashikawa
|
|
592
474
|
def send_request_for_this_collection(path, method={})
|
593
475
|
send_request "/collection/#{id}#{path}", method
|
594
476
|
end
|
595
|
-
|
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
|
602
|
-
# @api private
|
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
|
608
|
-
end
|
609
|
-
|
610
|
-
server_response = send_request path, :put => request_data
|
611
|
-
Cursor.new @database, server_response
|
612
|
-
end
|
613
477
|
end
|
614
478
|
end
|
615
479
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "rest-client"
|
2
2
|
require "json"
|
3
|
+
require "uri"
|
3
4
|
|
4
5
|
module Ashikawa
|
5
6
|
module Core
|
@@ -49,68 +50,93 @@ module Ashikawa
|
|
49
50
|
# @api public
|
50
51
|
# @example Create a new Connection
|
51
52
|
# connection = Connection.new "http://localhost:8529"
|
52
|
-
def initialize(api_string="http://localhost:8529")
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
uri = URI(@api_string)
|
57
|
-
@host = uri.host
|
58
|
-
@port = uri.port
|
53
|
+
def initialize(api_string = "http://localhost:8529")
|
54
|
+
uri = URI api_string
|
55
|
+
@host = uri.host
|
56
|
+
@port = uri.port
|
59
57
|
@scheme = uri.scheme
|
60
58
|
end
|
61
59
|
|
62
|
-
|
63
|
-
|
64
|
-
@username = options[:username]
|
65
|
-
@password = options[:password]
|
66
|
-
else
|
67
|
-
raise ArgumentError, 'missing username or password'
|
68
|
-
end
|
69
|
-
|
70
|
-
self
|
71
|
-
end
|
72
|
-
|
73
|
-
# Sends a request to a given path (Prepends the api_string automatically)
|
60
|
+
# Sends a request to a given path returning the parsed result
|
61
|
+
# (Prepends the api_string automatically)
|
74
62
|
#
|
75
63
|
# @example get request
|
76
64
|
# connection.send_request('/collection/new_collection')
|
77
65
|
# @example post request
|
78
66
|
# connection.send_request('/collection/new_collection', :post => { :name => 'new_collection' })
|
79
67
|
# @param [String] path the path you wish to send a request to.
|
80
|
-
# @
|
81
|
-
# @option method_params [Hash] :post POST data in case you want to send a POST request.
|
68
|
+
# @option params [Hash] :post POST data in case you want to send a POST request.
|
82
69
|
# @return [Hash] parsed JSON response from the server
|
83
|
-
# @api
|
84
|
-
def send_request(path,
|
85
|
-
|
70
|
+
# @api public
|
71
|
+
def send_request(path, params = {})
|
72
|
+
raw = raw_result_for path, params
|
73
|
+
JSON.parse raw
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sends a request to a given path returning the raw result
|
77
|
+
# (Prepends the api_string automatically)
|
78
|
+
#
|
79
|
+
# @example get request
|
80
|
+
# connection.raw_result_for('/collection/new_collection')
|
81
|
+
# @example post request
|
82
|
+
# connection.raw_result_for('/collection/new_collection', :post => { :name => 'new_collection' })
|
83
|
+
# @param [String] path the path you wish to send a request to.
|
84
|
+
# @option params [Hash] :post POST data in case you want to send a POST request.
|
85
|
+
# @return [String] raw response from the server
|
86
|
+
# @api public
|
87
|
+
def raw_result_for(path, params = {})
|
88
|
+
path = full_path path
|
89
|
+
method = [:post, :put, :delete].find { |method_name|
|
90
|
+
params.has_key? method_name
|
91
|
+
} || :get
|
86
92
|
|
87
|
-
|
88
|
-
RestClient.
|
89
|
-
elsif method_params.has_key? :put
|
90
|
-
RestClient.put path, method_params[:put].to_json
|
91
|
-
elsif method_params.has_key? :delete
|
92
|
-
RestClient.delete path
|
93
|
+
if [:post, :put].include? method
|
94
|
+
RestClient.send method, path, params[method].to_json
|
93
95
|
else
|
94
|
-
RestClient.
|
96
|
+
RestClient.send method, path
|
95
97
|
end
|
96
|
-
|
97
|
-
JSON.parse answer
|
98
98
|
end
|
99
99
|
|
100
|
+
# Checks if authentication for this Connection is active or not
|
101
|
+
#
|
102
|
+
# @return [Boolean]
|
103
|
+
# @api public
|
100
104
|
def authentication?
|
101
105
|
!!@username
|
102
106
|
end
|
103
107
|
|
104
|
-
|
108
|
+
# Authenticate with given username and password
|
109
|
+
#
|
110
|
+
# @option [String] username
|
111
|
+
# @option [String] password
|
112
|
+
# @return [self]
|
113
|
+
# @raise [ArgumentError] if username or password are missing
|
114
|
+
# @api public
|
115
|
+
def authenticate_with(options = {})
|
116
|
+
if options.key? :username and options.key? :password
|
117
|
+
@username = options[:username]
|
118
|
+
@password = options[:password]
|
119
|
+
else
|
120
|
+
raise ArgumentError, 'missing username or password'
|
121
|
+
end
|
122
|
+
|
123
|
+
self
|
124
|
+
end
|
105
125
|
|
106
|
-
|
107
|
-
|
126
|
+
# Return the full path for a given API path
|
127
|
+
#
|
128
|
+
# @param [String] path The API path
|
129
|
+
# @return [String] Full path
|
130
|
+
# @api public
|
131
|
+
def full_path(path)
|
132
|
+
prefix = if authentication?
|
108
133
|
"#{@scheme}://#{@username}:#{@password}@#{@host}:#{@port}"
|
109
134
|
else
|
110
|
-
@
|
135
|
+
"#{@scheme}://#{@host}:#{@port}"
|
111
136
|
end
|
112
|
-
end
|
113
137
|
|
138
|
+
"#{prefix}/_api/#{path.gsub(/^\//, '')}"
|
139
|
+
end
|
114
140
|
end
|
115
141
|
end
|
116
142
|
end
|
data/lib/ashikawa-core/cursor.rb
CHANGED
@@ -24,10 +24,7 @@ module Ashikawa
|
|
24
24
|
# @api public
|
25
25
|
def initialize(database, raw_cursor)
|
26
26
|
@database = database
|
27
|
-
|
28
|
-
@has_more = raw_cursor['hasMore']
|
29
|
-
@length = raw_cursor['count'].to_i if raw_cursor.has_key? 'count'
|
30
|
-
@current = raw_cursor['result']
|
27
|
+
parse_raw_cursor raw_cursor
|
31
28
|
end
|
32
29
|
|
33
30
|
# Iterate over the documents found by the cursor
|
@@ -43,22 +40,31 @@ module Ashikawa
|
|
43
40
|
end
|
44
41
|
|
45
42
|
# Delete the cursor
|
43
|
+
# @api public
|
46
44
|
def delete
|
47
45
|
@database.send_request "/cursor/#{@id}", delete: {}
|
48
46
|
end
|
49
47
|
|
50
48
|
private
|
51
49
|
|
50
|
+
# Pull the raw data from the cursor into this object
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
def parse_raw_cursor(raw_cursor)
|
54
|
+
@id = raw_cursor['id'].to_i if raw_cursor.has_key? 'id'
|
55
|
+
@has_more = raw_cursor['hasMore']
|
56
|
+
@length = raw_cursor['count'].to_i if raw_cursor.has_key? 'count'
|
57
|
+
@current = raw_cursor['result']
|
58
|
+
end
|
59
|
+
|
52
60
|
# Get a new batch from the server
|
53
61
|
#
|
54
62
|
# @return [Boolean] Is there a next batch?
|
63
|
+
# @api private
|
55
64
|
def next_batch
|
56
|
-
return
|
65
|
+
return false unless @has_more
|
57
66
|
raw_cursor = @database.send_request "/cursor/#{@id}", put: {}
|
58
|
-
|
59
|
-
@has_more = raw_cursor['hasMore']
|
60
|
-
@length = raw_cursor['count']
|
61
|
-
@current = raw_cursor['result']
|
67
|
+
parse_raw_cursor raw_cursor
|
62
68
|
end
|
63
69
|
end
|
64
70
|
end
|
@@ -68,19 +68,12 @@ module Ashikawa
|
|
68
68
|
Ashikawa::Core::Collection.new self, server_response
|
69
69
|
end
|
70
70
|
|
71
|
-
#
|
71
|
+
# Return a Query initialized with this database
|
72
72
|
#
|
73
|
-
# @
|
74
|
-
# @
|
75
|
-
|
76
|
-
|
77
|
-
parameter = { query: query }
|
78
|
-
|
79
|
-
parameter[:count] = opts[:count] if opts.has_key? :count
|
80
|
-
parameter[:batchSize] = opts[:batch_size] if opts.has_key? :batch_size
|
81
|
-
|
82
|
-
server_response = send_request "/cursor", post: parameter
|
83
|
-
Cursor.new self, server_response
|
73
|
+
# @return [Query]
|
74
|
+
# @api public
|
75
|
+
def query
|
76
|
+
Query.new self
|
84
77
|
end
|
85
78
|
end
|
86
79
|
end
|