Source

graphalchemy / graphalchemy / direct / workers.py

Full commit
# -*- coding: utf-8 -*-
'''graph managers'''

from appspace import AppLookupError

from graphalchemy.core import octopus, app, factory, defer
from graphalchemy.mixins.workers import WriterMixin, ReaderMixin

__all__ = ('Links', 'Nodes')
# settings
conf = octopus.G
backends = conf.backends
db = conf.key.db


class _Direct(WriterMixin, ReaderMixin, octopus.process.Worker):

    '''direct graph database interface'''

    ###########################################################################
    ## graph write methods ####################################################
    ###########################################################################

    @defer
    def delete(self, this, indices=None):
        '''
        delete graph element

        @param this: graph object
        @param indicies: graph indices (default: None)
        '''
        self._w.delete(this, indices)

    @defer
    def update(self, this, **data):
        '''
        update a graph element's properties

        @param this: graph object
        @param **data: data
        '''
        self._w.update(this, data)
        this._refresh()
        return this

    ###########################################################################
    ## graph read methods #####################################################
    ###########################################################################

    def filter(self, index, queries):
        '''
        full text search using index

        @param index: name of index
        @param queries: queries built with query builder
        '''
        return self._r.filter(index, queries, self._model)

    def filter_by(self, index, key, value):
        '''
        filter by keywords

        @param index: index name
        @param key: keyword in index
        @param value: value in index (or second key)
        '''
        return self._r.filter_by(index, key, value, self._model)

    def get(self, element):
        '''
        get database element by id

        @param element: element id
        '''
        return self._model(self._r.get(element))

    def traverse(self, this, tester=None, links=None, unique=None):
        '''
        traverse graph, yielding graph elements

        @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)
        '''
        model = self._model
        for element in self._r.traverser(this, tester, links, unique):
            yield model(element)


class Links(_Direct):

    '''direct graph link interface'''

    # graph source
    _db = app(conf.key.backend, conf.userspace)
    _model = app(conf.direct.element.link, conf.managers)
    # direct link reader
    _r = factory(conf.read.link, backends, db)
    # direct link writer
    _w = factory(conf.write.link, backends, db)

    ###########################################################################
    ## link write methods #####################################################
    ###########################################################################

    @defer
    def create(self, link, start, end, **data):
        '''
        create a new graph link

        @param link: link name
        @param start: start node for link
        @param end: end node for link
        @param **data: data
        '''
        data.update(_created=self.now(), _uuid=self.Q.uuid())
        thing = self._w.create(link, start, end, data)
        thing._refresh()
        return thing

    ###########################################################################
    ## link read  methods #####################################################
    ###########################################################################

    def kind(self, element):
        '''
        kind of link

        @param element: graph element
        '''
        return self._r.kind(element)

    def walk(self, this, direction=None, label=None, keys=None):
        '''
        iterate links and yield graph elements

        @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)
        '''
        model = self._model
        for element in self._r.walker(this, direction, label, keys):
            yield model(element)


class Nodes(_Direct):

    '''direct graph node interface'''

    _model = app(conf.direct.element.node, conf.managers)
    # direct node reader
    _r = factory(conf.read.node, backends, db)
    # direct node writer
    _w = factory(conf.write.node, backends, db)

    ###########################################################################
    ## node write methods #####################################################
    ###########################################################################

    @defer
    def create(self, **data):
        '''
        create a new graph node

        @param **data: data
        '''
        data.update(_created=self.now(), _uuid=self.Q.uuid())
        thing = self._w.create(data)
        thing._refresh()
        return thing

    ###########################################################################
    ## link read methods ######################################################
    ###########################################################################

    def root(self):
        '''reference root for graph'''
        try:
            G = self.G
            return self.Q.app(G.root, G.userspace)
        except AppLookupError:
            root = self._r.root
            root = self._model(root)
            self.Q.register(root, G.root, G.userspace)
            return root

    def walk(self, this, direction=None, label=None, keys=None, end='end'):
        '''
        iterate links and yield node from link

        @param this: graph node 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: which end of link to return (default: 'end')
        '''
        model = self._model
        for element in self._r.walker(this, direction, label, keys, end):
            yield model(element)