Allow filtering on all table columns

This commit is contained in:
mprahl
2017-11-27 14:32:32 -05:00
parent 6c8fad0338
commit 53dc444214
3 changed files with 83 additions and 36 deletions

View File

@@ -492,29 +492,27 @@ parameters::
Filtering module builds
-----------------------
The module-builds can be filtered by a variety of GET parameters. These
parameters are:
The module builds can be filtered by a variety of GET parameters. Some of these
parameters include:
- ``name`` - Shows builds of modules with a particular name (e.g.
``name=testmodule``)
- ``koji_tag`` - Shows builds tagged with a particular Koji tag (e.g.
``koji_tag=module-984ed60dd37b9361``)
- ``owner`` - Shows builds submitted by a particular user (e.g.
``owner=mprahl``)
- ``state`` - Shows builds in a particular state (can be the state name or
the state ID) (e.g. ``state=done``)
- ``submitted_before`` - Shows builds that were submitted before a particular
Zulu ISO 8601 timestamp (e.g. ``submitted_before=2016-08-23T09:40:07Z``)
- ``submitted_after`` - Shows builds that were submitted after a particular
Zulu ISO 8601 timestamp (e.g. ``submitted_after=2016-08-22T09:40:07Z``)
- ``modified_before`` - Shows builds that were modified before a particular
Zulu ISO 8601 timestamp (e.g. ``modified_before=2016-08-23T09:40:07Z``)
- ``modified_after`` - Shows builds that were modified after a particular
Zulu ISO 8601 timestamp (e.g. ``modified_after=2016-08-22T09:40:07Z``)
- ``completed_before`` - Shows builds that were completed before a particular
Zulu ISO 8601 timestamp (e.g. ``completed_before=2016-08-22T09:40:07Z``)
- ``completed_after`` - Shows builds that were completed after a particular
Zulu ISO 8601 timestamp (e.g. ``completed_after=2016-08-23T09:40:07Z``)
- ``batch``
- ``cg_build_koji_tag``
- ``completed_after`` (Zulu ISO 8601 format e.g. ``completed_after=2016-08-23T09:40:07Z``)
- ``completed_before`` (Zulu ISO 8601 format e.g. ``completed_before=2016-08-22T09:40:07Z``)
- ``koji_tag``
- ``modified_after`` (Zulu ISO 8601 format e.g. ``modified_after=2016-08-22T09:40:07Z``)
- ``modified_before`` (Zulu ISO 8601 format e.g. ``modified_before=2016-08-23T09:40:07Z``)
- ``name``
- ``new_repo_task_id``
- ``owner``
- ``rebuild_strategy``
- ``scmurl``
- ``state`` (can be the state name or the state ID e.g. ``state=done``)
- ``state_reason``
- ``stream``
- ``submitted_after`` (Zulu ISO 8601 format e.g. ``submitted_after=2016-08-22T09:40:07Z``)
- ``submitted_before`` (Zulu ISO 8601 format e.g. ``submitted_before=2016-08-23T09:40:07Z``)
- ``version``
An example of querying the "module-builds" resource with the "state",
and the "submitted_before" parameters::
@@ -658,6 +656,28 @@ parameters::
}
Filtering component builds
--------------------------
The component builds can be filtered by a variety of GET parameters. Some of these
parameters include:
- ``batch``
- ``build_time_only`` (boolean e.g. "true" or "false")
- ``format``
- ``module_id`` or ``module_build``
- ``nvr``
- ``package``
- ``ref``
- ``scmurl``
- ``state``
- ``state_reason``
- ``tagged`` (boolean e.g. "true" or "false")
- ``tagged_in_final`` (boolean e.g. "true" or "false")
- ``task_id``
Listing about
-------------

View File

@@ -39,6 +39,7 @@ import yaml
from flask import request, url_for, Response
from datetime import datetime
from sqlalchemy.sql.sqltypes import Boolean as sqlalchemy_boolean
from module_build_service import log, models
from module_build_service.errors import (ValidationError, UnprocessableEntity,
@@ -436,6 +437,15 @@ def _add_order_by_clause(flask_request, query, column_source):
return query.order_by(column)
def str_to_bool(value):
"""
Parses a string to determine its boolean value
:param value: a string
:return: a boolean
"""
return value.lower() in ["true", "1"]
def filter_component_builds(flask_request):
"""
Returns a flask_sqlalchemy.Pagination object based on the request parameters
@@ -443,8 +453,15 @@ def filter_component_builds(flask_request):
:return: flask_sqlalchemy.Pagination
"""
search_query = dict()
state = flask_request.args.get('state', None)
for key in request.args.keys():
# Only filter on valid database columns
if key in models.ComponentBuild.__table__.columns.keys():
if isinstance(models.ComponentBuild.__table__.columns[key].type, sqlalchemy_boolean):
search_query[key] = str_to_bool(flask_request.args[key])
else:
search_query[key] = flask_request.args[key]
state = flask_request.args.get('state', None)
if state:
if state.isdigit():
search_query['state'] = state
@@ -454,11 +471,9 @@ def filter_component_builds(flask_request):
else:
raise ValidationError('An invalid state was supplied')
# Lookup module_build from task_id, ref, format, nvr or tagged attribute
# of a component build.
for key in ['task_id', 'ref', 'nvr', 'format', 'tagged']:
if flask_request.args.get(key, None):
search_query[key] = flask_request.args[key]
# Allow the user to specify the module build ID with a more intuitive key name
if 'module_build' in flask_request.args:
search_query['module_id'] = flask_request.args['module_build']
query = models.ComponentBuild.query
@@ -479,8 +494,14 @@ def filter_module_builds(flask_request):
:return: flask_sqlalchemy.Pagination
"""
search_query = dict()
state = flask_request.args.get('state', None)
special_columns = ['time_submitted', 'time_modified', 'time_completed', 'state']
for key in request.args.keys():
# Only filter on valid database columns but skip columns that are treated specially or
# ignored
if key not in special_columns and key in models.ModuleBuild.__table__.columns.keys():
search_query[key] = flask_request.args[key]
state = flask_request.args.get('state', None)
if state:
if state.isdigit():
search_query['state'] = state
@@ -490,10 +511,6 @@ def filter_module_builds(flask_request):
else:
raise ValidationError('An invalid state was supplied')
for key in ['name', 'owner', 'koji_tag']:
if flask_request.args.get(key, None):
search_query[key] = flask_request.args[key]
query = models.ModuleBuild.query
if search_query:

View File

@@ -365,10 +365,9 @@ class TestViews(unittest.TestCase):
self.assertEquals(data['meta']['total'], 0)
def test_query_component_builds_filter_tagged(self):
rv = self.client.get('/module-build-service/1/component-builds/'
'?tagged=this-filter-query-should-return-zero-items')
rv = self.client.get('/module-build-service/1/component-builds/?tagged=true')
data = json.loads(rv.data)
self.assertEquals(data['meta']['total'], 0)
self.assertEquals(data['meta']['total'], 40)
def test_query_component_builds_filter_nvr(self):
rv = self.client.get(
@@ -446,6 +445,17 @@ class TestViews(unittest.TestCase):
data = json.loads(rv.data)
self.assertEquals(data['meta']['total'], 4)
def test_query_builds_filter_nsv(self):
rv = self.client.get(
'/module-build-service/1/module-builds/?name=postgressql&stream=1&version=2')
data = json.loads(rv.data)
# TODO: The nsv should really be unique in the test data
for item in data['items']:
self.assertEqual(item['name'], 'postgressql')
self.assertEqual(item['stream'], '1')
self.assertEqual(item['version'], '2')
self.assertEquals(data['meta']['total'], 10)
def test_query_builds_filter_invalid_date(self):
rv = self.client.get(
'/module-build-service/1/module-builds/?modified_after=2016-09-03T12:25:00-05:00')