Skip to content

Commit e9569ef

Browse files
committed
Add changes for ArangoDB 3.4
1 parent 37dd0ab commit e9569ef

32 files changed

+805
-216
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ python:
88
services:
99
- docker
1010
before_install:
11-
- docker run --name arango -d -p 8529:8529 -e ARANGO_ROOT_PASSWORD=passwd arangodb/arangodb:3.3.9
11+
- docker run --name arango -d -p 8529:8529 -e ARANGO_ROOT_PASSWORD=passwd arangodb/arangodb:3.4.0
1212
- docker cp tests/static/service.zip arango:/tmp/service.zip
1313
install:
1414
- pip install flake8 mock pytest pytest-cov python-coveralls sphinx sphinx_rtd_theme

arango/aql.py

+41-10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
AQLFunctionCreateError,
1919
AQLFunctionDeleteError,
2020
AQLFunctionListError,
21+
AQLCacheEntriesError,
2122
AQLCacheClearError,
2223
AQLCacheConfigureError,
2324
AQLCachePropertiesError
@@ -442,8 +443,8 @@ def response_handler(resp):
442443
def functions(self):
443444
"""List the AQL functions defined in the database.
444445
445-
:return: Mapping of AQL function names to their javascript code.
446-
:rtype: dict
446+
:return: AQL functions.
447+
:rtype: [dict]
447448
:raise arango.exceptions.AQLFunctionListError: If retrieval fails.
448449
"""
449450
request = Request(
@@ -454,8 +455,17 @@ def functions(self):
454455
def response_handler(resp):
455456
if not resp.is_success:
456457
raise AQLFunctionListError(resp, request)
458+
457459
body = resp.body or {}
458-
return {func['name']: func['code'] for func in map(dict, body)}
460+
461+
if 'result' not in body: # pragma: no cover
462+
return []
463+
464+
for item in body['result']:
465+
if 'isDeterministic' in item:
466+
item['is_deterministic'] = item.pop('isDeterministic')
467+
468+
return body['result']
459469

460470
return self._execute(request, response_handler)
461471

@@ -466,8 +476,9 @@ def create_function(self, name, code):
466476
:type name: str | unicode
467477
:param code: Function definition in Javascript.
468478
:type code: str | unicode
469-
:return: True if AQL function was created successfully.
470-
:rtype: bool
479+
:return: Whether the AQL function was newly created or an existing one
480+
was replaced.
481+
:rtype: dict
471482
:raise arango.exceptions.AQLFunctionCreateError: If create fails.
472483
"""
473484
request = Request(
@@ -479,7 +490,7 @@ def create_function(self, name, code):
479490
def response_handler(resp):
480491
if not resp.is_success:
481492
raise AQLFunctionCreateError(resp, request)
482-
return True
493+
return {'is_new': resp.body['isNewlyCreated']}
483494

484495
return self._execute(request, response_handler)
485496

@@ -495,9 +506,10 @@ def delete_function(self, name, group=False, ignore_missing=False):
495506
:type group: bool
496507
:param ignore_missing: Do not raise an exception on missing function.
497508
:type ignore_missing: bool
498-
:return: True if AQL function was deleted successfully, False if
499-
function was not found and **ignore_missing** was set to True.
500-
:rtype: bool
509+
:return: Number of AQL functions deleted if operation was successful,
510+
False if function(s) was not found and **ignore_missing** was set
511+
to True.
512+
:rtype: dict | bool
501513
:raise arango.exceptions.AQLFunctionDeleteError: If delete fails.
502514
"""
503515
request = Request(
@@ -511,7 +523,7 @@ def response_handler(resp):
511523
return False
512524
if not resp.is_success:
513525
raise AQLFunctionDeleteError(resp, request)
514-
return True
526+
return {'deleted': resp.body['deletedCount']}
515527

516528
return self._execute(request, response_handler)
517529

@@ -578,6 +590,25 @@ def response_handler(resp):
578590

579591
return self._execute(request, response_handler)
580592

593+
def entries(self):
594+
"""Return the query cache entries.
595+
596+
:return: Query cache entries.
597+
:rtype: list
598+
:raise AQLCacheEntriesError: If retrieval fails.
599+
"""
600+
request = Request(
601+
method='get',
602+
endpoint='/_api/query-cache/entries'
603+
)
604+
605+
def response_handler(resp):
606+
if not resp.is_success:
607+
raise AQLCacheEntriesError(resp, request)
608+
return resp.body
609+
610+
return self._execute(request, response_handler)
611+
581612
def clear(self):
582613
"""Clear the query cache.
583614

arango/collection.py

+69-29
Original file line numberDiff line numberDiff line change
@@ -376,10 +376,10 @@ def response_handler(resp):
376376
raise CollectionStatisticsError(resp, request)
377377

378378
stats = resp.body.get('figures', resp.body)
379-
for field in ['compactors', 'datafiles', 'journals']:
380-
if field in stats and 'fileSize' in stats[field]:
381-
stats[field]['file_size'] = stats[field].pop('fileSize')
382-
if 'compactionStatus' in stats:
379+
for f in ['compactors', 'datafiles', 'journals']:
380+
if f in stats and 'fileSize' in stats[f]: # pragma: no cover
381+
stats[f]['file_size'] = stats[f].pop('fileSize')
382+
if 'compactionStatus' in stats: # pragma: no cover
383383
status = stats.pop('compactionStatus')
384384
if 'bytesRead' in status:
385385
status['bytes_read'] = status.pop('bytesRead')
@@ -388,15 +388,15 @@ def response_handler(resp):
388388
if 'filesCombined' in status:
389389
status['files_combined'] = status.pop('filesCombined')
390390
stats['compaction_status'] = status
391-
if 'documentReferences' in stats:
391+
if 'documentReferences' in stats: # pragma: no cover
392392
stats['document_refs'] = stats.pop('documentReferences')
393-
if 'lastTick' in stats:
393+
if 'lastTick' in stats: # pragma: no cover
394394
stats['last_tick'] = stats.pop('lastTick')
395-
if 'waitingFor' in stats:
395+
if 'waitingFor' in stats: # pragma: no cover
396396
stats['waiting_for'] = stats.pop('waitingFor')
397397
if 'documentsSize' in stats: # pragma: no cover
398398
stats['documents_size'] = stats.pop('documentsSize')
399-
if 'uncollectedLogfileEntries' in stats:
399+
if 'uncollectedLogfileEntries' in stats: # pragma: no cover
400400
stats['uncollected_logfile_entries'] = \
401401
stats.pop('uncollectedLogfileEntries')
402402
return stats
@@ -793,7 +793,7 @@ def response_handler(resp):
793793

794794
return self._execute(request, response_handler)
795795

796-
def find_near(self, latitude, longitude, limit=None):
796+
def find_near(self, latitude, longitude, limit=None): # pragma: no cover
797797
"""Return documents near a given coordinate.
798798
799799
Documents returned are sorted according to distance, with the nearest
@@ -1219,7 +1219,7 @@ def response_handler(resp):
12191219
index['min_length'] = index.pop('minLength')
12201220
if 'geoJson' in index:
12211221
index['geo_json'] = index.pop('geoJson')
1222-
if 'ignoreNull' in index:
1222+
if 'ignoreNull' in index: # pragma: no cover
12231223
index['ignore_none'] = index.pop('ignoreNull')
12241224
if 'selectivityEstimate' in index:
12251225
index['selectivity'] = index.pop('selectivityEstimate')
@@ -1255,7 +1255,7 @@ def response_handler(resp):
12551255
details['min_length'] = details.pop('minLength')
12561256
if 'geoJson' in details:
12571257
details['geo_json'] = details.pop('geoJson')
1258-
if 'ignoreNull' in details:
1258+
if 'ignoreNull' in details: # pragma: no cover
12591259
details['ignore_none'] = details.pop('ignoreNull')
12601260
if 'selectivityEstimate' in details:
12611261
details['selectivity'] = details.pop('selectivityEstimate')
@@ -1496,7 +1496,13 @@ def response_handler(resp):
14961496

14971497
return self._execute(request, response_handler)
14981498

1499-
def insert(self, document, return_new=False, sync=None, silent=False):
1499+
def insert(self,
1500+
document,
1501+
return_new=False,
1502+
sync=None,
1503+
silent=False,
1504+
overwrite=False,
1505+
return_old=False):
15001506
"""Insert a new document.
15011507
15021508
:param document: Document to insert. If it contains the "_key" or "_id"
@@ -1511,14 +1517,25 @@ def insert(self, document, return_new=False, sync=None, silent=False):
15111517
:param silent: If set to True, no document metadata is returned. This
15121518
can be used to save resources.
15131519
:type silent: bool
1520+
:param overwrite: If set to True, operation does not fail on duplicate
1521+
key and the existing document is replaced.
1522+
:type overwrite: bool
1523+
:param return_old: Include body of the old document if replaced.
1524+
Applies only when value of **overwrite** is set to True.
1525+
:type return_old: bool
15141526
:return: Document metadata (e.g. document key, revision) or True if
15151527
parameter **silent** was set to True.
15161528
:rtype: bool | dict
15171529
:raise arango.exceptions.DocumentInsertError: If insert fails.
15181530
"""
15191531
document = self._ensure_key_from_id(document)
15201532

1521-
params = {'returnNew': return_new, 'silent': silent}
1533+
params = {
1534+
'returnNew': return_new,
1535+
'silent': silent,
1536+
'overwrite': overwrite,
1537+
'returnOld': return_old
1538+
}
15221539
if sync is not None:
15231540
params['waitForSync'] = sync
15241541

@@ -1540,15 +1557,21 @@ def insert(self, document, return_new=False, sync=None, silent=False):
15401557
def response_handler(resp):
15411558
if not resp.is_success:
15421559
raise DocumentInsertError(resp, request)
1543-
return True if silent else resp.body
1560+
if silent:
1561+
return True
1562+
if '_oldRev' in resp.body:
1563+
resp.body['_old_rev'] = resp.body.pop('_oldRev')
1564+
return resp.body
15441565

15451566
return self._execute(request, response_handler)
15461567

15471568
def insert_many(self,
15481569
documents,
15491570
return_new=False,
15501571
sync=None,
1551-
silent=False):
1572+
silent=False,
1573+
overwrite=False,
1574+
return_old=False):
15521575
"""Insert multiple documents.
15531576
15541577
If inserting a document fails, the exception object is placed in the
@@ -1566,14 +1589,25 @@ def insert_many(self,
15661589
:param silent: If set to True, no document metadata is returned. This
15671590
can be used to save resources.
15681591
:type silent: bool
1592+
:param overwrite: If set to True, operation does not fail on duplicate
1593+
keys and the existing documents are replaced.
1594+
:type overwrite: bool
1595+
:param return_old: Include body of the old documents if replaced.
1596+
Applies only when value of **overwrite** is set to True.
1597+
:type return_old: bool
15691598
:return: List of document metadata (e.g. document keys, revisions) and
15701599
any exception, or True if parameter **silent** was set to True.
15711600
:rtype: [dict | ArangoError] | bool
15721601
:raise arango.exceptions.DocumentInsertError: If insert fails.
15731602
"""
15741603
documents = [self._ensure_key_from_id(doc) for doc in documents]
15751604

1576-
params = {'returnNew': return_new, 'silent': silent}
1605+
params = {
1606+
'returnNew': return_new,
1607+
'silent': silent,
1608+
'overwrite': overwrite,
1609+
'returnOld': return_old
1610+
}
15771611
if sync is not None:
15781612
params['waitForSync'] = sync
15791613

@@ -1601,6 +1635,8 @@ def response_handler(resp):
16011635
results = []
16021636
for result in resp.body:
16031637
if '_id' in result:
1638+
if '_oldRev' in result:
1639+
result['_old_rev'] = result.pop('_oldRev')
16041640
results.append(result)
16051641
else:
16061642
sub_resp = Response(
@@ -1783,7 +1819,7 @@ def response_handler(resp):
17831819
)
17841820
if result['errorNum'] == 1200:
17851821
result = DocumentRevisionError(sub_resp, request)
1786-
else:
1822+
else: # pragma: no cover
17871823
result = DocumentUpdateError(sub_resp, request)
17881824
else:
17891825
result['_old_rev'] = result.pop('_oldRev')
@@ -2006,7 +2042,7 @@ def response_handler(resp):
20062042
)
20072043
if result['errorNum'] == 1200:
20082044
result = DocumentRevisionError(sub_resp, request)
2009-
else:
2045+
else: # pragma: no cover
20102046
result = DocumentReplaceError(sub_resp, request)
20112047
else:
20122048
result['_old_rev'] = result.pop('_oldRev')
@@ -2332,9 +2368,9 @@ def import_bulk(self,
23322368
params['complete'] = halt_on_error
23332369
if details is not None:
23342370
params['details'] = details
2335-
if from_prefix is not None:
2371+
if from_prefix is not None: # pragma: no cover
23362372
params['fromPrefix'] = from_prefix
2337-
if to_prefix is not None:
2373+
if to_prefix is not None: # pragma: no cover
23382374
params['toPrefix'] = to_prefix
23392375
if overwrite is not None:
23402376
params['overwrite'] = overwrite
@@ -2495,7 +2531,9 @@ def update(self,
24952531
check_rev=True,
24962532
keep_none=True,
24972533
sync=None,
2498-
silent=False):
2534+
silent=False,
2535+
return_old=False,
2536+
return_new=False):
24992537
"""Update a vertex document.
25002538
25012539
:param vertex: Partial or full vertex document with updated values. It
@@ -2523,7 +2561,9 @@ def update(self,
25232561
params = {
25242562
'keepNull': keep_none,
25252563
'overwrite': not check_rev,
2526-
'silent': silent
2564+
'silent': silent,
2565+
'returnNew': return_new,
2566+
'returnOld': return_old
25272567
}
25282568
if sync is not None:
25292569
params['waitForSync'] = sync
@@ -2549,7 +2589,7 @@ def update(self,
25492589
)
25502590

25512591
def response_handler(resp):
2552-
if resp.status_code == 412:
2592+
if resp.status_code == 412: # pragma: no cover
25532593
raise DocumentRevisionError(resp, request)
25542594
elif not resp.is_success:
25552595
raise DocumentUpdateError(resp, request)
@@ -2611,7 +2651,7 @@ def replace(self, vertex, check_rev=True, sync=None, silent=False):
26112651
)
26122652

26132653
def response_handler(resp):
2614-
if resp.status_code == 412:
2654+
if resp.status_code == 412: # pragma: no cover
26152655
raise DocumentRevisionError(resp, request)
26162656
elif not resp.is_success:
26172657
raise DocumentReplaceError(resp, request)
@@ -2680,7 +2720,7 @@ def delete(self,
26802720
def response_handler(resp):
26812721
if resp.error_code == 1202 and ignore_missing:
26822722
return False
2683-
if resp.status_code == 412:
2723+
if resp.status_code == 412: # pragma: no cover
26842724
raise DocumentRevisionError(resp, request)
26852725
if not resp.is_success:
26862726
raise DocumentDeleteError(resp, request)
@@ -2759,7 +2799,7 @@ def get(self, edge, rev=None, check_rev=True):
27592799
def response_handler(resp):
27602800
if resp.error_code == 1202:
27612801
return None
2762-
if resp.status_code == 412:
2802+
if resp.status_code == 412: # pragma: no cover
27632803
raise DocumentRevisionError(resp, request)
27642804
if not resp.is_success:
27652805
raise DocumentGetError(resp, request)
@@ -2883,7 +2923,7 @@ def update(self,
28832923
)
28842924

28852925
def response_handler(resp):
2886-
if resp.status_code == 412:
2926+
if resp.status_code == 412: # pragma: no cover
28872927
raise DocumentRevisionError(resp, request)
28882928
if not resp.is_success:
28892929
raise DocumentUpdateError(resp, request)
@@ -2946,7 +2986,7 @@ def replace(self, edge, check_rev=True, sync=None, silent=False):
29462986
)
29472987

29482988
def response_handler(resp):
2949-
if resp.status_code == 412:
2989+
if resp.status_code == 412: # pragma: no cover
29502990
raise DocumentRevisionError(resp, request)
29512991
if not resp.is_success:
29522992
raise DocumentReplaceError(resp, request)
@@ -3015,7 +3055,7 @@ def delete(self,
30153055
def response_handler(resp):
30163056
if resp.error_code == 1202 and ignore_missing:
30173057
return False
3018-
if resp.status_code == 412:
3058+
if resp.status_code == 412: # pragma: no cover
30193059
raise DocumentRevisionError(resp, request)
30203060
if not resp.is_success:
30213061
raise DocumentDeleteError(resp, request)

0 commit comments

Comments
 (0)