ashikawa-core 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/.rspec +0 -1
  2. data/.travis.yml +2 -0
  3. data/CONTRIBUTING.md +14 -29
  4. data/Gemfile.devtools +9 -10
  5. data/README.md +30 -9
  6. data/Rakefile +1 -1
  7. data/ashikawa-core.gemspec +9 -8
  8. data/config/flay.yml +2 -2
  9. data/config/flog.yml +1 -1
  10. data/config/roodi.yml +4 -5
  11. data/config/site.reek +40 -16
  12. data/config/yardstick.yml +1 -1
  13. data/lib/ashikawa-core/collection.rb +109 -22
  14. data/lib/ashikawa-core/connection.rb +42 -110
  15. data/lib/ashikawa-core/cursor.rb +13 -6
  16. data/lib/ashikawa-core/database.rb +67 -17
  17. data/lib/ashikawa-core/document.rb +41 -10
  18. data/lib/ashikawa-core/edge.rb +50 -0
  19. data/lib/ashikawa-core/exceptions/client_error/bad_syntax.rb +24 -0
  20. data/lib/ashikawa-core/exceptions/{collection_not_found.rb → client_error/resource_not_found/collection_not_found.rb} +3 -1
  21. data/lib/ashikawa-core/exceptions/{document_not_found.rb → client_error/resource_not_found/document_not_found.rb} +3 -1
  22. data/lib/ashikawa-core/exceptions/{index_not_found.rb → client_error/resource_not_found/index_not_found.rb} +3 -1
  23. data/lib/ashikawa-core/exceptions/client_error/resource_not_found.rb +25 -0
  24. data/lib/ashikawa-core/exceptions/client_error.rb +23 -0
  25. data/lib/ashikawa-core/exceptions/server_error/json_error.rb +25 -0
  26. data/lib/ashikawa-core/exceptions/server_error.rb +23 -0
  27. data/lib/ashikawa-core/figure.rb +59 -2
  28. data/lib/ashikawa-core/index.rb +23 -7
  29. data/lib/ashikawa-core/query.rb +10 -10
  30. data/lib/ashikawa-core/request_preprocessor.rb +49 -0
  31. data/lib/ashikawa-core/response_preprocessor.rb +111 -0
  32. data/lib/ashikawa-core/version.rb +1 -1
  33. data/lib/ashikawa-core.rb +0 -1
  34. data/spec/acceptance/basic_spec.rb +61 -22
  35. data/spec/acceptance/index_spec.rb +11 -4
  36. data/spec/acceptance/query_spec.rb +4 -1
  37. data/spec/acceptance/spec_helper.rb +0 -2
  38. data/spec/acceptance_auth/spec_helper.rb +0 -2
  39. data/spec/fixtures/collections/60768679-count.json +13 -0
  40. data/spec/fixtures/collections/60768679-figures.json +35 -0
  41. data/spec/fixtures/collections/60768679-properties-volatile.json +12 -0
  42. data/spec/fixtures/collections/60768679-properties.json +12 -0
  43. data/spec/fixtures/collections/{4588.json → 60768679.json} +2 -2
  44. data/spec/fixtures/collections/all.json +5 -5
  45. data/spec/fixtures/cursor/26011191-2.json +1 -1
  46. data/spec/fixtures/cursor/26011191.json +1 -1
  47. data/spec/fixtures/documents/example_1-137249191.json +6 -0
  48. data/spec/fixtures/documents/new-example_1-137249191.json +6 -0
  49. data/spec/setup/arangodb.sh +1 -1
  50. data/spec/unit/collection_spec.rb +117 -42
  51. data/spec/unit/connection_spec.rb +161 -61
  52. data/spec/unit/cursor_spec.rb +39 -12
  53. data/spec/unit/database_spec.rb +119 -19
  54. data/spec/unit/document_spec.rb +4 -2
  55. data/spec/unit/edge_spec.rb +54 -0
  56. data/spec/unit/exception_spec.rb +36 -8
  57. data/spec/unit/figure_spec.rb +37 -11
  58. data/spec/unit/index_spec.rb +1 -1
  59. data/spec/unit/query_spec.rb +18 -18
  60. data/spec/unit/spec_helper.rb +4 -13
  61. data/tasks/adjustments.rake +3 -2
  62. metadata +59 -32
  63. data/lib/ashikawa-core/exceptions/unknown_path.rb +0 -15
  64. data/spec/fixtures/collections/4590-properties.json +0 -9
  65. data/spec/fixtures/collections/4590.json +0 -8
  66. data/spec/fixtures/collections/73482-figures.json +0 -23
  67. data/spec/fixtures/documents/4590-333.json +0 -5
  68. data/spec/fixtures/documents/new-4590-333.json +0 -5
@@ -0,0 +1,50 @@
1
+ require 'ashikawa-core/document'
2
+
3
+ module Ashikawa
4
+ module Core
5
+ # A certain Edge within a certain Collection
6
+ class Edge < Document
7
+ # The ID of the 'from' document
8
+ #
9
+ # @return [String]
10
+ # @api public
11
+ # @example Get the ID for the 'from' Document
12
+ # document = Ashikawa::Core::Edge.new(database, raw_document)
13
+ # document.from_id # => "my_fancy_collection/2345678"
14
+ attr_reader :from_id
15
+
16
+ # The ID of the 'to' document
17
+ #
18
+ # @return [String]
19
+ # @api public
20
+ # @example Get the ID for the 'to' Document
21
+ # document = Ashikawa::Core::Edge.new(database, raw_document)
22
+ # document.to_id # => "my_fancy_collection/2345678"
23
+ attr_reader :to_id
24
+
25
+ # Initialize an Edge with the database and raw data
26
+ #
27
+ # @param [Database] database
28
+ # @param [Hash] raw_edge
29
+ # @api public
30
+ # @example Create an Edge
31
+ # document = Ashikawa::Core::Edge.new(database, raw_edge)
32
+ def initialize(database, raw_edge)
33
+ @from_id = raw_edge["_from"]
34
+ @to_id = raw_edge["_to"]
35
+ super(database, raw_edge)
36
+ end
37
+
38
+ protected
39
+
40
+ # Send a request for this edge with the given opts
41
+ #
42
+ # @param [Hash] opts Options for this request
43
+ # @return [Hash] The parsed response from the server
44
+ # @api private
45
+ def send_request_for_document(opts = {})
46
+ @database.send_request("edge/#{@id}", opts)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,24 @@
1
+ require "ashikawa-core/exceptions/client_error.rb"
2
+
3
+ module Ashikawa
4
+ module Core
5
+ # This exception is thrown when the client used bad syntax in a request
6
+ class BadSyntax < ClientError
7
+ # Create a new instance
8
+ #
9
+ # @return RuntimeError
10
+ # @api private
11
+ def initialize
12
+ super(400)
13
+ end
14
+
15
+ # String representation of the exception
16
+ #
17
+ # @return String
18
+ # @api private
19
+ def to_s
20
+ "Status 400: The syntax of the request was bad"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,8 +1,10 @@
1
+ require "ashikawa-core/exceptions/client_error/resource_not_found"
2
+
1
3
  module Ashikawa
2
4
  module Core
3
5
  # This Exception is thrown when a document was requested from
4
6
  # the server that does not exist.
5
- class CollectionNotFoundException < RuntimeError
7
+ class CollectionNotFoundException < ResourceNotFound
6
8
  # String representation of the exception
7
9
  #
8
10
  # @return String
@@ -1,8 +1,10 @@
1
+ require "ashikawa-core/exceptions/client_error/resource_not_found"
2
+
1
3
  module Ashikawa
2
4
  module Core
3
5
  # This Exception is thrown when a document was requested from
4
6
  # the server that does not exist.
5
- class DocumentNotFoundException < RuntimeError
7
+ class DocumentNotFoundException < ResourceNotFound
6
8
  # String representation of the exception
7
9
  #
8
10
  # @return String
@@ -1,8 +1,10 @@
1
+ require "ashikawa-core/exceptions/client_error/resource_not_found"
2
+
1
3
  module Ashikawa
2
4
  module Core
3
5
  # This Exception is thrown when an index was requested from
4
6
  # the server that does not exist.
5
- class IndexNotFoundException < RuntimeError
7
+ class IndexNotFoundException < ResourceNotFound
6
8
  # String representation of the exception
7
9
  #
8
10
  # @return String
@@ -0,0 +1,25 @@
1
+ require "ashikawa-core/exceptions/client_error.rb"
2
+
3
+ module Ashikawa
4
+ module Core
5
+ # This Exception is thrown when you request
6
+ # a resource that does not exist on the server
7
+ class ResourceNotFound < ClientError
8
+ # Create a new instance
9
+ #
10
+ # @return RuntimeError
11
+ # @api private
12
+ def initialize
13
+ super(404)
14
+ end
15
+
16
+ # String representation of the exception
17
+ #
18
+ # @return String
19
+ # @api private
20
+ def to_s
21
+ "Status 404: The Resource you requested was not found on the server"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ module Ashikawa
2
+ module Core
3
+ # The client had an error in the request
4
+ class ClientError < RuntimeError
5
+ # Create a new instance
6
+ #
7
+ # @param [Integer] status
8
+ # @return RuntimeError
9
+ # @api private
10
+ def initialize(status)
11
+ @status = status
12
+ end
13
+
14
+ # String representation of the exception
15
+ #
16
+ # @return String
17
+ # @api private
18
+ def to_s
19
+ "Status #{@status}: An Error occured in the client"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ require "ashikawa-core/exceptions/server_error"
2
+
3
+ module Ashikawa
4
+ module Core
5
+ # This Exception is thrown when the Json
6
+ # from the server was malformed
7
+ class JsonError < ServerError
8
+ # Create a new instance
9
+ #
10
+ # @return RuntimeError
11
+ # @api private
12
+ def initialize
13
+ super(nil)
14
+ end
15
+
16
+ # String representation of the exception
17
+ #
18
+ # @return String
19
+ # @api private
20
+ def to_s
21
+ "Either the JSON from the server was malformed or the content type incorrect"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ module Ashikawa
2
+ module Core
3
+ # The server had an error during the request
4
+ class ServerError < RuntimeError
5
+ # Create a new instance
6
+ #
7
+ # @param [Integer] status
8
+ # @return RuntimeError
9
+ # @api private
10
+ def initialize(status)
11
+ @status = status
12
+ end
13
+
14
+ # String representation of the exception
15
+ #
16
+ # @return String
17
+ # @api private
18
+ def to_s
19
+ "Status #{@status}: An Error occured on the server"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -10,8 +10,10 @@ module Ashikawa
10
10
  # figure = Ashikawa::Core::Figure.new(raw_figure)
11
11
  def initialize(raw_figure)
12
12
  @datafiles = raw_figure["datafiles"]
13
- @alive = raw_figure["alive"]
14
- @dead = raw_figure["dead"]
13
+ @alive = raw_figure["alive"]
14
+ @dead = raw_figure["dead"]
15
+ @shapes = raw_figure["shapes"]
16
+ @journals = raw_figure["journals"]
15
17
  end
16
18
 
17
19
  # The number of active datafiles
@@ -25,6 +27,17 @@ module Ashikawa
25
27
  @datafiles["count"]
26
28
  end
27
29
 
30
+ # The file size of datafiles
31
+ #
32
+ # @return Fixnum
33
+ # @api public
34
+ # @example Get the file size of datafiles
35
+ # figure = Ashikawa::Core::Figure.new(raw_figure)
36
+ # figure.datafile_size #=> 1337
37
+ def datafiles_file_size
38
+ @datafiles["fileSize"]
39
+ end
40
+
28
41
  # The total size in bytes used by all living documents
29
42
  #
30
43
  # @return Fixnum
@@ -68,6 +81,50 @@ module Ashikawa
68
81
  def dead_count
69
82
  @dead["count"]
70
83
  end
84
+
85
+ # The total number of shapes used in the collection
86
+ #
87
+ # @return Fixnum
88
+ # @api public
89
+ # @example Get the number of shapes
90
+ # figure = Ashikawa::Core::Figure.new(raw_figure)
91
+ # figure.shapes_count #=> 1337
92
+ def shapes_count
93
+ @shapes["count"]
94
+ end
95
+
96
+ # The number of deletion markers
97
+ #
98
+ # @return Fixnum
99
+ # @api public
100
+ # @example Get the number of deletion markers
101
+ # figure = Ashikawa::Core::Figure.new(raw_figure)
102
+ # figure.dead_deletion #=> 1337
103
+ def dead_deletion
104
+ @dead["deletion"]
105
+ end
106
+
107
+ # The number of journals
108
+ #
109
+ # @return Fixnum
110
+ # @api public
111
+ # @example Get the number of journals
112
+ # figure = Ashikawa::Core::Figure.new(raw_figure)
113
+ # figure.journal_count #=> 1337
114
+ def journals_count
115
+ @journals["count"]
116
+ end
117
+
118
+ # The file size of journals
119
+ #
120
+ # @return Fixnum
121
+ # @api public
122
+ # @example Get the file size of journals
123
+ # figure = Ashikawa::Core::Figure.new(raw_figure)
124
+ # figure.journal_size #=> 1337
125
+ def journals_file_size
126
+ @journals["fileSize"]
127
+ end
71
128
  end
72
129
  end
73
130
  end
@@ -3,6 +3,7 @@ module Ashikawa
3
3
  # An index on a certain collection
4
4
  class Index
5
5
  # The fields the index is defined on as symbols
6
+ #
6
7
  # @return [Array<Symbol>]
7
8
  # @api public
8
9
  # @example Get the fields the index is set on
@@ -11,6 +12,7 @@ module Ashikawa
11
12
  attr_reader :on
12
13
 
13
14
  # The type of index as a symbol
15
+ #
14
16
  # @return [Symbol]
15
17
  # @api public
16
18
  # @example Get the type of the index
@@ -19,6 +21,7 @@ module Ashikawa
19
21
  attr_reader :type
20
22
 
21
23
  # Is the unique constraint set?
24
+ #
22
25
  # @return [Boolean]
23
26
  # @api public
24
27
  # @example Get the fields the index is set on
@@ -26,8 +29,9 @@ module Ashikawa
26
29
  # index.unique #=> false
27
30
  attr_reader :unique
28
31
 
29
- # The id of the index
30
- # @return [Int]
32
+ # The ID of the index (includes a Collection prefix)
33
+ #
34
+ # @return [String]
31
35
  # @api public
32
36
  # @example Get the id of this index
33
37
  # index = Ashikawa::Core::Index.new(collection, raw_index)
@@ -44,10 +48,7 @@ module Ashikawa
44
48
  # index = Ashikawa::Core::Index.new(collection, raw_index)
45
49
  def initialize(collection, raw_index)
46
50
  @collection = collection
47
- @id = raw_index["id"].split("/")[1].to_i if raw_index.has_key?("id")
48
- @on = raw_index["fields"].map { |field| field.to_sym } if raw_index.has_key?("fields")
49
- @type = raw_index["type"].to_sym if raw_index.has_key?("type")
50
- @unique = raw_index["unique"] if raw_index.has_key?("unique")
51
+ parse_raw_index(raw_index)
51
52
  end
52
53
 
53
54
  # Remove the index from the collection
@@ -58,7 +59,22 @@ module Ashikawa
58
59
  # index = Ashikawa::Core::Index.new(collection, raw_index)
59
60
  # index.delete
60
61
  def delete
61
- @collection.send_request("index/#{@collection.id}/#{@id}", :delete => {})
62
+ @collection.send_request("index/#{@id}", :delete => {})
63
+ end
64
+
65
+ private
66
+
67
+ # Parse information returned from the server
68
+ #
69
+ # @param [Hash] raw_index
70
+ # @return self
71
+ # @api private
72
+ def parse_raw_index(raw_index)
73
+ @id = raw_index["id"]
74
+ @on = raw_index["fields"].map { |field| field.to_sym } if raw_index.has_key?("fields")
75
+ @type = raw_index["type"].to_sym if raw_index.has_key?("type")
76
+ @unique = raw_index["unique"]
77
+ self
62
78
  end
63
79
  end
64
80
  end
@@ -1,9 +1,9 @@
1
1
  require 'ashikawa-core/cursor'
2
2
  require 'ashikawa-core/document'
3
3
  require 'ashikawa-core/exceptions/no_collection_provided'
4
+ require 'ashikawa-core/exceptions/client_error/bad_syntax'
4
5
  require 'forwardable'
5
6
  require 'backports'
6
- require 'rest-client'
7
7
 
8
8
  module Ashikawa
9
9
  module Core
@@ -38,7 +38,7 @@ module Ashikawa
38
38
  # query = Ashikawa::Core::Query.new(collection)
39
39
  # query.all # => #<Cursor id=33>
40
40
  def all(options={})
41
- simple_query_request("/simple/all",
41
+ simple_query_request("simple/all",
42
42
  options,
43
43
  [:limit, :skip])
44
44
  end
@@ -56,7 +56,7 @@ module Ashikawa
56
56
  # query = Ashikawa::Core::Query.new(collection)
57
57
  # query.by_example({ "color" => "red" }, :options => { :limit => 1 }) #=> #<Cursor id=2444>
58
58
  def by_example(example={}, options={})
59
- simple_query_request("/simple/by-example",
59
+ simple_query_request("simple/by-example",
60
60
  { :example => example }.merge(options),
61
61
  [:limit, :skip, :example])
62
62
  end
@@ -71,7 +71,7 @@ module Ashikawa
71
71
  # query = Ashikawa::Core::Query.new(collection)
72
72
  # query.first_example({ "color" => "red"}) # => #<Document id=2444 color="red">
73
73
  def first_example(example = {})
74
- response = simple_query_request("/simple/first-example",
74
+ response = simple_query_request("simple/first-example",
75
75
  { :example => example },
76
76
  [:example])
77
77
  response.first
@@ -92,7 +92,7 @@ module Ashikawa
92
92
  # query = Ashikawa::Core::Query.new(collection)
93
93
  # query.near(:latitude => 37.331693, :longitude => -122.030468)
94
94
  def near(options={})
95
- simple_query_request("/simple/near",
95
+ simple_query_request("simple/near",
96
96
  options,
97
97
  [:latitude, :longitude, :distance, :skip, :limit, :geo])
98
98
  end
@@ -113,7 +113,7 @@ module Ashikawa
113
113
  # query = Ashikawa::Core::Query.new(collection)
114
114
  # query.within(:latitude => 37.331693, :longitude => -122.030468, :radius => 100)
115
115
  def within(options={})
116
- simple_query_request("/simple/within",
116
+ simple_query_request("simple/within",
117
117
  options,
118
118
  [:latitude, :longitude, :radius, :distance, :skip, :limit, :geo])
119
119
  end
@@ -133,7 +133,7 @@ module Ashikawa
133
133
  # query = Ashikawa::Core::Query.new(collection)
134
134
  # query.within(:latitude => 37.331693, :longitude => -122.030468, :radius => 100)
135
135
  def in_range(options={})
136
- simple_query_request("/simple/range",
136
+ simple_query_request("simple/range",
137
137
  options,
138
138
  [:attribute, :left, :right, :closed, :limit, :skip])
139
139
  end
@@ -149,7 +149,7 @@ module Ashikawa
149
149
  # query = Ashikawa::Core::Query.new(collection)
150
150
  # query.execute("FOR u IN users LIMIT 2") # => #<Cursor id=33>
151
151
  def execute(query, options = {})
152
- post_request("/cursor",
152
+ post_request("cursor",
153
153
  options.merge({ :query => query }),
154
154
  [:query, :count, :batch_size])
155
155
  end
@@ -163,8 +163,8 @@ module Ashikawa
163
163
  # query = Ashikawa::Core::Query.new(collection)
164
164
  # query.valid?("FOR u IN users LIMIT 2") # => true
165
165
  def valid?(query)
166
- !!post_request("/query", { :query => query })
167
- rescue RestClient::BadRequest
166
+ !!post_request("query", { :query => query })
167
+ rescue Ashikawa::Core::BadSyntax
168
168
  false
169
169
  end
170
170