Source

graphalchemy / graphalchemy / mixins / elements.py

Full commit
# -*- coding: utf-8 -*-
'''graph element mixins'''

from stuf.utils import both, getcls, lazy, clsname

from graphalchemy.core import octopus

__all__ = ('LinksMixin', 'NodesMixin')

# settings
conf = getattr(octopus, 'S')


class ElementMixin(object):

    '''graph element'''

    def __init__(self, element=None, **kw):
        '''
        init

        @param element: graph element (default: None)
        '''
        # element direction
        self.direction = kw.pop('direction', 'outgoing')
        super(ElementMixin, self).__init__(element, **kw)

    @property
    def id(self):
        '''graph element id'''
        return self._p.id(self.source)

    @both
    def links(self):
        '''sequence of all links'''
        return self._links(self, getcls(self))

    def _source(self, this):
        '''
        synchronized data structure

        @param this: this element
        '''
        return self._p.properties(this)

    def _refresh(self):
        '''refresh original'''
        super(ElementMixin, self).sync()
        # reset links collector
        self.links.reset()

    def index_by(self, index=None, *indexed):
        '''
        index properties on a graph element

        @param index: graph index label (default: None)
        @param *indexed: properties to index
        '''
        self._p.index_many(index, self, indexed)

    def index_under(self, index, key, value):
        '''
        index one property of a graph element

        @param index: graph index label
        @param key: graph element property key
        @param value: graph element property value
        '''
        self._p.index_one(index, key, value, self)


class LinkMixin(object):

    '''link element'''

    def __init__(self, element=None, link=None, this=None, that=None, **kw):
        '''
        init

        @param element: link element (default: None)
        @param link: link kind name (default: None)
        @param this: one node in a link (default: None)
        @param that: another node in a link (default: None)
        '''
        super(LinkMixin, self).__init__(element, **kw)
        # link kind name
        self.link = link
        # one end
        self.that = that if that is not None else self._node()(element.end)
        # the other end
        self.this = this if this is not None else self._node()(element.start)

    def __repr__(self):
        return '{0}: {1}'.format(self.kind, super(LinkMixin, self).__repr__())

    @lazy
    def end(self):
        '''ending node of link'''
        return self.that if self.direction == 'incoming' else self.this

    @property
    def kind(self):
        '''kind of link'''
        return self.session.links.kind(self.source)

    @lazy
    def start(self):
        '''starting node of link'''
        return self.this if self.direction == 'incoming' else self.that

    def deep_dump(self):
        '''deep dump link and both nodes'''
        return self.copy(
            end=self.end.deep_dump(),
            id=self.id,
            kind=self.kind,
            start=self.start.deep_dump(),
        )

    def dump(self):
        '''dump link and both nodes'''
        return self.copy(
            end=self.end.dump(),
            id=self.id,
            kind=self.kind,
            start=self.start.dump(),
        )


class NodeMixin(object):

    '''node element'''

    def __repr__(self):
        return '{0}: {1}'.format(
            clsname(self), super(NodeMixin, self).__repr__(),
        )

    @lazy
    def nodes(self):
        '''connector to all nodes linked to this node'''
        return self._nodes(self, getcls(self))

    def _refresh(self):
        '''refresh node objects'''
        super(NodeMixin, self)._refresh()
        # reset nodes connector
        self.nodes.reset()

    def deep_dump(self):
        '''
        serialize this node, its outgoing related nodes, and their outgoing
        related nodes
        '''
        return self.copy(id=self.id, nodes=self.nodes.deep_dump())

    def dump(self):
        '''serialize this node and outgoing related nodes'''
        return self.copy(id=self.id)

    def link(self, link, node, **kw):
        '''
        link this node to another node

        @param link: kind of link
        @param node: the other node
        @param **kw: link properties
        '''
        self.session.links.create(link, self, node, kw)