Source

graphalchemy / graphalchemy / models / writers.py

# -*- coding: utf-8 -*-
'''graph model writers'''

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

__all__ = ['Nodes']
# settings
conf = octopus.G
backends = conf.backends
db = conf.key.db


class Nodes(WriterMixin, octopus.workflow.worker):

    '''graph node writer'''

    # graph source
    _db = app(conf.key.backend, conf.userspace)
    # model finder
    _finder = app(conf.model.finder.node, conf.appspace)
    # direct node reader
    r = factory(conf.read.node, backends, db)
    # direct node writer
    w = factory(conf.write.node, backends, db)

    def __init__(self, model):
        '''
        init

        @param model: graph model
        '''
        super(Nodes, self).__init__()
        self.model = model

    def anchor(self, **kw):
        '''create an anchor node'''
        model = self.model
        C = model.C
        name = C.name
        S = self.S.anchor
        label = S.label
        index_one = self.index_one
        def callback(node): #@IgnorePep8
            node = self._finder(element=node)(node)
            # put in root index
            root_index = C.root_index
            if root_index:
                index_one(root_index, label, name, node)
            # put in model index
            index = C.index
            if index:
                index_one(index, label, label, node)
            return node
        data = dict(
            _created=self.now(),
            _uuid=self.Q.uuid(),
            text=S.description.format(name=name),
        )
        data.update(kw)
        return self.w.create(
            data,
            C.reference_link,
            model.nodes.reference(),
            callback,
        )

    def fork(self, this):
        '''
        clone a graph node

        @param this: graph object
        '''
        created = self.now()
        model = self.model
        C = model.C
        index = C.index
        S = self.S.fork
        if index:
            # create callback
            index_one = self.index_one
            def callback(fork): #@IgnorePep8
                # add hash
                fork['_hash'] = this.hash_current()
                # refer back to original
                fork['_forked'] = this.id
                fork = model(fork)
                # index fork
                index_one(index, S.label, this.id, fork)
                # index forked time
                index_one(index, S.created, created, fork)
                return fork
        else:
            callback = None
        return self.w.clone(this, C.fork_link, callback, _created=created)

    def refer(self, **kw):
        '''create a reference node'''
        finder = self._finder
        model = self.model
        C = model.C
        name = C.name
        S = self.S.reference
        label = S.label
        w = self.w
        index_one = w.index_one
        create_index = w.create_index
        r = self.r
        def callback(node): #@IgnorePep8
            node = finder(element=node)(node)
            # put in root index
            root_index = r.index(C.root_index)
            index_one(root_index, label, name, node)
            # create any main index
            index = C.index
            if index:
                index_one(create_index(index), label, label, node)
            # create any full text index
            fts_index = C.get('fts_index', False)
            if fts_index:
                create_index(fts_index, fts=True)
            return node
        root = r.root
        h = self
        data = dict(
            _created=h.now(),
            _uuid=self.Q.uuid(),
            text=S.description.format(name=name),
        )
        data.update(kw)
        return w.create(
            data, C.reference_link, finder(element=root)(root), callback,
        )

    def revert(self, this, snapshot):
        '''
        change a graph node to an older snapshot

        @param this: graph object
        @param snapshot: snapshot to revert to
        '''
        self.update(
            this, self.r.filter_by(self.S.snapshot.label, snapshot).properties,
        )

    def snapshot(self, this, diff):
        '''
        capture changes between different versions of a graph node

        @param this: graph object
        @param diff: differences between two versions of a graph node
        '''
        created = self.now()
        # populate diff
        diff.update(_created=created, _versioned=this.id)
        S = self.S.version
        model = self.model
        C = model.C
        index = C.index
        if index:
            # create callback if index
            index_one = self.index_one
            def callback(snapshot): #@IgnorePep8
                snapshot = model(snapshot)
                # index snapshot with parent snapshot
                index_one(index, S.reference, this.id, snapshot)
                # index snapshot as snapshot
                index_one(index, S.label, snapshot.id, snapshot)
                # index versioned time
                index_one(index, S.created, created, snapshot)
                return snapshot
        else:
            callback = None
        # create snapshot and link back to previous snapshot
        return self.w.create(
            diff, C.version_link, this, callback, _created=created,
        )