Skip to content

Commit

Permalink
Changing semantics of when values are coerced.
Browse files Browse the repository at this point in the history
  • Loading branch information
coleifer committed Feb 7, 2014
1 parent 89e3326 commit 6c70632
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 10 deletions.
31 changes: 21 additions & 10 deletions peewee.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,17 @@ class Func(Node):
def __init__(self, name, *arguments):
self.name = name
self.arguments = arguments
self._coerce = True
super(Func, self).__init__()

@returns_clone
def coerce(self, coerce=True):
self._coerce = coerce

def clone_base(self):
return Func(self.name, *self.arguments)
res = Func(self.name, *self.arguments)
res._coerce = self._coerce
return res

def over(self, partition_by=None, order_by=None):
# Basic window function support.
Expand Down Expand Up @@ -1427,21 +1434,25 @@ def initialize(self, description):
for i in range(len(description)):
func = identity
column = description[i][0]
if column in model._meta.columns:
field_obj = model._meta.columns[column]
column = field_obj.name
func = field_obj.python_value
elif self.column_meta is not None:
found = False
if self.column_meta is not None:
select_column = self.column_meta[i]
if isinstance(select_column, Field):
func = select_column.python_value
column = select_column._alias or select_column.name
found = True
elif (isinstance(select_column, Func) and
isinstance(select_column.arguments[0], Field)):
# Special-case handling aggregations.
func = select_column.arguments[0].python_value
else:
func = identity
if select_column._coerce:
# Special-case handling aggregations.
func = select_column.arguments[0].python_value
found = True

if not found and column in model._meta.columns:
field_obj = model._meta.columns[column]
column = field_obj.name
func = field_obj.python_value

conv.append((i, column, func))
self.conv = conv

Expand Down
77 changes: 77 additions & 0 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,15 @@ class Snippet(TestModel):

SnippetProxy.initialize(Snippet)

class _UpperField(CharField):
def python_value(self, value):
return value.upper() if value else value

class UpperUser(TestModel):
username = _UpperField()
class Meta:
db_table = User._meta.db_table


MODELS = [
User,
Expand Down Expand Up @@ -1509,6 +1518,74 @@ def test_prepared(self):
self.assertEqual(b.user.foo, b.user.username)


class QueryResultCoerceTestCase(ModelTestCase):
requires = [User]

def setUp(self):
super(QueryResultCoerceTestCase, self).setUp()
for i in range(3):
User.create(username='u%d' % i)

def assertNames(self, query, expected, attr='username'):
id_field = query.model_class.id
self.assertEqual(
[getattr(item, attr) for item in query.order_by(id_field)],
expected)

def test_simple_select(self):
query = UpperUser.select()
self.assertNames(query, ['U0', 'U1', 'U2'])

query = User.select()
self.assertNames(query, ['u0', 'u1', 'u2'])

def test_with_alias(self):
# Even when aliased to a different attr, the column is coerced.
query = UpperUser.select(UpperUser.username.alias('foo'))
self.assertNames(query, ['U0', 'U1', 'U2'], 'foo')

def test_scalar(self):
max_username = (UpperUser
.select(fn.Max(UpperUser.username))
.scalar(convert=True))
self.assertEqual(max_username, 'U2')

max_username = (UpperUser
.select(fn.Max(UpperUser.username))
.scalar())
self.assertEqual(max_username, 'u2')

def test_function(self):
substr = fn.SubStr(UpperUser.username, 1, 3)

# Being the first parameter of the function, it meets the special-case
# criteria.
query = UpperUser.select(substr.alias('foo'))
self.assertNames(query, ['U0', 'U1', 'U2'], 'foo')

query = UpperUser.select(substr.coerce(False).alias('foo'))
self.assertNames(query, ['u0', 'u1', 'u2'], 'foo')

query = UpperUser.select(substr.coerce(False).alias('username'))
self.assertNames(query, ['u0', 'u1', 'u2'])

query = UpperUser.select(fn.Lower(UpperUser.username).alias('username'))
self.assertNames(query, ['U0', 'U1', 'U2'])

query = UpperUser.select(
fn.Lower(UpperUser.username).alias('username').coerce(False))
self.assertNames(query, ['u0', 'u1', 'u2'])

# Since it is aliased to an existing column, we will use that column's
# coerce.
query = UpperUser.select(
fn.SubStr(fn.Lower(UpperUser.username), 1, 3).alias('username'))
self.assertNames(query, ['U0', 'U1', 'U2'])

query = UpperUser.select(
fn.SubStr(fn.Lower(UpperUser.username), 1, 3).alias('foo'))
self.assertNames(query, ['u0', 'u1', 'u2'], 'foo')

class ModelQueryResultWrapperTestCase(ModelTestCase):
requires = [TestModelA, TestModelB, TestModelC, User, Blog]

Expand Down

0 comments on commit 6c70632

Please sign in to comment.