Skip to content

Commit

Permalink
Resolve datetime strings to datetime objects as required by ORM.
Browse files Browse the repository at this point in the history
Also delves into relations to resolve date strings.
  • Loading branch information
doobeh authored and jfinkels committed Feb 18, 2015
1 parent b736d28 commit 62cfcea
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
6 changes: 5 additions & 1 deletion flask_restless/helpers.py
Expand Up @@ -562,7 +562,11 @@ def strings_to_dates(model, dictionary):
elif value in CURRENT_TIME_MARKERS:
result[fieldname] = getattr(func, value.lower())()
else:
result[fieldname] = parse_datetime(value)
fieldtype = get_field_type(model, fieldname)
if isinstance(fieldtype, Date):
result[fieldname] = parse_datetime(value).date()
else:
result[fieldname] = parse_datetime(value)
elif (is_interval_field(model, fieldname) and value is not None
and isinstance(value, int)):
result[fieldname] = datetime.timedelta(seconds=value)
Expand Down
28 changes: 28 additions & 0 deletions flask_restless/views.py
Expand Up @@ -43,6 +43,8 @@
from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm.query import Query
from sqlalchemy.orm.attributes import InstrumentedAttribute
from sqlalchemy.ext.associationproxy import AssociationProxy
from werkzeug.exceptions import BadRequest
from werkzeug.exceptions import HTTPException
from werkzeug.urls import url_quote_plus
Expand All @@ -63,6 +65,7 @@
from .helpers import strings_to_dates
from .helpers import to_dict
from .helpers import upper_keys
from .helpers import get_related_association_proxy_model
from .search import create_query
from .search import search

Expand Down Expand Up @@ -1139,6 +1142,31 @@ def _search(self):
for preprocessor in self.preprocessors['GET_MANY']:
preprocessor(search_params=search_params)

# resolve date-strings as required by the model
for param in search_params.get('filters', list()):
if 'name' in param and 'val' in param:
query_model = self.model
query_field = param['name']

if '__' in param['name']:
fieldname, relation = param['name'].split('__')
submodel = getattr(self.model, fieldname)
if isinstance(submodel, InstrumentedAttribute):
query_model = submodel.property.mapper.class_
query_field = relation
elif isinstance(submodel, AssociationProxy):
query_model = get_related_association_proxy_model(submodel)
query_field = relation
try:
result = strings_to_dates(
query_model,
{query_field: param['val']}
)
param['val'] = result.get(query_field)
except ValueError as exception:
current_app.logger.exception(str(exception))
return dict(message='Unable to construct query'), 400

# perform a filtered search
try:
result = search(self.session, self.model, search_params)
Expand Down
30 changes: 30 additions & 0 deletions tests/test_views.py
Expand Up @@ -1878,6 +1878,36 @@ def test_search2(self):
assert resp.status_code == 400
assert loads(resp.data)['message'] == 'Multiple results found'

def test_search_dates(self):
"""Test date parsing"""
# Lincoln has been allocated a birthday of 1900-01-02.
# We'll ask for dates in a variety of formats, including invalid ones.
search = {
'single': True,
'filters': [{'name': 'birth_date', 'op': 'eq'}]
}

# 1900-01-02
search['filters'][0]['val'] = '1900-01-02'
resp = self.app.search('/api/person', dumps(search))
assert loads(resp.data)['name'] == u'Lincoln'

# 2nd Jan 1900
search['filters'][0]['val'] = '2nd Jan 1900'
resp = self.app.search('/api/person', dumps(search))
assert loads(resp.data)['name'] == u'Lincoln'

# Invalid Date
search['filters'][0]['val'] = 'REALLY-BAD-DATE'
resp = self.app.search('/api/person', dumps(search))
assert resp.status_code == 400

# DateTime
# This will be cropped to a date, since birth_date is a Date column
search['filters'][0]['val'] = '2nd Jan 1900 14:35'
resp = self.app.search('/api/person', dumps(search))
assert loads(resp.data)['name'] == u'Lincoln'

def test_search_boolean_formula(self):
"""Tests for Boolean formulas of filters in a search query."""
# This searches for people whose name is John, or people older than age
Expand Down

0 comments on commit 62cfcea

Please sign in to comment.