~ubuntu-branches/ubuntu/utopic/ceilometer/utopic-proposed

« back to all changes in this revision

Viewing changes to ceilometer/storage/sqlalchemy/utils.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2014-10-16 14:07:11 UTC
  • mfrom: (1.2.1) (28.1.5 utopic-proposed)
  • Revision ID: package-import@ubuntu.com-20141016140711-95mki6bdkivvfr2x
Tags: 2014.2-0ubuntu1
New upstream release. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Author: John Tran <jhtran@att.com>
 
2
#         Julien Danjou <julien@danjou.info>
 
3
#
 
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
 
5
# not use this file except in compliance with the License. You may obtain
 
6
# a copy of the License at
 
7
#
 
8
#      http://www.apache.org/licenses/LICENSE-2.0
 
9
#
 
10
# Unless required by applicable law or agreed to in writing, software
 
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
13
# License for the specific language governing permissions and limitations
 
14
# under the License.
 
15
#
 
16
 
 
17
import operator
 
18
import types
 
19
 
 
20
from sqlalchemy import and_
 
21
from sqlalchemy import asc
 
22
from sqlalchemy import desc
 
23
from sqlalchemy import not_
 
24
from sqlalchemy import or_
 
25
from sqlalchemy.orm import aliased
 
26
 
 
27
import ceilometer
 
28
from ceilometer.storage.sqlalchemy import models
 
29
 
 
30
 
 
31
META_TYPE_MAP = {bool: models.MetaBool,
 
32
                 str: models.MetaText,
 
33
                 unicode: models.MetaText,
 
34
                 types.NoneType: models.MetaText,
 
35
                 int: models.MetaBigInt,
 
36
                 long: models.MetaBigInt,
 
37
                 float: models.MetaFloat}
 
38
 
 
39
 
 
40
class QueryTransformer(object):
 
41
    operators = {"=": operator.eq,
 
42
                 "<": operator.lt,
 
43
                 ">": operator.gt,
 
44
                 "<=": operator.le,
 
45
                 "=<": operator.le,
 
46
                 ">=": operator.ge,
 
47
                 "=>": operator.ge,
 
48
                 "!=": operator.ne,
 
49
                 "in": lambda field_name, values: field_name.in_(values)}
 
50
 
 
51
    complex_operators = {"or": or_,
 
52
                         "and": and_,
 
53
                         "not": not_}
 
54
 
 
55
    ordering_functions = {"asc": asc,
 
56
                          "desc": desc}
 
57
 
 
58
    def __init__(self, table, query):
 
59
        self.table = table
 
60
        self.query = query
 
61
 
 
62
    def _handle_complex_op(self, complex_op, nodes):
 
63
        op = self.complex_operators[complex_op]
 
64
        if op == not_:
 
65
            nodes = [nodes]
 
66
        element_list = []
 
67
        for node in nodes:
 
68
            element = self._transform(node)
 
69
            element_list.append(element)
 
70
        return op(*element_list)
 
71
 
 
72
    def _handle_simple_op(self, simple_op, nodes):
 
73
        op = self.operators[simple_op]
 
74
        field_name = nodes.keys()[0]
 
75
        value = nodes.values()[0]
 
76
        if field_name.startswith('resource_metadata.'):
 
77
            return self._handle_metadata(op, field_name, value)
 
78
        else:
 
79
            return op(getattr(self.table, field_name), value)
 
80
 
 
81
    def _handle_metadata(self, op, field_name, value):
 
82
        if op == self.operators["in"]:
 
83
            raise ceilometer.NotImplementedError('Metadata query with in '
 
84
                                                 'operator is not implemented')
 
85
 
 
86
        field_name = field_name[len('resource_metadata.'):]
 
87
        meta_table = META_TYPE_MAP[type(value)]
 
88
        meta_alias = aliased(meta_table)
 
89
        on_clause = and_(self.table.internal_id == meta_alias.id,
 
90
                         meta_alias.meta_key == field_name)
 
91
        # outer join is needed to support metaquery
 
92
        # with or operator on non existent metadata field
 
93
        # see: test_query_non_existing_metadata_with_result
 
94
        # test case.
 
95
        self.query = self.query.outerjoin(meta_alias, on_clause)
 
96
        return op(meta_alias.value, value)
 
97
 
 
98
    def _transform(self, sub_tree):
 
99
        operator = sub_tree.keys()[0]
 
100
        nodes = sub_tree.values()[0]
 
101
        if operator in self.complex_operators:
 
102
            return self._handle_complex_op(operator, nodes)
 
103
        else:
 
104
            return self._handle_simple_op(operator, nodes)
 
105
 
 
106
    def apply_filter(self, expression_tree):
 
107
        condition = self._transform(expression_tree)
 
108
        self.query = self.query.filter(condition)
 
109
 
 
110
    def apply_options(self, orderby, limit):
 
111
        self._apply_order_by(orderby)
 
112
        if limit is not None:
 
113
            self.query = self.query.limit(limit)
 
114
 
 
115
    def _apply_order_by(self, orderby):
 
116
        if orderby is not None:
 
117
            for field in orderby:
 
118
                ordering_function = self.ordering_functions[field.values()[0]]
 
119
                self.query = self.query.order_by(ordering_function(
 
120
                    getattr(self.table, field.keys()[0])))
 
121
        else:
 
122
            self.query = self.query.order_by(desc(self.table.timestamp))
 
123
 
 
124
    def get_query(self):
 
125
        return self.query
 
126
 
 
127
 
 
128
trait_models_dict = {'string': models.Trait.t_string,
 
129
                     'integer': models.Trait.t_int,
 
130
                     'datetime': models.Trait.t_datetime,
 
131
                     'float': models.Trait.t_float}
 
132
 
 
133
 
 
134
def trait_op_condition(conditions, trait_type, value, op='eq'):
 
135
    trait_model = trait_models_dict[trait_type]
 
136
    op_dict = {'eq': (trait_model == value), 'lt': (trait_model < value),
 
137
               'le': (trait_model <= value), 'gt': (trait_model > value),
 
138
               'ge': (trait_model >= value), 'ne': (trait_model != value)}
 
139
    conditions.append(op_dict[op])
 
140
    return conditions