135 lines
4.6 KiB
Python
135 lines
4.6 KiB
Python
from app.core import db
|
|
|
|
GROUPS = ['sum', 'avg', 'count']
|
|
FILTERS = ['$gt', '$lt', '$eq']
|
|
PERIODS = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second']
|
|
ORDERS = ['asc', 'desc']
|
|
|
|
|
|
def run_query_on(query_object, field_provider, **kwargs):
|
|
"""
|
|
Generates a query for target object based on query provided as kwargs
|
|
|
|
:param query_object: Initial query object as returned by SQLAlchemy for
|
|
target table
|
|
:type query_object: Query
|
|
:param field_provider: Function which provides fields based on name, with
|
|
optional parameter formatted which returns the field formatted using sql
|
|
functions
|
|
:type field_provider: func(col_name:String, formatted:Boolean)
|
|
"""
|
|
selections, filters, groups, orderings = validate_selections(**kwargs)
|
|
entities = []
|
|
|
|
if selections is not None:
|
|
if groups is not None:
|
|
for group in groups.keys():
|
|
entities.append(
|
|
get_group(
|
|
field_provider(group),
|
|
groups[group]
|
|
).label(
|
|
'group_' + str(group) # + '_' + groups[group]
|
|
)
|
|
)
|
|
|
|
for selection in selections.keys():
|
|
entities.append(get_column(selections[selection],
|
|
field_provider(selection, True)).label(selection))
|
|
|
|
query_object = query_object.with_entities(*entities)
|
|
|
|
if filters is not None:
|
|
for filtered_column in filters.keys():
|
|
for actual_filter in filters[filtered_column].keys():
|
|
query_object = query_object.filter(
|
|
get_filter(field_provider(filtered_column),
|
|
actual_filter,
|
|
filters[filtered_column][actual_filter]))
|
|
|
|
if groups is not None:
|
|
for group in groups.keys():
|
|
query_object = query_object.group_by('group_' + str(group))
|
|
|
|
if orderings is not None:
|
|
for order in orderings.keys():
|
|
if ((selections is not None and
|
|
order not in selections.keys())
|
|
and
|
|
(groups is None or
|
|
order not in ['group_' + str(group) for group in
|
|
groups.keys()])):
|
|
raise ValueError(
|
|
'Invalid order! Must use one of' +
|
|
' selections or groups')
|
|
query_object = query_object.order_by(
|
|
order + ' ' + orderings[order])
|
|
|
|
return query_object
|
|
|
|
|
|
def get_column(selection_name, field):
|
|
if selection_name == 'value':
|
|
return field
|
|
if selection_name == 'sum':
|
|
return db.func.sum(field)
|
|
if selection_name == 'avg':
|
|
return db.func.avg(field)
|
|
if selection_name == 'count':
|
|
return db.func.count(field)
|
|
|
|
|
|
def get_filter(filter_column, filter_key, filter_value):
|
|
if filter_key == '$gt':
|
|
return filter_column > filter_value
|
|
if filter_key == '$lt':
|
|
return filter_column < filter_value
|
|
if filter_key == '$eq':
|
|
return filter_column == filter_value
|
|
|
|
|
|
def get_group(group_column, group_value):
|
|
if group_value == 'value':
|
|
return group_column
|
|
if group_value in PERIODS:
|
|
return db.func.date_part(group_value, group_column)
|
|
# We now expect a date format
|
|
return db.func.to_char(group_column, group_value)
|
|
|
|
|
|
def is_group(**kwargs):
|
|
if kwargs.get('group') is not None:
|
|
return True
|
|
|
|
|
|
def validate_selections(**kwargs):
|
|
selections = kwargs.get('selections')
|
|
filters = kwargs.get('filters')
|
|
groups = kwargs.get('groups')
|
|
orderings = kwargs.get('orders')
|
|
|
|
if selections is None:
|
|
raise ValueError("Missing selections!")
|
|
|
|
if is_group(**kwargs):
|
|
for key in selections.keys():
|
|
if selections[key] not in GROUPS:
|
|
raise ValueError("Can only use " + str(GROUPS) + " when " +
|
|
"grouping!")
|
|
|
|
if filters is not None:
|
|
for key in filters.keys():
|
|
for inner_key in filters[key].keys():
|
|
if inner_key not in FILTERS:
|
|
raise ValueError("Invalid filter (" + str(
|
|
inner_key) + "). Valid filters: " + str(FILTERS))
|
|
|
|
if orderings is not None:
|
|
for key in orderings.keys():
|
|
if orderings[key] not in ORDERS:
|
|
raise ValueError("Invalid order type ("
|
|
+ orderings[key] + "). " +
|
|
"Valid types: " + str(ORDERS))
|
|
|
|
return selections, filters, groups, orderings
|