Commits

Mike Bayer  committed 654c15e

- Added func.min(), func.max(), func.sum() as "generic functions",
which basically allows for their return type to be determined
automatically. Helps with dates on SQLite, decimal types,
others. [ticket:1160]

- added decimal.Decimal as an "auto-detect" type; bind parameters
and generic functions will set their type to Numeric when a
Decimal is used.

  • Participants
  • Parent commits 658320d

Comments (0)

Files changed (4)

       [ticket:1068].  This feature is on hold pending further
       development.
 
+    - Added func.min(), func.max(), func.sum() as "generic functions",
+      which basically allows for their return type to be determined
+      automatically.  Helps with dates on SQLite, decimal types, 
+      others. [ticket:1160]
+    
+    - added decimal.Decimal as an "auto-detect" type; bind parameters
+      and generic functions will set their type to Numeric when a 
+      Decimal is used.
+      
 - mysql
     - The 'length' argument to MSInteger, MSBigInteger, MSTinyInteger,
       MSSmallInteger and MSYear has been renamed to 'display_width'.

File lib/sqlalchemy/sql/functions.py

     def __init__(self, **kwargs):
         GenericFunction.__init__(self, **kwargs)
 
-
-class coalesce(GenericFunction):
+class ReturnTypeFromArgs(GenericFunction):
+    """Define a function whose return type is the same as its arguments."""
+    
     def __init__(self, *args, **kwargs):
         kwargs.setdefault('type_', _type_from_args(args))
         GenericFunction.__init__(self, args=args, **kwargs)
 
+class coalesce(ReturnTypeFromArgs):
+    pass
+
+class max(ReturnTypeFromArgs):
+    pass
+
+class min(ReturnTypeFromArgs):
+    pass
+
+class sum(ReturnTypeFromArgs):
+    pass
+
 class now(GenericFunction):
     __return_type__ = sqltypes.DateTime
 

File lib/sqlalchemy/types.py

     unicode : NCHAR,
     int : Integer,
     float : Numeric,
+    _python_Decimal : Numeric,
     dt.date : Date,
     dt.datetime : DateTime,
     dt.time : Time,

File test/sql/functions.py

 from testlib import *
 from sqlalchemy.sql.functions import GenericFunction
 from testlib.testing import eq_
+from decimal import Decimal as _python_Decimal
 
 from sqlalchemy.databases import *
 
         except TypeError:
             assert True
 
-    def test_typing(self):
-        assert isinstance(func.coalesce(datetime.date(2007, 10, 5), datetime.date(2005, 10, 15)).type, sqltypes.Date)
+    def test_return_type_detection(self):
+        
+        for fn in [func.coalesce, func.max, func.min, func.sum]:
+            for args, type_ in [
+                            ((datetime.date(2007, 10, 5), datetime.date(2005, 10, 15)), sqltypes.Date),
+                            ((3, 5), sqltypes.Integer),
+                            ((_python_Decimal(3), _python_Decimal(5)), sqltypes.Numeric),
+                            (("foo", "bar"), sqltypes.String),
+                            ((datetime.datetime(2007, 10, 5, 8, 3, 34), datetime.datetime(2005, 10, 15, 14, 45, 33)), sqltypes.DateTime)
+                        ]:
+                assert isinstance(fn(*args).type, type_), "%s / %s" % (fn(), type_)
+        
+        assert isinstance(func.concat("foo", "bar").type, sqltypes.String)
 
-        assert isinstance(func.coalesce(None, datetime.date(2005, 10, 15)).type, sqltypes.Date)
-
-        assert isinstance(func.concat("foo", "bar").type, sqltypes.String)
 
     def test_assorted(self):
         table1 = table('mytable',