Skip to content

Commit

Permalink
Merge pull request #98 from giovannicuriel/add-attr-type-filter
Browse files Browse the repository at this point in the history
feat: adding attribute type filter
  • Loading branch information
giovannicuriel committed Mar 21, 2019
2 parents 8b6882b + 76f455c commit 6086f25
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 14 deletions.
19 changes: 13 additions & 6 deletions DeviceManager/DeviceHandler.py
Expand Up @@ -245,13 +245,20 @@ def get_devices(req, sensitive_data=False):

attr_filter = []
query = req.args.getlist('attr')
for attr in query:
parsed = re.search('^(.+){1}=(.+){1}$', attr)
attr = []
attr.append("attrs.label = '{}'".format(parsed.group(1)))
for attr_label_item in query:
parsed = re.search('^(.+){1}=(.+){1}$', attr_label_item)
attr_label = []
attr_label.append("attrs.label = '{}'".format(parsed.group(1)))
# static value must be the override, if any
attr.append("coalesce(overrides.static_value, attrs.static_value) = '{}'".format(parsed.group(2)))
attr_filter.append(and_(*attr))
attr_label.append("coalesce(overrides.static_value, attrs.static_value) = '{}'".format(parsed.group(2)))
LOGGER.debug(f"Adding filter ${attr_label} to query")
attr_filter.append(and_(*attr_label))

query = req.args.getlist('attr_type')
for attr_type_item in query:
attr_type = []
attr_type.append("attrs.value_type = '{}'".format(attr_type_item))
attr_filter.append(and_(*attr_type))

label_filter = []
target_label = req.args.get('label', None)
Expand Down
37 changes: 31 additions & 6 deletions DeviceManager/TemplateHandler.py
@@ -1,7 +1,7 @@
import logging
import re
from flask import Blueprint, request, jsonify, make_response
from flask_sqlalchemy import BaseQuery
from flask_sqlalchemy import BaseQuery, Pagination
from sqlalchemy.exc import IntegrityError
from sqlalchemy.sql import text, collate, func

Expand Down Expand Up @@ -50,6 +50,19 @@ def remove(d,k):

return result

def paginate(query, page, per_page=20, error_out=False):
if error_out and page < 1:
return None
items = query.limit(per_page).offset((page - 1) * per_page).all()
if not items and page != 1 and error_out:
return None

if page == 1 and len(items) < per_page:
total = len(items)
else:
total = query.count()

return Pagination(query, page, per_page, total, items)

class TemplateHandler:

Expand Down Expand Up @@ -87,6 +100,10 @@ def get_templates(req):
parsed_query.append(text("attrs.static_value = '{}'".format(parsed.group(2))))
LOGGER.debug("... query parameter was added to filter list.")

query = req.args.getlist('attr_type')
for attr_type_item in query:
parsed_query.append(text("attrs.value_type = '{}'".format(attr_type_item)))

target_label = req.args.get('label', None)
if target_label:
LOGGER.debug(f"Adding label filter to query...")
Expand All @@ -95,19 +112,25 @@ def get_templates(req):

SORT_CRITERION = {
'label': DeviceTemplate.label,
None: DeviceTemplate.id
None: None
}
sortBy = SORT_CRITERION.get(req.args.get('sortBy', None), DeviceTemplate.id)
sortBy = SORT_CRITERION.get(req.args.get('sortBy', None), None)
LOGGER.debug(f"Sortby filter is {sortBy}")
if parsed_query:
LOGGER.debug(f" Filtering template by {parsed_query}")

# Always sort by DeviceTemplate.id
page = db.session.query(DeviceTemplate) \
.join(DeviceAttr, isouter=True) \
.filter(*parsed_query) \
.order_by(sortBy) \
.distinct(DeviceTemplate.id)
.order_by(DeviceTemplate.id)
if sortBy:
page = page.order_by(sortBy)

page = page.distinct(DeviceTemplate.id)

LOGGER.debug(f"Current query: {type(page)}")
page = BaseQuery(page.subquery(), db.session()).paginate(**pagination)
page = paginate(page, **pagination)
else:
LOGGER.debug(f" Querying templates sorted by {sortBy}")
page = db.session.query(DeviceTemplate).order_by(sortBy).paginate(**pagination)
Expand All @@ -130,6 +153,8 @@ def get_templates(req):
'templates': templates
}

LOGGER.debug(f"Full response is {result}")

return result

@staticmethod
Expand Down
38 changes: 36 additions & 2 deletions docs/apiary.apib
Expand Up @@ -111,7 +111,7 @@ Register a new template
}


### Get the current list of templates [GET /template{?page_size,page_num,attr_format,attr,label,sortBy}]
### Get the current list of templates [GET /template{?page_size,page_num,attr_format,attr,attr_type,label,sortBy}]
Get the full list of templates with all their associated attributes.

+ Parameters
Expand All @@ -124,6 +124,7 @@ Get the full list of templates with all their associated attributes.
template attributes that are listed by both 'data_attrs' and 'config_attrs'.

+ attr: foo=bar (string, optional) - Return only templates that posess a given attribute's value
+ attr_type: geopoint (string, optional) - Return only templates with attributes of a particular type.
+ label: dummy (string, optional) - Return only templates that are named accordingly (prefix or suffix match)
+ sortBy: label (string, optional) - Return entries sorted by given field. Currently only `label` is supported.

Expand Down Expand Up @@ -155,6 +156,14 @@ Get the full list of templates with all their associated attributes.
"type": "static",
"id": 2,
"template_id": "1"
},
{
"created": "2018-02-27T16:10:23.178557+00:00",
"label": "position",
"value_type": "geopoint",
"type": "dynamic",
"id": 3,
"template_id": "1"
}
],
"label": "SensorModel",
Expand All @@ -176,6 +185,14 @@ Get the full list of templates with all their associated attributes.
"value_type": "float",
"type": "dynamic",
"id": 1
},
{
"created": "2018-02-27T16:10:23.178557+00:00",
"label": "position",
"value_type": "geopoint",
"type": "dynamic",
"id": 3,
"template_id": "1"
}
],
"id": 1
Expand Down Expand Up @@ -402,6 +419,14 @@ Removes a template. If any device is based on the template being removed, then a
{
"removed": {
"attrs": [
{
"created": "2018-11-20T20:58:28.462464+00:00",
"id": 182,
"label": "position",
"template_id": "4865",
"type": "dynamic",
"value_type": "geopoint"
},
{
"created": "2017-12-27T15:22:13.331950+00:00",
"id": 9,
Expand Down Expand Up @@ -570,7 +595,7 @@ Retrieves all information from a specific device
}


### Get the current list of devices [GET /device{?page_size,page_num,idsOnly,label,attr,sortBy}]
### Get the current list of devices [GET /device{?page_size,page_num,idsOnly,label,attr,attr_type,sortBy}]
Get the full list of devices with all their associated attributes.
Each attribute from *attrs* is the template ID from where the attributes came from.
In this example, there is only one template (ID 1).
Expand All @@ -579,6 +604,7 @@ In this example, there is only one template (ID 1).
+ page_num: 1 (integer, optional)
+ idsOnly: false (booelan, optional) - Return only the ids of all existing devices. Ignores any `page_size` and `page_num` configurations
+ attr: foo=bar (string, optional) - Return only devices that posess a given attribute's value
+ attr_type: geopoint (string, optional) - Return only devices with attributes of a particular type.
+ label: dummy (string, optional) - Return only devices that are named accordingly (prefix or suffix match)
+ sortBy: label (string, optional) - Return entries sorted by given field. Currently only `label` is supported.

Expand Down Expand Up @@ -672,6 +698,14 @@ Get the full list of devices that belong to a given template..
{
"attrs": {
"4865": [
{
"created": "2018-11-20T20:58:29.564672+00:00",
"id": 198,
"label": "position",
"template_id": "668",
"type": "dynamic",
"value_type": "geopoint"
},
{
"label": "temperature",
"type": "dynamic",
Expand Down
5 changes: 5 additions & 0 deletions tests/dredd-hooks/operation_hook.py
Expand Up @@ -30,6 +30,11 @@ def create_sample_template():
"type": "dynamic",
"value_type": "float"
},
{
"label": "position",
"type": "dynamic",
"value_type": "geopoint"
},
{
"label": "model-id",
"type": "static",
Expand Down

0 comments on commit 6086f25

Please sign in to comment.