view src/ltpdarepo/query.py @ 248:fbfd3129fe4d stable

Version bump.
author Daniele Nicolodi <daniele@grinta.net>
date Tue, 27 Dec 2011 18:59:28 +0100
parents fbab144c296c
children
line wrap: on
line source

# Copyright 2011 Daniele Nicolodi <nicolodi@science.unitn.it>
#
# This software may be used and distributed according to the terms of
# the GNU Affero General Public License version 3 or any later version.

import re

from flask import g, json
from MySQLdb.cursors import DictCursor
from wtforms.fields import TextField, HiddenField
from wtforms import validators
from wtforms.validators import ValidationError

from ltpdarepo.form import Form


class IQuery(Form):
    query = HiddenField()
    title = TextField(validators=[validators.Required()])
    db = TextField('Databases',
                   description='Databaseses to which the query may be applied. '
                               'Comma separated list or regular expression',
                   validators=[validators.Required()])

    def validate_db(form, field):
        # automagically transform comma separated list into regular expression
        if not re.match(r'\^\(.*\)\$', field.data):
            field.data = '^(' + '|'.join(v.strip() for v in field.data.split(',')) + ')$'
        # validate regular expression
        try:
            re.compile(field.data)
        except re.error, error:
            raise ValidationError('Invalid regular expression: ' + str(error))


class Query(dict):
    __slots__ = ('id', 'title', 'db', '_query', '_order', '_times')

    def __init__(self, query='', id=None, title=None, db=None):
        self.id = id
        self.title = title
        self.db = db
        self.query = query

    def _getquery(self):
        if self._times is not None:
            return json.dumps({'query': self._query, 'order': self._order, 'times': self._times})
        return json.dumps({'query': self._query, 'order': self._order})

    def _setquery(self, string):
        if not string:
            return
        obj = json.loads(string)
        self._query = obj.get('query')
        self._order = obj.get('order')
        self._times = obj.get('times')

    query = property(_getquery, _setquery)

    @property
    def kind(self):
        return self._times is not None and 'timeseries' or 'query'

    @staticmethod
    def load(id):
        curs = g.db.cursor(DictCursor)
        curs.execute("""SELECT id, title, db, query
                        FROM queries WHERE id=%s""", (id, ))
        query = curs.fetchone()
        if query is None:
            return None
        obj = Query(**query)
        return obj

    def parse(self, string):
        # parse url params        
        from urlparse import parse_qs
        from werkzeug.datastructures import MultiDict

        # parse string into dictionary
        formdata = parse_qs(string, keep_blank_values=True, strict_parsing=True)
        formdata = MultiDict(formdata)

        # query parameters
        fields = formdata.getlist('field')
        operators = formdata.getlist('operator')
        values = formdata.getlist('value')
        self._query = zip(fields, operators, values)

        # ordering
        self._order = formdata.get('o', 'id'), formdata.get('r', 0)

        # timeseries search
        self._times = formdata.get('t1'), formdata.get('t2')
        if self._times[0] is None and self._times[1] is None:
            self._times = None

    @property
    def params(self, **kwargs):
        # return url params to compose the query
        fields = []
        operators = []
        values = []
        for f, o, v in self._query:
            fields.append(f)
            operators.append(o)
            values.append(v)
        params = {'field': fields,
                  'operator': operators,
                  'value': values,
                  'o': self._order[0],
                  'r': self._order[1]}
        if self._times:
            params.update({'t1': self._times[0],
                           't2': self._times[1]})
        params.update(**kwargs)
        return params

    def create(self):
        curs = g.db.cursor()
        curs.execute("""INSERT INTO queries (title, db, query)
                        VALUES (%s, %s, %s)""", (self.title, self.db, self.query))
        g.db.commit()
        return curs.lastrowid

    def save(self):
        curs = g.db.cursor()
        curs.execute("""UPDATE queries SET title=%s, db=%s, query=%s
                        WHERE id=%s""", (self.title, self.db, self.query, self.id))
        g.db.commit()

    def drop(self):
        curs = g.db.cursor()
        curs.execute("""DELETE FROM queries WHERE id=%s""", self.id)
        g.db.commit()

    def __str__(self):
        query = []
        if self._times:
            query.append("time BETWEEN '%s' AND '%s'" % (self._times[0], self._times[1]))
        query += ["%s %s '%s'" % (field, op, value) for field, op, value in self._query]
        string = " AND ".join(query)
        if self._order[0]:
            string += " ORDER BY %s" % self._order[0]
        if self._order[1]:
            string += " DESC"
        return string