User Guide

Database Connection

To start working with libtree, make sure PostgreSQL 9.4 is running. If you don’t have a database yet, create one now:

$ createdb libtree

Next, start a Python interpreter, import libtree and create a Tree object object. To make it connect to PostgreSQL, you must create a psycopg2 connection. After that, you can install libtree:

$ python
Python 3.4.2 (default, Nov 12 2014, 10:43:21)
>>> from libtree import Tree
>>> import psycopg2
>>> connection = psycopg2.connect("dbname=test_tree user=vortec")
>>> transaction = Tree(connection).make_transaction()
>>> transaction.install()
>>> transaction.commit()

The transaction object represents a database transaction and must be passed to every function when you want to query or modify the tree. Running install() creates the SQL tables and must only be executed if you haven’t done so before. Executing commit() writes the changes you made to the database. If you want to discard the changes, run transaction.rollback().

For more convenience, you can use the auto-committing context manager:

>>> tree = Tree(connection)
>>> with tree() as transaction:
...     transaction.install()

When the context manager leaves it will commit the transaction to the database. If an exception occurs, it will rollback automatically.

Modify the tree

Now, you can create some nodes:

>>> html = transaction.insert_root_node()
>>> title = html.insert_child({'title': 'title', 'content': 'libtree'})
>>> head = html.insert_child({'title': 'head'})
>>> body = html.insert_child({'title': 'body'})
>>> h2 = body.insert_child({'title': 'h2', 'content': 'to libtree'})
>>> transaction.commit()

This should render as a nice, DOM-like tree:

>>> transaction.print_tree()
<NodeData id=1>
  <NodeData id=2, title='title'>
  <NodeData id=3, title='head'>
  <NodeData id=4, title='body'>
    <NodeData id=5, title='h2'>

But do you spot the mistake? In HTML, a <title> tag goes beneath the <head> tag, so let’s move it:

>>> title.move(head)
>>> transaction.print_tree()
<NodeData id=1>
  <NodeData id=3, title='head'>
    <NodeData id=2, title='title'>
  <NodeData id=4, title='body'>
    <NodeData id=5, title='h2'>

And you also forgot the <h1> node, let’s insert it before <h2>:

>>> body.insert_child({'title': 'h1', 'content': 'Welcome'}, position=0)
<Node id=6, title='h1'>
>>> transaction.print_tree()
<NodeData id=1>
  <NodeData id=3, title='head'>
    <NodeData id=2, title='title'>
  <NodeData id=4, title='body'>
    <NodeData id=6, title='h1'>
    <NodeData id=5, title='h2'>

Since you know the ID, you can easily delete nodes without a Node object:

>>> h2.delete()
>>> transaction.print_tree()
<NodeData id=1>
  <NodeData id=3, title='head'>
    <NodeData id=2, title='title'>
  <NodeData id=4, title='body'>
    <NodeData id=6, title='h1'>
>>> transaction.commit()

Query the tree

If you want to get a Node object, you can easily get one by querying for the ID:

>>> title.properties
{'content': 'libtree', 'title': 'title'}

You can get the immediate children of a node:

>>> html.children
[<Node id=3, title='head'>, <Node id=4, title='body'>]

You can get all nodes that have a certain property key set:

>>> transaction.get_nodes_by_property_key('content')
{<Node id=6, title='h1'>, <Node id=2, title='title'>}

Or ask for nodes that have a certain property value set:

>>> transaction.get_nodes_by_property_value('content', 'Welcome')
{<Node id=6, title='h1'>}

If you have a node, you can output the path from the root node to it too:

>>> h1.ancestors
[<Node id=1>, <Node id=4, title='body'>]