On Wed, Oct 6, 2010 at 9:06 AM, Michael Bayer <mik...@zzzcomputing.com> wrote:
> SQlite has no lossless DECIMAL type and SQLAlchemy can't work around that.
Well SQLAlchemy itself suggests workarounds that it doesn't implement,
so here we are...
> The approaches to working around this are:
> 1. store the decimals as strings. Use String, and place a TypeDecorator
> around it which marshals Decimal objects.
Is it as simple as this?
"""
class DecimalString(sqlalchemy.types.TypeDecorator):
impl = sqlalchemy.types.String
def process_bind_param(self, value, dialect):
return str(value)
def process_result_value(self, value, dialect):
return decimal.Decimal(value)
"""
> 2. store the decimals as integers, using a type with a fixed exponent. Use
> Integer, and place a TypeDecorator around it which multiplies Decimal
> objects upwards by the fixed exponent going in and back down going out.
Is it as simple as this?
"""
class DecimalInt(sqlalchemy.types.TypeDecorator):
impl = sqlalchemy.types.Integer
def process_bind_param(self, value, dialect):
return int(value * 10**4) # basis pt precision
def process_result_value(self, value, dialect):
return decimal.Decimal(value / 10**4) # basis pt precision
"""
> 3. stick with the FP program.
Who actually desires this behavior? I'm not trying to flame here, I
am genuinely curious why that is the preferred default for SQLite.
One more question, if I may. I suppose what would be ideal would be
to create a type that wrapped a String or Integer if the dialect was
sqlite, but wrapped a Numeric type if the dialect was something a
little more full-fledged. Possible/difficult/ill-advised to do within
the SQLAlchemy type system?
Well, despite raising the ominous specter of accounting identity
violations, so far I'm really liking the looks of SQLAlchemy. Thanks
for the help.
cursory glance, sure
>
>> 3. stick with the FP program.
>
> Who actually desires this behavior? I'm not trying to flame here, I
> am genuinely curious why that is the preferred default for SQLite.
if you're using the same table metadata with another database, and you'd like to do some non-critical tests using SQLite, or you just want Decimal objects back and didn't want to say Float(as_decimal=True)
>
> One more question, if I may. I suppose what would be ideal would be
> to create a type that wrapped a String or Integer if the dialect was
> sqlite, but wrapped a Numeric type if the dialect was something a
> little more full-fledged. Possible/difficult/ill-advised to do within
> the SQLAlchemy type system?
Well such a type wouldn't be backend agnostic. The String/Integer wrapped one would act very differently than a Numeric. So not much point in a transparent switch like that. We try to keep "switches" like that to a minimum (there are some, like Enum).
[...]
2. store the decimals as integers, using a type with a fixed exponent. Use Integer, and place a TypeDecorator around it which multiplies Decimal objects upwards by the fixed exponent going in and back down going out.Is it as simple as this? """ class DecimalInt(sqlalchemy.types.TypeDecorator): impl = sqlalchemy.types.Integer def process_bind_param(self, value, dialect): return int(value * 10**4) # basis pt precision def process_result_value(self, value, dialect): return decimal.Decimal(value / 10**4) # basis pt precision """
"value / 10**4" will either truncate to an integer (Python 2) or return a float (Python 3 or with "from __future__ import division") if value is not divisible by 10**4. I think you want "decimal.Decimal(value) / 10**4" instead.
-Conor
> Well such a type wouldn't be backend agnostic. The String/Integer wrapped one would act very differently than a Numeric. So not much point in a transparent switch like that. We try to keep "switches" like that to a minimum (there are some, like Enum).
>
Makes sense.
A somewhat related follow-up question: is it possible to use
SQLAlchemy with "embedded" MySQL (libmysqld)? If so, how?
On Wed, Oct 6, 2010 at 10:36 AM, Conor <conor.edw...@gmail.com> wrote:
> "value / 10**4" will either truncate to an integer (Python 2) or return a
> float (Python 3 or with "from __future__ import division") if value is not
> divisible by 10**4. I think you want "decimal.Decimal(value) / 10**4"
> instead.
Good catch. Obviously the pseudocode still had skid marks on it from
being pulled straight out of my butt; just trying to catch the sense
of sqlalchemy data model.
Thanks guys, it's appreciated.