Commits

Lynn Rees committed f3d454c

- more

Comments (0)

Files changed (9)

graphalchemy/apps.py

     class include(Branch):
         backends = 'graphalchemy.backends.apps'
         managers = 'graphalchemy.managers.apps'
-        models = 'graphalchemy.managers.apps'
+        models = 'graphalchemy.models.apps'
 
     class session(Namespace):
-        object = 'graphalchemy.sessions.Object'
-        manager = 'graphalchemy.sessions.Manager'
+        master = 'graphalchemy.sessions.Session'

graphalchemy/backends/apps.py

 
 class Appconf(Pathways):
 
-    class neo4j(Namespace):
-        embedded = 'graphalchemy.backends.neo4jbe.embedded'
+    class neo4jem(Namespace):
+        close = 'graphalchemy.backends.neo4jem.close'
+        connection = 'graphalchemy.backends.neo4jem.embedded'
+        raw = 'graphalchemy.backends.neo4jem.Raw'
+        transaction = 'graphalchemy.backends.neo4jem.transaction'
 
         class read(Namespace):
-            link = 'graphalchemy.backends.neo4jbe.LinkRead'
-            node = 'graphalchemy.backends.neo4jbe.NodeRead'
+            link = 'graphalchemy.backends.neo4jem.LinkRead'
+            node = 'graphalchemy.backends.neo4jem.NodeRead'
 
         class write(Namespace):
-            link = 'graphalchemy.backends.neo4jbe.LinkWrite'
-            node = 'graphalchemy.backends.neo4jbe.NodeWrite'
+            link = 'graphalchemy.backends.neo4jem.LinkWrite'
+            node = 'graphalchemy.backends.neo4jem.NodeWrite'
 
 
 appconf = Appconf.build()

graphalchemy/backends/neo4jbe.py

-# -*- coding: utf-8 -*-
-#pylint: disable-msg=w0221
-'''neo4j backends'''
-
-from lucenequerybuilder import Q
-from stuf.utils import getdefault
-from appspace.six import iteritems
-
-from graphalchemy.backends.utils import Backend, BackendRead
-
-__all__ = ('LinkRead', 'LinkWrite', 'NodeRead', 'NodeWrite', 'embedded')
-
-
-def embedded(url):
-    '''
-    neo4j embedded database loader
-
-    @param url: path to database on file system
-    '''
-    from neo4j import GraphDatabase
-    return GraphDatabase(url)
-
-
-class Read(BackendRead):
-
-    '''neo4j reader base'''
-
-    @property
-    def root(self):
-        '''get root graph element'''
-        return self._db.reference_node
-
-    @staticmethod
-    def ands(**kw):
-        '''
-        "AND" lucene query builder
-
-        see https://github.com/scholrly/lucene-querybuilder
-        '''
-        def R(k, v):
-            return Q(k, v, wildcard=True)
-        qs = None
-        for k, v in iteritems(kw):
-            qs = qs & R(k, v) if qs is not None else R(k, v)
-        return qs
-
-    @staticmethod
-    def and_nots(**kw):
-        '''
-        "AND NOT" lucene query builder
-
-        see https://github.com/scholrly/lucene-querybuilder
-        '''
-        def R(k, v):
-            return -Q(k, v, wildcard=True)
-        qs = None
-        for k, v in iteritems(kw):
-            qs = qs & R(k, v) if qs is not None else R(k, v)
-        return qs
-
-    def close(self):
-        '''shutdown database'''
-        self._db.shutdown()
-
-    def filter(self, index, queries, model=None):
-        '''
-        full text search using index
-
-        @param index: name of index
-        @param queries: queries build with query builder
-        @param model: element model (default: None)
-        '''
-        return self.one_or_all(self.index(index).query(queries), model)
-
-    def filter_by(self, index, key, value, callback=None):
-        '''
-        fetch graph elements filtered by keywords
-
-        @param index: index name
-        @param key: keyword in index
-        @param value: value in index (or second key)
-        @param callback: filter callback function (default: None)
-        '''
-        return self.one_or_all_and_close(
-            self.index(index)[key][value], callback,
-        )
-
-    def id(self, element):
-        '''
-        graph element identifier
-
-        @param element: a graph element
-        '''
-        return getdefault(element, 'id', None)
-
-    @staticmethod
-    def ors(**kw):
-        '''
-        "OR" lucene query builder
-
-        see https://github.com/scholrly/lucene-querybuilder
-        '''
-        qs = None
-
-        def R(k, v):
-            return Q(k, v, wildcard=True)
-        for k, v in iteritems(kw):
-            qs = qs | R(k, v) if qs is not None else R(k, v)
-        return qs
-
-    @staticmethod
-    def or_nots(**kw):
-        '''
-        "OR NOT" lucene query builder
-
-        see https://github.com/scholrly/lucene-querybuilder
-        '''
-        qs = None
-
-        def R(k, v):
-            return -Q(k, v, wildcard=True)
-        for k, v in iteritems(kw):
-            qs = qs | R(k, v) if qs is not None else R(k, v)
-        return qs
-
-    def properties(self, element):
-        '''
-        get graph element properties
-
-        @param element: graph element
-        '''
-        return dict(element.items()) if element is not None else {}
-
-    def raw(self, model, expr, **kw):
-        '''
-        fetch graph items with Cypher query language
-
-        @param model: graph model
-        @param express: Cypher query
-        @param **kw: variables for Cypher query
-        '''
-        return self.one_or_all(self._db.query(expr, **kw), model)
-
-    def traverser(self, this, tester=None, links=None, unique=None):
-        '''
-        build a traverse function
-
-        @param this: graph object
-        @param tester: filter for traversed elements (default: None)
-        @param links: links to traverse (default: None)
-        @param unique: how often to traverse the same element (default: None)
-        '''
-        tv = self._db.traversal()
-        if links is not None:
-            for link in links:
-                if len(link) == 2:
-                    tv = tv.relationships(*link)
-                else:
-                    tv = tv.relationships(link)
-        if unique is not None:
-            tv = tv.uniqueness(unique)
-        if tester is not None:
-            tv = tv.evaluator(tester)
-        return tv.traverse(this.source)
-
-    def walker(self, this, direction=None, label=None, keys=None):
-        '''
-        iterate over and yield links
-
-        @param this: graph object
-        @param direction: direction of links (default: None)
-        @param label: label for links (default: None)
-        @param keys: keys to find on elements (default: None)
-        '''
-        if label is not None:
-            links = self.get_links(this.source, label)
-        else:
-            links = self.get_links(this.source, 'rels')
-            if direction is not None:
-                links = self.get_links(links, direction)
-        for link in links:
-            if keys:
-                if not set([keys, tuple(link.keys())]).intersection():
-                    pass
-            yield link
-
-
-class Write(Backend):
-
-    '''neo4j writer base'''
-
-    @property
-    def transaction(self):
-        return self._db.transaction
-
-    def close(self):
-        '''shutdown database'''
-        self._db.shutdown()
-
-    def delete_index(self, index):
-        '''
-        delete graph index
-
-        @param index: graph index
-        '''
-        self._db.nodes.indexes.get(index).delete()
-
-    def delete_property(self, this, key):
-        '''
-        delete graph element property
-
-        @param this: graph object
-        @param key: graph element property key
-        '''
-        del this.source[key]
-
-    def index_many(self, index, this, indexed):
-        '''
-        index properties on a graph element
-
-        @param index: graph index label
-        @param this: graph object
-        @param indexed: properties to index
-        '''
-        element = this.source
-        for field in indexed:
-            index[field][element[field]] = element
-
-    def index_one(self, index, key, value, this):
-        '''
-        index one property of a graph element
-
-        @param index: graph index label
-        @param key: graph element property key
-        @param value: graph element property value
-        @param this: graph object
-        '''
-        index[key][value] = this.source
-
-    def update(self, this, data, callback=None):
-        '''
-        update a graph element's properties
-
-        @param this: graph object
-        @param data: cleaned data
-        @param callback: callback function (default: None)
-        '''
-        element = this.source
-        for k, v in iteritems(data):
-            element[k] = v
-        if callback is not None:
-            callback(element)
-
-
-class LinkRead(Read):
-
-    '''neo4j link reader'''
-
-    def get(self, element):
-        '''
-        get link by link id
-
-        @param element: element identifier
-        '''
-        return self._db.relationships[element]
-
-    def index(self, index):
-        '''
-        get link index by name
-
-        @param index: index name
-        '''
-        return self._db.relationships.indexes.get(index)
-
-    def kind(self, element):
-        '''
-        kind of link
-
-        @param element: a link graph element
-        '''
-        return element.type.name()
-
-    def traverser(self, this, tester=None, links=None, unique=None):
-        '''
-        build a traverse function
-
-        @param this: graph object
-        @param tester: filter for traversed elements (default: None)
-        @param links: links to traverse (default: None)
-        @param unique: how often to traverse the same element (default: None)
-        '''
-        tv = super(LinkRead, self).traverser(this, tester, links, unique)
-        return tv.traverse(this.source).relationships
-
-
-class LinkWrite(Write):
-
-    '''neo4j link writer'''
-
-    def build(self, link, start, end, callback=None, **kw):
-        '''
-        build a new graph link
-
-        @param link: link name
-        @param start: start node for link
-        @param end: end node for link
-        @param callback: callback function (default: None)
-        @param kw: keywords (default: None)
-        '''
-        this = start.source.rels.create(link, end.source, **kw)
-        if callback is not None:
-            this = callback(this)
-        return this
-
-    def create_index(self, index, fts=False):
-        '''
-        create link index
-
-        @param index: node index name
-        @param fts: create a full text index (default: False)
-        '''
-        kind = 'fulltext' if fts else None
-        self._db.relationships.indexes.create(index, type=kind)
-
-    def delete_element(self, this, indices=None):
-        '''
-        delete graph element
-
-        @param this: graph object
-        @param index: graph index (default: None)
-        '''
-        db = self._db.relationships.indexes.get
-        element = this.source
-        if indices is not None:
-            for index in indices:
-                del db(index)[element]
-        for link in element.rels:
-            link.delete()
-        element.delete()
-
-
-class NodeRead(Read):
-
-    '''neo4j node reader'''
-
-    def get(self, element):
-        '''get node by link id'''
-        return self._db.nodes[element]
-
-    def index(self, index):
-        '''
-        get node lucene index by name
-
-        @param index: node index name
-        '''
-        return self._db.nodes.indexes.get(index)
-
-    def traverser(self, this, tester=None, links=None, unique=None):
-        '''
-        build a traverse function
-
-        @param this: graph object
-        @param tester: filter for traversed elements (default: None)
-        @param links: links to traverse (default: None)
-        @param unique: how often to traverse the same element (default: None)
-        '''
-        tv = super(NodeRead, self).traverser(this, links, unique, tester)
-        return tv.traverse(this.source).nodes
-
-    def walker(self, this, direction=None, label=None, keys=None, end=None):
-        '''
-        iterate links and yield links
-
-        @param this: graph object
-        @param direction: direction of links (default: None)
-        @param label: label for links (default: None)
-        @param keys: keys to find on elements (default: None)
-        @param end: end of link to return (default: None)
-        '''
-        walker = super(NodeRead, self).walker(this, direction, label, keys)
-        for link in walker:
-            lnk = link
-            yield getattr(lnk, end)
-
-
-class NodeWrite(Write):
-
-    '''neo4j node writer'''
-
-    def build(self, data, link=None, other=None, callback=None, **kw):
-        '''
-        build a new graph node
-
-        @param link: link name
-        @param start: start node for link
-        @param end: end node for link
-        @param callback: callback function (default: None)
-        @param kw: keywords (default: None)
-        '''
-        # create node
-        node = self._db.node(**data)
-        # link back to reference
-        if link is not None and other is not None:
-            node.rels.create(link, other.source, **kw)
-        if callback is not None:
-            node = callback(node)
-        return node
-
-    def clone(self, this, model_link, callback=None, **kw):
-        '''
-        clone node
-
-        @param this: graph object
-        @param model_link: model link to clone
-        @param callback: callback function (default: None)
-        '''
-        # link list
-        links = []
-        # node id map
-        id_map = {}
-        # root node of fork
-        fork = None
-        db = self._db
-        node_func = db.node
-        # traverse outgoing nodes
-        for source in db.traversal().traverse(this.source).nodes:
-            # copy outgoing relationships
-            links.extend([link for link in source.rels.outgoing])
-            # copy node
-            target = node_func(**dict(source.items()))
-            # capture root this
-            if source.id == this.id:
-                fork = target
-                reference = this.n.reference()
-                target.rels.create(
-                    this.C.reference_link, reference.source,
-                )
-            # add to node map
-            id_map[source.id] = target.id
-        # copy relationships
-        for link in links:
-            node_func[id_map[link.start.id]].rels.create(
-                link.type,
-                node_func[id_map[link.end.id]],
-                **dict(link.items())
-            )
-        # tie back to original
-        fork.rels.create(model_link, this.source, **kw)
-        if callback is not None:
-            fork = callback(fork)
-        return fork
-
-    def create_index(self, index, fts=False):
-        '''
-        create node index
-
-        @param index: index name
-        @param fts: create a full text index (default: False)
-        '''
-        kind = 'fulltext' if fts else None
-        return self._db.nodes.indexes.create(index, type=kind)
-
-    def delete_element(self, this, indices=None):
-        '''
-        delete graph element
-
-        @param this: graph object
-        @param index: graph index (default: None)
-        '''
-        db = self._db.nodes.indexes.get
-        element = this.source
-        if indices is not None:
-            for index in indices:
-                del db(index)[element]
-        for link in element.rels:
-            link.delete()
-        element.delete()

graphalchemy/backends/neo4jem.py

+# -*- coding: utf-8 -*-
+#pylint: disable-msg=w0221
+'''neo4j backends'''
+
+from lucenequerybuilder import Q
+from stuf.utils import getdefault
+from appspace.six import iteritems
+
+from graphalchemy.backends.utils import Backend, BackendRead
+
+__all__ = ('LinkRead', 'LinkWrite', 'NodeRead', 'NodeWrite', 'embedded')
+
+
+def close(db):
+    '''
+    shutdown database
+
+    @param db: database connection
+    '''
+    db.shutdown()
+
+
+def embedded(url):
+    '''
+    neo4j embedded database loader
+
+    @param url: path to database on file system
+    '''
+    from neo4j import GraphDatabase
+    return GraphDatabase(url)
+
+
+def transaction(db):
+    '''
+    database transaction
+
+    @param db: database connection
+    '''
+    return db.transaction
+
+
+class Raw(BackendRead):
+
+    @staticmethod
+    def ands(**kw):
+        '''
+        "AND" lucene query builder
+
+        see https://github.com/scholrly/lucene-querybuilder
+        '''
+        def R(k, v):
+            return Q(k, v, wildcard=True)
+        qs = None
+        for k, v in iteritems(kw):
+            qs = qs & R(k, v) if qs is not None else R(k, v)
+        return qs
+
+    @staticmethod
+    def and_nots(**kw):
+        '''
+        "AND NOT" lucene query builder
+
+        see https://github.com/scholrly/lucene-querybuilder
+        '''
+        def R(k, v):
+            return -Q(k, v, wildcard=True)
+        qs = None
+        for k, v in iteritems(kw):
+            qs = qs & R(k, v) if qs is not None else R(k, v)
+        return qs
+
+    @staticmethod
+    def ors(**kw):
+        '''
+        "OR" lucene query builder
+
+        see https://github.com/scholrly/lucene-querybuilder
+        '''
+        qs = None
+
+        def R(k, v):
+            return Q(k, v, wildcard=True)
+        for k, v in iteritems(kw):
+            qs = qs | R(k, v) if qs is not None else R(k, v)
+        return qs
+
+    @staticmethod
+    def or_nots(**kw):
+        '''
+        "OR NOT" lucene query builder
+
+        see https://github.com/scholrly/lucene-querybuilder
+        '''
+        qs = None
+
+        def R(k, v):
+            return -Q(k, v, wildcard=True)
+        for k, v in iteritems(kw):
+            qs = qs | R(k, v) if qs is not None else R(k, v)
+        return qs
+
+    def execute(self, model, expr, **kw):
+        '''
+        fetch graph items with Cypher query language
+
+        @param model: graph model
+        @param express: Cypher query
+        @param **kw: variables for Cypher query
+        '''
+        return self.one_or_all(self._db.query(expr, **kw), model)
+
+
+class Read(BackendRead):
+
+    '''neo4j reader base'''
+
+    @property
+    def root(self):
+        '''get root graph element'''
+        return self._db.reference_node
+
+    def filter(self, index, queries, model=None):
+        '''
+        full text search using index
+
+        @param index: name of index
+        @param queries: queries build with query builder
+        @param model: element model (default: None)
+        '''
+        return self.one_or_all(self.index(index).query(queries), model)
+
+    def filter_by(self, index, key, value, callback=None):
+        '''
+        fetch graph elements filtered by keywords
+
+        @param index: index name
+        @param key: keyword in index
+        @param value: value in index (or second key)
+        @param callback: filter callback function (default: None)
+        '''
+        return self.one_or_all_and_close(
+            self.index(index)[key][value], callback,
+        )
+
+    def id(self, element):
+        '''
+        graph element identifier
+
+        @param element: a graph element
+        '''
+        return getdefault(element, 'id', None)
+
+    def properties(self, element):
+        '''
+        get graph element properties
+
+        @param element: graph element
+        '''
+        return dict(element.items()) if element is not None else {}
+
+    def traverser(self, this, tester=None, links=None, unique=None):
+        '''
+        build a traverse function
+
+        @param this: graph object
+        @param tester: filter for traversed elements (default: None)
+        @param links: links to traverse (default: None)
+        @param unique: how often to traverse the same element (default: None)
+        '''
+        tv = self._db.traversal()
+        if links is not None:
+            for link in links:
+                if len(link) == 2:
+                    tv = tv.relationships(*link)
+                else:
+                    tv = tv.relationships(link)
+        if unique is not None:
+            tv = tv.uniqueness(unique)
+        if tester is not None:
+            tv = tv.evaluator(tester)
+        return tv.traverse(this.source)
+
+    def walker(self, this, direction=None, label=None, keys=None):
+        '''
+        iterate over and yield links
+
+        @param this: graph object
+        @param direction: direction of links (default: None)
+        @param label: label for links (default: None)
+        @param keys: keys to find on elements (default: None)
+        '''
+        if label is not None:
+            links = self.get_links(this.source, label)
+        else:
+            links = self.get_links(this.source, 'rels')
+            if direction is not None:
+                links = self.get_links(links, direction)
+        for link in links:
+            if keys:
+                if not set([keys, tuple(link.keys())]).intersection():
+                    pass
+            yield link
+
+
+class Write(Backend):
+
+    '''neo4j writer base'''
+
+    def delete_index(self, index):
+        '''
+        delete graph index
+
+        @param index: graph index
+        '''
+        self._db.nodes.indexes.get(index).delete()
+
+    def delete_property(self, this, key):
+        '''
+        delete graph element property
+
+        @param this: graph object
+        @param key: graph element property key
+        '''
+        del this.source[key]
+
+    def index_many(self, index, this, indexed):
+        '''
+        index properties on a graph element
+
+        @param index: graph index label
+        @param this: graph object
+        @param indexed: properties to index
+        '''
+        element = this.source
+        for field in indexed:
+            index[field][element[field]] = element
+
+    def index_one(self, index, key, value, this):
+        '''
+        index one property of a graph element
+
+        @param index: graph index label
+        @param key: graph element property key
+        @param value: graph element property value
+        @param this: graph object
+        '''
+        index[key][value] = this.source
+
+    def update(self, this, data, callback=None):
+        '''
+        update a graph element's properties
+
+        @param this: graph object
+        @param data: cleaned data
+        @param callback: callback function (default: None)
+        '''
+        element = this.source
+        for k, v in iteritems(data):
+            element[k] = v
+        if callback is not None:
+            callback(element)
+
+
+class LinkRead(Read):
+
+    '''neo4j link reader'''
+
+    def get(self, element):
+        '''
+        get link by link id
+
+        @param element: element identifier
+        '''
+        return self._db.relationships[element]
+
+    def index(self, index):
+        '''
+        get link index by name
+
+        @param index: index name
+        '''
+        return self._db.relationships.indexes.get(index)
+
+    def kind(self, element):
+        '''
+        kind of link
+
+        @param element: a link graph element
+        '''
+        return element.type.name()
+
+    def traverser(self, this, tester=None, links=None, unique=None):
+        '''
+        build a traverse function
+
+        @param this: graph object
+        @param tester: filter for traversed elements (default: None)
+        @param links: links to traverse (default: None)
+        @param unique: how often to traverse the same element (default: None)
+        '''
+        tv = super(LinkRead, self).traverser(this, tester, links, unique)
+        return tv.traverse(this.source).relationships
+
+
+class LinkWrite(Write):
+
+    '''neo4j link writer'''
+
+    def build(self, link, start, end, callback=None, **kw):
+        '''
+        build a new graph link
+
+        @param link: link name
+        @param start: start node for link
+        @param end: end node for link
+        @param callback: callback function (default: None)
+        @param kw: keywords (default: None)
+        '''
+        this = start.source.rels.create(link, end.source, **kw)
+        if callback is not None:
+            this = callback(this)
+        return this
+
+    def create_index(self, index, fts=False):
+        '''
+        create link index
+
+        @param index: node index name
+        @param fts: create a full text index (default: False)
+        '''
+        kind = 'fulltext' if fts else None
+        self._db.relationships.indexes.create(index, type=kind)
+
+    def delete_element(self, this, indices=None):
+        '''
+        delete graph element
+
+        @param this: graph object
+        @param index: graph index (default: None)
+        '''
+        db = self._db.relationships.indexes.get
+        element = this.source
+        if indices is not None:
+            for index in indices:
+                del db(index)[element]
+        for link in element.rels:
+            link.delete()
+        element.delete()
+
+
+class NodeRead(Read):
+
+    '''neo4j node reader'''
+
+    def get(self, element):
+        '''get node by link id'''
+        return self._db.nodes[element]
+
+    def index(self, index):
+        '''
+        get node lucene index by name
+
+        @param index: node index name
+        '''
+        return self._db.nodes.indexes.get(index)
+
+    def traverser(self, this, tester=None, links=None, unique=None):
+        '''
+        build a traverse function
+
+        @param this: graph object
+        @param tester: filter for traversed elements (default: None)
+        @param links: links to traverse (default: None)
+        @param unique: how often to traverse the same element (default: None)
+        '''
+        tv = super(NodeRead, self).traverser(this, links, unique, tester)
+        return tv.traverse(this.source).nodes
+
+    def walker(self, this, direction=None, label=None, keys=None, end=None):
+        '''
+        iterate links and yield links
+
+        @param this: graph object
+        @param direction: direction of links (default: None)
+        @param label: label for links (default: None)
+        @param keys: keys to find on elements (default: None)
+        @param end: end of link to return (default: None)
+        '''
+        walker = super(NodeRead, self).walker(this, direction, label, keys)
+        for link in walker:
+            lnk = link
+            yield getattr(lnk, end)
+
+
+class NodeWrite(Write):
+
+    '''neo4j node writer'''
+
+    def build(self, data, link=None, other=None, callback=None, **kw):
+        '''
+        build a new graph node
+
+        @param link: link name
+        @param start: start node for link
+        @param end: end node for link
+        @param callback: callback function (default: None)
+        @param kw: keywords (default: None)
+        '''
+        # create node
+        node = self._db.node(**data)
+        # link back to reference
+        if link is not None and other is not None:
+            node.rels.create(link, other.source, **kw)
+        if callback is not None:
+            node = callback(node)
+        return node
+
+    def clone(self, this, model_link, callback=None, **kw):
+        '''
+        clone node
+
+        @param this: graph object
+        @param model_link: model link to clone
+        @param callback: callback function (default: None)
+        '''
+        # link list
+        links = []
+        # node id map
+        id_map = {}
+        # root node of fork
+        fork = None
+        db = self._db
+        node_func = db.node
+        # traverse outgoing nodes
+        for source in db.traversal().traverse(this.source).nodes:
+            # copy outgoing relationships
+            links.extend([link for link in source.rels.outgoing])
+            # copy node
+            target = node_func(**dict(source.items()))
+            # capture root this
+            if source.id == this.id:
+                fork = target
+                reference = this.n.reference()
+                target.rels.create(
+                    this.C.reference_link, reference.source,
+                )
+            # add to node map
+            id_map[source.id] = target.id
+        # copy relationships
+        for link in links:
+            node_func[id_map[link.start.id]].rels.create(
+                link.type,
+                node_func[id_map[link.end.id]],
+                **dict(link.items())
+            )
+        # tie back to original
+        fork.rels.create(model_link, this.source, **kw)
+        if callback is not None:
+            fork = callback(fork)
+        return fork
+
+    def create_index(self, index, fts=False):
+        '''
+        create node index
+
+        @param index: index name
+        @param fts: create a full text index (default: False)
+        '''
+        kind = 'fulltext' if fts else None
+        return self._db.nodes.indexes.create(index, type=kind)
+
+    def delete_element(self, this, indices=None):
+        '''
+        delete graph element
+
+        @param this: graph object
+        @param index: graph index (default: None)
+        '''
+        db = self._db.nodes.indexes.get
+        element = this.source
+        if indices is not None:
+            for index in indices:
+                del db(index)[element]
+        for link in element.rels:
+            link.delete()
+        element.delete()

graphalchemy/core.py

 
 octopus = Spine(graphalchemy, Required, Defaults)
 
-# decorators
-app = octopus.decorator.app
-defer = octopus.decorator.defer
-extend = octopus.decorator.extend
-factory = octopus.decorator.factory
+# descriptors
+app = octopus.descriptor.app
+call = octopus.descriptor.call
+defer = octopus.descriptor.defer
+extend = octopus.descriptor.extend
+factory = octopus.descriptor.factory
+method = octopus.descriptor.method

graphalchemy/graphs.py

 
 from stuf.utils import clsname
 
-from graphalchemy.core import octopus, extend
+from graphalchemy.core import octopus, extend, method
 
 __all__ = ['Graph']
 
 
     '''graph interface'''
 
+    close = method(conf.close, conf.appspace)
     session = extend(conf.session, conf.appspace)
 
     def __init__(self, url, **kw):
             name=clsname(self._db).split('.')[-1], url=self.url,
         )
 
-    def close(self):
-        '''run abort callbacks'''
-        self.Q.app(self._db, self.S.key.backend).close()
+    def _datasource(self, url):
+        pass

graphalchemy/sessions.py

 # -*- coding: utf-8 -*-
 '''graph sessions'''
 
-from graphalchemy.core import octopus, extend
+from graphalchemy.core import octopus, extend, call
 
 __all__ = ['Session']
-
-# global settings
 conf = octopus.G
 
 
     links = extend(conf.manager.link, conf.appspace)
     # node monager
     nodes = extend(conf.manager.node, conf.appspace)
+    # transaction monager
+    transaction = call(conf.transaction, conf.appspace)
 
     def __exit__(self, e, b, c):
         with self.transaction:

graphalchemy/settings.py

 
 
 class Required(RequiredSettings):
-
     appspace = 'graphalchemy'
     backends = 'backends'
     models = 'models'
-    generics = 'generics'
+    managers = 'managers'
+    session = 'manager.session'
 
 
 class Defaults(DefaultSettings):
-
     root = 'root'
     userspace = Required.appspace
     backend = 'neo4j.embedded'
 
+    class core:
+        graph = 'manager.graph'
+        db = '_db'
+        backend = 'backend'
+        nodes = 'nodes'
+        links = 'links'
+
     class anchor:
         label = 'anchor'
         description = '{name} anchor node'
         reference = 'version_of'
         created = 'version_created'
 
-    class key:
-        db = '_db'
-        backend = 'backend'
-        nodes = 'nodes'
-        links = 'links'
-
     class manager:
-        graph = 'manager.graph'
 
         class collection:
             link = 'manager.collection.link'
             link = 'manager.writer.link'
             node = 'manager.writer.node'
 
-    class session:
-        manager = 'sessions.manager'
-        object = 'sessions.object'
+    class datasource:
+        connection = 'connect'
+        close = 'close'
+        connection = 'connection'
+        raw = 'raw'
+        transaction = 'transaction'
+
+        class read:
+            link = 'read.link'
+            node = 'read.node'
+
+        class write:
+            link = 'write.link'
+            node = 'write.node'

graphalchemy/tests/test_models.py

 from markupsafe import escape
 
 from graphalchemy.graphs import Graph
-from graphalchemy.objects.elements import Node
-from graphalchemy.objects.collectors import In, Out
-from graphalchemy.objects.properties import IntegerField, TextField
+from graphalchemy.models.elements import Node
+from graphalchemy.models.collectors import In, Out
+from graphalchemy.models.properties import IntegerField, TextField
 
 
 class Tag(Node):