o
    KDi^                     @   s  d dl mZ d dlZd dlmZmZ d dlmZ d dlmZmZ ddl	m
Z
mZmZ G dd	 d	eZG d
d deZG dd deZG dd deZG dd deZG dd deZG dd deZi Zdd Zededd ededd eded ed ed! ed"ed# ed$ed% ed&e  ed'e  ed(ee  ed)ed* ed+ed, ed-ed. ed/ed*d0 ed1ed,d0 ed2ed.d0 ed3e  G d4d5 d5eZG d6d7 d7eZG d8d9 d9eZG d:d; d;eZG d<d= d=eZd>d? eeefD ZdS )@    )unicode_literalsN)copydeepcopy)ceil)datedatetime   )
comma_joinstring_or_func
arg_to_sqlc                   @   s"   e Zd ZdZdd ZdddZdS )	Operatorz-
    Base class for filtering operators.
    c                 C      t )z
        Subclasses should implement this method. It returns an SQL string
        that applies this operator on the given field and value.
        NotImplementedErrorself	model_cls
field_namevalue r   R/var/www/Datamplify/venv/lib/python3.10/site-packages/infi/clickhouse_orm/query.pyto_sql   s   zOperator.to_sqlTc                 C   s4   ddl m} t||r| S |||tj|S )Nr   F)infi.clickhouse_orm.funcsr   
isinstancer   to_db_string	to_pythonpytzutc)r   fieldr   quoter   r   r   r   _value_to_sql   s   
zOperator._value_to_sqlNT)__name__
__module____qualname____doc__r   r"   r   r   r   r   r      s    r   c                   @   s"   e Zd ZdZdddZdd ZdS )SimpleOperatorz=
    A simple binary operator such as a=b, a<b, a>b etc.
    Nc                 C      || _ || _d S N)_sql_operator_sql_for_null)r   sql_operatorsql_for_nullr   r   r   __init__%      
zSimpleOperator.__init__c                 C   sJ   t ||}| ||}|dkr| jd urd|| jgS d|| j|gS )Nz\N )getattrr"   r,   joinr+   r   r   r   r   r    r   r   r   r   )   s
   
zSimpleOperator.to_sqlr*   r$   r%   r&   r'   r/   r   r   r   r   r   r(       s    
r(   c                   @      e Zd ZdZdd ZdS )
InOperatorz
    An operator that implements IN.
    Accepts 3 different types of values:
    - a list or tuple of simple values
    - a string (used verbatim as the contents of the parenthesis)
    - a queryset (subquery)
    c                    sN   t || t|tr| }nt|trnt fdd|D }d||f S )Nc                    s   g | ]}  |qS r   )r"   ).0vr    r   r   r   
<listcomp>A   s    z%InOperator.to_sql.<locals>.<listcomp>z
%s IN (%s))r2   r   QuerySetas_sqlstrr	   r   r   r:   r   r   :   s   



zInOperator.to_sqlNr$   r%   r&   r'   r   r   r   r   r   r7   1   s    r7   c                   @   s"   e Zd ZdZdddZdd ZdS )	LikeOperatorzn
    A LIKE operator that matches the field to a given pattern. Can be
    case sensitive or insensitive.
    Tc                 C   r)   r*   )_pattern_case_sensitive)r   patterncase_sensitiver   r   r   r/   K   r0   zLikeOperator.__init__c                 C   s`   t ||}| j||dd}|dddddd}| j|}| jr*d	||f S d
||f S )NF)r!   \z\\%z\\%_z\\_z%s LIKE '%s'z"lowerUTF8(%s) LIKE lowerUTF8('%s'))r2   r"   replacerA   formatrB   )r   r   r   r   r    rC   r   r   r   r   O   s   
zLikeOperator.to_sqlNr#   r5   r   r   r   r   r@   E   s    
r@   c                   @   r6   )IExactOperatorz=
    An operator for case insensitive string comparison.
    c                 C   s"   t ||}| ||}d||f S )NzlowerUTF8(%s) = lowerUTF8(%s))r2   r"   r4   r   r   r   r   _   s   
zIExactOperator.to_sqlNr?   r   r   r   r   rJ   Z       rJ   c                   @   s    e Zd ZdZdd Zdd ZdS )NotOperatorz>
    A wrapper around another operator, which negates it.
    c                 C   s
   || _ d S r*   )_base_operator)r   base_operatorr   r   r   r/   j   s   
zNotOperator.__init__c                 C   s   d| j ||| S )NNOT (%s))rM   r   r   r   r   r   r   m   s   zNotOperator.to_sqlNr5   r   r   r   r   rL   e   s    rL   c                   @   r6   )BetweenOperatorat  
    An operator that implements BETWEEN.
    Accepts list or tuple of two elements and generates sql condition:
    - 'BETWEEN value[0] AND value[1]' if value[0] and value[1] are not None and not empty
    Then imitations of BETWEEN, where one of two limits is missing
    - '>= value[0]' if value[1] is None or empty
    - '<= value[1]' if value[0] is None or empty
    c                 C   s   t ||}|d d ustt|d dkr| ||d nd }|d d us/tt|d dkr7| ||d nd }|rD|rDd|||f S |rP|sPd|d|gS |r\|s^d|d|gS d S d S )Nr   r   z%s BETWEEN %s AND %sr1   >=<=)r2   lenr>   r"   r3   )r   r   r   r   r    value0value1r   r   r   r   |   s   
44zBetweenOperator.to_sqlNr?   r   r   r   r   rP   r   s    	rP   c                 C   s   |t | < d S r*   )
_operators)namesqlr   r   r   register_operator   s   rY   eq=zIS NULLnez!=zIS NOT NULLgt>gterQ   lt<lterR   betweeninnot_incontainsz%{}%
startswithz{}%endswithz%{}	icontainsFistartswith	iendswithiexactc                   @   r6   )Condz[
    An abstract object for storing a single query condition Field + Operator + Value.
    c                 C   r   r*   r   r   r   r   r   r   r      s   zCond.to_sqlNr?   r   r   r   r   rm      rK   rm   c                   @   s,   e Zd ZdZdd Zdd Zi fddZdS )		FieldCondzG
    A single query condition made up of Field + Operator + Value.
    c                 C   s>   || _ t|| _| jd u r|d | | _ td | _|| _d S )N__rZ   )_field_namerV   get	_operator_value)r   r   operatorr   r   r   r   r/      s   


zFieldCond.__init__c                 C   s   | j || j| jS r*   )rs   r   rq   rt   rn   r   r   r   r      s   zFieldCond.to_sqlc                 C   s   t | }t| j|_|S r*   )r   r   rt   )r   memodictresr   r   r   __deepcopy__   s   zFieldCond.__deepcopy__N)r$   r%   r&   r'   r/   r   rx   r   r   r   r   ro      s
    	ro   c                   @   sp   e Zd ZdZdZdd Zedd Zedd Z	d	d
 Z
dd Zdd Zdd Zdd Zdd Zi fddZdS )QANDORc                    s8   t | fdd| D   _g  _d _ j _d S )Nc                    s   g | ]
\}}  ||qS r   )_build_condr8   kr9   r   r   r   r;          zQ.__init__.<locals>.<listcomp>F)listitems_conds	_children_negateAND_MODE_mode)r   filter_funcsfilter_fieldsr   r   r   r/      s    z
Q.__init__c                 C   s   t | jp| j S )zY
        Checks if there are any conditions in Q object
        Returns: Boolean
        )boolr   r   r   r   r   r   is_empty   s   z
Q.is_emptyc                 C   sr   ||j kr|jst|}|jt| |S ||j kr,|js,t|}|jt| |S t }||g|_||_ |S r*   )r   r   r   r   appendry   )clsl_childr_childmodeqr   r   r   _construct_from   s   

zQ._construct_fromc                 C   s0   d|v r| dd\}}n|d}}t|||S )Nrp   r   rZ   )rsplitro   )r   keyr   r   ru   r   r   r   r|      s   
zQ._build_condc                    s   g }| j r| fdd| j D  | jr"| fdd| jD  |s'd}nt|dkr2|d }ndd| j| }| jrDd	| }|S )
Nc                    s   g | ]}|  qS r   r   r8   condr   r   r   r;      s    zQ.to_sql.<locals>.<listcomp>c                    s   g | ]	}|r|  qS r   r   r8   childr   r   r   r;      s    1r   r   z(%s)z) {} (rO   )r   extendr   rS   rI   r   r3   r   )r   r   condition_sqlrX   r   r   r   r      s   
zQ.to_sqlc                 C      t | || jS r*   )ry   r   OR_MODEr   otherr   r   r   __or__     zQ.__or__c                 C   r   r*   )ry   r   r   r   r   r   r   __and__  r   z	Q.__and__c                 C      t | }d|_|S )NT)r   r   )r   r   r   r   r   
__invert__  s   zQ.__invert__c                 C   s   | j  S r*   )r   r   r   r   r   __bool__     z
Q.__bool__c                 C   sD   t  }dd | jD |_| j|_| j|_| jr dd | jD |_|S )Nc                 S      g | ]}t |qS r   r   r   r   r   r   r;         z"Q.__deepcopy__.<locals>.<listcomp>c                 S   r   r   r   r   r   r   r   r;     r   )ry   r   r   r   r   )r   rv   r   r   r   r   rx     s   zQ.__deepcopy__N)r$   r%   r&   r   r   r/   propertyr   classmethodr   r|   r   r   r   r   r   rx   r   r   r   r   ry      s    

ry   c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zd6ddZdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd7d'd(Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5S )8r<   z
    A queryset is an object that represents a database query using a specific `Model`.
    It is lazy, meaning that it does not hit the database until you iterate over its
    matching rows (model instances).
    c                 C   sd   || _ || _|| _g | _t | _t | _g | _d| _|	 
 | _d| _d| _d| _d| _d| _dS )z
        Initializer. It is possible to create a queryset like this, but the standard
        way is to use `MyModel.objects_in(database)`.
        FN)model
_model_cls	_database	_order_byry   _where_q_prewhere_q_grouping_fields_grouping_with_totalsfieldskeys_fields_limits	_limit_by_limit_by_fields	_distinct_final)r   r   databaser   r   r   r/   "  s   
zQuerySet.__init__c                 C   s   | j |  | jS )zJ
        Iterates over the model instances matching this queryset
        )r   selectr=   r   r   r   r   r   __iter__6  s   zQuerySet.__iter__c                 C   s   t |  S )zA
        Returns true if this queryset matches any rows.
        )r   countr   r   r   r   r   <  s   zQuerySet.__bool__c                 C   s   t | | S r*   )typer   r   r   r   r   __nonzero__B  s   zQuerySet.__nonzero__c                 C   s   |   S r*   )r=   r   r   r   r   __str__E  r   zQuerySet.__str__c                 C   s   t |tr|dksJ dt| }|df|_tt|S |jdv s%J d|jp)d}|jp.d}|dkr7|dks;J d||ksCJ dt| }||| f|_|S )Nr   z"negative indexes are not supportedr   )Nr   zstep is not supported in slicesl    z-start of slice cannot be smaller than its end)	r   intr   r   nextiterstepstartstop)r   sqsr   r   r   r   r   __getitem__H  s   



zQuerySet.__getitem__c                 G   sV   t |tr	d|f}|d }|d }|dkr|dksJ dt| }||f|_||_|S )z
        Adds a LIMIT BY clause to the query.
        - `offset_limit`: either an integer specifying the limit, or a tuple of integers (offset, limit).
        - `fields_or_expr`: the field names or expressions to use in the clause.
        r   r   z!negative limits are not supported)r   r   r   r   r   )r   offset_limitfields_or_exproffsetlimitr   r   r   r   limit_byZ  s   

zQuerySet.limit_byc                 C   s"   d}| j rtdd | j D }|S )M
        Returns the selected fields or expressions as a SQL string.
        *c                 s       | ]}d | V  qdS `%s`Nr   r8   r    r   r   r   	<genexpr>q      z0QuerySet.select_fields_as_sql.<locals>.<genexpr>)r   r	   )r   r   r   r   r   select_fields_as_sqlk  s   zQuerySet.select_fields_as_sqlc                 C   s&  | j rdnd}| jrdnd}d| j  }| j rd| }||  ||f}d| }| jr;| jjs;|d| jdd	 7 }| j	rL| j	jsL|d
| jdd	 7 }| j
rd|dtdd | j
D  7 }| jrd|d7 }| jro|d|   7 }| jr|d| j 7 }|dtdd | jD  7 }| jr|d| j 7 }|S )z:
        Returns the whole query as a SQL string.
        z	DISTINCT  z FINALr   z	`system`.zSELECT %s%s
FROM %s%sz

PREWHERE T)prewherez
WHERE Fz
GROUP BY %sc                 s   r   r   r   r   r   r   r   r     r   z"QuerySet.as_sql.<locals>.<genexpr>z WITH TOTALSz

ORDER BY z
LIMIT %d, %dz BY %sc                 s   s    | ]}t |V  qd S r*   )r
   r   r   r   r   r     r   )r   r   r   
table_nameis_system_modelr   r   r   conditions_as_sqlr   r   r	   r   r   order_by_as_sqlr   r   r   )r   distinctfinalr   paramsrX   r   r   r   r=   t  s.   
zQuerySet.as_sqlc                 C   s   t dd | jD S )zT
        Returns the contents of the query's `ORDER BY` clause as a string.
        c                 S   s:   g | ]}t |tr|d  dkrd|dd  nt|qS )r   -z%s DESCr   N)r   r>   r   r   r   r   r;     s    ,z,QuerySet.order_by_as_sql.<locals>.<listcomp>)r	   r   r   r   r   r   r     s   zQuerySet.order_by_as_sqlFc                 C   s   |r| j n| j}|| jS )z_
        Returns the contents of the query's `WHERE` or `PREWHERE` clause as a string.
        )r   r   r   r   )r   r   q_objectr   r   r   r     s   zQuerySet.conditions_as_sqlc                 C   sX   | j s| jrd|   }| j|}|rt|S dS | j| j@ | j	}| j
| j	|S )zA
        Returns the number of matching model instances.
        SELECT count() FROM (%s)r   )r   r   r=   r   rawr   r   r   r   r   r   )r   rX   r   
conditionsr   r   r   r     s   zQuerySet.countc                 G      t | }||_|S )zL
        Returns a copy of this queryset with the ordering changed.
        )r   r   r   field_namesr   r   r   r   order_by  s   zQuerySet.order_byc                 G   r   )z
        Returns a copy of this queryset limited to the specified field names.
        Useful when there are large fields that are not needed,
        or for creating a subquery to use with an IN operator.
        )r   r   r   r   r   r   only     zQuerySet.onlyc           	      O   s   ddl m} |dd}|dd}t| }t }|D ]}t|tr'||M }qt||r3|t|M }qtd| |rD|tdi |M }|rI| }t|rO| jn| j|@ }|r\||_|S ||_|S )Nr   r   _inverseFr   z(Invalid argument "%r" to queryset filterr   )	funcsr   popr   ry   r   	TypeErrorr   r   )	r   r   kwargsr   inverser   r   	conditionargr   r   r   _filter_or_exclude  s*   


zQuerySet._filter_or_excludec                 O   s   | j |i |S )z
        Returns a copy of this queryset that includes only rows matching the conditions.
        Pass `prewhere=True` to apply the conditions as PREWHERE instead of WHERE.
        r   r   r   r   r   r   r   filter  s   zQuerySet.filterc                 O   s   | j |ddi|S )z
        Returns a copy of this queryset that excludes all rows matching the conditions.
        Pass `prewhere=True` to apply the conditions as PREWHERE instead of WHERE.
        r   Tr   r   r   r   r   exclude  s   zQuerySet.excluder   d   c                 C   sx   ddl m} |  }tt|t| }|dkr|}n
|dk r%td| |d | }|t| |||  ||||dS )a  
        Returns a single page of model instances that match the queryset.
        Note that `order_by` should be used first, to ensure a correct
        partitioning of records into pages.

        - `page_num`: the page number (1-based), or -1 to get the last page.
        - `page_size`: number of records to return per page.

        The result is a namedtuple containing `objects` (list), `number_of_objects`,
        `pages_total`, `number` (of the current page), and `page_size`.
        r   )PagezInvalid page number: %d)objectsnumber_of_objectspages_totalnumber	page_size)r   r   r   r   r   float
ValueErrorr   )r   page_numr  r   r   r  r   r   r   r   paginate  s   zQuerySet.paginatec                 C   r   )z~
        Adds a DISTINCT clause to the query, meaning that any duplicate rows
        in the results will be omitted.
        T)r   r   r   r   r   r   r   r     s   zQuerySet.distinctc                 C   s<   ddl m}m} t| jj||fstdt| }d|_|S )z
        Adds a FINAL modifier to table, meaning data will be collapsed to final version.
        Can be used with the `CollapsingMergeTree` and `ReplacingMergeTree` engines only.
        r   )CollapsingMergeTreeReplacingMergeTreez[final() method can be used only with the CollapsingMergeTree and ReplacingMergeTree enginesT)	enginesr
  r  r   r   enginer   r   r   )r   r
  r  r   r   r   r   r     s   zQuerySet.finalc                 C   s>   |    | j| j@ | j}d| j |f }| j| | S )z
        Deletes all records matched by this queryset's conditions.
        Note that ClickHouse performs deletions in the background, so they are not immediate.
        z$ALTER TABLE $db.`%s` DELETE WHERE %s)_verify_mutation_allowedr   r   r   r   r   r   r   )r   r   rX   r   r   r   delete'  s
   zQuerySet.deletec                 K   sb   |sJ d|    tdd | D }| j| j@ | j}d| j ||f }| j	| | S )a  
        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.
        zNo fields specified for updatec                 s   s$    | ]\}}d |t |f V  qdS )z	`%s` = %sN)r   )r8   rW   exprr   r   r   r   :  s   " z"QuerySet.update.<locals>.<genexpr>z'ALTER TABLE $db.`%s` UPDATE %s WHERE %s)
r  r	   r   r   r   r   r   r   r   r   )r   r   r   r   rX   r   r   r   update2  s   zQuerySet.updatec                 C   s<   | j rJ d| jrJ d| jrJ d| jrJ ddS )ze
        Checks that the queryset's state allows mutations. Raises an AssertionError if not.
        z4Mutations are not allowed after slicing the querysetz5Mutations are not allowed after calling limit_by(...)z2Mutations are not allowed after calling distinct()z/Mutations are not allowed after calling final()N)r   r   r   r   r   r   r   r   r  @  s   z!QuerySet._verify_mutation_allowedc                 O   s   t | ||S )a  
        Returns an `AggregateQuerySet` over this query, with `args` serving as
        grouping fields and `kwargs` serving as calculated fields. At least one
        calculated field is required. For example:
        ```
            Event.objects_in(database).filter(date__gt='2017-08-01').aggregate('event_type', count='count()')
        ```
        is equivalent to:
        ```
            SELECT event_type, count() AS count FROM event
            WHERE data > '2017-08-01'
            GROUP BY event_type
        ```
        )AggregateQuerySetr   argsr   r   r   r   	aggregateI  s   zQuerySet.aggregateN)F)r   r   )r$   r%   r&   r'   r/   r   r   r   r   r   r   r   r=   r   r   r   r   r   r   r   r   r  r   r   r  r  r  r  r   r   r   r   r<     s4    	$
	

		r<   c                       s`   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Z  ZS )r  z*
    A queryset used for aggregation.
    c                    sd   t t| |j|j |sJ d|| _|| _|| _t|j	| _	|j
| _
|j| _|j| _|j| _dS )a  
        Initializer. Normally you should not call this but rather use `QuerySet.aggregate()`.

        The grouping fields should be a list/tuple of field names from the model. For example:
        ```
            ('event_type', 'event_subtype')
        ```
        The calculated fields should be a mapping from name to a ClickHouse aggregation function. For example:
        ```
            {'weekday': 'toDayOfWeek(event_date)', 'number_of_events': 'count()'}
        ```
        At least one calculated field is required.
        z.No calculated fields specified for aggregationN)superr  r/   r   r   r   r   _calculated_fieldsr   r   r   r   r   r   )r   base_qsgrouping_fieldscalculated_fields	__class__r   r   r/   `  s   zAggregateQuerySet.__init__c                 G   s<   |D ]}|| j v s|| jv sJ d| qt| }||_|S )z
        This method lets you specify the grouping fields explicitly. The `args` must
        be names of grouping fields or calculated fields that this queryset was
        created with.
        z:Cannot group by `%s` since it is not included in the query)r   r  r   r   )r   r  rW   r   r   r   r   group_byy  s   zAggregateQuerySet.group_byc                 G      t d)F
        This method is not supported on `AggregateQuerySet`.
        z(Cannot use "only" with AggregateQuerySetr   )r   r   r   r   r   r        zAggregateQuerySet.onlyc                 O   r  )r  z(Cannot re-aggregate an AggregateQuerySetr   r  r   r   r   r    r   zAggregateQuerySet.aggregatec                 C   s(   t dd | jD dd | j D  S )r   c                 S   r   r   )r>   )r8   fr   r   r   r;     r   z:AggregateQuerySet.select_fields_as_sql.<locals>.<listcomp>c                 S   s   g | ]
\}}d ||f qS )z%s AS %sr   r}   r   r   r   r;     r   )r	   r   r  r   r   r   r   r   r     s   (z&AggregateQuerySet.select_fields_as_sqlc                 C   s   | j |  S r*   )r   r   r=   r   r   r   r   r     r   zAggregateQuerySet.__iter__c                 C   s(   d|    }| j|}|rt|S dS )z?
        Returns the number of rows after aggregation.
        r   r   )r=   r   r   r   )r   rX   r   r   r   r   r     s   zAggregateQuerySet.countc                 C   r   )z
        Adds WITH TOTALS modifier ot GROUP BY, making query return extra row
        with aggregate function calculated across all the rows. More information:
        https://clickhouse.tech/docs/en/query_language/select/#with-totals-modifier
        T)r   r   r	  r   r   r   with_totals  r   zAggregateQuerySet.with_totalsc                 C   r  )Nz"Cannot mutate an AggregateQuerySet)AssertionErrorr   r   r   r   r    r   z*AggregateQuerySet._verify_mutation_allowed)r$   r%   r&   r'   r/   r  r   r  r   r   r   r"  r  __classcell__r   r   r  r   r  [  s    
r  c                 C   s   g | ]}|j qS r   )r$   )r8   cr   r   r   r;     s    r;   )
__future__r   r   r   r   mathr   r   r   utilsr	   r
   r   objectr   r(   r7   r@   rJ   rL   rP   rV   rY   rm   ro   ry   r<   r  __all__r   r   r   r   <module>   sN    	\  BW