arango-driver 3.5.0.alpha0

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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +1073 -0
  4. data/arango_opal.js +15 -0
  5. data/lib/arango-driver.rb +61 -0
  6. data/lib/arango.rb +96 -0
  7. data/lib/arango/aql.rb +188 -0
  8. data/lib/arango/collection.rb +575 -0
  9. data/lib/arango/collection/documents.rb +122 -0
  10. data/lib/arango/collection/edges.rb +149 -0
  11. data/lib/arango/collection/importing.rb +57 -0
  12. data/lib/arango/collection/indexes.rb +53 -0
  13. data/lib/arango/collection/replication.rb +24 -0
  14. data/lib/arango/collection/user.rb +28 -0
  15. data/lib/arango/cursor.rb +67 -0
  16. data/lib/arango/database.rb +188 -0
  17. data/lib/arango/database/analyzer.rb +21 -0
  18. data/lib/arango/database/aql_functions.rb +54 -0
  19. data/lib/arango/database/aql_queries.rb +114 -0
  20. data/lib/arango/database/aql_query_cache.rb +27 -0
  21. data/lib/arango/database/collections.rb +100 -0
  22. data/lib/arango/database/foxx_services.rb +103 -0
  23. data/lib/arango/database/graph_access.rb +27 -0
  24. data/lib/arango/database/http_route.rb +9 -0
  25. data/lib/arango/database/replication.rb +96 -0
  26. data/lib/arango/database/stream_transactions.rb +25 -0
  27. data/lib/arango/database/tasks.rb +67 -0
  28. data/lib/arango/database/transactions.rb +15 -0
  29. data/lib/arango/database/user.rb +26 -0
  30. data/lib/arango/database/view_access.rb +37 -0
  31. data/lib/arango/document.rb +443 -0
  32. data/lib/arango/edge.rb +164 -0
  33. data/lib/arango/error.rb +97 -0
  34. data/lib/arango/error_db.rb +27 -0
  35. data/lib/arango/foxx.rb +255 -0
  36. data/lib/arango/graph.rb +202 -0
  37. data/lib/arango/graph/basics.rb +39 -0
  38. data/lib/arango/graph/edge_access.rb +56 -0
  39. data/lib/arango/graph/vertex_access.rb +33 -0
  40. data/lib/arango/helper/collection_assignment.rb +13 -0
  41. data/lib/arango/helper/database_assignment.rb +14 -0
  42. data/lib/arango/helper/request_method.rb +45 -0
  43. data/lib/arango/helper/return.rb +21 -0
  44. data/lib/arango/helper/satisfaction.rb +28 -0
  45. data/lib/arango/helper/server_assignment.rb +13 -0
  46. data/lib/arango/helper/traversal.rb +12 -0
  47. data/lib/arango/index.rb +103 -0
  48. data/lib/arango/replication.rb +231 -0
  49. data/lib/arango/request.rb +92 -0
  50. data/lib/arango/request_batch.rb +174 -0
  51. data/lib/arango/result.rb +130 -0
  52. data/lib/arango/search_view.rb +23 -0
  53. data/lib/arango/server.rb +68 -0
  54. data/lib/arango/server/administration.rb +296 -0
  55. data/lib/arango/server/agency.rb +23 -0
  56. data/lib/arango/server/async.rb +51 -0
  57. data/lib/arango/server/batch.rb +35 -0
  58. data/lib/arango/server/config.rb +76 -0
  59. data/lib/arango/server/databases.rb +71 -0
  60. data/lib/arango/server/monitoring.rb +17 -0
  61. data/lib/arango/server/opal_support.rb +95 -0
  62. data/lib/arango/server/tasks.rb +69 -0
  63. data/lib/arango/server/user.rb +22 -0
  64. data/lib/arango/task.rb +223 -0
  65. data/lib/arango/transaction.rb +113 -0
  66. data/lib/arango/traversal.rb +212 -0
  67. data/lib/arango/user.rb +174 -0
  68. data/lib/arango/version.rb +3 -0
  69. data/lib/arango/vertex.rb +112 -0
  70. data/lib/arango/view.rb +124 -0
  71. data/lib/arango/view/basics.rb +25 -0
  72. metadata +296 -0
@@ -0,0 +1,164 @@
1
+ # === GRAPH VERTEX ===
2
+
3
+ module Arango
4
+ class Edge < Arango::Document
5
+ def initialize(name: nil, collection:, body: {}, rev: nil, from: nil,
6
+ to: nil)
7
+ assign_collection(collection)
8
+ body[:_key] ||= name
9
+ body[:_rev] ||= rev
10
+ body[:_from] ||= from
11
+ body[:_to] ||= to
12
+ body[:_id] ||= "#{@collection.name}/#{name}" unless name.nil?
13
+ assign_attributes(body)
14
+ end
15
+
16
+ # === DEFINE ===
17
+
18
+ attr_reader :collection, :database, :graph, :server
19
+
20
+ def collection=(collection)
21
+ satisfy_class?(collection, [Arango::Collection])
22
+ if collection.graph.nil?
23
+ raise Arango::Error.new err: :collection_does_not_have_a_graph, data:
24
+ {name_collection: collection.name, graph: nil}
25
+ end
26
+ @collection = collection
27
+ @graph = @collection.graph
28
+ @database = @collection.database
29
+ @server = @database.server
30
+ end
31
+ alias assign_collection collection=
32
+
33
+ # == GET ==
34
+
35
+ def retrieve(if_match: false)
36
+ headers = {}
37
+ headers[:"If-Match"] = @body[:_rev] if if_match
38
+ result = @graph.request("GET", "edge/#{@collection.name}/#{@body[:_key]}",
39
+ headers: headers, key: :edge)
40
+ return_element(result)
41
+ end
42
+
43
+ # == POST ==
44
+
45
+ def create(body: {}, wait_for_sync: nil)
46
+ body = @body.merge(body)
47
+ query = {
48
+ waitForSync: wait_for_sync,
49
+ _from: @body[:_from],
50
+ _to: @body[:_to]
51
+ }
52
+ result = @graph.request("POST", "edge/#{@collection.name}", body: body,
53
+ query: query, key: :edge)
54
+ return result if @server.async != false
55
+ body2 = result.clone
56
+ body = body.merge(body2)
57
+ assign_attributes(body)
58
+ return return_directly?(result) ? result : self
59
+ end
60
+
61
+ # == PUT ==
62
+
63
+ def replace(body: {}, wait_for_sync: nil, keep_null: nil, if_match: false)
64
+ query = {
65
+ waitForSync: wait_for_sync,
66
+ keepNull: keep_null
67
+ }
68
+ headers = {}
69
+ headers[:"If-Match"] = @body[:_rev] if if_match
70
+ result = @graph.request("PUT", "edge/#{@collection.name}/#{@body[:_key]}",
71
+ body: body, query: query, headers: headers, key: :edge)
72
+ return result if @server.async != false
73
+ body2 = result.clone
74
+ body = body.merge(body2)
75
+ assign_attributes(body)
76
+ return return_directly?(result) ? result : self
77
+ end
78
+
79
+ def update(body: {}, wait_for_sync: nil, if_match: false)
80
+ query = {waitForSync: wait_for_sync}
81
+ headers = {}
82
+ headers[:"If-Match"] = @body[:_rev] if if_match
83
+ result = @graph.request("PATCH", "edge/#{@collection.name}/#{@body[:_key]}",
84
+ body: body, query: query, headers: headers, key: :edge)
85
+ return result if @server.async != false
86
+ body2 = result.clone
87
+ body = body.merge(body2)
88
+ body = @body.merge(body)
89
+ assign_attributes(body)
90
+ return return_directly?(result) ? result : self
91
+ end
92
+
93
+ # === DELETE ===
94
+
95
+ def destroy(wait_for_sync: nil, if_match: false)
96
+ query = {waitForSync: wait_for_sync}
97
+ headers = {}
98
+ headers[:"If-Match"] = @body[:_rev] if if_match
99
+ result = @graph.request("DELETE", "edge/#{@collection.name}/#{@body[:_key]}",
100
+ query: query, headers: headers)
101
+ return_delete(result)
102
+ end
103
+
104
+ def from=(att)
105
+ att = att.id if att.is_a?(Arango::Document)
106
+ assign_attributes({_from: att})
107
+ end
108
+
109
+ def to=(att)
110
+ att = att.id if att.is_a?(Arango::Document)
111
+ assign_attributes({_to: att})
112
+ end
113
+
114
+ def set_up_from_or_to(attrs, var)
115
+ case var
116
+ when NilClass
117
+ @body[:"_#{attrs}"] = nil
118
+ when String
119
+ unless var.include?("/")
120
+ raise Arango::Error.new err: :attribute_is_not_valid, data:
121
+ {attribute: attrs, wrong_value: var}
122
+ end
123
+ @body[:"_#{attrs}"] = var
124
+ when Arango::Document
125
+ @body[:"_#{attrs}"] = var.id
126
+ @from = var if attrs == "from"
127
+ @to = var if attrs == "to"
128
+ else
129
+ raise Arango::Error.new err: :attribute_is_not_valid, data:
130
+ {attribute: attrs, wrong_value: var}
131
+ end
132
+ end
133
+ private :set_up_from_or_to
134
+
135
+ def from(string: false)
136
+ return @body[:_from] if string
137
+ @from ||= retrieve_instance_from_and_to(@body[:_from])
138
+ return @from
139
+ end
140
+
141
+ def to(string: false)
142
+ return @body[:_to] if string
143
+ @to ||= retrieve_instance_from_and_to(@body[:_to])
144
+ return @to
145
+ end
146
+
147
+ def retrieve_instance_from_and_to(var)
148
+ case var
149
+ when NilClass
150
+ return nil
151
+ when String
152
+ collection_name, document_name = var.split("/")
153
+ collection = Arango::Collection.new collection_name, database: @database
154
+ if @graph.nil?
155
+ return Arango::Document.new(document_name, collection: collection)
156
+ else
157
+ collection.graph = @graph
158
+ return Arango::Vertex.new(name: document_name, collection: collection)
159
+ end
160
+ end
161
+ end
162
+ private :retrieve_instance_from_and_to
163
+ end
164
+ end
@@ -0,0 +1,97 @@
1
+ # === ERROR ===
2
+
3
+ module Arango
4
+ class Error < StandardError
5
+ ARANGODB_ERRORS = {
6
+ no_other_aql_next: {
7
+ code: 10001, message: "No other values with AQL next"
8
+ },
9
+ no_other_simple_next: {
10
+ code: 10002, message: "No other values with AQL next"
11
+ },
12
+ is_a_edge_collection: {
13
+ code: 10003, message: "This collection is an Edge collection"
14
+ },
15
+ is_a_document_collection: {
16
+ code: 10004, message: "This collection is a Document collection"
17
+ },
18
+ database_graph_no_same_as_collection_database: {
19
+ code: 10005, message: "Database of graph is not the same as the class"
20
+ },
21
+ wrong_type_instead_of_expected_one: {
22
+ code: 10006, message: "Expected a type, received another"
23
+ },
24
+ no_other_export_next: {
25
+ code: 10007, message: "No other values with AQL next"
26
+ },
27
+ no_aql_id_available: {
28
+ code: 10008, message: "AQL does not have id. It could have already been killed"
29
+ },
30
+ id_is_not_valid: {
31
+ code: 10009, message: "Given attribute is not a valid document id or an Arango::Document"
32
+ },
33
+ collection_does_not_have_a_graph: {
34
+ code: 10010, message: "Collection does not have a graph"
35
+ },
36
+ arangodb_did_not_return_a_valid_result: {
37
+ code: 10011, message: "ArangoDB didn't return a valid result"
38
+ },
39
+ read_or_write_should_be_string_or_collections: {
40
+ code: 10012, message: "read or write should be an array of name classes or Arango::Collections"
41
+ },
42
+ wrong_class: {
43
+ code: 10013, message: "Wrong class"
44
+ },
45
+ wrong_element: {
46
+ code: 10014, message: "Element is not part of the list"
47
+ },
48
+ orphan_collection_used_by_edge_definition: {
49
+ code: 10015, message: "Orphan collection is already used by an edge definition"
50
+ },
51
+ impossible_to_parse_arangodb_response: {
52
+ code: 10016, message: "Impossible to parse ArangoDB response"
53
+ },
54
+ batch_query_not_valid: {
55
+ code: 10017, message: "Query is not valid"
56
+ },
57
+ arangorb_didnt_return_a_valid_result: {
58
+ code: 10018, message: "ArangoRB didn't return a valid result"
59
+ },
60
+ impossible_to_connect_with_database: {
61
+ code: 10019, message: "Impossible to connect with database"
62
+ },
63
+ you_cannot_assign_from_or_to_to_a_vertex: {
64
+ code: 10020, message: "You cannot assign from or to to a Vertex"
65
+ },
66
+ wrong_start_vertex_type: {
67
+ code: 10021, message: "Starting vertex should be an Arango::Vertex, an Arango::Document (not Edge) or a valid vertex id"
68
+ },
69
+ database_undefined_for_traversal: {
70
+ code: 10022, message: "Database undefined for traversal"
71
+ },
72
+ edge_collection_should_be_of_type_edge: {
73
+ code: 10022, message: "Database undefined for traversal"
74
+ }
75
+ }.freeze
76
+
77
+ def initialize(err:, data: nil, skip_assignment: false)
78
+ unless skip_assignment
79
+ @message = ARANGODB_ERRORS[err][:message]
80
+ @code = ARANGODB_ERRORS[err][:code]
81
+ @internal_code = err
82
+ @data = data
83
+ end
84
+ super(@message)
85
+ end
86
+ attr_reader :data, :code, :message
87
+
88
+ def to_h
89
+ {
90
+ message: @message,
91
+ code: @code,
92
+ data: @data,
93
+ internal_code: @internal_code
94
+ }.delete_if{|k,v| v.nil?}
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,27 @@
1
+ module Arango
2
+ class ErrorDB < Arango::Error
3
+ def initialize(message:, code:, data:, error_num:, action: nil, url: nil, request:)
4
+ @message = message
5
+ @code = code
6
+ @data = data
7
+ @error_num = error_num
8
+ @action = action
9
+ @url = url
10
+ @request = request
11
+ super(err: nil, skip_assignment: true)
12
+ end
13
+ attr_reader :action, :code, :data, :error_num, :message, :request, :url
14
+
15
+ def to_h
16
+ {
17
+ action: @action,
18
+ url: @url,
19
+ request: @request,
20
+ message: @message,
21
+ code: @code,
22
+ data: @data,
23
+ errorNum: @error_num
24
+ }.delete_if{|k,v| v.nil?}
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,255 @@
1
+ # === FOXX ===
2
+
3
+ module Arango
4
+ class Foxx
5
+ include Arango::Helper::Satisfaction
6
+ include Arango::Helper::Return
7
+ include Arango::Helper::DatabaseAssignment
8
+
9
+ def initialize(database:, body: {}, mount:, development: nil, legacy: nil,
10
+ provides: nil, name: nil, version: nil, type: "application/json",
11
+ setup: nil, teardown: nil, cache_name: nil)
12
+ assign_database(database)
13
+ unless cache_name.nil?
14
+ @cache_name = cache_name
15
+ @server.cache.save(:foxx, cache_name, self)
16
+ end
17
+ assign_attributes(body)
18
+ assign_type(type)
19
+ @development ||= development
20
+ @legacy ||= legacy
21
+ @mount ||= mount
22
+ @name ||= name
23
+ @provides ||= provides
24
+ @setup ||= setup
25
+ @teardown ||= teardown
26
+ @version ||= version
27
+ end
28
+
29
+ # === DEFINE ===
30
+
31
+ attr_reader :body, :cache_name, :database, :server, :type
32
+ attr_accessor :development, :legacy, :mount, :name, :provides, :setup, :teardown, :version
33
+
34
+ def body=(result)
35
+ if result.is_a?(Hash)
36
+ @body = result
37
+ @development = result[:development] || @development
38
+ @legacy = result[:legacy] || @legacy
39
+ @mount = result[:mount] || @mount
40
+ @name = result[:name] || @name
41
+ @provides = result[:provides] || @provides
42
+ @version = result[:version] || @version
43
+ if @server.active_cache && @cache_name.nil?
44
+ @cache_name = "#{@database.name}/#{@mount}"
45
+ @server.cache.save(:task, @cache_name, self)
46
+ end
47
+ end
48
+ end
49
+ alias assign_attributes body=
50
+
51
+ def type=(type)
52
+ satisfy_category?(type, %w[application/zip zip application/javascript javascript application/json json multipart/form-data data])
53
+ type = "application/#{type}" if %w[zip javascript json].include?(type)
54
+ type = "multipart/form-data" if type == "data"
55
+ @type = type
56
+ end
57
+ alias assign_type type=
58
+
59
+ # === TO HASH ===
60
+
61
+ def to_h
62
+ {
63
+ cache_name: @cache_name,
64
+ database: @database.name,
65
+ development: @development,
66
+ legacy: @legacy,
67
+ mount: @mount,
68
+ name: @name,
69
+ provides: @provides,
70
+ teardown: @teardown,
71
+ type: @type,
72
+ version: @version
73
+ }.delete_if{|k,v| v.nil?}
74
+ end
75
+
76
+ def return_foxx(result, val=nil)
77
+ return result if @server.async != false
78
+ case val
79
+ when :configuration
80
+ @configuration = result
81
+ when :dependencies
82
+ @dependencies = result
83
+ else
84
+ assign_attributes(result)
85
+ end
86
+ return return_directly?(result) ? result : self
87
+ end
88
+ private :return_foxx
89
+
90
+ # === ACTIONS ===
91
+
92
+ def retrieve
93
+ query = {mount: @mount}
94
+ result = @database.request("GET", url: "_api/foxx/service")
95
+ return_foxx(result)
96
+ end
97
+
98
+ def create(body: @body, type: @type, development: @development,
99
+ setup: @setup, legacy: @legacy)
100
+ headers = { Accept: type }
101
+ skip_to_json = type != "application/json"
102
+ query = {
103
+ mount: @mount,
104
+ setup: setup,
105
+ development: development,
106
+ legacy: legacy
107
+ }
108
+ result = @database.request("POST",
109
+ url: "_api/foxx", body: body, headers: headers,
110
+ skip_to_json: skip_to_json, query: query)
111
+ return_foxx(result)
112
+ end
113
+
114
+ def destroy(teardown: @teardown)
115
+ query = {
116
+ mount: @mount,
117
+ teardown: teardown
118
+ }
119
+ result = @database.request("DELETE", "_api/foxx/service", query: query)
120
+ return_foxx(result)
121
+ end
122
+
123
+ def replace(body: @body, type: @type, teardown: @teardown, setup: @setup,
124
+ legacy: @legacy)
125
+ headers = { Accept: type }
126
+ skip_to_json = type != "application/json"
127
+ query = {
128
+ mount: @mount,
129
+ setup: setup,
130
+ teardown: teardown,
131
+ legacy: legacy
132
+ }
133
+ result = @database.request("PUT", "_api/foxx/service", body: body,
134
+ headers: headers, skip_to_json: skip_to_json, query: query)
135
+ return_foxx(result)
136
+ end
137
+
138
+ def update(body: @body, type: @type, teardown: @teardown,
139
+ setup: @setup, legacy: @legacy)
140
+ assign_type(type)
141
+ headers = { Accept: type }
142
+ skip_to_json = @type != "application/json"
143
+ query = {
144
+ mount: @mount,
145
+ setup: setup,
146
+ teardown: teardown,
147
+ legacy: legacy
148
+ }
149
+ result = @database.request("PATCH", "_api/foxx/service", body: body,
150
+ headers: headers, skip_to_json: skip_to_json, query: query)
151
+ return_foxx(result)
152
+ end
153
+
154
+ # === CONFIGURATION ===
155
+
156
+ def retrieve_configuration
157
+ query = { mount: @mount }
158
+ result = @database.request("GET", "_api/foxx/configuration", query: query)
159
+ return_foxx(result, :configuration)
160
+ end
161
+
162
+ def update_configuration(body:)
163
+ query = { mount: @mount }
164
+ result = @database.request("PATCH", "_api/foxx/configuration", query: query, body: body)
165
+ return_foxx(result, :configuration)
166
+ end
167
+
168
+ def replace_configuration(body:)
169
+ query = { mount: @mount }
170
+ result = @database.request("PUT", "_api/foxx/configuration", query: query, body: body)
171
+ return_foxx(result, :configuration)
172
+ end
173
+
174
+ # === DEPENDENCY ===
175
+
176
+ def retrieve_dependencies
177
+ query = { mount: @mount }
178
+ result = @database.request("GET", "_api/foxx/dependencies", query: query)
179
+ return_foxx(result, :dependencies)
180
+ end
181
+
182
+ def update_dependencies(body:)
183
+ query = { mount: @mount }
184
+ result = @database.request("PATCH", "_api/foxx/dependencies", query: query, body: body)
185
+ return_foxx(result, :dependencies)
186
+ end
187
+
188
+ def replace_dependencies(body:)
189
+ query = { mount: @mount }
190
+ result = @database.request("PUT", "_api/foxx/dependencies", query: query, body: body)
191
+ return_foxx(result, :dependencies)
192
+ end
193
+
194
+ # === MISCELLANEOUS
195
+
196
+ def scripts
197
+ query = { mount: @mount }
198
+ @database.request("GET", "_api/foxx/scripts", query: query)
199
+ end
200
+
201
+ def run_script(name:, body: {})
202
+ query = { mount: @mount }
203
+ @database.request("POST", "_api/foxx/scripts/#{name}", query: query, body: body)
204
+ end
205
+
206
+ def tests(reporter: nil, idiomatic: nil)
207
+ satisfy_category?(reporter, [nil, "default", "suite", "stream", "xunit", "tap"])
208
+ headers = {}
209
+ headers[:"Content-Type"] = case reporter
210
+ when "stream"
211
+ "application/x-ldjson"
212
+ when "tap"
213
+ "text/plain, text/*"
214
+ when "xunit"
215
+ "application/xml, text/xml"
216
+ else
217
+ nil
218
+ end
219
+ query = { mount: @mount }
220
+ @database.request("GET", "_api/foxx/scripts", query: query, headers: headers)
221
+ end
222
+
223
+ def enable_development
224
+ query = { mount: @mount }
225
+ @database.request("POST", "_api/foxx/development", query: query)
226
+ end
227
+
228
+ def disable_development
229
+ query = { mount: @mount }
230
+ @database.request("DELETE", "_api/foxx/development", query: query)
231
+ end
232
+
233
+ def readme
234
+ query = { mount: @mount }
235
+ @database.request("GET", "_api/foxx/readme", query: query)
236
+ end
237
+
238
+ def swagger
239
+ query = { mount: @mount }
240
+ @database.request("GET", "_api/foxx/swagger", query: query)
241
+ end
242
+
243
+ def download(path:, warning: @server.warning)
244
+ query = { mount: @mount }
245
+ @server.download("POST", "_db/#{@database.name}/_api/foxx/download",
246
+ path: path, query: query)
247
+ puts "File saved in #{path}" if warning
248
+ end
249
+
250
+ def commit(body:, replace: nil)
251
+ query = { replace: replace }
252
+ @database.request("POST", "_api/foxx/commit", body: body, query: query)
253
+ end
254
+ end
255
+ end