1
# Author: John Tran <jhtran@att.com>
2
# Julien Danjou <julien@danjou.info>
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
8
# http://www.apache.org/licenses/LICENSE-2.0
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
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
28
from ceilometer.storage.sqlalchemy import models
31
META_TYPE_MAP = {bool: models.MetaBool,
33
unicode: models.MetaText,
34
types.NoneType: models.MetaText,
35
int: models.MetaBigInt,
36
long: models.MetaBigInt,
37
float: models.MetaFloat}
40
class QueryTransformer(object):
41
operators = {"=": operator.eq,
49
"in": lambda field_name, values: field_name.in_(values)}
51
complex_operators = {"or": or_,
55
ordering_functions = {"asc": asc,
58
def __init__(self, table, query):
62
def _handle_complex_op(self, complex_op, nodes):
63
op = self.complex_operators[complex_op]
68
element = self._transform(node)
69
element_list.append(element)
70
return op(*element_list)
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)
79
return op(getattr(self.table, field_name), value)
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')
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
95
self.query = self.query.outerjoin(meta_alias, on_clause)
96
return op(meta_alias.value, value)
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)
104
return self._handle_simple_op(operator, nodes)
106
def apply_filter(self, expression_tree):
107
condition = self._transform(expression_tree)
108
self.query = self.query.filter(condition)
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)
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])))
122
self.query = self.query.order_by(desc(self.table.timestamp))
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}
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])