Merge "Move filter_limit_query out of sql.Base"

This commit is contained in:
Jenkins
2014-02-20 03:24:19 +00:00
committed by Gerrit Code Review
4 changed files with 137 additions and 131 deletions

View File

@@ -213,7 +213,7 @@ class Assignment(sql.Base, assignment.Driver):
def list_projects(self, hints):
with sql.transaction() as session:
query = session.query(Project)
project_refs = self.filter_limit_query(Project, query, hints)
project_refs = sql.filter_limit_query(Project, query, hints)
return [project_ref.to_dict() for project_ref in project_refs]
def list_projects_in_domain(self, domain_id):
@@ -386,7 +386,7 @@ class Assignment(sql.Base, assignment.Driver):
def list_domains(self, hints):
with sql.transaction() as session:
query = session.query(Domain)
refs = self.filter_limit_query(Domain, query, hints)
refs = sql.filter_limit_query(Domain, query, hints)
return [ref.to_dict() for ref in refs]
def _get_domain(self, session, domain_id):
@@ -447,7 +447,7 @@ class Assignment(sql.Base, assignment.Driver):
def list_roles(self, hints):
with sql.transaction() as session:
query = session.query(Role)
refs = self.filter_limit_query(Role, query, hints)
refs = sql.filter_limit_query(Role, query, hints)
return [ref.to_dict() for ref in refs]
def _get_role(self, session, role_id):

View File

@@ -158,7 +158,7 @@ class Catalog(sql.Base, catalog.Driver):
def list_services(self, hints):
session = db_session.get_session()
services = session.query(Service)
services = self.filter_limit_query(Service, services, hints)
services = sql.filter_limit_query(Service, services, hints)
return [s.to_dict() for s in list(services)]
def _get_service(self, session, service_id):
@@ -227,7 +227,7 @@ class Catalog(sql.Base, catalog.Driver):
def list_endpoints(self, hints):
session = db_session.get_session()
endpoints = session.query(Endpoint)
endpoints = self.filter_limit_query(Endpoint, endpoints, hints)
endpoints = sql.filter_limit_query(Endpoint, endpoints, hints)
return [e.to_dict() for e in list(endpoints)]
def update_endpoint(self, endpoint_id, endpoint_ref):

View File

@@ -211,146 +211,152 @@ def truncated(f):
# Backends
class Base(object):
def _filter(self, model, query, hints):
"""Applies filtering to a query.
# TODO(blk-u): remove this class since doesn't do anything.
pass
def _filter(model, query, hints):
"""Applies filtering to a query.
:param model: the table model in question
:param query: query to apply filters to
:param hints: contains the list of filters yet to be satisfied.
Any filters satisfied here will be removed so that
the caller will know if any filters remain.
:returns query: query, updated with any filters satisfied
"""
def inexact_filter(model, query, filter_, hints):
"""Applies an inexact filter to a query.
:param model: the table model in question
:param query: query to apply filters to
:param filter_: the dict that describes this filter
:param hints: contains the list of filters yet to be satisfied.
Any filters satisfied here will be removed so that
the caller will know if any filters remain.
:returns query: query, updated with any filters satisfied
:returns query: query updated to add any inexact filters we could
satisfy
"""
def inexact_filter(model, query, filter_, hints):
"""Applies an inexact filter to a query.
column_attr = getattr(model, filter_['name'])
:param model: the table model in question
:param query: query to apply filters to
:param filter_: the dict that describes this filter
:param hints: contains the list of filters yet to be satisfied.
Any filters satisfied here will be removed so that
the caller will know if any filters remain.
# TODO(henry-nash): Sqlalchemy 0.7 defaults to case insensitivity
# so once we find a way of changing that (maybe on a call-by-call
# basis), we can add support for the case sensitive versions of
# the filters below. For now, these case sensitive versions will
# be handled at the controller level.
:returns query: query updated to add any inexact filters we could
satisfy
"""
column_attr = getattr(model, filter_['name'])
# TODO(henry-nash): Sqlalchemy 0.7 defaults to case insensitivity
# so once we find a way of changing that (maybe on a call-by-call
# basis), we can add support for the case sensitive versions of
# the filters below. For now, these case sensitive versions will
# be handled at the controller level.
if filter_['case_sensitive']:
return query
if filter_['comparator'] == 'contains':
query_term = column_attr.ilike('%%%s%%' % filter_['value'])
elif filter_['comparator'] == 'startswith':
query_term = column_attr.ilike('%s%%' % filter_['value'])
elif filter_['comparator'] == 'endswith':
query_term = column_attr.ilike('%%%s' % filter_['value'])
else:
# It's a filter we don't understand, so let the caller
# work out if they need to do something with it.
return query
hints.remove(filter_)
return query.filter(query_term)
def exact_filter(model, filter_, cumulative_filter_dict, hints):
"""Applies an exact filter to a query.
:param model: the table model in question
:param filter_: the dict that describes this filter
:param cumulative_filter_dict: a dict that describes the set of
exact filters built up so far
:param hints: contains the list of filters yet to be satisfied.
Any filters satisfied here will be removed so that
the caller will know if any filters remain.
:returns: updated cumulative dict
"""
key = filter_['name']
if isinstance(getattr(model, key).property.columns[0].type,
sql.types.Boolean):
cumulative_filter_dict[key] = (
utils.attr_as_boolean(filter_['value']))
else:
cumulative_filter_dict[key] = filter_['value']
hints.remove(filter_)
return cumulative_filter_dict
filter_dict = {}
for filter_ in hints.filters():
# TODO(henry-nash): Check if name is valid column, if not skip
if filter_['comparator'] == 'equals':
filter_dict = exact_filter(model, filter_, filter_dict, hints)
else:
query = inexact_filter(model, query, filter_, hints)
# Apply any exact filters we built up
if filter_dict:
query = query.filter_by(**filter_dict)
return query
def _limit(self, query, hints):
"""Applies a limit to a query.
:param query: query to apply filters to
:param hints: contains the list of filters and limit details.
:returns updated query
"""
# NOTE(henry-nash): If we were to implement pagination, then we
# we would expand this method to support pagination and limiting.
# If we satisfied all the filters, set an upper limit if supplied
list_limit = hints.get_limit()
if list_limit:
query = query.limit(list_limit['limit'])
return query
def filter_limit_query(self, model, query, hints):
"""Applies filtering and limit to a query.
:param model: table model
:param query: query to apply filters to
:param hints: contains the list of filters and limit details. This may
be None, indicating that there are no filters or limits
to be applied. If it's not None, then any filters
satisfied here will be removed so that the caller will
know if any filters remain.
:returns: updated query
"""
if hints is None:
if filter_['case_sensitive']:
return query
# First try and satisfy any filters
query = self._filter(model, query, hints)
# NOTE(henry-nash): Any unsatisfied filters will have been left in
# the hints list for the controller to handle. We can only try and
# limit here if all the filters are already satisfied since, if not,
# doing so might mess up the final results. If there are still
# unsatisfied filters, we have to leave any limiting to the controller
# as well.
if not hints.filters():
return self._limit(query, hints)
if filter_['comparator'] == 'contains':
query_term = column_attr.ilike('%%%s%%' % filter_['value'])
elif filter_['comparator'] == 'startswith':
query_term = column_attr.ilike('%s%%' % filter_['value'])
elif filter_['comparator'] == 'endswith':
query_term = column_attr.ilike('%%%s' % filter_['value'])
else:
# It's a filter we don't understand, so let the caller
# work out if they need to do something with it.
return query
hints.remove(filter_)
return query.filter(query_term)
def exact_filter(model, filter_, cumulative_filter_dict, hints):
"""Applies an exact filter to a query.
:param model: the table model in question
:param filter_: the dict that describes this filter
:param cumulative_filter_dict: a dict that describes the set of
exact filters built up so far
:param hints: contains the list of filters yet to be satisfied.
Any filters satisfied here will be removed so that
the caller will know if any filters remain.
:returns: updated cumulative dict
"""
key = filter_['name']
if isinstance(getattr(model, key).property.columns[0].type,
sql.types.Boolean):
cumulative_filter_dict[key] = (
utils.attr_as_boolean(filter_['value']))
else:
cumulative_filter_dict[key] = filter_['value']
hints.remove(filter_)
return cumulative_filter_dict
filter_dict = {}
for filter_ in hints.filters():
# TODO(henry-nash): Check if name is valid column, if not skip
if filter_['comparator'] == 'equals':
filter_dict = exact_filter(model, filter_, filter_dict, hints)
else:
query = inexact_filter(model, query, filter_, hints)
# Apply any exact filters we built up
if filter_dict:
query = query.filter_by(**filter_dict)
return query
def _limit(query, hints):
"""Applies a limit to a query.
:param query: query to apply filters to
:param hints: contains the list of filters and limit details.
:returns updated query
"""
# NOTE(henry-nash): If we were to implement pagination, then we
# we would expand this method to support pagination and limiting.
# If we satisfied all the filters, set an upper limit if supplied
list_limit = hints.get_limit()
if list_limit:
query = query.limit(list_limit['limit'])
return query
def filter_limit_query(model, query, hints):
"""Applies filtering and limit to a query.
:param model: table model
:param query: query to apply filters to
:param hints: contains the list of filters and limit details. This may
be None, indicating that there are no filters or limits
to be applied. If it's not None, then any filters
satisfied here will be removed so that the caller will
know if any filters remain.
:returns: updated query
"""
if hints is None:
return query
# First try and satisfy any filters
query = _filter(model, query, hints)
# NOTE(henry-nash): Any unsatisfied filters will have been left in
# the hints list for the controller to handle. We can only try and
# limit here if all the filters are already satisfied since, if not,
# doing so might mess up the final results. If there are still
# unsatisfied filters, we have to leave any limiting to the controller
# as well.
if not hints.filters():
return _limit(query, hints)
else:
return query
def handle_conflicts(conflict_type='object'):
"""Converts select sqlalchemy exceptions into HTTP 409 Conflict."""

View File

@@ -128,7 +128,7 @@ class Identity(sql.Base, identity.Driver):
def list_users(self, hints):
session = db_session.get_session()
query = session.query(User)
user_refs = self.filter_limit_query(User, query, hints)
user_refs = sql.filter_limit_query(User, query, hints)
return [identity.filter_user(x.to_dict()) for x in user_refs]
def _get_user(self, session, user_id):
@@ -261,7 +261,7 @@ class Identity(sql.Base, identity.Driver):
def list_groups(self, hints):
session = db_session.get_session()
query = session.query(Group)
refs = self.filter_limit_query(Group, query, hints)
refs = sql.filter_limit_query(Group, query, hints)
return [ref.to_dict() for ref in refs]
def _get_group(self, session, group_id):