# Path: src/infi/clickhouse_orm/utils.py
# def comma_join(items, stringify=False):
#     """
#     Joins an iterable of strings with commas.
#     """
#     if stringify:
#         return ', '.join(str(item) for item in items)
#     else:
#         return ', '.join(items)
# 
# def string_or_func(obj):
#     return obj.to_sql() if hasattr(obj, 'to_sql') else obj
# 
# def arg_to_sql(arg):
#     """
#     Converts a function argument to SQL string according to its type.
#     Supports functions, model fields, strings, dates, datetimes, timedeltas, booleans,
#     None, numbers, timezones, arrays/iterables.
#     """
#     from infi.clickhouse_orm import Field, StringField, DateTimeField, DateField, F, QuerySet
#     if isinstance(arg, F):
#         return arg.to_sql()
#     if isinstance(arg, Field):
#         return "`%s`" % arg
#     if isinstance(arg, str):
#         return StringField().to_db_string(arg)
#     if isinstance(arg, datetime):
#         return "toDateTime(%s)" % DateTimeField().to_db_string(arg)
#     if isinstance(arg, date):
#         return "toDate('%s')" % arg.isoformat()
#     if isinstance(arg, timedelta):
#         return "toIntervalSecond(%d)" % int(arg.total_seconds())
#     if isinstance(arg, bool):
#         return str(int(arg))
#     if isinstance(arg, tzinfo):
#         return StringField().to_db_string(arg.tzname(None))
#     if arg is None:
#         return 'NULL'
#     if isinstance(arg, QuerySet):
#         return "(%s)" % arg
#     if isinstance(arg, tuple):
#         return '(' + comma_join(arg_to_sql(x) for x in arg) + ')'
#     if is_iterable(arg):
#         return '[' + comma_join(arg_to_sql(x) for x in arg) + ']'
#     return str(arg)


import pytz
from copy import copy, deepcopy
from math import ceil
from datetime import date, datetime
from .utils import comma_join, string_or_func, arg_to_sql
        from infi.clickhouse_orm.funcs import F
        from .funcs import F
        from .database import Page
        from .engines import CollapsingMergeTree, ReplacingMergeTree
        """
        Adds a FINAL modifier to table, meaning data will be collapsed to final version.
        Can be used with the `CollapsingMergeTree` and `ReplacingMergeTree` engines only.
        """
        if not isinstance(self._model_cls.engine, (CollapsingMergeTree, ReplacingMergeTree)):
            raise TypeError('final() method can be used only with the CollapsingMergeTree and ReplacingMergeTree engines')

        qs = copy(self)
        qs._final = True
        return qs

    def delete(self):
        """
        Deletes all records matched by this queryset's conditions.
        Note that ClickHouse performs deletions in the background, so they are not immediate.
        """
        self._verify_mutation_allowed()
        conditions = (self._where_q & self._prewhere_q).to_sql(self._model_cls)
        sql = 'ALTER TABLE $db.`%s` DELETE WHERE %s' % (self._model_cls.table_name(), conditions)
        self._database.raw(sql)
        return self

    def update(self, **kwargs):
        """
        Updates all records matched by this queryset's conditions.
        Keyword arguments specify the field names and expressions to use for the update.
        Note that ClickHouse performs updates in the background, so they are not immediate.
        """
        assert kwargs, 'No fields specified for update'
        self._verify_mutation_allowed()

# Path: src/infi/clickhouse_orm/utils.py
# def comma_join(items, stringify=False):
#     """
#     Joins an iterable of strings with commas.
#     """
#     if stringify:
#         return ', '.join(str(item) for item in items)
#     else:
#         return ', '.join(items)
# 
# def string_or_func(obj):
#     return obj.to_sql() if hasattr(obj, 'to_sql') else obj
# 
# def arg_to_sql(arg):
#     """
#     Converts a function argument to SQL string according to its type.
#     Supports functions, model fields, strings, dates, datetimes, timedeltas, booleans,
#     None, numbers, timezones, arrays/iterables.
#     """
#     from infi.clickhouse_orm import Field, StringField, DateTimeField, DateField, F, QuerySet
#     if isinstance(arg, F):
#         return arg.to_sql()
#     if isinstance(arg, Field):
#         return "`%s`" % arg
#     if isinstance(arg, str):
#         return StringField().to_db_string(arg)
#     if isinstance(arg, datetime):
#         return "toDateTime(%s)" % DateTimeField().to_db_string(arg)
#     if isinstance(arg, date):
#         return "toDate('%s')" % arg.isoformat()
#     if isinstance(arg, timedelta):
#         return "toIntervalSecond(%d)" % int(arg.total_seconds())
#     if isinstance(arg, bool):
#         return str(int(arg))
#     if isinstance(arg, tzinfo):
#         return StringField().to_db_string(arg.tzname(None))
#     if arg is None:
#         return 'NULL'
#     if isinstance(arg, QuerySet):
#         return "(%s)" % arg
#     if isinstance(arg, tuple):
#         return '(' + comma_join(arg_to_sql(x) for x in arg) + ')'
#     if is_iterable(arg):
#         return '[' + comma_join(arg_to_sql(x) for x in arg) + ']'
#     return str(arg)


# Path: src/infi/clickhouse_orm/query.py
import pytz
from copy import copy, deepcopy
from math import ceil
from datetime import date, datetime
from .utils import comma_join, string_or_func, arg_to_sql
        from infi.clickhouse_orm.funcs import F
        from .funcs import F
        from .database import Page
        from .engines import CollapsingMergeTree, ReplacingMergeTree

        """
        Adds a FINAL modifier to table, meaning data will be collapsed to final version.
        Can be used with the `CollapsingMergeTree` and `ReplacingMergeTree` engines only.
        """
        if not isinstance(self._model_cls.engine, (CollapsingMergeTree, ReplacingMergeTree)):
            raise TypeError('final() method can be used only with the CollapsingMergeTree and ReplacingMergeTree engines')

        qs = copy(self)
        qs._final = True
        return qs

    def delete(self):
        """
        Deletes all records matched by this queryset's conditions.
        Note that ClickHouse performs deletions in the background, so they are not immediate.
        """
        self._verify_mutation_allowed()
        conditions = (self._where_q & self._prewhere_q).to_sql(self._model_cls)
        sql = 'ALTER TABLE $db.`%s` DELETE WHERE %s' % (self._model_cls.table_name(), conditions)
        self._database.raw(sql)
        return self

    def update(self, **kwargs):
        """
        Updates all records matched by this queryset's conditions.
        Keyword arguments specify the field names and expressions to use for the update.
        Note that ClickHouse performs updates in the background, so they are not immediate.
        """
        assert kwargs, 'No fields specified for update'
        self._verify_mutation_allowed()

        fields = comma_join('`%s` = %s' % (name, arg_to_sql(expr)) for name, expr in kwargs.items())