Issue: Coersion failing because of function type conversion
Author: caelx
State: closed
Created: 2014-04-17 01:25:53

I'm trying to use the mysql function 'INET_ATON' which takes a string representation of an IP address and returns an integer, and the comparing that integer to a integer stored in my database.  The issue is that when I do peewee is trying to coerce the original string input into an integer before executing the query and error'ing out.

Here's a snippet of code that will generate the error:

``` python
from peewee import *

# configure your mysql db here
database = MySQLDatabase(DB, host=DB_HOST, port=DB_PORT, user=DB_USER, passwd=DB_PASSWD)


class BaseModel(Model):
    class Meta:
        database = database


class IP(BaseModel):
    ip = IntegerField()


def main():
    database.connect()
    IP.create_table()

    IP.insert(ip=fn.INET_ATON('8.8.8.8')).execute()

    IP.select().where(IP.ip == fn.INET_ATON('8.8.8.8')).execute()


if __name__ == '__main__':
    main()
```

Is there some way to disable the coersion for functions, I tried to look through the source code but I didn't really see a way.

Error:

```
2014-04-16 15:20:31,358 - peewee - DEBUG - ('INSERT INTO `ip` (`ip`) VALUES (INET_ATON(%s))', ['8.8.8.8'])
Traceback (most recent call last):
  File "snippet.py", line 28, in <module>
    main()
  File "snippet.py", line 24, in main
    IP.select().where(IP.ip == fn.INET_ATON('8.8.8.8')).execute()
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 2036, in execute
    self._qr = ResultWrapper(model_class, self._execute(), query_meta)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1752, in _execute
    sql, params = self.sql()
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 2012, in sql
    return self.compiler().generate_select(self)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1260, in generate_select
    return self.build_query(clauses, alias_map)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1171, in build_query
    return self.parse_node(Clause(*clauses), alias_map)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1135, in parse_node
    sql, params, unknown = self._parse(node, alias_map, conv)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1081, in _parse
    node.nodes, alias_map, conv, node.glue)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1152, in parse_node_list
    node_sql, node_params = self.parse_node(node, alias_map, conv)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1135, in parse_node
    sql, params, unknown = self._parse(node, alias_map, conv)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1067, in _parse
    rhs, rparams = self.parse_node(node.rhs, alias_map, conv)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1135, in parse_node
    sql, params, unknown = self._parse(node, alias_map, conv)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1077, in _parse
    sql, params = self.parse_node_list(node.arguments, alias_map, conv)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1152, in parse_node_list
    node_sql, node_params = self.parse_node(node, alias_map, conv)
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 1137, in parse_node
    params = [conv.db_value(i) for i in params]
  File "/Users/cael/.virtualenvs/sqlgen/lib/python2.7/site-packages/peewee.py", line 579, in db_value
    return value if value is None else self.coerce(value)
ValueError: invalid literal for int() with base 10: '8.8.8.8'
```

Versions:

```
MySQL-python==1.2.3
bottle==0.12.5
dnspython==1.11.1
dnsq==1.1.2
expiringdict==1.1
peewee==2.2.2
wsgiref==0.1.2
```


Unfortunately that code is there for a reason. Consider a field like this:

``` python
class CSVField(CharField):
    def db_value(self, value):
        return ','.join(value)

    def python_value(self, value):
        return value.split(',')
```

This field would be used to store or retrieve lists of data encoded in CSV.

What if you wanted to do a case insensitive search for some particular items? Then we'd want to pass the value to the field's conversion function:

``` python
MyModel.select().where(MyModel.csv_data == fn.LOWER(Param(['item1', 'item2'])))
```

I admit it's a bit of a contrived example, but that was the reasoning behind the conversion.


This is now fixed. In order to avoid coercing the values you would write:

``` python
IP.select().where(IP.ip == fn.INET_ATON('8.8.8.8').coerce(False)).execute()
```


Awesome as usual, thanks!

I understand why you need to do the coercion, I was just looking for an expressive interface for manually disabling it which you have provided perfectly.

I actually tried calling the coerce method with false myself but it didn't do what I hoped it did at that time.