diff --git a/app/api/resources/device.py b/app/api/resources/device.py index 9a17b30..7780ae1 100644 --- a/app/api/resources/device.py +++ b/app/api/resources/device.py @@ -38,6 +38,7 @@ class RecordingsQuerySchema(Schema): selections = fields.Raw() filters = fields.Raw() groups = fields.Raw() + orders = fields.Raw() class DeviceSecretSchema(BaseResourceSchema): diff --git a/app/jsonql/api.py b/app/jsonql/api.py index 0b7efc9..e051343 100644 --- a/app/jsonql/api.py +++ b/app/jsonql/api.py @@ -3,10 +3,11 @@ 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): - selections, filters, groups = validate_selections(**kwargs) + selections, filters, groups, orderings = validate_selections(**kwargs) entities = [] print('Starting with args: ' + str(kwargs)) @@ -42,6 +43,20 @@ def run_query_on(query_object, field_provider, **kwargs): 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 @@ -83,6 +98,7 @@ 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!") @@ -90,14 +106,21 @@ def validate_selections(**kwargs): if is_group(**kwargs): for key in selections.keys(): if selections[key] not in GROUPS: - raise ValueError("Can only use sum, avg and count when\ - grouping!") + 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("Unknown filter: " + str( - inner_key)) + raise ValueError("Invalid filter (" + str( + inner_key) + "). Valid filters: " + str(FILTERS)) - return selections, filters, groups + 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 diff --git a/app/jsonql/example_query.json b/app/jsonql/example_query.json index 14a8ba4..6c17c3c 100644 --- a/app/jsonql/example_query.json +++ b/app/jsonql/example_query.json @@ -12,5 +12,7 @@ }, "group": { "date": "month" + }, + "order": { } } diff --git a/app/swagger/template.yaml b/app/swagger/template.yaml index 02d02d2..46a83ef 100644 --- a/app/swagger/template.yaml +++ b/app/swagger/template.yaml @@ -167,6 +167,7 @@ definitions: - selections - filters - groups + - orders properties: selections: type: object @@ -180,6 +181,10 @@ definitions: type: object description: GROUP BY part of query example: { "recorded_at": "year" } + orders: + type: object + description: ORDER BY part of query + example: { "group_recorded_at": "asc" } RecordingCreation: type: object diff --git a/config.py b/config.py index 16725e8..890b690 100644 --- a/config.py +++ b/config.py @@ -2,7 +2,7 @@ import os # App configuration DEBUG = os.environ['DEBUG'] -APP_VERSION = '0.3.5' +APP_VERSION = '0.3.6' # Define the application directory BASE_DIR = os.path.abspath(os.path.dirname(__file__))