Skip to content

Commit

Permalink
Initial revision of the two-level graphs documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
vmagamedov committed Sep 13, 2016
1 parent 57d0500 commit 94b3681
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 33 deletions.
2 changes: 0 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
extensions = ['sphinx.ext.autodoc']

templates_path = ['_templates']
html_static_path = ['_static']
source_suffix = '.rst'
master_doc = 'index'

Expand Down
21 changes: 13 additions & 8 deletions docs/guide/sqlalchemy.rst → docs/guide/database.rst
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
SQLAlchemy support
==================
Using databases
===============

Hiku provides support for loading data from SQL databases using SQLAlchemy_
library, but Hiku doesn't requires to use it's ORM layer, it requires only Core
SQLAlchemy_ functionality - tables definition and expression language to
construct SELECT queries.

Database schema
~~~~~~~~~~~~~~~
Prerequisites
~~~~~~~~~~~~~

We will translate our previous example from the :doc:`introduction`, here is it's
database schema:
Expand Down Expand Up @@ -48,7 +48,10 @@ And let's store the same :ref:`data <introduction-data>` in our database:
for actor_data in data['actor'].values():
engine.execute(actor_table.insert().values(actor_data))
Then we will be able to expose these tables in our graph:
Graph definition
~~~~~~~~~~~~~~~~

Defined tables can be exposed as graph of edges:

.. code-block:: python
Expand Down Expand Up @@ -132,14 +135,16 @@ looking like this:

.. code-block:: sql
SELECT actor.id from actor WHERE actor.character_id IN $character_ids;
SELECT actor.id FROM actor
WHERE actor.character_id IN (character_ids);
List of ``$character_ids`` we already know (it is an ``id`` field of the current
List of ``character_ids`` we already know (it is an ``id`` field of the current
edge), all we need is to fetch ``actor.id`` column to make a link from
``character`` edge to the ``actor`` edge.
:py:class:`~hiku.sources.sqlalchemy.LinkQuery` does this for you.

Query:
Querying graph
~~~~~~~~~~~~~~

.. code-block:: python
Expand Down
3 changes: 2 additions & 1 deletion docs/guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ User's Guide
:maxdepth: 2

introduction
sqlalchemy
database
subgraph
40 changes: 18 additions & 22 deletions docs/guide/subgraph.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# setup storage

from sqlalchemy import MetaData, Table, Column, Integer, Unicode, ForeignKey
from sqlalchemy import create_engine

metadata = MetaData()

Expand All @@ -20,28 +21,19 @@
Column('name', Unicode),
)

data = {
'image': {
1: dict(id=1, location=1, name='j.kirk.jpg'),
2: dict(id=2, location=1, name='spock.jpg'),
3: dict(id=3, location=1, name='l.mccoy.jpg'),
},
'character': {
1: dict(id=1, image_id=1, name='James T. Kirk'),
2: dict(id=2, image_id=2, name='Spock'),
3: dict(id=3, image_id=3, name='Leonard McCoy'),
},
}

from sqlalchemy import create_engine

sa_engine = create_engine('sqlite://')
metadata.create_all(sa_engine)

for image_data in data['image'].values():
sa_engine.execute(image_table.insert().values(image_data))
for character_data in data['character'].values():
sa_engine.execute(character_table.insert().values(character_data))
sa_engine.execute(image_table.insert().values([
dict(id=1, location=1, name='j.kirk.jpg'),
dict(id=2, location=1, name='spock.jpg'),
dict(id=3, location=1, name='l.mccoy.jpg'),
]))
sa_engine.execute(character_table.insert().values([
dict(id=1, image_id=1, name='James T. Kirk'),
dict(id=2, image_id=2, name='Spock'),
dict(id=3, image_id=3, name='Leonard McCoy'),
]))

# define low-level graph

Expand Down Expand Up @@ -104,9 +96,11 @@ def execute(graph, query_string):
def test_low_level():
result = execute(_GRAPH, '[{:characters [:name :image_id]}]')
assert result == {
'characters': [{'image_id': 1, 'name': 'James T. Kirk'},
{'image_id': 2, 'name': 'Spock'},
{'image_id': 3, 'name': 'Leonard McCoy'}],
'characters': [
{'image_id': 1, 'name': 'James T. Kirk'},
{'image_id': 2, 'name': 'Spock'},
{'image_id': 3, 'name': 'Leonard McCoy'},
],
}

# define high-level graph
Expand Down Expand Up @@ -139,6 +133,8 @@ def image_url(image):
]),
])

# test high-level graph

def test_high_level():
result = execute(GRAPH, '[{:characters [:name :image-url]}]')
assert result == {
Expand Down
46 changes: 46 additions & 0 deletions docs/guide/subgraph.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Two-level graph
===============

Two-level graph is a way to express business-logic once and provide it
on-demand.

Prerequisites
~~~~~~~~~~~~~

In order to show this feature we will try to adapt our
:doc:`previous example <database>`, ``actor`` table was removed and ``image``
table was added:

.. literalinclude:: subgraph.py
:lines: 3-36

Low-level graph definition
~~~~~~~~~~~~~~~~~~~~~~~~~~

.. literalinclude:: subgraph.py
:lines: 40-79
:linenos:
:emphasize-lines: 33-34

Test helper:

.. literalinclude:: subgraph.py
:lines: 83-94

Test:

.. literalinclude:: subgraph.py
:lines: 97-104
:dedent: 4

High-level graph definition
~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. literalinclude:: subgraph.py
:lines: 108-134

Test:

.. literalinclude:: subgraph.py
:lines: 139-149
:dedent: 4

0 comments on commit 94b3681

Please sign in to comment.