Commits

Lynn Rees committed 59a302d

- update innards

  • Participants
  • Parent commits ba2c39c
  • Branches default

Comments (0)

Files changed (9)

 syntax: regexp
 ^graphalchemy/tests/foo$
 syntax: regexp
-^graphalchemy/tests/foo3$
+^graphalchemy/tests/foo3$
+syntax: regexp
+^profile$

File graphalchemy/backends/h5pybe.py

+# -*- coding: utf-8 -*-
+'''hdf5 backend'''
+
+from __future__ import absolute_import
+
+from stuf.utils import get_or_default
+
+from .utils import Backend, BackendRead
+
+
+def hdf5(url):
+    '''
+    hdf5 database loader
+
+    @param url: path to database on file system
+    '''
+    import h5py
+    return h5py.File(url)
+
+
+class Read(BackendRead):
+
+    '''h5py reader base'''
+
+    @property
+    def root(self):
+        '''get root graph element'''
+        return self._db
+
+    def close(self):
+        '''shutdown database'''
+        self._db.close()
+
+    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 get(self, element):
+        '''
+        get link by link id
+
+        @param element: element identifier
+        '''
+        return self._db[element]
+
+    def index(self, index):
+        '''
+        get node lucene index by name
+
+        @param index: node index name
+        '''
+
+    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 get_or_default(element, 'name', None)
+
+    def properties(self, element):
+        '''
+        get graph element properties
+
+        @param element: graph element
+        '''
+        return dict(element.iteritems()) 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 model instance
+        @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.element)
+
+    def walker(self, this, direction=None, label=None, keys=None):
+        '''
+        iterate over and yield links
+
+        @param this: graph model instance
+        @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.element, label)
+        else:
+            links = self.get_links(this.element, '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):
+
+    '''h5py writer base'''
+
+    @property
+    def transaction(self):
+        ''''''
+
+    def create_index(self, index, fts=False):
+        '''
+        create node index
+
+        @param index: index name
+        @param fts: create a full text index (default: False)
+        '''
+
+    def delete_element(self, this, indices=None):
+        '''
+        delete graph element
+
+        @param this: graph model instance
+        @param index: graph index (default: None)
+        '''
+        del self._db[this.element.name]
+        return indices
+
+    def delete_index(self, index):
+        '''
+        delete graph index
+
+        @param index: graph index
+        '''
+
+    def delete_property(self, this, key):
+        '''
+        delete graph element property
+
+        @param this: graph model instance
+        @param key: graph element property key
+        '''
+        del this.element[key]
+
+    def index_many(self, index, this, indexed):
+        '''
+        index properties on a graph element
+
+        @param index: graph index label
+        @param this: graph model instance
+        @param indexed: properties to index
+        '''
+
+    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 model instance
+        '''
+
+    def update(self, this, data, callback=None):
+        '''
+        update a graph element's properties
+
+        @param this: graph model instance
+        @param data: cleaned data
+        @param callback: callback function (default: None)
+        '''
+        element = this.element
+        for k, v in data.iteritems():
+            element[k] = v
+        if callback is not None:
+            callback(element)
+
+
+class LinkRead(Read):
+
+    '''h5py link reader'''
+
+    def kind(self, element):
+        '''
+        kind of link
+
+        @param element: a link graph element
+        '''
+        return element['kind']
+
+    def linked(self, this, key):
+        '''
+        search link for specified key
+
+        @param this: a link
+        @param key: key to search for
+        '''
+        for link in this.element.rels:
+            if key in link.keys():
+                return link
+        else:
+            return None
+
+    def traverser(self, this, tester=None, links=None, unique=None):
+        '''
+        build a traverse function
+
+        @param this: graph model instance
+        @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.element).relationships
+
+
+class LinkWrite(Write):
+
+    '''h5py 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.element.attrs[link] = end.element.ref
+        if callback is not None:
+            this = callback(this)
+        return this
+
+
+class NodeRead(Read):
+
+    '''h5py node reader'''
+
+    def linked(self, this, key):
+        '''
+        get node from a node's links filtered by keywords
+
+        @param this: graph model instance
+        @param key: keyword in linked node
+        '''
+        for link in this.element.rels:
+            if key in link.end.keys():
+                return link.end
+            elif key in link.start.keys():
+                return link.start
+        else:
+            return None
+
+    def traverser(self, this, tester=None, links=None, unique=None):
+        '''
+        build a traverse function
+
+        @param this: graph model instance
+        @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.element).nodes
+
+    def walker(self, this, direction=None, label=None, keys=None, end=None):
+        '''
+        iterate links and yield links
+
+        @param this: graph model instance
+        @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):
+
+    '''h5py 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.create_group(kw.pop('name', None))
+        for k, v in data.iteritems():
+            node[k] = v
+        # link back to reference
+        if link is not None and other is not None:
+            node.attrs[link] = other.element.ref
+        if callback is not None:
+            node = callback(node)
+        return node
+
+    def clone(self, this, model_link, callback=None, **kw):
+        '''
+        clone node
+
+        @param this: graph model instance
+        @param model_link: model link to clone
+        @param callback: callback function (default: None)
+        '''
+        fork = self._db.copy(this.name, this.name2, this.name)
+        for k, v in kw.iteritems():
+            fork[k] = v
+        this['versions'][this.name2][model_link] = fork.ref
+        if callback is not None:
+            fork = callback(fork)
+        return fork
+
+
+__all__ = ('LinkRead', 'LinkWrite', 'NodeRead', 'NodeWrite', 'hdf5')

File graphalchemy/core.py

 
 from __future__ import absolute_import
 
-from appspace.query import Queue
+from appspace.services import Client, Server
 from appspace.traits import Traits, TraitQuery
-from appspace.services import Services, Client, Server
 from appspace.composing import Composed, Master, Synced
 
 from .apps import graphalchemy
 from .settings import Defaults, Required
 
 query = TraitQuery.appspace(graphalchemy, Required, Defaults)
-queue = Queue(query.manager)
 # traits
 query.register(Traits)
-query.trait(Traits)
-queue.queue(Traits)
 # synched
 query.register(Synced)
-queue.queue(Synced)
 # composed
 query.register(Composed)
 # master
 query.register(Master)
-query.compose(Master)
-queue.queue(Master)
 # client
 query.register(Client)
-Client._S = Services(query.manager)
 # server
 query.register(Server)
 
-__all__ = ('Composed', 'Client', 'Server', 'Traits', 'Synced')
+__all__ = ('Client', 'Composed', 'Server', 'Synced', 'Traits')

File graphalchemy/generics/elements.py

         '''node class'''
         return Node
 
-    @defer
     def save(self):
         '''save link'''
         # update if exists...

File graphalchemy/graphs.py

         '''
         super(Graph, self).__init__()
         # get query
-        __ = self._C
+        __ = self._CQ
         # default settings
         defaults = __.defaults()
         # required settings
 
         @param model: graph element model
         '''
-        self._C.set(model, selfname(model), conf.userspace)
+        self._CQ.set(model, selfname(model), conf.userspace)
 
     @contextmanager
     def transaction(self, callback=None, *args, **kw):
         pass
 
     def sortKey(self):
-        return 'not here'
+        pass
 
     def tpc_abort(self, trans):
         self._U.clear_outgoing()

File graphalchemy/models/elements.py

     _nodes = direct(conf.model.collector.node, conf.models)
 
     @defer
+    def _finalize(self):
+        self.commit()
+        # update if exists...
+        if self.element is not None:
+            self.n.update(self, self._sync())
+        # ...or create
+        else:
+            self.element = self.n.build(self._sync()).element
+        self._refresh()
+
+    @defer
     def anchor(self, **kw):
         '''link node to anchor'''
         self.l.make(self.C.anchor_link, self, self.n.anchorer(), kw)
 
     @class_defer
     def referrer(self, **kw):
+        '''make referring node for this model'''
         self.n.refer(**kw)
 
     @defer
             self.version()
         raise ReversionError('could not revert version {0}'.format(version))
 
-    @defer
     def save(self):
         '''save this node'''
         if self.validate():
             # version if flag set
-            if self.element is not None and self.C.versioned:
+            if self.C.versioned:
                 self.version()
-            self.commit()
-            # update if exists...
-            if self.element is not None:
-                self.n.update(self, self._sync())
-            # ...or create
-            else:
-                self.element = self.n.build(self._sync()).element
-            self._refresh()
+            self._finalize()
         else:
             raise ValidationError('data is invalid %s' % self._trait_errors)
 

File graphalchemy/readers.py

             label = conf.anchor.label
             anchor = self.filter_by(model.C.index, label, label)
             if anchor:
-                self._B.set(anchor, model.C.anchor_link, conf.userspace)
+                self._BQ.set(anchor, model.C.anchor_link, conf.userspace)
                 return anchor
         return None
 
             label = conf.reference.label
             ref = self.filter_by(model.C.index, label, label)
             if ref:
-                self._B.set(ref, model.C.reference_link, conf.userspace)
+                self._BQ.set(ref, model.C.reference_link, conf.userspace)
                 return ref
         return None
 
         except AppLookupError:
             root = self.r.root
             root = self._finder(element=root)(root)
-            self._B.set(root, conf.root, conf.userspace)
+            self._BQ.set(root, conf.root, conf.userspace)
             return root
 
     @service()

File graphalchemy/tests/test_models.py

         graph.register(Idea)
         graph.nodes.w.create_index('roots')
         question = Question.referrer(user=1)  # @UnusedVariable
-        # idea base create
         idea = Idea.referrer(user=1)  # @UnusedVariable
-        # pro base create
         pro = Pro.referrer(user=1)  # @UnusedVariable
-        # con base create
         con = Con.referrer(user=1)  # @UnusedVariable
-        # tag base create
         tag = Tag.referrer(user=1)  # @UnusedVariable
-        # example tags
         tag_1 = Tag.nodes.create(_status=1, text='wicked problem', user=1)
-#        assert tag_1.text == 'wicked problem'
-#        assert tag_1.user == 1
-#        assert tag_1.user != 2
         tag_1.index_under('tags', 'name', 'wicked problem')
         tag_2 = Tag.nodes.create(text='avoid', user=1, _status=1)
-#        assert tag_2.text == 'avoid'
-#        assert tag_2.user == 1
         tag_2.index_under('tags', 'name', 'avoid')
-        # prime question
         question_0 = Question.anchorer(user=1)  # @UnusedVariable
-        # root example question
         question_1 = Question(
             _status=1,
             down=0,
         )
         question_1.save()
         question_1.anchor(user=1)
-        # tag example question
         question_1.index_under('questions', 'tag', 'wicked problem')
         tag_1.link('TAGGED', question_1)
         question_1.index_under('questions', 'tag', 'avoid')
         )
         pro_4 = pro_2.fork()
         pro_4.save()
-#        pro_4.nodes.both._inner
-#        pro_4.nodes.forks._inner
-#        pro_4.nodes.versions._inner
         pro_2.user = pro_4.user
         pro_2.save()
         pro_3 = idea_1.pros.create(
         )
         pro_9.delete()
 
+    pro_4.nodes.both._inner
+    pro_4.nodes.forks._inner
+    pro_4.nodes.versions._inner
+    assert tag_1.text == 'wicked problem'
+    assert tag_1.user == 1
+    assert tag_1.user != 2
+    assert tag_2.text == 'avoid'
+    assert tag_2.user == 1
     cleanup()
 
 if __name__ == '__main__':

File graphalchemy/writers.py

         # add slug
         properties[slug_field] = tmpslug
 
-    @service()
     def delete_element(self, this, indices=None):
         '''
         delete graph element
         '''
         self.w.delete_element(this, indices)
 
-    @service()
-    def delete_property(self, this, key):
-        '''
-        delete graph element property
-
-        @param this: graph model instance
-        @param key: graph element property key
-        '''
-        self.w.delete_property(this, key)
-
-    @service()
     def index_many(self, index, this, indexed):
         '''
         index properties on a graph element
         '''
         self.w.index_many(self.r.index(index), this, indexed)
 
-    @service()
     def index_one(self, index, key, value, this):
         '''
         index one property of a graph element
         new_link.save()
         return new_link
 
-    @service()
     def make(self, link, start, end, kw=None):
         '''
         build a new graph link
         instance.save()
         return instance
 
-    @service()
     def make(self, cleaned):
         '''
         build a new graph node