graphalchemy / graphalchemy / models /

# -*- 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(, 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:
        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:
            tmpslug = '{slug}-{count}'.format(slug=slug, count=cnt)
        # add slug
        properties[slug_field] = tmpslug

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

        @param data: data
        model = self.model
        C = model.C
        data.update(,, _uuid=self.Q.uuid())
        # number of versions to maintain
        if C.versioned:
            data['_versions'] = 0
        thing = self.w.create(
            partial(self._postprocess, model=model),

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

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

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

    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'] =
        # slug field

    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',, 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)