tortoise/tortoise-orm

NumericField make

daeeros opened this issue · 5 comments

I would like to create a numericfield that is floatless and has a large limit, allowing me to store giant numbers. But how to make one on tortoise can you tell me? Here is my old implementation on peewee

class NumericField(pw.DecimalField):
    def get_modifiers(self):
        pass
    
    def python_value(self, value):
        # Convert the decimal value to int before returning
        if value is not None:
            return int(value)
        return value

test = NumericField(default=10000)

How about BigIntField

They have max 9,223,372,036,854,775,807. Sometime i need bigger then this value to store(

@daeeros A sample for you:

from typing import Any, Type

from tortoise import run_async
from tortoise.contrib.test import init_memory_sqlite
from tortoise.fields import Field, IntField
from tortoise.fields.data import SqlTypes, Term, functions
from tortoise.models import Model


class BigBigIntField(Field[int], int):
    SQL_TYPE = "DECIMAL(40,0)"

    def to_python_value(self, value: Any) -> int | None:
        self.validate(value)
        if value is not None:
            value = int(value)
        return value

    def to_db_value(self, value: Any, instance: Type[Model] | Model) -> str | None:
        if value is not None:
            value = str(value)
        self.validate(value)
        return value

    class _db_sqlite:
        SQL_TYPE = "VARCHAR(40)"

        def function_cast(self, term: Term) -> Term:
            return functions.Cast(term, SqlTypes.NUMERIC)


class User(Model):
    id = IntField(pk=True)
    money = BigBigIntField(default=10000)


@init_memory_sqlite
async def main() -> None:
    u = await User.create()
    print(u.money)
    a = 9_223_372_036_854_775_807
    u = await User.create(money=a * 10)
    print(u.money)
    print(f"{type(u.money)= }")
    assert u.money == a * 10


if __name__ == "__main__":
    run_async(main())

Pass test with sqlite and mysql.

@daeeros A sample for you:

from typing import Any, Type

from tortoise import run_async
from tortoise.contrib.test import init_memory_sqlite
from tortoise.fields import Field, IntField
from tortoise.fields.data import SqlTypes, Term, functions
from tortoise.models import Model


class BigBigIntField(Field[int], int):
    SQL_TYPE = "DECIMAL(40,0)"

    def to_python_value(self, value: Any) -> int | None:
        self.validate(value)
        if value is not None:
            value = int(value)
        return value

    def to_db_value(self, value: Any, instance: Type[Model] | Model) -> str | None:
        if value is not None:
            value = str(value)
        self.validate(value)
        return value

    class _db_sqlite:
        SQL_TYPE = "VARCHAR(40)"

        def function_cast(self, term: Term) -> Term:
            return functions.Cast(term, SqlTypes.NUMERIC)


class User(Model):
    id = IntField(pk=True)
    money = BigBigIntField(default=10000)


@init_memory_sqlite
async def main() -> None:
    u = await User.create()
    print(u.money)
    a = 9_223_372_036_854_775_807
    u = await User.create(money=a * 10)
    print(u.money)
    print(f"{type(u.money)= }")
    assert u.money == a * 10


if __name__ == "__main__":
    run_async(main())

Pass test with sqlite and mysql.

I'm using Postgresql, is it for it?

Sure.