Infinidat/infi.clickhouse_orm

utils.arg_to_sql function can not be redeclared in Field subclass

M1ha-Shvn opened this issue · 0 comments

Hi.
I want to implement a small wrapper around StringField which automatically dumps and loads JSON and stores it in ClickHouse as a string. Here is my code:

class JSONField(StringField):
    class_default = {}

    def to_python(self, value, timezone_in_use):
        if isinstance(value, (list, dict, int, float, bool)):
            return value

        result = super().to_python(value, timezone_in_use)
        return json.loads(result) if result is not None else None

    def validate(self, value):
        if value is not None and not isinstance(value, (int, float, bool, str, list, dict)):
            raise ValueError(f"{self.__class__.__name__} is not valid JSON type - {value}")

    def to_db_string(self, value, quote=True):
        if isinstance(value, (list, dict)):
            value = json.dumps(value)

        return super().to_db_string(value, quote=quote)

But when I use a QuerySet.update(...) frunction trying to update this field I get an error:

infi.clickhouse_orm.database.ServerError: There is no supertype for types Array(String), String because some of them are Array and some of them are not

This is caused by clickhouse_orm utils.arg_to_sql which determines argument type based on its form and there is no any ability to add functionality there using Field child class methods.

I suggest get suitable field from model for every updated value. Than call Field.to_db_string(...) method to convert field value instead of using arg_to_sql function.