Skip to content

Commit

Permalink
Use the correct cursor for document exports and improve documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
joowani committed Dec 10, 2016
1 parent ecc3184 commit 9e53762
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 33 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ install:
- python setup.py install
script:
- py.test --cov-report= --cov=arango tests/
after_success:
- coveralls
# after_success:
# - coveralls
6 changes: 3 additions & 3 deletions arango/collections/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import absolute_import, unicode_literals

from arango.api import APIWrapper, api_method
from arango.cursor import Cursor
from arango.cursor import Cursor, ExportCursor
from arango.exceptions import *
from arango.request import Request
from arango.utils import HTTP_OK
Expand Down Expand Up @@ -49,7 +49,7 @@ def __iter__(self):
)
if res.status_code not in HTTP_OK:
raise DocumentGetError(res)
return Cursor(self._conn, res.body)
return ExportCursor(self._conn, res.body)

def __len__(self):
"""Return the number of documents in the collection.
Expand Down Expand Up @@ -542,7 +542,7 @@ def all(self,
def handler(res):
if res.status_code not in HTTP_OK:
raise DocumentGetError(res)
return Cursor(self._conn, res.body)
return ExportCursor(self._conn, res.body)

return request, handler

Expand Down
42 changes: 42 additions & 0 deletions arango/cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,45 @@ def close(self, ignore_missing=True):
return False
raise CursorCloseError(res)
return True


class ExportCursor(Cursor):
"""ArangoDB cursor for export queries only.
.. note::
This class is designed to be instantiated internally only.
"""

def next(self):
"""Read the next result from the cursor.
:returns: the next item in the cursor
:rtype: dict
:raises: StopIteration, CursorNextError
"""
if not self.batch() and self.has_more():
res = self._conn.put("/_api/export/{}".format(self.id))
if res.status_code not in HTTP_OK:
raise CursorNextError(res)
self._data = res.body
elif not self.batch() and not self.has_more():
raise StopIteration
return self.batch().pop(0)

def close(self, ignore_missing=True):
"""Close the cursor and free the resources tied to it.
:returns: whether the cursor was closed successfully
:rtype: bool
:param ignore_missing: ignore missing cursors
:type ignore_missing: bool
:raises: CursorCloseError
"""
if not self.id:
return False
res = self._conn.delete("/_api/export/{}".format(self.id))
if res.status_code not in HTTP_OK:
if res.status_code == 404 and ignore_missing:
return False
raise CursorCloseError(res)
return True
36 changes: 18 additions & 18 deletions docs/aql.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
AQL
----

**ArangoDB AQL Language (AQL)** is used to retrieve and modify data stored in
ArangoDB. AQL is similar to SQL for relational databases but without the
support for data-definition operations such as creating or deleting
**ArangoDB Query Language (AQL)** is used to retrieve and modify data in
ArangoDB. AQL is similar to SQL for relational databases, but without the
support for data definition operations such as creating/deleting
:ref:`databases <database-page>`, :ref:`collections <collection-page>` and
:ref:`indexes <index-page>` etc. For more general information on AQL visit this
`page <https://docs.arangodb.com/AQL>`__.
:ref:`indexes <index-page>`. For more general information on AQL visit
`here <https://docs.arangodb.com/AQL>`__.

AQL Queries
===========

**AQL queries** can be invoked using the :ref:`AQL` class, which returns
instances of :ref:`Cursor`. For more information on AQL syntax visit this
`page <https://docs.arangodb.com/AQL/Fundamentals/Syntax.html>`__.
**AQL queries** can be invoked using the :ref:`AQL` class, which outputs
instances of the :ref:`Cursor` class. For more information on the syntax of AQL
visit `here <https://docs.arangodb.com/AQL/Fundamentals/Syntax.html>`__.

Here is an example showing how AQL queries can be executed:
Below is an example of executing a query:

.. code-block:: python
Expand Down Expand Up @@ -51,13 +51,13 @@ Here is an example showing how AQL queries can be executed:
AQL User Functions
==================

**AQL user functions** are custom functions defined by the users to extend the
functionality of AQL. Although python-arango provides ways to add, delete and
retrieve user functions in Python, the functions themselves must be defined in
Javascript. For more general information on AQL user functions visit this
`page <https://docs.arangodb.com/AQL/Extending>`__.
**AQL user functions** are custom functions which can be defined by users to
extend the functionality of AQL. While python-arango provides ways to add,
delete and retrieve user functions in Python, the functions themselves must be
defined in Javascript. For more general information on AQL user functions visit
this `page <https://docs.arangodb.com/AQL/Extending>`__.

Here is an example showing how AQL functions can be created or deleted:
Below is an example of creating and deleting an AQL function:

.. code-block:: python
Expand All @@ -83,9 +83,9 @@ Refer to :ref:`AQL` class for more details.
AQL Query Cache
===============

**AQL query cache** minimizes redundant calculation of the same query results.
If it useful when read queries are called frequently and write queries are not.
For more general information on AQL query caches visit this
**AQL query cache** is used to minimize redundant calculation of the same
query result. It is useful when read queries are called frequently and write
queries are not. For more general information on AQL query caches visit this
`page <https://docs.arangodb.com/AQL/ExecutionAndPerformance/QueryCache.html>`__.

Here is an example showing how the AQL query cache can be used:
Expand Down
5 changes: 3 additions & 2 deletions docs/client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
Getting Started
---------------

Here is an example showing how **python-arango** client can be used:
Here is an example showing how a **python-arango** client can be initialized
and used:

.. code-block:: python
Expand Down Expand Up @@ -41,4 +42,4 @@ Here is an example showing how **python-arango** client can be used:
result = db.aql.execute('FOR s IN students RETURN s')
print([student['name'] for student in result])
Read the rest of the documentation to discover much more!
Pretty simple right? Read the rest of the documentation to discover much more!
15 changes: 9 additions & 6 deletions docs/database.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
Databases
---------

A single ArangoDB instance can house multiple databases, which in turn can have
A single ArangoDB instance can house multiple databases, which in turn contain
their own set of worker processes, :ref:`collections <collection-page>`, and
:ref:`graphs <graph-page>`. There is also a default database named ``_system``.
This database cannot be dropped, can only be accessed with root privileges, and
provides operations for managing other user-defined databases.
:ref:`graphs <graph-page>`. There must always be a default database named
``_system``. This database cannot be dropped, can only be accessed with root
privileges, and provides operations for managing other user-defined databases.

Here is an example showing how databases can be managed with different users:

Expand All @@ -18,7 +18,8 @@ Here is an example showing how databases can be managed with different users:
# Initialize the ArangoDB client as root
client = ArangoClient(username='root', password='')
# Create a database, again as root (the user is inherited if not specified)
# Create a database, again as root (the user is inherited from client
# initialization if the username and password are not specified)
db = client.create_database('my_database', username=None, password=None)
# Retrieve the properties of the new database
Expand All @@ -27,12 +28,14 @@ Here is an example showing how databases can be managed with different users:
# Create another database, this time with a predefined set of users
db = client.create_database(
name='another_database',
# Users jane, john and jake will have access to the new database
users=[
{'username': 'jane', 'password': 'foo', 'active': True},
{'username': 'john', 'password': 'bar', 'active': True},
{'username': 'jake', 'password': 'baz', 'active': True},
],
username='jake', # The new database object uses jake's credentials
# API calls through this database object uses jake's credentials
username='jake',
password='baz'
)
Expand Down
4 changes: 2 additions & 2 deletions scripts/setup_arangodb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR

VERSION=3.0.5
VERSION=3.1.3
NAME=ArangoDB-$VERSION

if [ ! -d "$DIR/$NAME" ]; then
Expand Down Expand Up @@ -56,4 +56,4 @@ then
fi


echo "ArangoDB is up"
echo "ArangoDB is up"
14 changes: 14 additions & 0 deletions tests/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,20 @@ def test_all():
with pytest.raises(DocumentGetError):
bad_col.all()

# Test closing export cursor
result = col.all(count=True, batch_size=1)
assert result.close(ignore_missing=False) is True
assert result.close(ignore_missing=True) is False

assert clean_keys(result.next()) == doc1
with pytest.raises(CursorNextError):
result.next()
with pytest.raises(CursorCloseError):
result.close(ignore_missing=False)

result = col.all(count=True)
assert result.close(ignore_missing=True) is False


def test_random():
# Set up test documents
Expand Down

0 comments on commit 9e53762

Please sign in to comment.