On Sep 4, 2012, at 7:02 AM, David McKeone wrote:

> I've been using hybrid properties recently and ran into a solution that would 
> only work on PostgreSQL.  That's fine for my usage, but it's so ugly I was 
> curious if there was a better, more portable way to do this.
> 
> Here is the scenario: x minutes before a given date things can happen in my 
> program.  This is used for things like notifications and things where storing 
> the actual date is more onerous than storing the delta itself.  Here is some 
> code to give an idea (note that this is simplified example and 
> self.minutes_before could actually come from a different table, so saving the 
> calculated date would be impractical)
> 
> @hybrid_property
> def notify_date(self)
>     return self.date - timedelta(minutes=self.minutes_before)
> 
> @notify_date.expression
> def notify_date(cls)
>     return cls.date - cast(cast(cls.minutes_before, Unicode) + ' minutes', 
> Interval)
> 
> So that last part is attempting to mimic this in PostgreSQL:
> 
> SELECT date - (minutes_before::varchar || ' minutes')::interval FROM my_table
> 
> So that's it.  Anyone aware of a better way to accomplish this?  Is there 
> something in SQLAlchemy that would do something similar to timedelta?  
> Something like sqlalchemy.interval(minutes=cls.minutes_before) that can use 
> attributes as well as literals and can translate between databases?

I've had to deal with exactly this issue, and the solution is to build up 
custom @compiles constructs against the target databases you need.   Ideally it 
would be nice if SQLAlchemy had a suite of portable date arithmetic included, 
but this is a hard problem with a lot of tradeoffs on different backends.   
Here's code I've been using to get the interval between two dates that works on 
Postgresql and MSSQL.   You'd need to adapt this to the date arithmetic and 
backends you're looking for:

from sqlalchemy.sql import expression
from sqlalchemy import Integer
from sqlalchemy.ext.compiler import compiles

class date_diff(expression.FunctionElement):
    type = Integer()
    name = 'age'

@compiles(date_diff, 'postgresql')
def _pg_date_diff(element, compiler, **kw):
    # this is using the same method as SQL Server
    return "(%s::date - %s::date)" % (
        compiler.process(element.clauses.clauses[1]),
        compiler.process(element.clauses.clauses[0]),
    )

@compiles(date_diff, 'mssql')
def _ms_date_diff(element, compiler, **kw):
    return "DATEDIFF(day, %s, %s)" % (
            compiler.process(element.clauses.clauses[0], **kw),
            compiler.process(element.clauses.clauses[1], **kw),
        )


from sqlalchemy.dialects import mssql, postgresql

import datetime

expr = date_diff(datetime.date(2012, 4, 18), datetime.date(2012, 5, 20))

print expr.compile(dialect=mssql.dialect())
print expr.compile(dialect=postgresql.dialect())



> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To view this discussion on the web visit 
> https://groups.google.com/d/msg/sqlalchemy/-/myAFyaY-m4EJ.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to