Add support for multiple value filters

The goal of this patch is to introduce support for multi-valued
parameters. For instance, for the `type` parameter, even though the code
was treating it as a possible list of types, the API would not allow a
user to send multiple types.

This patch enables users to send filters with multiple values, which can
be useful for filtering by project_ids for instance, or different types
(metric types).

Change-Id: I59397b33d014709eb976c78d517f009b8a2be4cf
This commit is contained in:
Rafael Weingärtner 2021-03-05 10:52:35 -03:00 committed by Pierre Riteau
parent 6ba9d45ea6
commit 76e98ffd1b
6 changed files with 28 additions and 9 deletions

View File

@ -36,7 +36,7 @@ class Summary(base.BaseResource):
voluptuous.Optional('custom_fields'): api_utils.SingleQueryParam(str),
voluptuous.Optional('groupby'): api_utils.MultiQueryParam(str),
voluptuous.Optional('filters'):
api_utils.SingleDictQueryParam(str, str),
api_utils.MultiDictQueryParam(str, str),
voluptuous.Optional('begin'): api_utils.SingleQueryParam(
tzutils.dt_from_iso),
voluptuous.Optional('end'): api_utils.SingleQueryParam(
@ -68,7 +68,10 @@ class Summary(base.BaseResource):
}
filters['project_id'] = flask.request.context.project_id
metric_types = [filters.pop('type')] if 'type' in filters else None
metric_types = filters.pop('type', [])
if not isinstance(metric_types, list):
metric_types = [metric_types]
arguments = {
'begin': begin,
'end': end,

View File

@ -160,6 +160,12 @@ class InfluxClient(object):
@staticmethod
def _get_filter(key, value):
if isinstance(value, list):
if len(value) == 1:
return InfluxClient._get_filter(key, value[0])
return "(" + " OR ".join('"{}"=\'{}\''.format(key, v)
for v in value) + ")"
format_string = ''
if isinstance(value, str):
format_string = """"{}"='{}'"""
@ -182,9 +188,7 @@ class InfluxClient(object):
def _get_type_query(types):
if not types:
return ''
type_query = ' OR '.join("type='{}'".format(mtype)
for mtype in types)
return ' AND (' + type_query + ')'
return " AND " + InfluxClient._get_filter("type", types)
def get_total(self, types, begin, end, custom_fields,
groupby=None, filters=None):
@ -209,6 +213,8 @@ class InfluxClient(object):
query += ' GROUP BY ' + groupby_query
query += ';'
LOG.debug("Executing query [%s].", query)
total = self._conn.query(query)
LOG.debug(
"Data [%s] received when executing query [%s].", total, query)

View File

@ -47,7 +47,7 @@ class TestSummaryEndpoint(tests.TestCase):
begin=tzutils.get_month_start(),
end=tzutils.get_next_month(),
groupby=None,
filters={'a': 'b'},
filters={'a': ['b']},
metric_types=['awesome'],
offset=0,
limit=100,

View File

@ -150,11 +150,11 @@ class TestInfluxClient(unittest.TestCase):
"SELECT COUNT(groupby) FROM \"dataframes\""
" WHERE time >= '{0}'"
" AND time < '{1}'"
" AND (type='foo' OR type='bar');"
" AND (\"type\"='foo' OR \"type\"='bar');"
"SELECT * FROM \"dataframes\""
" WHERE time >= '{0}'"
" AND time < '{1}'"
" AND (type='foo' OR type='bar')"
" AND (\"type\"='foo' OR \"type\"='bar')"
" LIMIT 1000 OFFSET 0;".format(
self.period_begin, self.period_end,
))

View File

@ -39,7 +39,13 @@ end: &end
filters:
in: query
description: |
Optional filters.
Optional filters. These filters accept multiple query parameters. To use
this option with multiple parameters, repeat it as many time as desired in
the query string. For instance, to restrict the result to only two
projects, add to the query string
``filters=project_id:<project_id_one>&filters=project_id:<project_id_two>``.
Bear in mind that this string must be URL escaped. Therefore, it becomes
``filters=project_id%3A<project_id_one>&filters=project_id%3A<project_id_two>``.
type: dict
required: false

View File

@ -0,0 +1,4 @@
---
features:
- |
Add support for multiple value filters in the summary GET V2 API.