1. Lynn Rees
  2. graphalchemy


graphalchemy / graphalchemy / models / workers.py

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

from itertools import count
from functools import partial

from markupsafe import escape
from stuf.utils import getcls

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.models)
    # model query
    _query = app(conf.model.reader.node, conf.models)
    # model user
    _using = app(conf.model.writer.node, conf.models)
    # node reader
    _r = factory(conf.read.node, backends, db)
    # node writer
    _w = factory(conf.write.node, backends, db)
    # direct
    direct = factory(conf.direct.worker.node, conf.directs, conf.key.session)
    # raw
    raw = factory(conf.raw, conf.appspace, conf.key.session)

    def _prepare(self, thing):
        # snapshot if flag set
        if thing.L.versioned:
        super(Nodes, self)._prepare(thing)

    def _preprocess(self, thing, model):
        pre-process graph element

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

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

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

    def _postprocess(self, thing, model):
        postprocess graph node

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

    def _create(self, thing):
        create a new graph node

        @param data: data
        model = getcls(thing)
        L = model.L
        data = thing.final
        data.update(_created=self.now(), _model=L.name, _uuid=self.Q.uuid())
        # number of versions to maintain
        if L.versioned:
            data['_versions'] = 0
        self._preprocess(data, model)
        thing = self._w.create(
            partial(self._postprocess, model=model),

    def _update(self, thing):
        update a graph element's properties

        @param thing: graph object
        model = getcls(thing)
        data = self.final
        self._w.update(thing, data, partial(self._postprocess, model=model))

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

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

    def remove(self, thing):
        del thing

    def using(self, model):
        use graph model

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