arangorb 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/ArangoRB.gemspec +18 -18
  3. data/Gemfile +8 -7
  4. data/LICENSE +21 -21
  5. data/README.md +906 -867
  6. data/lib/ArangoRB_AQL.rb +181 -160
  7. data/lib/ArangoRB_Cache.rb +174 -174
  8. data/lib/ArangoRB_Col.rb +526 -499
  9. data/lib/ArangoRB_DB.rb +363 -339
  10. data/lib/ArangoRB_Doc.rb +319 -298
  11. data/lib/ArangoRB_Edg.rb +184 -169
  12. data/lib/ArangoRB_Gra.rb +201 -180
  13. data/lib/ArangoRB_Index.rb +135 -115
  14. data/lib/ArangoRB_Replication.rb +261 -0
  15. data/lib/ArangoRB_Ser.rb +446 -441
  16. data/lib/ArangoRB_Task.rb +129 -113
  17. data/lib/ArangoRB_Tra.rb +169 -142
  18. data/lib/ArangoRB_Tran.rb +68 -53
  19. data/lib/ArangoRB_User.rb +149 -136
  20. data/lib/ArangoRB_Ver.rb +162 -147
  21. data/lib/arangorb.rb +16 -15
  22. data/spec/arangoRB_helper.rb +4 -4
  23. data/spec/arangoRestart_helper.rb +14 -14
  24. data/spec/lib/0.1.0/arangoAQL_helper.rb +64 -64
  25. data/spec/lib/0.1.0/arangoC_helper.rb +170 -170
  26. data/spec/lib/0.1.0/arangoDB_helper.rb +119 -119
  27. data/spec/lib/0.1.0/arangoDoc_helper.rb +79 -79
  28. data/spec/lib/0.1.0/arangoE_helper.rb +50 -50
  29. data/spec/lib/0.1.0/arangoG_helper.rb +78 -78
  30. data/spec/lib/0.1.0/arangoS_helper.rb +37 -37
  31. data/spec/lib/0.1.0/arangoT_helper.rb +48 -48
  32. data/spec/lib/0.1.0/arangoV_helper.rb +65 -65
  33. data/spec/lib/1.0.0/arangoC_helper.rb +73 -73
  34. data/spec/lib/1.0.0/arangoDB_helper.rb +48 -48
  35. data/spec/lib/1.0.0/arangoI_helper.rb +43 -43
  36. data/spec/lib/1.0.0/arangoS_helper.rb +192 -192
  37. data/spec/lib/1.0.0/arangoTa_helper.rb +49 -49
  38. data/spec/lib/1.0.0/arangoTr_helper.rb +15 -15
  39. data/spec/lib/1.0.0/arangoU_helper.rb +72 -72
  40. data/spec/lib/1.1.0/arangoRB_helper.rb +144 -144
  41. data/spec/lib/1.1.0/arangoRB_walks_helper.rb +19 -19
  42. data/spec/lib/1.2.0/arangoCache_helper.rb +66 -66
  43. data/spec/lib/1.3.0/arangoHash_helper.rb +30 -0
  44. data/spec/lib/arangoRB_0.1.0_helper.rb +9 -9
  45. data/spec/lib/arangoRB_1.0.0_helper.rb +6 -6
  46. data/spec/lib/arangoRB_1.1.0_helper.rb +2 -2
  47. data/spec/lib/arangoRB_1.2.0_helper.rb +2 -1
  48. data/spec/spec_helper.rb +41 -41
  49. metadata +6 -5
@@ -1,499 +1,526 @@
1
- # === COLLECTION ===
2
-
3
- class ArangoCollection < ArangoServer
4
- def initialize(collection: @@collection, database: @@database, body: {}, type: nil) # TESTED
5
- if collection.is_a?(String)
6
- @collection = collection
7
- elsif collection.is_a?(ArangoCollection)
8
- @collection = collection.collection
9
- else
10
- raise "collection should be a String or an ArangoCollection instance, not a #{collection.class}"
11
- end
12
-
13
- if database.is_a?(String)
14
- @database = database
15
- elsif database.is_a?(ArangoDatabase)
16
- @database = database.database
17
- else
18
- raise "database should be a String or an ArangoDatabase instance, not a #{database.class}"
19
- end
20
-
21
- if body.is_a?(Hash)
22
- @body = body
23
- else
24
- raise "body should be a Hash, not a #{body.class}"
25
- end
26
-
27
- if !@type.nil? && @type != "Document" && @type != "Edge"
28
- raise "type should be \"Document\" or \"Edge\""
29
- else
30
- @type = type
31
- if @type == "Document"
32
- @body["type"] = 2
33
- elsif @type == "Edge"
34
- @body["type"] = 3
35
- end
36
- end
37
- @idCache = "COL_#{@collection}"
38
- end
39
-
40
- attr_reader :collection, :body, :type, :idCache
41
- alias name collection
42
-
43
- # === RETRIEVE ===
44
-
45
- def [](document_name)
46
- ArangoDocument.new(key: document_name, collection: @collection, database: @database)
47
- end
48
- alias document []
49
-
50
- def database
51
- ArangoDatabase.new(database: @database)
52
- end
53
-
54
- # === GET ===
55
-
56
- def retrieve # TESTED
57
- result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}", @@request)
58
- self.return_result result: result, checkType: true
59
- end
60
-
61
- def properties # TESTED
62
- result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/properties", @@request)
63
- result = self.return_result result: result
64
- return result.is_a?(ArangoCollection) ? result.body : result
65
- end
66
-
67
- def count # TESTED
68
- result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/count", @@request)
69
- self.return_result result: result, key: "count"
70
- end
71
-
72
- def statistics # TESTED
73
- result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/figures", @@request)
74
- self.return_result result: result, key: "figures"
75
- end
76
-
77
- def revision # TESTED
78
- result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/revision", @@request)
79
- self.return_result result: result, key: "revision"
80
- end
81
-
82
- def checksum(withRevisions: nil, withData: nil) # TESTED
83
- query = {
84
- "withRevisions": withRevisions,
85
- "withData": withData
86
- }.delete_if{|k,v| v.nil?}
87
- request = @@request.merge({ :query => query })
88
- result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/checksum", request)
89
- self.return_result result: result, key: "checksum"
90
- end
91
-
92
- # === POST ===
93
-
94
- def create(type: nil, journalSize: nil, keyOptions: nil, waitForSync: nil, doCompact: nil, isVolatile: nil, shardKeys: nil, numberOfShards: nil, isSystem: nil, indexBuckets: nil) # TESTED
95
- type = 3 if type == "Edge"
96
- type = nil if type == "Document"
97
- body = {
98
- "name" => collection,
99
- "type" => type,
100
- "journalSize" => journalSize,
101
- "keyOptions" => keyOptions,
102
- "waitForSync" => waitForSync,
103
- "doCompact" => doCompact,
104
- "isVolatile" => isVolatile,
105
- "shardKeys" => shardKeys,
106
- "numberOfShards" => numberOfShards,
107
- "isSystem" => isSystem,
108
- "indexBuckets" => indexBuckets
109
- }
110
- body = body.delete_if{|k,v| v.nil?}.to_json
111
- request = @@request.merge({ :body => body })
112
- result = self.class.post("/_db/#{@database}/_api/collection", request)
113
- self.return_result result: result, checkType: true
114
- end
115
- alias create_collection create
116
- alias create_document_collection create
117
- alias create_vertex_collection create
118
-
119
- def create_edge_collection(journalSize: nil, keyOptions: nil, waitForSync: nil, doCompact: nil, isVolatile: nil, shardKeys: nil, numberOfShards: nil, isSystem: nil, indexBuckets: nil) # TESTED
120
- self.create type: 3, journalSize: journalSize, keyOptions: keyOptions, waitForSync: waitForSync, doCompact: doCompact, isVolatile: isVolatile, shardKeys: shardKeys, numberOfShards: numberOfShards, isSystem: isSystem, indexBuckets: indexBuckets
121
- end
122
-
123
- def create_document(document: {}, waitForSync: nil, returnNew: nil) # TESTED
124
- ArangoDocument.create(body: document, waitForSync: waitForSync, returnNew: returnNew, database: @database, collection: @collection)
125
- end
126
- alias create_vertex create_document
127
-
128
- def create_edge(document: {}, from:, to:, waitForSync: nil, returnNew: nil) # TESTED
129
- ArangoDocument.create_edge(body: document, from: from, to: to, waitForSync: waitForSync, returnNew: returnNew, database: @database, collection: @collection)
130
- end
131
-
132
- # === DELETE ===
133
-
134
- def destroy # TESTED
135
- result = self.class.delete("/_db/#{@database}/_api/collection/#{@collection}", @@request)
136
- self.return_result result: result, caseTrue: true
137
- end
138
-
139
- def truncate # TESTED
140
- result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/truncate", @@request)
141
- self.return_result result: result
142
- end
143
-
144
- # === MODIFY ===
145
-
146
- def load # TESTED
147
- result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/load", @@request)
148
- self.return_result result: result
149
- end
150
-
151
- def unload # TESTED
152
- result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/unload", @@request)
153
- self.return_result result: result
154
- end
155
-
156
- def change(waitForSync: nil, journalSize: nil) # TESTED
157
- body = {
158
- "journalSize" => journalSize,
159
- "waitForSync" => waitForSync
160
- }
161
- body = body.delete_if{|k,v| k.nil?}.to_json
162
- request = @@request.merge({ :body => body })
163
- result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/properties", request)
164
- self.return_result result: result
165
- end
166
-
167
- def rename(newName) # TESTED
168
- body = { "name" => newName }
169
- request = @@request.merge({ :body => body.to_json })
170
- result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/rename", request)
171
- @collection = newName unless result.parsed_response["error"]
172
- self.return_result result: result
173
- end
174
-
175
- def rotate
176
- result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/rotate", @@request)
177
- self.return_result result: result, caseTrue: true
178
- end
179
-
180
- # === SIMPLE FUNCTIONS ===
181
-
182
- def documents(type: nil) # "path", "id", "key" # TESTED
183
- body = {
184
- "collection" => @collection,
185
- "type" => type
186
- }.delete_if{|k,v| v.nil?}.to_json
187
- request = @@request.merge({ :body => body })
188
- result = self.class.put("/_db/#{@database}/_api/simple/all-keys", request)
189
- return result.headers["x-arango-async-id"] if @@async == "store"
190
- result = result.parsed_response
191
- if type.nil?
192
- @@verbose ? result : result["error"] ? result["errorMessage"] : result["result"].map{|x| value = self.class.get(x).parsed_response; ArangoDocument.new(key: value["_key"], collection: @collection, body: value)}
193
- else
194
- @@verbose ? result : result["error"] ? result["errorMessage"] : result["result"]
195
- end
196
- end
197
-
198
- def allDocuments(skip: nil, limit: nil, batchSize: nil) # TESTED
199
- body = {
200
- "collection" => @collection,
201
- "skip" => skip,
202
- "limit" => limit,
203
- "batchSize" => batchSize
204
- }.delete_if{|k,v| v.nil?}.to_json
205
- request = @@request.merge({ :body => body })
206
- result = self.class.put("/_db/#{@database}/_api/simple/all", request)
207
- result.headers["x-arango-async-id"] if @@async == "store"
208
- result = result.parsed_response
209
- @@verbose ? result : result["error"] ? result["errorMessage"] : result["result"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, body: x)}
210
- end
211
-
212
- def documentsMatch(match:, skip: nil, limit: nil, batchSize: nil) # TESTED
213
- body = {
214
- "collection" => @collection,
215
- "example" => match,
216
- "skip" => skip,
217
- "limit" => limit,
218
- "batchSize" => batchSize
219
- }.delete_if{|k,v| v.nil?}.to_json
220
- request = @@request.merge({ :body => body })
221
- result = self.class.put("/_db/#{@database}/_api/simple/by-example", request)
222
- return result.headers["x-arango-async-id"] if @@async == "store"
223
- result = result.parsed_response
224
- @@verbose ? result : result["error"] ? result["errorMessage"] : result["result"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, body: x)}
225
- end
226
-
227
- def documentMatch(match:) # TESTED
228
- body = {
229
- "collection" => @collection,
230
- "example" => match
231
- }.delete_if{|k,v| v.nil?}.to_json
232
- request = @@request.merge({ :body => body })
233
- result = self.class.put("/_db/#{@database}/_api/simple/first-example", request)
234
- return result.headers["x-arango-async-id"] if @@async == "store"
235
- result = result.parsed_response
236
- @@verbose ? result : result["error"] ? result["errorMessage"] : ArangoDocument.new(key: result["document"]["_key"], collection: @collection, body: result["document"])
237
- end
238
-
239
- def documentByKeys(keys:) # TESTED
240
- keys = keys.map{|x| x.is_a?(String) ? x : x.is_a?(ArangoDocument) ? x.key : nil} if keys.is_a? Array
241
- keys = [keys] if keys.is_a? String
242
- body = { "collection" => @collection, "keys" => keys }
243
- request = @@request.merge({ :body => body.to_json })
244
- result = self.class.put("/_db/#{@database}/_api/simple/lookup-by-keys", request)
245
- return result.headers["x-arango-async-id"] if @@async == "store"
246
- result = result.parsed_response
247
- @@verbose ? result : result["error"] ? result["errorMessage"] : result["documents"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, body: x)}
248
- end
249
-
250
- def random # TESTED
251
- body = { "collection" => @collection }.to_json
252
- request = @@request.merge({ :body => body })
253
- result = self.class.put("/_db/#{@database}/_api/simple/any", request)
254
- return result.headers["x-arango-async-id"] if @@async == "store"
255
- result = result.parsed_response
256
- @@verbose ? result : result["error"] ? result["errorMessage"] : ArangoDocument.new(key: result["document"]["_key"], collection: @collection, body: result["document"])
257
- end
258
-
259
- def removeByKeys(keys:, options: nil) # TESTED
260
- keys = keys.map{|x| x.is_a?(String) ? x : x.is_a?(ArangoDocument) ? x.key : nil}
261
- body = { "collection" => @collection, "keys" => keys, "options" => options }.delete_if{|k,v| v.nil?}.to_json
262
- request = @@request.merge({ :body => body })
263
- result = self.class.put("/_db/#{@database}/_api/simple/remove-by-keys", request)
264
- self.return_result result: result, key: "removed"
265
- end
266
-
267
- def removeMatch(match:, options: nil) # TESTED
268
- body = {
269
- "collection" => @collection,
270
- "example" => match,
271
- "options" => options
272
- }.delete_if{|k,v| v.nil?}.to_json
273
- request = @@request.merge({ :body => body })
274
- result = self.class.put("/_db/#{@database}/_api/simple/remove-by-example", request)
275
- self.return_result result: result, key: "deleted"
276
- end
277
-
278
- def replaceMatch(match:, newValue:, options: nil) # TESTED
279
- body = {
280
- "collection" => @collection,
281
- "example" => match,
282
- "options" => options,
283
- "newValue" => newValue
284
- }.delete_if{|k,v| v.nil?}.to_json
285
- request = @@request.merge({ :body => body })
286
- result = self.class.put("/_db/#{@database}/_api/simple/replace-by-example", request)
287
- self.return_result result: result, key: "replaced"
288
- end
289
-
290
- def updateMatch(match:, newValue:, options: nil) # TESTED
291
- body = {
292
- "collection" => @collection,
293
- "example" => match,
294
- "options" => options,
295
- "newValue" => newValue
296
- }.delete_if{|k,v| v.nil?}.to_json
297
- request = @@request.merge({ :body => body })
298
- result = self.class.put("/_db/#{@database}/_api/simple/update-by-example", request)
299
- self.return_result result: result, key: "updated"
300
- end
301
-
302
- # === IMPORT ===
303
-
304
- def import(attributes:, values:, from: nil, to: nil, overwrite: nil, waitForSync: nil, onDuplicate: nil, complete: nil, details: nil) # TESTED
305
- query = {
306
- "collection": @collection,
307
- "fromPrefix": from,
308
- "toPrefix": to,
309
- "overwrite": overwrite,
310
- "waitForSync": waitForSync,
311
- "onDuplicate": onDuplicate,
312
- "complete": complete,
313
- "details": details
314
- }.delete_if{|k,v| v.nil?}
315
- body = "#{attributes}\n"
316
- values[0].is_a?(Array) ? values.each{|x| body += "#{x}\n"} : body += "#{values}\n"
317
- request = @@request.merge({ :body => body, :query => query })
318
- result = self.class.post("/_db/#{@database}/_api/import", request)
319
- return result.headers["x-arango-async-id"] if @@async == "store"
320
- result = result.parsed_response
321
- @@verbose ? result : result["error"] ? result["errorMessage"] : result.delete_if{|k,v| k == "error" || k == "code"}
322
- end
323
-
324
- def importJSON(body:, type: "auto", from: nil, to: nil, overwrite: nil, waitForSync: nil, onDuplicate: nil, complete: nil, details: nil) # TESTED
325
- query = {
326
- "collection": @collection,
327
- "type": type,
328
- "fromPrefix": from,
329
- "toPrefix": to,
330
- "overwrite": overwrite,
331
- "waitForSync": waitForSync,
332
- "onDuplicate": onDuplicate,
333
- "complete": complete,
334
- "details": details
335
- }.delete_if{|k,v| v.nil?}
336
- request = @@request.merge({ :body => body.to_json, :query => query })
337
- result = self.class.post("/_db/#{@database}/_api/import", request)
338
- return result.headers["x-arango-async-id"] if @@async == "store"
339
- result = result.parsed_response
340
- @@verbose ? result : result["error"] ? result["errorMessage"] : result.delete_if{|k,v| k == "error" || k == "code"}
341
- end
342
-
343
- # === EXPORT ===
344
-
345
- def export(count: nil, restrict: nil, batchSize: nil, flush: nil, limit: nil, ttl: nil) # TESTED
346
- query = { "collection": @collection }
347
- body = {
348
- "count" => count,
349
- "restrict" => restrict,
350
- "batchSize" => batchSize,
351
- "flush" => flush,
352
- "limit" => limit,
353
- "ttl" => ttl
354
- }.delete_if{|k,v| v.nil?}
355
- request = @@request.merge({ :body => body.to_json, :query => query })
356
- result = self.class.post("/_db/#{@database}/_api/export", request)
357
- return result.headers["x-arango-async-id"] if @@async == "store"
358
- result = result.parsed_response
359
- return @@verbose ? result : result["errorMessage"] if result["error"]
360
- @countExport = result["count"]
361
- @hasMoreExport = result["hasMore"]
362
- @idExport = result["id"]
363
- if(result["result"][0].nil? || !result["result"][0].is_a?(Hash) || !result["result"][0].key?("_key"))
364
- result = result["result"]
365
- else
366
- result = result["result"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, database: @database, body: x)}
367
- end
368
- result
369
- end
370
-
371
- def exportNext # TESTED
372
- unless @hasMoreExport
373
- print "No other results"
374
- else
375
- query = { "collection": @collection }
376
- request = @@request.merge({ :query => query })
377
- result = self.class.put("/_db/#{@database}/_api/cursor/#{@idExport}", request)
378
- return result.headers["x-arango-async-id"] if @@async == "store"
379
- result = result.parsed_response
380
- return @@verbose ? result : result["errorMessage"] if result["error"]
381
- @countExport = result["count"]
382
- @hasMoreExport = result["hasMore"]
383
- @idExport = result["id"]
384
- if(result["result"][0].nil? || !result["result"][0].is_a?(Hash) || !result["result"][0].key?("_key"))
385
- result = result["result"]
386
- else
387
- result = result["result"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, database: @database, body: x)}
388
- end
389
- result
390
- end
391
- end
392
-
393
- # === INDEXES ===
394
-
395
- # def retrieveIndex(id:) # TESTED
396
- # result = self.class.get("/_db/#{@database}/_api/index/#{@collection}/#{id}", @@request)
397
- # if @@async == "store"
398
- # result.headers["x-arango-async-id"]
399
- # else
400
- # result = result.parsed_response
401
- # if @@verbose
402
- # result
403
- # else
404
- # if result["error"]
405
- # result["errorMessage"]
406
- # else
407
- # ArangoIndex.new(body: result, id: result["id"], database: @database, collection: @collection, type: result["type"], unique: result["unique"], fields: result["fields"])
408
- # end
409
- # end
410
- # end
411
- # end
412
-
413
- def indexes # TESTED
414
- query = { "collection": @collection }
415
- request = @@request.merge({ :query => query })
416
- result = self.class.get("/_db/#{@database}/_api/index", request)
417
- return result.headers["x-arango-async-id"] if @@async == "store"
418
- result = result.parsed_response
419
- return result if @@verbose
420
- return result["errorMessage"] if result["error"]
421
- result.delete_if{|k,v| k == "error" || k == "code"}
422
- result["indexes"] = result["indexes"].map{|x| ArangoIndex.new(body: x, id: x["id"], database: @database, collection: @collection, type: x["type"], unique: x["unique"], fields: x["fields"])}
423
- result
424
- end
425
-
426
- def createIndex(body: {}, unique: nil, type:, fields:, id: nil) # TESTED
427
- body["fields"] = fields.is_a?(Array) ? fields : [fields]
428
- body["unique"] = unique unless unique.nil?
429
- body["type"] = type unless type.nil?
430
- body["id"] = id unless type.nil?
431
- query = { "collection": @collection }
432
- request = @@request.merge({ :body => body.to_json, :query => query })
433
- result = self.class.post("/_db/#{@database}/_api/index", request)
434
- return result.headers["x-arango-async-id"] if @@async == "store"
435
- result = result.parsed_response
436
- @@verbose ? result : result["error"] ? result["errorMessage"] : ArangoIndex.new(body: result, id: result["id"], database: @database, collection: @collection, type: result["type"], unique: result["unique"], fields: result["fields"])
437
- end
438
- #
439
- # def deleteIndex(id:) # TESTED
440
- # result = self.class.delete("/_db/#{@database}/_api/index/#{@collection}/#{id}", @@request)
441
- # if @@async == "store"
442
- # result.headers["x-arango-async-id"]
443
- # else
444
- # result = result.parsed_response
445
- # if @@verbose
446
- # result
447
- # else
448
- # if result["error"]
449
- # result["errorMessage"]
450
- # else
451
- # true
452
- # end
453
- # end
454
- # end
455
- # end
456
-
457
- # === REPLICATION ===
458
-
459
- def data(from: nil, to: nil, chunkSize: nil, includeSystem: false, failOnUnknown: nil, ticks: nil, flush: nil) # TESTED
460
- query = {
461
- "collection": @collection,
462
- "from": from,
463
- "to": to,
464
- "chunkSize": chunkSize,
465
- "includeSystem": includeSystem,
466
- "failOnUnknown": failOnUnknown,
467
- "ticks": ticks,
468
- "flush": flush
469
- }.delete_if{|k,v| v.nil?}
470
- request = @@request.merge({ :query => query })
471
- result = self.class.get("/_db/#{@database}/_api/replication/dump", request)
472
- return result.headers["x-arango-async-id"] if @@async == "store"
473
- result = result.parsed_response
474
- @@verbose ? result : result["error"] ? result["errorMessage"] : result
475
- end
476
-
477
- # === UTILITY ===
478
-
479
- def return_result(result:, caseTrue: false, key: nil, checkType: false)
480
- return result.headers["x-arango-async-id"] if @@async == "store"
481
- result = result.parsed_response
482
- if @@verbose || !result.is_a?(Hash)
483
- resultTemp = result
484
- unless result["errorMessage"]
485
- result.delete_if{|k,v| k == "error" || k == "code"}
486
- @body = result
487
- @type = result["type"] == 2 ? "Document" : "Edge" if(checkType)
488
- end
489
- resultTemp
490
- else
491
- return result["errorMessage"] if result["error"]
492
- return true if caseTrue
493
- result.delete_if{|k,v| k == "error" || k == "code"}
494
- @body = result
495
- @type = result["type"] == 2 ? "Document" : "Edge" if(checkType)
496
- key.nil? ? self : result[key]
497
- end
498
- end
499
- end
1
+ # === COLLECTION ===
2
+
3
+ class ArangoCollection < ArangoServer
4
+ def initialize(collection: @@collection, database: @@database, body: {}, type: nil) # TESTED
5
+ if collection.is_a?(String)
6
+ @collection = collection
7
+ elsif collection.is_a?(ArangoCollection)
8
+ @collection = collection.collection
9
+ else
10
+ raise "collection should be a String or an ArangoCollection instance, not a #{collection.class}"
11
+ end
12
+
13
+ if database.is_a?(String)
14
+ @database = database
15
+ elsif database.is_a?(ArangoDatabase)
16
+ @database = database.database
17
+ else
18
+ raise "database should be a String or an ArangoDatabase instance, not a #{database.class}"
19
+ end
20
+
21
+ if body.is_a?(Hash)
22
+ @body = body
23
+ else
24
+ raise "body should be a Hash, not a #{body.class}"
25
+ end
26
+
27
+ if !@type.nil? && @type != "Document" && @type != "Edge"
28
+ raise "type should be \"Document\" or \"Edge\""
29
+ else
30
+ @type = type
31
+ if @type == "Document"
32
+ @body["type"] = 2
33
+ elsif @type == "Edge"
34
+ @body["type"] = 3
35
+ end
36
+ end
37
+ @idCache = "COL_#{@collection}"
38
+ end
39
+
40
+ attr_reader :collection, :body, :type, :idCache
41
+ alias name collection
42
+
43
+ # === RETRIEVE ===
44
+
45
+ def to_hash
46
+ {
47
+ "collection" => @collection,
48
+ "database" => @database,
49
+ "type" => @type,
50
+ "body" => @body,
51
+ "idCache" => @idCache
52
+ }.delete_if{|k,v| v.nil?}
53
+ end
54
+ alias to_h to_hash
55
+
56
+ def [](document_name)
57
+ ArangoDocument.new(key: document_name, collection: @collection, database: @database)
58
+ end
59
+ alias document []
60
+
61
+ def database
62
+ ArangoDatabase.new(database: @database)
63
+ end
64
+
65
+ # === GET ===
66
+
67
+ def retrieve # TESTED
68
+ result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}", @@request)
69
+ self.return_result result: result, checkType: true
70
+ end
71
+
72
+ def properties # TESTED
73
+ result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/properties", @@request)
74
+ result = self.return_result result: result
75
+ return result.is_a?(ArangoCollection) ? result.body : result
76
+ end
77
+
78
+ def count # TESTED
79
+ result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/count", @@request)
80
+ self.return_result result: result, key: "count"
81
+ end
82
+
83
+ def statistics # TESTED
84
+ result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/figures", @@request)
85
+ self.return_result result: result, key: "figures"
86
+ end
87
+
88
+ def revision # TESTED
89
+ result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/revision", @@request)
90
+ self.return_result result: result, key: "revision"
91
+ end
92
+
93
+ def checksum(withRevisions: nil, withData: nil) # TESTED
94
+ query = {
95
+ "withRevisions": withRevisions,
96
+ "withData": withData
97
+ }.delete_if{|k,v| v.nil?}
98
+ request = @@request.merge({ :query => query })
99
+ result = self.class.get("/_db/#{@database}/_api/collection/#{@collection}/checksum", request)
100
+ self.return_result result: result, key: "checksum"
101
+ end
102
+
103
+ # === POST ===
104
+
105
+ def create(type: nil, journalSize: nil, keyOptions: nil, waitForSync: nil, doCompact: nil, isVolatile: nil, shardKeys: nil, numberOfShards: nil, isSystem: nil, indexBuckets: nil) # TESTED
106
+ type = 3 if type == "Edge"
107
+ type = nil if type == "Document"
108
+ body = {
109
+ "name" => collection,
110
+ "type" => type,
111
+ "journalSize" => journalSize,
112
+ "keyOptions" => keyOptions,
113
+ "waitForSync" => waitForSync,
114
+ "doCompact" => doCompact,
115
+ "isVolatile" => isVolatile,
116
+ "shardKeys" => shardKeys,
117
+ "numberOfShards" => numberOfShards,
118
+ "isSystem" => isSystem,
119
+ "indexBuckets" => indexBuckets
120
+ }
121
+ body = body.delete_if{|k,v| v.nil?}.to_json
122
+ request = @@request.merge({ :body => body })
123
+ result = self.class.post("/_db/#{@database}/_api/collection", request)
124
+ self.return_result result: result, checkType: true
125
+ end
126
+ alias create_collection create
127
+ alias create_document_collection create
128
+ alias create_vertex_collection create
129
+
130
+ def create_edge_collection(journalSize: nil, keyOptions: nil, waitForSync: nil, doCompact: nil, isVolatile: nil, shardKeys: nil, numberOfShards: nil, isSystem: nil, indexBuckets: nil) # TESTED
131
+ self.create type: 3, journalSize: journalSize, keyOptions: keyOptions, waitForSync: waitForSync, doCompact: doCompact, isVolatile: isVolatile, shardKeys: shardKeys, numberOfShards: numberOfShards, isSystem: isSystem, indexBuckets: indexBuckets
132
+ end
133
+
134
+ def create_document(document: {}, waitForSync: nil, returnNew: nil) # TESTED
135
+ ArangoDocument.create(body: document, waitForSync: waitForSync, returnNew: returnNew, database: @database, collection: @collection)
136
+ end
137
+ alias create_vertex create_document
138
+
139
+ def create_edge(document: {}, from:, to:, waitForSync: nil, returnNew: nil) # TESTED
140
+ ArangoDocument.create_edge(body: document, from: from, to: to, waitForSync: waitForSync, returnNew: returnNew, database: @database, collection: @collection)
141
+ end
142
+
143
+ # === DELETE ===
144
+
145
+ def destroy # TESTED
146
+ result = self.class.delete("/_db/#{@database}/_api/collection/#{@collection}", @@request)
147
+ self.return_result result: result, caseTrue: true
148
+ end
149
+
150
+ def truncate # TESTED
151
+ result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/truncate", @@request)
152
+ self.return_result result: result
153
+ end
154
+
155
+ # === MODIFY ===
156
+
157
+ def load # TESTED
158
+ result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/load", @@request)
159
+ self.return_result result: result
160
+ end
161
+
162
+ def unload # TESTED
163
+ result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/unload", @@request)
164
+ self.return_result result: result
165
+ end
166
+
167
+ def change(waitForSync: nil, journalSize: nil) # TESTED
168
+ body = {
169
+ "journalSize" => journalSize,
170
+ "waitForSync" => waitForSync
171
+ }
172
+ body = body.delete_if{|k,v| k.nil?}.to_json
173
+ request = @@request.merge({ :body => body })
174
+ result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/properties", request)
175
+ self.return_result result: result
176
+ end
177
+
178
+ def rename(newName) # TESTED
179
+ body = { "name" => newName }
180
+ request = @@request.merge({ :body => body.to_json })
181
+ result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/rename", request)
182
+ @collection = newName unless result.parsed_response["error"]
183
+ self.return_result result: result
184
+ end
185
+
186
+ def rotate
187
+ result = self.class.put("/_db/#{@database}/_api/collection/#{@collection}/rotate", @@request)
188
+ self.return_result result: result, caseTrue: true
189
+ end
190
+
191
+ # === SIMPLE FUNCTIONS ===
192
+
193
+ def documents(type: nil) # "path", "id", "key" # TESTED
194
+ body = {
195
+ "collection" => @collection,
196
+ "type" => type
197
+ }.delete_if{|k,v| v.nil?}.to_json
198
+ request = @@request.merge({ :body => body })
199
+ result = self.class.put("/_db/#{@database}/_api/simple/all-keys", request)
200
+ return result.headers["x-arango-async-id"] if @@async == "store"
201
+ return true if @@async
202
+ result = result.parsed_response
203
+ if type.nil?
204
+ @@verbose ? result : result["error"] ? result["errorMessage"] : result["result"].map{|x| value = self.class.get(x).parsed_response; ArangoDocument.new(key: value["_key"], collection: @collection, body: value)}
205
+ else
206
+ @@verbose ? result : result["error"] ? result["errorMessage"] : result["result"]
207
+ end
208
+ end
209
+
210
+ def allDocuments(skip: nil, limit: nil, batchSize: nil) # TESTED
211
+ body = {
212
+ "collection" => @collection,
213
+ "skip" => skip,
214
+ "limit" => limit,
215
+ "batchSize" => batchSize
216
+ }.delete_if{|k,v| v.nil?}.to_json
217
+ request = @@request.merge({ :body => body })
218
+ result = self.class.put("/_db/#{@database}/_api/simple/all", request)
219
+ return result.headers["x-arango-async-id"] if @@async == "store"
220
+ return true if @@async
221
+ result = result.parsed_response
222
+ @@verbose ? result : result["error"] ? result["errorMessage"] : result["result"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, body: x)}
223
+ end
224
+
225
+ def documentsMatch(match:, skip: nil, limit: nil, batchSize: nil) # TESTED
226
+ body = {
227
+ "collection" => @collection,
228
+ "example" => match,
229
+ "skip" => skip,
230
+ "limit" => limit,
231
+ "batchSize" => batchSize
232
+ }.delete_if{|k,v| v.nil?}.to_json
233
+ request = @@request.merge({ :body => body })
234
+ result = self.class.put("/_db/#{@database}/_api/simple/by-example", request)
235
+ return result.headers["x-arango-async-id"] if @@async == "store"
236
+ return true if @@async
237
+ result = result.parsed_response
238
+ @@verbose ? result : result["error"] ? result["errorMessage"] : result["result"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, body: x)}
239
+ end
240
+
241
+ def documentMatch(match:) # TESTED
242
+ body = {
243
+ "collection" => @collection,
244
+ "example" => match
245
+ }.delete_if{|k,v| v.nil?}.to_json
246
+ request = @@request.merge({ :body => body })
247
+ result = self.class.put("/_db/#{@database}/_api/simple/first-example", request)
248
+ return result.headers["x-arango-async-id"] if @@async == "store"
249
+ return true if @@async
250
+ result = result.parsed_response
251
+ @@verbose ? result : result["error"] ? result["errorMessage"] : ArangoDocument.new(key: result["document"]["_key"], collection: @collection, body: result["document"])
252
+ end
253
+
254
+ def documentByKeys(keys:) # TESTED
255
+ keys = keys.map{|x| x.is_a?(String) ? x : x.is_a?(ArangoDocument) ? x.key : nil} if keys.is_a? Array
256
+ keys = [keys] if keys.is_a? String
257
+ body = { "collection" => @collection, "keys" => keys }
258
+ request = @@request.merge({ :body => body.to_json })
259
+ result = self.class.put("/_db/#{@database}/_api/simple/lookup-by-keys", request)
260
+ return result.headers["x-arango-async-id"] if @@async == "store"
261
+ return true if @@async
262
+ result = result.parsed_response
263
+ @@verbose ? result : result["error"] ? result["errorMessage"] : result["documents"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, body: x)}
264
+ end
265
+
266
+ def random # TESTED
267
+ body = { "collection" => @collection }.to_json
268
+ request = @@request.merge({ :body => body })
269
+ result = self.class.put("/_db/#{@database}/_api/simple/any", request)
270
+ return result.headers["x-arango-async-id"] if @@async == "store"
271
+ return true if @@async
272
+ result = result.parsed_response
273
+ @@verbose ? result : result["error"] ? result["errorMessage"] : ArangoDocument.new(key: result["document"]["_key"], collection: @collection, body: result["document"])
274
+ end
275
+
276
+ def removeByKeys(keys:, options: nil) # TESTED
277
+ keys = keys.map{|x| x.is_a?(String) ? x : x.is_a?(ArangoDocument) ? x.key : nil}
278
+ body = { "collection" => @collection, "keys" => keys, "options" => options }.delete_if{|k,v| v.nil?}.to_json
279
+ request = @@request.merge({ :body => body })
280
+ result = self.class.put("/_db/#{@database}/_api/simple/remove-by-keys", request)
281
+ self.return_result result: result, key: "removed"
282
+ end
283
+
284
+ def removeMatch(match:, options: nil) # TESTED
285
+ body = {
286
+ "collection" => @collection,
287
+ "example" => match,
288
+ "options" => options
289
+ }.delete_if{|k,v| v.nil?}.to_json
290
+ request = @@request.merge({ :body => body })
291
+ result = self.class.put("/_db/#{@database}/_api/simple/remove-by-example", request)
292
+ self.return_result result: result, key: "deleted"
293
+ end
294
+
295
+ def replaceMatch(match:, newValue:, options: nil) # TESTED
296
+ body = {
297
+ "collection" => @collection,
298
+ "example" => match,
299
+ "options" => options,
300
+ "newValue" => newValue
301
+ }.delete_if{|k,v| v.nil?}.to_json
302
+ request = @@request.merge({ :body => body })
303
+ result = self.class.put("/_db/#{@database}/_api/simple/replace-by-example", request)
304
+ self.return_result result: result, key: "replaced"
305
+ end
306
+
307
+ def updateMatch(match:, newValue:, options: nil) # TESTED
308
+ body = {
309
+ "collection" => @collection,
310
+ "example" => match,
311
+ "options" => options,
312
+ "newValue" => newValue
313
+ }.delete_if{|k,v| v.nil?}.to_json
314
+ request = @@request.merge({ :body => body })
315
+ result = self.class.put("/_db/#{@database}/_api/simple/update-by-example", request)
316
+ self.return_result result: result, key: "updated"
317
+ end
318
+
319
+ # === IMPORT ===
320
+
321
+ def import(attributes:, values:, from: nil, to: nil, overwrite: nil, waitForSync: nil, onDuplicate: nil, complete: nil, details: nil) # TESTED
322
+ query = {
323
+ "collection": @collection,
324
+ "fromPrefix": from,
325
+ "toPrefix": to,
326
+ "overwrite": overwrite,
327
+ "waitForSync": waitForSync,
328
+ "onDuplicate": onDuplicate,
329
+ "complete": complete,
330
+ "details": details
331
+ }.delete_if{|k,v| v.nil?}
332
+ body = "#{attributes}\n"
333
+ values[0].is_a?(Array) ? values.each{|x| body += "#{x}\n"} : body += "#{values}\n"
334
+ request = @@request.merge({ :body => body, :query => query })
335
+ result = self.class.post("/_db/#{@database}/_api/import", request)
336
+ return result.headers["x-arango-async-id"] if @@async == "store"
337
+ return true if @@async
338
+ result = result.parsed_response
339
+ @@verbose ? result : result["error"] ? result["errorMessage"] : result.delete_if{|k,v| k == "error" || k == "code"}
340
+ end
341
+
342
+ def importJSON(body:, type: "auto", from: nil, to: nil, overwrite: nil, waitForSync: nil, onDuplicate: nil, complete: nil, details: nil) # TESTED
343
+ query = {
344
+ "collection": @collection,
345
+ "type": type,
346
+ "fromPrefix": from,
347
+ "toPrefix": to,
348
+ "overwrite": overwrite,
349
+ "waitForSync": waitForSync,
350
+ "onDuplicate": onDuplicate,
351
+ "complete": complete,
352
+ "details": details
353
+ }.delete_if{|k,v| v.nil?}
354
+ request = @@request.merge({ :body => body.to_json, :query => query })
355
+ result = self.class.post("/_db/#{@database}/_api/import", request)
356
+ return result.headers["x-arango-async-id"] if @@async == "store"
357
+ return true if @@async
358
+ result = result.parsed_response
359
+ @@verbose ? result : result["error"] ? result["errorMessage"] : result.delete_if{|k,v| k == "error" || k == "code"}
360
+ end
361
+
362
+ # === EXPORT ===
363
+
364
+ def export(count: nil, restrict: nil, batchSize: nil, flush: nil, limit: nil, ttl: nil) # TESTED
365
+ query = { "collection": @collection }
366
+ body = {
367
+ "count" => count,
368
+ "restrict" => restrict,
369
+ "batchSize" => batchSize,
370
+ "flush" => flush,
371
+ "limit" => limit,
372
+ "ttl" => ttl
373
+ }.delete_if{|k,v| v.nil?}
374
+ request = @@request.merge({ :body => body.to_json, :query => query })
375
+ result = self.class.post("/_db/#{@database}/_api/export", request)
376
+ return result.headers["x-arango-async-id"] if @@async == "store"
377
+ return true if @@async
378
+ result = result.parsed_response
379
+ return @@verbose ? result : result["errorMessage"] if result["error"]
380
+ @countExport = result["count"]
381
+ @hasMoreExport = result["hasMore"]
382
+ @idExport = result["id"]
383
+ if(result["result"][0].nil? || !result["result"][0].is_a?(Hash) || !result["result"][0].key?("_key"))
384
+ result = result["result"]
385
+ else
386
+ result = result["result"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, database: @database, body: x)}
387
+ end
388
+ result
389
+ end
390
+
391
+ def exportNext # TESTED
392
+ unless @hasMoreExport
393
+ print "No other results"
394
+ else
395
+ query = { "collection": @collection }
396
+ request = @@request.merge({ :query => query })
397
+ result = self.class.put("/_db/#{@database}/_api/cursor/#{@idExport}", request)
398
+ return result.headers["x-arango-async-id"] if @@async == "store"
399
+ return true if @@async
400
+ result = result.parsed_response
401
+ return @@verbose ? result : result["errorMessage"] if result["error"]
402
+ @countExport = result["count"]
403
+ @hasMoreExport = result["hasMore"]
404
+ @idExport = result["id"]
405
+ if(result["result"][0].nil? || !result["result"][0].is_a?(Hash) || !result["result"][0].key?("_key"))
406
+ result = result["result"]
407
+ else
408
+ result = result["result"].map{|x| ArangoDocument.new(key: x["_key"], collection: @collection, database: @database, body: x)}
409
+ end
410
+ result
411
+ end
412
+ end
413
+
414
+ # === INDEXES ===
415
+
416
+ # def retrieveIndex(id:) # TESTED
417
+ # result = self.class.get("/_db/#{@database}/_api/index/#{@collection}/#{id}", @@request)
418
+ # if @@async == "store"
419
+ # result.headers["x-arango-async-id"]
420
+ # else
421
+ # result = result.parsed_response
422
+ # if @@verbose
423
+ # result
424
+ # else
425
+ # if result["error"]
426
+ # result["errorMessage"]
427
+ # else
428
+ # ArangoIndex.new(body: result, id: result["id"], database: @database, collection: @collection, type: result["type"], unique: result["unique"], fields: result["fields"])
429
+ # end
430
+ # end
431
+ # end
432
+ # end
433
+
434
+ def indexes # TESTED
435
+ query = { "collection": @collection }
436
+ request = @@request.merge({ :query => query })
437
+ result = self.class.get("/_db/#{@database}/_api/index", request)
438
+ return result.headers["x-arango-async-id"] if @@async == "store"
439
+ return true if @@async
440
+ result = result.parsed_response
441
+ return result if @@verbose
442
+ return result["errorMessage"] if result["error"]
443
+ result.delete_if{|k,v| k == "error" || k == "code"}
444
+ result["indexes"] = result["indexes"].map{|x| ArangoIndex.new(body: x, id: x["id"], database: @database, collection: @collection, type: x["type"], unique: x["unique"], fields: x["fields"])}
445
+ result
446
+ end
447
+
448
+ def createIndex(body: {}, unique: nil, type:, fields:, id: nil) # TESTED
449
+ body["fields"] = fields.is_a?(Array) ? fields : [fields]
450
+ body["unique"] = unique unless unique.nil?
451
+ body["type"] = type unless type.nil?
452
+ body["id"] = id unless type.nil?
453
+ query = { "collection": @collection }
454
+ request = @@request.merge({ :body => body.to_json, :query => query })
455
+ result = self.class.post("/_db/#{@database}/_api/index", request)
456
+ return result.headers["x-arango-async-id"] if @@async == "store"
457
+ return true if @@async
458
+ result = result.parsed_response
459
+ @@verbose ? result : result["error"] ? result["errorMessage"] : ArangoIndex.new(body: result, id: result["id"], database: @database, collection: @collection, type: result["type"], unique: result["unique"], fields: result["fields"])
460
+ end
461
+ #
462
+ # def deleteIndex(id:) # TESTED
463
+ # result = self.class.delete("/_db/#{@database}/_api/index/#{@collection}/#{id}", @@request)
464
+ # if @@async == "store"
465
+ # result.headers["x-arango-async-id"]
466
+ # else
467
+ # result = result.parsed_response
468
+ # if @@verbose
469
+ # result
470
+ # else
471
+ # if result["error"]
472
+ # result["errorMessage"]
473
+ # else
474
+ # true
475
+ # end
476
+ # end
477
+ # end
478
+ # end
479
+
480
+ # === REPLICATION ===
481
+
482
+ def data(from: nil, to: nil, chunkSize: nil, includeSystem: false, failOnUnknown: nil, ticks: nil, flush: nil) # TESTED
483
+ query = {
484
+ "collection": @collection,
485
+ "from": from,
486
+ "to": to,
487
+ "chunkSize": chunkSize,
488
+ "includeSystem": includeSystem,
489
+ "failOnUnknown": failOnUnknown,
490
+ "ticks": ticks,
491
+ "flush": flush
492
+ }.delete_if{|k,v| v.nil?}
493
+ request = @@request.merge({ :query => query })
494
+ result = self.class.get("/_db/#{@database}/_api/replication/dump", request)
495
+ return result.headers["x-arango-async-id"] if @@async == "store"
496
+ return true if @@async
497
+ result = result.parsed_response
498
+ return nil if result.nil?
499
+ @@verbose ? result : result["error"] ? result["errorMessage"] : result
500
+ end
501
+ alias dump data
502
+
503
+ # === UTILITY ===
504
+
505
+ def return_result(result:, caseTrue: false, key: nil, checkType: false)
506
+ return result.headers["x-arango-async-id"] if @@async == "store"
507
+ return true if @@async
508
+ result = result.parsed_response
509
+ if @@verbose || !result.is_a?(Hash)
510
+ resultTemp = result
511
+ unless result["errorMessage"]
512
+ result.delete_if{|k,v| k == "error" || k == "code"}
513
+ @body = result
514
+ @type = result["type"] == 2 ? "Document" : "Edge" if(checkType)
515
+ end
516
+ resultTemp
517
+ else
518
+ return result["errorMessage"] if result["error"]
519
+ return true if caseTrue
520
+ result.delete_if{|k,v| k == "error" || k == "code"}
521
+ @body = result
522
+ @type = result["type"] == 2 ? "Document" : "Edge" if(checkType)
523
+ key.nil? ? self : result[key]
524
+ end
525
+ end
526
+ end