Source

graphalchemy / graphalchemy / models / workers.py

Full commit
# -*- coding: utf-8 -*-
'''graph model manager'''

from itertools import count
from functools import partial

from markupsafe import escape

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

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


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

    '''graph node worker'''

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

    def _autoslug(self, properties):
        '''
        auto slug an element

        @param properties: graph element properties
        '''
        C = self.model.C
        slug_from = C.slug_from
        if not slug_from:
            return
        slug = tmpslug = self.Q.slugify(properties[slug_from])
        slug_field = C.slug_field
        # loop until unique slug is located
        filter_by = self.r.filter_by
        index = C.index
        for cnt in count(1):
            prev = filter_by(index, slug_field, tmpslug)
            if not prev:
                break
            tmpslug = '{slug}-{count}'.format(slug=slug, count=cnt)
        # add slug
        properties[slug_field] = tmpslug

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

        @param data: data
        '''
        model = self.model
        C = model.C
        data.update(_created=self.now(), _model=C.name, _uuid=self.Q.uuid())
        # number of versions to maintain
        if C.versioned:
            data['_versions'] = 0
        self._preprocess(data)
        thing = self.w.create(
            data,
            C.reference_link,
            model.nodes.reference(),
            partial(self._postprocess, model=model),
        )
        thing._refresh()

    def _prepare(self, this):
        # snapshot if flag set
        if this.C.versioned:
            self._snapshot(this)
        super(Nodes, self)._prepare(this)

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

        @param this: graph object
        @param data: data
        '''
        self._preprocess(data)
        self.w.update(this, data, partial(self._postprocess, model=self.model))
        this._refresh()

    def _preprocess(self, this):
        '''
        pre-process graph element

        @param this: graph object
        '''
        esc = escape
        for k in self.model.C.escaped:
            this[k] = esc(this[k])
        this['_modified'] = self.now()
        # slug field
        self._autoslug(this)

    def _postprocess(self, this):
        '''
        postprocess graph node

        @param this: graph object
        '''
        this = self.model(this)
        C = self.model.C
        index = C.index
        # index created date
        index_one = self.index_one
        if index:
            index_one(index, 'created', self.now(), this)
        # index any listed properties
        indexed = C.indexed
        if indexed:
            self.index_many(index, this, indexed)
        # add a slug if present
        slug_from = C.slug_from
        if slug_from:
            index_one(index, slug_from, getattr(this, slug_from), this)
        # index properties that support full text search
        fts_indexed = C.fts_indexed
        if fts_indexed:
            self.index_many(C.fts_index, this, fts_indexed)
        return this

    def query(self, model):
        '''
        query using a graph model

        @param model: graph model
        '''
        return self._query(model)

    def using(self, model):
        '''
        use graph model

        @param model: graph model
        '''
        return self._using(model)