o
    NDi                     @   s  d dl Z d dlmZmZ d dlmZ d dlZd dlmZ d dlm	Z	m
ZmZ d dlmZmZmZmZ d dlmZ d dlmZmZmZ d d	lmZmZmZmZmZmZmZm Z  d d
l!m"Z"m#Z#m$Z$m%Z%m&Z&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/dd Z0G dd deZ1G dd de2Z
G dd de2Z3G dd  d e2Z4G d!d" d"e2Z5G d#d$ d$e6Z7G d%d& d&e5Z8G d'd( d(e5Z9G d)d* d*e2Z:d-d+d,Z;dS ).    N)datetime	timedelta)partial)warn)SimpleStatement	BatchTypeBatchStatement)columnsCQLEngineExceptionValidationErrorUnicodeMixin
connection)TokenBaseQueryFunction
QueryValue)
InOperatorEqualsOperatorGreaterThanOperatorGreaterThanOrEqualOperatorLessThanOperatorLessThanOrEqualOperatorContainsOperatorBaseWhereOperator)WhereClauseSelectStatementDeleteStatementUpdateStatementInsertStatementBaseCQLStatementMapDeleteClauseConditionalClausec                   @      e Zd ZdS )QueryExceptionN__name__
__module____qualname__ r(   r(   R/var/www/Datamplify/venv/lib/python3.10/site-packages/cassandra/cqlengine/query.pyr#   !       r#   c                   @   r"   )IfNotExistsWithCounterColumnNr$   r(   r(   r(   r)   r+   %   r*   r+   c                   @   r"   )IfExistsWithCounterColumnNr$   r(   r(   r(   r)   r,   )   r*   r,   c                       s    e Zd ZdZ fddZ  ZS )LWTExceptionaI  Lightweight conditional exception.

    This exception will be raised when a write using an `IF` clause could not be
    applied due to existing data violating the condition. The existing data is
    available through the ``existing`` attribute.

    :param existing: The current state of the data which prevented the write.
    c                    s   t t| d || _d S )NzLWT Query was not applied)superr-   __init__existing)selfr0   	__class__r(   r)   r/   6   s   
zLWTException.__init__)r%   r&   r'   __doc__r/   __classcell__r(   r(   r2   r)   r-   -   s    r-   c                   @   r"   )DoesNotExistNr$   r(   r(   r(   r)   r6   ;   r*   r6   c                   @   r"   )MultipleObjectsReturnedNr$   r(   r(   r(   r)   r7   ?   r*   r7   c                 C   s6   z| j }W n ty   d}Y nw |st|  dS )z
    Raises LWTException if it looks like a failed LWT request. A LWTException
    won't be raised in the special case in which there are several failed LWT
    in a  :class:`~cqlengine.query.BatchQuery`.
    TN)was_applied	Exceptionr-   one)resultappliedr(   r(   r)   check_appliedC   s   
r=   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dS )AbstractQueryableColumnzT
    exposes cql query operators through pythons
    builtin comparator symbols
    c                 C      t NNotImplementedErrorr1   r(   r(   r)   _get_columnW      z#AbstractQueryableColumn._get_columnc                 C   r?   r@   rA   rC   r(   r(   r)   __unicode__Z   rE   z#AbstractQueryableColumn.__unicode__c                 C   s   t |tr|S |  |S r@   )
isinstancer   rD   to_database)r1   valr(   r(   r)   _to_database]   s   
z$AbstractQueryableColumn._to_databasec                 C      t t| t |S )zo
        Returns an in operator

        used where you'd typically want to use python's `in` operator
        )r   strr   r1   itemr(   r(   r)   in_c   s   zAbstractQueryableColumn.in_c                 C   rK   )z-
        Returns a CONTAINS operator
        )r   rL   r   rM   r(   r(   r)   	contains_k   s   z!AbstractQueryableColumn.contains_c                 C      t t| t | |S r@   )r   rL   r   rJ   r1   otherr(   r(   r)   __eq__r      zAbstractQueryableColumn.__eq__c                 C   rQ   r@   )r   rL   r   rJ   rR   r(   r(   r)   __gt__u   rU   zAbstractQueryableColumn.__gt__c                 C   rQ   r@   )r   rL   r   rJ   rR   r(   r(   r)   __ge__x   rU   zAbstractQueryableColumn.__ge__c                 C   rQ   r@   )r   rL   r   rJ   rR   r(   r(   r)   __lt__{   rU   zAbstractQueryableColumn.__lt__c                 C   rQ   r@   )r   rL   r   rJ   rR   r(   r(   r)   __le__~   rU   zAbstractQueryableColumn.__le__N)r%   r&   r'   r4   rD   rF   rJ   rO   rP   rT   rV   rW   rX   rY   r(   r(   r(   r)   r>   Q   s    r>   c                   @   s   e Zd ZdZdZdS )r   UNLOGGEDCOUNTERN)r%   r&   r'   UnloggedCounterr(   r(   r(   r)   r      s    r   c                   @   sp   e Zd ZdZdZdZdZdZddddej	d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S )
BatchQueryz
    Handles the batching of queries

    http://docs.datastax.com/en/cql/3.0/cql/cql_reference/batch_r.html

    See :doc:`/cqlengine/batches` for more details.
    TNFc                 C   sl   g | _ || _|durt|ttfstd|| _|| _|| _|| _	g | _
d| _d| _|| _|r4d| _dS dS )a  
        :param batch_type: (optional) One of batch type values available through BatchType enum
        :type batch_type: BatchType, str or None
        :param timestamp: (optional) A datetime or timedelta object with desired timestamp to be applied
            to the batch conditional.
        :type timestamp: datetime or timedelta or None
        :param consistency: (optional) One of consistency values ("ANY", "ONE", "QUORUM" etc)
        :type consistency: The :class:`.ConsistencyLevel` to be used for the batch query, or None.
        :param execute_on_exception: (Defaults to False) Indicates that when the BatchQuery instance is used
            as a context manager the queries accumulated within the context must be executed despite
            encountering an error within the context. By default, any exception raised from within
            the context scope will cause the batched queries not to be executed.
        :type execute_on_exception: bool
        :param timeout: (optional) Timeout for the entire batch (in seconds), if not specified fallback
            to default session timeout
        :type timeout: float or None
        :param str connection: Connection name to use for the batch execution
        Nz0timestamp object must be an instance of datetimeFT)queries
batch_typerG   r   r   r
   	timestamp_consistency_execute_on_exception_timeout
_callbacks	_executed_context_entered_connection_connection_explicit)r1   r`   ra   consistencyexecute_on_exceptiontimeoutr   r(   r(   r)   r/      s   
zBatchQuery.__init__c                 C   s"   t |ts	td| j| d S )Nz4only BaseCQLStatements can be added to a batch query)rG   r   r
   r_   append)r1   queryr(   r(   r)   	add_query   s   
zBatchQuery.add_queryc                 C   s
   || _ d S r@   )rb   )r1   rj   r(   r(   r)   rj         
zBatchQuery.consistencyc                 C   s$   | j D ]\}}}||i | qd S r@   )re   )r1   callbackargskwargsr(   r(   r)   _execute_callbacks   s   zBatchQuery._execute_callbacksc                 O   s0   t |stdt|| j|||f dS )a  Add a function and arguments to be passed to it to be executed after the batch executes.

        A batch can support multiple callbacks.

        Note, that if the batch does not execute, the callbacks are not executed.
        A callback, thus, is an "on batch success" handler.

        :param fn: Callable object
        :type fn: callable
        :param args: Positional arguments to be passed to the callback at the time of execution
        :param kwargs: Named arguments to be passed to the callback at the time of execution
        z<Value for argument 'fn' is {0} and is not a callable object.N)callable
ValueErrorformattypere   rm   )r1   fnrr   rs   r(   r(   r)   add_callback   s   zBatchQuery.add_callbackc                 C   s  | j r| jrd}| jr|d7 }t| d| _ t| jdkr#|   d S | jtj	u r+d n| j}d|r7t
|d nd d }| jrzt| jtrI| j}n*t| jttfro| j}t| jtr`|t 7 }tt| d	 |j }ntd
|d|7 }|g}i }d}| jD ]}|| | }	|t|	7 }|dt
|  ||	 q|d tjd||| j| j| j d}
t!|
 g | _|   d S )NzBatch executed multiple times.zT If using the batch as a context manager, there is no need to call execute directly.Tr   zBEGIN   z BATCHg    .Az0Batch expects a long, a timedelta, or a datetimez USING TIMESTAMP {0}z  zAPPLY BATCH;
r   )"rf   warn_multiple_execrg   r   lenr_   rt   r`   
CBatchTypeLOGGEDrL   ra   rG   intr   r   nowtimemktime	timetuplemicrosecondrv   rw   update_context_idget_contextrm   updateconnexecutejoinrb   rd   rh   r=   )r1   msgr`   openerts
query_list
parametersctx_counterrn   ctxtmpr(   r(   r)   r      sF   


 zBatchQuery.executec                 C   s
   d| _ | S )NT)rg   rC   r(   r(   r)   	__enter__  s   zBatchQuery.__enter__c                 C   s   |d ur	| j s	d S |   d S r@   )rc   r   r1   exc_typeexc_valexc_tbr(   r(   r)   __exit__  s   zBatchQuery.__exit__)r%   r&   r'   r4   r~   rb   rh   ri   r   NOT_SETr/   ro   rj   rt   rz   r   r   r   r(   r(   r(   r)   r^      s     
#0r^   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	ContextQuerya|  
    A Context manager to allow a Model to switch context easily. Presently, the context only
    specifies a keyspace for model IO.

    :param args: One or more models. A model should be a class type, not an instance.
    :param kwargs: (optional) Context parameters: can be *keyspace* or *connection*

    For example:

    .. code-block:: python

            with ContextQuery(Automobile, keyspace='test2') as A:
                A.objects.create(manufacturer='honda', year=2008, model='civic')
                print(len(A.objects.all()))  # 1 result

            with ContextQuery(Automobile, keyspace='test4') as A:
                print(len(A.objects.all()))  # 0 result

            # Multiple models
            with ContextQuery(Automobile, Automobile2, connection='cluster2') as (A, A2):
                print(len(A.objects.all()))
                print(len(A2.objects.all()))

    c              	   O   s   ddl m} g | _t|dk rtd|dd }|dd }|r-tdd| |D ],}zt||j	 W n t
yD   td	w ||i }|rP||_|rU||_| j| q/d S )
Nr   )models   zNo model provided.keyspacer   z Unknown keyword argument(s): {0},z'Models must be derived from base Model.)cassandra.cqlenginer   r   rv   poprw   r   keys
issubclassModel	TypeError_clone_model_class__keyspace____connection__rm   )r1   rr   rs   r   r   r   modelmr(   r(   r)   r/   ,  s.   zContextQuery.__init__c                 C   s"   t | jdkrt| jS | jd S )Nr   r   )r   r   tuplerC   r(   r(   r)   r   J  s   

zContextQuery.__enter__c                 C   s   d S r@   r(   r   r(   r(   r)   r   O  rE   zContextQuery.__exit__N)r%   r&   r'   r4   r/   r   r   r(   r(   r(   r)   r     s
    r   c                       sx  e Zd Z f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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ed#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Z d9d: Z!d;d< Z"dXd>d?Z#d@dA Z$dBdC Z%dDdE Z&dFdG Z'dHdI Z(dJdK Z)dLdM Z*dNdO Z+dPdQ Z,dRdS Z-dTdU Z.dYdVdWZ/  Z0S )ZAbstractQuerySetc                    s   t t|   || _g | _g | _g | _d| _d| _t	 | _
i | _g | _d| _d| _d | _d | _d | _d| _d | _d | _d | _d | _d | _d | _d| _tj| _d| _d | _d | _d S )NFi'  T) r.   r   r/   r   _where_conditional_order_allow_filtering_limitset_defer_fields_deferred_values_only_fields_values_list_flat_values_list_result_cache_result_idx_result_generator_materialize_results_distinct_fields_count_batch_ttlrb   
_timestamp_if_not_existsr   r   rd   
_if_exists_fetch_sizerh   )r1   r   r2   r(   r)   r/   U  s6   
zAbstractQuerySet.__init__c                 C   s
   | j  S r@   )r   column_family_namerC   r(   r(   r)   r     s   
z#AbstractQuerySet.column_family_namec                 C   sX   | j r	| j |S | jp| j }t| j|| j| j|d}| js&| j	s&| j
r*t| |S )Nr   )r   ro   rh   r   _get_connection_execute_statementrb   rd   r   r   r   r=   )r1   	statementr   r;   r(   r(   r)   _execute  s   zAbstractQuerySet._executec                 C      t |  S r@   )rL   _select_queryrC   r(   r(   r)   rF        zAbstractQuerySet.__unicode__c                 C   r   r@   )rL   rF   rC   r(   r(   r)   __str__  r   zAbstractQuerySet.__str__c                 O   s   | j |i |S r@   )filter)r1   rr   rs   r(   r(   r)   __call__  s   zAbstractQuerySet.__call__c                 C   sv   |  | j}| j D ]-\}}|dv rd |j|< q|dkr$| j|j|< q|dkr/| j|j|< qt|||j|< q|S )N)_con_curr   r   r   _construct_resultr   rd   )r3   r   __dict__itemsr   rd   copydeepcopy)r1   memoclonekvr(   r(   r)   __deepcopy__  s   zAbstractQuerySet.__deepcopy__c                 C   s   |    |  S r@   )_execute_querycountrC   r(   r(   r)   __len__  s   zAbstractQuerySet.__len__c                 C   s   g S )z returns the fields to select r(   rC   r(   r(   r)   _select_fields  s   zAbstractQuerySet._select_fieldsc                 C   s   dS )z" put select query validation here Nr(   rC   r(   r(   r)   _validate_select_where  s    z'AbstractQuerySet._validate_select_wherec              
   C   s8   | j r|   t| j|  | j | j| j| j| j| j	dS )zH
        Returns a select clause based on the given filter args
        )fieldswhereorder_bylimitallow_filteringdistinct_fields
fetch_size)
r   r   r   r   r   r   r   r   r   r   rC   r(   r(   r)   r     s   zAbstractQuerySet._select_queryc                 C   sh   | j rtd| jd u r0dd | |  D | _g | _| |  | _| j	s*| j
r2|   d S d S d S )N>Only inserts, updates, and deletes are available in batch modec                 s   s    | ]}|V  qd S r@   r(   ).0ir(   r(   r)   	<genexpr>  s    z2AbstractQuerySet._execute_query.<locals>.<genexpr>)r   r
   r   r   r   r   _maybe_inject_deferred_get_result_constructorr   r   r   _fill_result_cacherC   r(   r(   r)   r     s   
zAbstractQuerySet._execute_queryc                 C   s>   d}z	 |d7 }|  | q ty   Y nw t| j| _dS )z9
        Fill the result cache with all results.
        r   Ti  N)_fill_result_cache_to_idxStopIterationr   r   r   )r1   idxr(   r(   r)   r     s   
z#AbstractQuerySet._fill_result_cachec              	   C   s   |    | jd u rd| _|| j }|dk rd S t|D ]-}|  jd7  _	 z| | j| j | j| j< W n tyF   | jt| j Y nw q%qd S )Nr   )	r   r   ranger   r   
IndexErrorrm   nextr   )r1   r   qtyr(   r(   r)   r     s$   

z*AbstractQuerySet._fill_result_cache_to_idxc                 c   s~    |    d}	 t| j|kr%z| jt| j W n
 ty$   Y d S w | j| }t|tr4| 	| | j| V  |d7 }q)Nr   Tr   )
r   r   r   rm   r   r   r   rG   dictr   )r1   r   instancer(   r(   r)   __iter__  s    


zAbstractQuerySet.__iter__c              	   C   s&  |    t|trT|jr|jnd}|dk s|jd ur$|jdk r$tdt |j}|dk s5|jd u s5|jdk r9|  }z| | W n	 t	yI   Y nw | j
||j|j S zt|}W n ttfyg   tdw |dk rqtdt |dk r}|  }||7 }z| | W n	 t	y   tw | j
| S )Nr   zKModelQuerySet slicing with negative indices support will be removed in 4.0.z!QuerySet indices must be integerszLModelQuerySet indexing with negative indices support will be removed in 4.0.)r   rG   slicestartstopr   DeprecationWarningr   r   r   r   stepr   rv   r   r   )r1   sr   endnum_resultsr(   r(   r)   __getitem__  sD   

zAbstractQuerySet.__getitem__c                 C   r?   zS
        Returns a function that will be used to instantiate query results
        rA   rC   r(   r(   r)   r   >     z(AbstractQuerySet._get_result_constructorc                 C   s   | | | |S r@   )r   )fdeferredrowr(   r(   r)   _construct_with_deferredD  s   
z)AbstractQuerySet._construct_with_deferredc                 C   s   | j rt| j|| j S |S r@   )r   r   r	  )r1   constructorr(   r(   r)   r   I  s   z'AbstractQuerySet._maybe_inject_deferredc                 C   s<   | j rtd|durt|tstdt| }||_|S )z
        Set a batch object to run the query on.

        Note: running a select query with a batch object will raise an exception
        z5Cannot specify the connection on model in batch mode.N/batch_obj must be a BatchQuery instance or None)rh   r
   rG   r^   r   r   r   )r1   	batch_objr   r(   r(   r)   batchM  s   
zAbstractQuerySet.batchc                 C   s$   zt t| W S  ty   Y d S w r@   )r   iterr   rC   r(   r(   r)   first\  s
   zAbstractQuerySet.firstc                 C   s
   t | S )z
        Returns a queryset matching all rows

        .. code-block:: python

            for user in User.objects().all():
                print(user)
        )r   r   rC   r(   r(   r)   allb  s   
	zAbstractQuerySet.allc                 C      t | }||_|S )z
        Sets the consistency level for the operation. See :class:`.ConsistencyLevel`.

        .. code-block:: python

            for user in User.objects(id=3).consistency(CL.ONE):
                print(user)
        )r   r   rb   )r1   rj   r   r(   r(   r)   rj   m  s   
	zAbstractQuerySet.consistencyc                 C   sZ   | dd}t|dkr|dfS t|dkr&|dkr"|d |d fS |dfS td|)zp
        Parses a filter arg in the format:
        <colname>__<op>
        :returns: colname, op tuple
        __r   N   	pk__tokenr   zCan't parse '{0}')rsplitr   r#   rw   )r1   argr   r(   r(   r)   _parse_filter_argz  s    z"AbstractQuerySet._parse_filter_argc              	   O   s   t dd | D rtdt| }|D ]}t|ts$td||j	
| q| D ]M\}}t|tr<td| |\}}z| j|}	W n tyY   td|w t|trb|}
n|	|}
t|pld}| }|j	
t|	j||
 q/|S )zAdds IF statements to querysetc                 S      g | ]}|d u r|qS r@   r(   r   xr(   r(   r)   
<listcomp>      z(AbstractQuerySet.iff.<locals>.<listcomp>z"None values on iff are not allowed!{0} is not a valid query operatorz,Token() values are not valid in conditionals Can't resolve column name: '{0}'EQ)r   valuesr
   r   r   rG   r!   r#   rw   r   rm   r   r   r  r   rD   KeyErrorr   rH   r   get_operatorr   db_field_name)r1   rr   rs   r   operatorr  rI   col_namecol_opcolumn	query_valoperator_classr(   r(   r)   iff  s.   




zAbstractQuerySet.iffc              	      s  t dd | D rtdt| }|D ]}t|ts$td||j	
| q| D ]\}}| |\}}d}	t|tsXz| j| W n< tyW   td|w |dkr`tdt| j d	}	 j}
t |
t |jkrtd
t |jt |
||
 t|pd}| }t|trt|ttfstd fdd|D }n/t|tr|}n't|trt tjtjtjfr|}n  |}|s|j!" j# ||j$ j#< |j	
t j#|||	d q/|S )z
        Adds WHERE arguments to the queryset, returning a new queryset

        See :ref:`retrieving-objects-with-filters`

        Returns a QuerySet filtered on the keyword arguments
        c                 S   r  r@   r(   r  r(   r(   r)   r    r  z+AbstractQuerySet.filter.<locals>.<listcomp>z%None values on filter are not allowedr  Tr  r  zEToken() values may only be compared to the 'pk__token' virtual columnFz?Token() received {0} arguments but model has {1} partition keysr  z&IN queries must use a list/tuple valuec                    s   g | ]}  |qS r(   )rH   r   r   r'  r(   r)   r        )quote_field)%r   r   r
   r   r   rG   r   r#   rw   r   rm   r   r  r   r   rD   r!  r	   _PartitionKeysTokenpartition_columnsvalueset_columnsr   r"  r   listr   r   r   ListSetMaprH   r   addr#  r   )r1   rr   rs   r   r$  r  rI   r%  r&  r.  r0  r)  r(  r(   r,  r)   r     s\   	







zAbstractQuerySet.filterc                 O   sr   |s|r| j |i | S |   z
| d  | jd ty%   Y nw z| d }W |S  ty8   | jjw )a  
        Returns a single instance matching this query, optionally with additional filter kwargs.

        See :ref:`retrieving-objects-with-filters`

        Returns a single object matching the QuerySet.

        .. code-block:: python

            user = User.get(id=1)

        If no objects are matched, a :class:`~.DoesNotExist` exception is raised.

        If more than one object is found, a :class:`~.MultipleObjectsReturned` exception is raised.
        r   zMultiple objects foundr   )r   getr   r   r7   r   r6   )r1   rr   rs   objr(   r(   r)   r8    s   
zAbstractQuerySet.getc                 C   s&   | drdnd}|dd}||fS )N-DESCASCr|   )
startswithreplace)r1   colname
order_typer(   r(   r)   _get_ordering_condition  s   z(AbstractQuerySet._get_ordering_conditionc                 G   s^   t |dkrt| }g |_|S g }|D ]}|dj| |  qt| }|j| |S )a  
        Sets the column(s) to be used for ordering

        Default order is ascending, prepend a '-' to any column name for descending

        *Note: column names must be a clustering key*

        .. code-block:: python

            from uuid import uuid1,uuid4

            class Comment(Model):
                photo_id = UUID(primary_key=True)
                comment_id = TimeUUID(primary_key=True, default=uuid1) # second primary key component is a clustering key
                comment = Text()

            sync_table(Comment)

            u = uuid4()
            for x in range(5):
                Comment.create(photo_id=u, comment="test %d" % x)

            print("Normal")
            for comment in Comment.objects(photo_id=u):
                print(comment.comment_id)

            print("Reversed")
            for comment in Comment.objects(photo_id=u).order_by("-comment_id"):
                print(comment.comment_id)
        r   z	"{0}" {1})r   r   r   r   rm   rw   rA  extend)r1   colnamesr   
conditionsr?  r(   r(   r)   r     s   

zAbstractQuerySet.order_byc                 C   sL   | j rtd| jdu r#|  }d|_| |}|  }|d | _| jS )z
        Returns the number of rows matched by this query.

        *Note: This function executes a SELECT COUNT() and has a performance cost on large datasets*
        r   NTr   )r   r
   r   r   r   r   r:   popitem)r1   rn   r;   	count_rowr(   r(   r)   r   >  s   


zAbstractQuerySet.countNc                 C   s4   t | }|r||_|S dd | jj D |_|S )a  
        Returns the DISTINCT rows matched by this query.

        distinct_fields default to the partition key fields if not specified.

        *Note: distinct_fields must be a partition key or a static column*

        .. code-block:: python

            class Automobile(Model):
                manufacturer = columns.Text(partition_key=True)
                year = columns.Integer(primary_key=True)
                model = columns.Text(primary_key=True)
                price = columns.Decimal()

            sync_table(Automobile)

            # create rows

            Automobile.objects.distinct()

            # or

            Automobile.objects.distinct(['manufacturer'])

        c                 S      g | ]}|j qS r(   )column_namer  r(   r(   r)   r  o      z-AbstractQuerySet.distinct.<locals>.<listcomp>)r   r   r   r   _partition_keysr   )r1   r   r   r(   r(   r)   distinctO  s   
zAbstractQuerySet.distinctc                 C   sL   |du rd}t |tst|| jkr| S |dk rtdt| }||_|S )a  
        Limits the number of results returned by Cassandra. Use *0* or *None* to disable.

        *Note that CQL's default limit is 10,000, so all queries without a limit set explicitly will have an implicit limit of 10,000*

        .. code-block:: python

            # Fetch 100 users
            for user in User.objects().limit(100):
                print(user)

            # Fetch all users
            for user in User.objects().limit(None):
                print(user)
        Nr   zNegative limit is not allowed)rG   r   r   r   r#   r   r   r1   r   r   r(   r(   r)   r   s  s   


zAbstractQuerySet.limitc                 C   s@   t |tst|| jkr| S |dk rtdt| }||_|S )z
        Sets the number of rows that are fetched at a time.

        *Note that driver's default fetch size is 5000.*

        .. code-block:: python

            for user in User.objects().fetch_size(500):
                print(user)
        r   z%fetch size less than 1 is not allowed)rG   r   r   r   r#   r   r   rL  r(   r(   r)   r     s   


zAbstractQuerySet.fetch_sizec                 C   s   t | }d|_|S )z}
        Enables the (usually) unwise practive of querying on a clustering key without also defining a partition key
        T)r   r   r   r1   r   r(   r(   r)   r        
z AbstractQuerySet.allow_filteringc                    s   |dkr j rtdt } fdd|D }|r(tdd| jj fdd|D }|dkr=|j	| |S |dkrF||_ |S t
)	Nonlyz*QuerySet already has 'only' fields definedc                    s    g | ]}| j j vr|qS r(   )r   _columnsr   r   r  rC   r(   r)   r    s     z3AbstractQuerySet._only_or_defer.<locals>.<listcomp>zCan't resolve fields {0} in {1}z, c                    s   g | ]	} j j| jqS r(   )r   rP  r#  )r   fieldrC   r(   r)   r        defer)r   r#   r   r   rw   r   r   r%   r   r   rv   )r1   actionr   r   missing_fieldsr(   rC   r)   _only_or_defer  s$   
zAbstractQuerySet._only_or_deferc                 C      |  d|S )z/ Load only these fields for the returned query rO  rW  r1   r   r(   r(   r)   rO       zAbstractQuerySet.onlyc                 C   rX  )z0 Don't load these fields for the returned query rT  rY  rZ  r(   r(   r)   rT    r[  zAbstractQuerySet.deferc                 K   sN   | j di || j| j| j| j	| j
| jj| jd S )Nr   r(   )r   r  r   ttlr   rj   rb   if_not_existsr   ra   r   	if_existsr   usingrh   save)r1   rs   r(   r(   r)   create  s   zAbstractQuerySet.createc                 C   sd   t dd | jj D }|t dd | jD  rtdt| j| j| j| j	| j
d}| | dS )z1
        Deletes the contents of a query
        c                 s       | ]}|j V  qd S r@   r#  r  r(   r(   r)   r         z*AbstractQuerySet.delete.<locals>.<genexpr>c                 s   rb  r@   rR  )r   cr(   r(   r)   r     rd  z3The partition key must be defined on delete queries)r   ra   conditionalsr^  N)r   r   rJ  r   r   r#   r   r   r   r   r   r   )r1   partition_keysdqr(   r(   r)   delete  s   zAbstractQuerySet.deletec                    s0   t | jt  jkrt fdd| jD S dS )Nc                    s   g | ]}| j v qS r(   )r   r   wqr(   r)   r    r-  z+AbstractQuerySet.__eq__.<locals>.<listcomp>F)r   r   r  r1   rn  r(   rm  r)   rT     s   zAbstractQuerySet.__eq__c                 C   s
   | |k S r@   r(   ro  r(   r(   r)   __ne__  rp   zAbstractQuerySet.__ne__c                 C   r  )zi
        :param timeout: Timeout for the query (in seconds)
        :type timeout: float or None
        )r   r   rd   )r1   rl   r   r(   r(   r)   rl     s   
zAbstractQuerySet.timeoutc                 C   sL   |r	| j r	tdt| }|rddlm} || jd|i|_|r$||_|S )zY
        Change the context on-the-fly of the Model class (keyspace, connection)
        z3Cannot specify a connection on model in batch mode.r   )r   r   )r   r
   r   r   cassandra.cqlengine.modelsr   r   rh   )r1   r   r   r   r   r(   r(   r)   r_    s   

zAbstractQuerySet.usingr@   )NN)1r%   r&   r'   r/   propertyr   r   rF   r   r   r   r   r   r   r   r   r   r   r   r  r   staticmethodr	  r   r  r  r  rj   r  r*  r   r8  rA  r   r   rK  r   r   r   rW  rO  rT  ra  rj  rT   rp  rl   r_  r5   r(   r(   r2   r)   r   S  s\    5

+
 A#,
$ 	r   c                   @      e Zd ZdZdd ZdS )ResultObjectz/
    adds attribute access to a dictionary
    c                 C   s   z| | W S  t y   tw r@   )r!  AttributeErrorrM   r(   r(   r)   __getattr__  s
   
zResultObject.__getattr__N)r%   r&   r'   r4   rw  r(   r(   r(   r)   ru        ru  c                   @   rt  )SimpleQuerySetzn
    Overrides _get_result_constructor for querysets that do not define a model (e.g. NamedTable queries)
    c                 C   s   t S r  )ru  rC   r(   r(   r)   r   %  r  z&SimpleQuerySet._get_result_constructorN)r%   r&   r'   r4   r   r(   r(   r(   r)   ry     rx  ry  c                       sl   e Zd ZdZdd Z fddZdd Z fdd	Zd
d Zdd Z	dd Z
dd Zdd Zdd Z  ZS )ModelQuerySetz
    c                    s    fdd j D }tdd  j D }tdd |D s&|s& js&td jsAtdd |D sCtdd |D sE|sGtd	d
S d
S d
S d
S )zB Checks that a filterset will not create invalid select statement c                    sB   g | ]}t |jtst |jts j|jjr j|jqS r(   )	rG   r1  r   r$  r   r   _get_column_by_db_namerR  custom_indexrk  rC   r(   r)   r  5  s    
z8ModelQuerySet._validate_select_where.<locals>.<listcomp>c                 S   s   g | ]
}t |jtr|qS r(   )rG   r1  r   rk  r(   r(   r)   r  9  s    c                 s   s    | ]	}|j p	|jV  qd S r@   )primary_key	has_indexrk  r(   r(   r)   r   :  s    z7ModelQuerySet._validate_select_where.<locals>.<genexpr>zWhere clauses require either  =, a IN or a CONTAINS (collection) comparison with either a primary key or indexed field. You might want to consider setting custom_index on fields that you manage index outside cqlengine.c                 s   rb  r@   )r~  rk  r(   r(   r)   r   D  rd  c                 S   rG  r(   )partition_keyrk  r(   r(   r)   r  E  rI  zFiltering on a clustering key without a partition key is not allowed unless allow_filtering() is called on the queryset. You might want to consider setting custom_index on fields that you manage index outside cqlengine.N)r   anyr   r#   )r1   	equal_opstoken_comparisonr(   rC   r)   r   /  s"   
z$ModelQuerySet._validate_select_wherec                    s    j s jrJdd  jj D } j r* fdd|D }|s*dd  jj D } jr6 fdd|D }|sHtdd jd j |S t	t
  S )Nc                 S   rG  r(   rc  r   r	   r(   r(   r)   r  O  rI  z0ModelQuerySet._select_fields.<locals>.<listcomp>c                    s   g | ]	}| j vr|qS r(   )r   rQ  rC   r(   r)   r  Q  rS  c                 S   rG  r(   rc  r  r(   r(   r)   r  T  rI  c                    s   g | ]	}| j v r|qS r(   r   rQ  rC   r(   r)   r  V  rS  zBNo fields in select query. Only fields: "{0}", defer fields: "{1}"r   )r   r   r   rP  r   rJ  r#   rw   r   r.   rz  r   rZ  r2   rC   r)   r   M  s   zModelQuerySet._select_fieldsc                    s6   j sjjS jrjd   fddS fddS )zC Returns a function that will be used to instantiate query results r   c                    s   |   S r@   r(   r  )keyr(   r)   <lambda>c  s    z7ModelQuerySet._get_result_constructor.<locals>.<lambda>c                    s    fddj D S )Nc                    s   g | ]} | qS r(   r(   rQ  r  r(   r)   r  e      zKModelQuerySet._get_result_constructor.<locals>.<lambda>.<locals>.<listcomp>r  r  rC   r  r)   r  e  r  )r   r   _construct_instancer   r   rC   r(   )r  r1   r)   r   ]  s   
z%ModelQuerySet._get_result_constructorc                    s   t t| |\}}| jj|}|d u rtd||js&td|dd | jj	 D }||d kr;td|j
|fS )Nz$Can't resolve the column name: '{0}'z@Can't order on '{0}', can only order on (clustered) primary keysc                 S   s   g | ]	\}}|j r|qS r(   )r}  )r   r   r   r(   r(   r)   r  s  rS  z9ModelQuerySet._get_ordering_condition.<locals>.<listcomp>r   zVCan't order by the first primary key (partition key), clustering (secondary) keys only)r.   rz  rA  r   rP  r8  r#   rw   r}  r   r#  )r1   r?  r@  r'  pksr2   r(   r)   rA  g  s   
z%ModelQuerySet._get_ordering_conditionc                 O   sT   | dd}|rtd| f |rt|dkrtd| |}d|_||_|S )z> Instructs the query set to return tuples, not model instance flatFz/Unexpected keyword arguments to values_list: %sr   zH'flat' is not valid when values_list is called with more than one field.T)r   r   r   r   rO  r   r   )r1   r   rs   r  r   r(   r(   r)   values_listz  s   
zModelQuerySet.values_listc                 C   r  )z
        Sets the ttl (in seconds) for modified data.

        *Note that running a select query with a ttl value will raise an exception*
        )r   r   r   )r1   r\  r   r(   r(   r)   r\    s   
zModelQuerySet.ttlc                 C   r  )zK
        Allows for custom timestamps to be saved with the record.
        )r   r   r   )r1   ra   r   r(   r(   r)   ra     rN  zModelQuerySet.timestampc                 C   $   | j jrtdt| }d|_|S )z
        Check the existence of an object before insertion.

        If the insertion isn't applied, a LWTException is raised.
        zCif_not_exists cannot be used with tables containing counter columnsT)r   _has_counterr+   r   r   r   rM  r(   r(   r)   r]    
   
zModelQuerySet.if_not_existsc                 C   r  )z
        Check the existence of an object before an update or delete.

        If the update or delete isn't applied, a LWTException is raised.
        z?if_exists cannot be used with tables containing counter columnsT)r   r  r,   r   r   r   rM  r(   r(   r)   r^    r  zModelQuerySet.if_existsc                    st  |sdS t  }t   t| j| j| j| j| j| jd}| D ]m\}}| 	|\}}| j
j|}|du r@td| j| j
j||jrOtd|| j| j
j|dkrot|tjrot|t sgtd|||dd |D }n||}|du r~|| q|j|||d	  | q|jr| | |r| jr fd
d| jD nd}	t| j|| j|	| jd}
| |
 dS dS )a&  
        Performs an update on the row selected by the queryset. Include values to update in the
        update like so:

        .. code-block:: python

            Model.objects(key=n).update(value='x')

        Passing in updates for columns which are not part of the model will raise a ValidationError.

        Per column validation will be performed, but instance level validation will not
        (i.e., `Model.validate` is not called).  This is sometimes referred to as a blind update.

        For example:

        .. code-block:: python

            class User(Model):
                id = Integer(primary_key=True)
                name = Text()

            setup(["localhost"], "test")
            sync_table(User)

            u = User.create(id=1, name="jon")

            User.objects(id=1).update(name="Steve")

            # sets name to null
            User.objects(id=1).update(name=None)


        Also supported is blindly adding and removing elements from container columns,
        without loading a model instance from Cassandra.

        Using the syntax `.update(column_name={x, y, z})` will overwrite the contents of the container, like updating a
        non container column. However, adding `__<operation>` to the end of the keyword arg, makes the update call add
        or remove items from the collection, without overwriting then entire column.

        Given the model below, here are the operations that can be performed on the different container columns:

        .. code-block:: python

            class Row(Model):
                row_id      = columns.Integer(primary_key=True)
                set_column  = columns.Set(Integer)
                list_column = columns.List(Integer)
                map_column  = columns.Map(Integer, Integer)

        :class:`~cqlengine.columns.Set`

        - `add`: adds the elements of the given set to the column
        - `remove`: removes the elements of the given set to the column


        .. code-block:: python

            # add elements to a set
            Row.objects(row_id=5).update(set_column__add={6})

            # remove elements to a set
            Row.objects(row_id=5).update(set_column__remove={4})

        :class:`~cqlengine.columns.List`

        - `append`: appends the elements of the given list to the end of the column
        - `prepend`: prepends the elements of the given list to the beginning of the column

        .. code-block:: python

            # append items to a list
            Row.objects(row_id=5).update(list_column__append=[6, 7])

            # prepend items to a list
            Row.objects(row_id=5).update(list_column__prepend=[1, 2])


        :class:`~cqlengine.columns.Map`

        - `update`: adds the given keys/values to the columns, creating new entries if they didn't exist, and overwriting old ones if they did

        .. code-block:: python

            # add items to a map
            Row.objects(row_id=5).update(map_column__update={1: 2, 3: 4})

            # remove items from a map
            Row.objects(row_id=5).update(map_column__remove={1, 2})
        N)r   r\  ra   rg  r^  z {0}.{1} has no column named: {2}z4Cannot apply update to primary key '{0}' for {1}.{2}removezXCannot apply update operation '{0}' on column '{1}' with value '{2}'. A set is required.c                 S   s   i | ]}|d qS r@   r(   r+  r(   r(   r)   
<dictcomp>   rI  z(ModelQuerySet.update.<locals>.<dictcomp>)	operationc                       g | ]	}|j  vr|qS r(   re  r   	conditionupdated_columnsr(   r)   r  0      
z(ModelQuerySet.update.<locals>.<listcomp>)r   r   rg  r^  )r   r   r   r   r   r   r   r   r   r  r   rP  r8  r   rw   r&   r%   is_primary_keyrG   r	   r6  validater7  
add_updateassignmentsr   r   )r1   r   nulled_columnsusnamerI   r%  r&  coldelete_conditionaldsr(   r  r)   r     sL   Z




zModelQuerySet.update)r%   r&   r'   r4   r   r   r   rA  r  r\  ra   r]  r^  r   r5   r(   r(   r2   r)   rz  ,  s    

rz  c                	   @   st   e Zd ZdZdZdZdZdZdZddddddde	j
df	ddZdd Zdd	 Zdd
dZdd Zdd Zdd ZdS )DMLQueryz
    A query object used for queries performing inserts, updates, or deletes

    this is usually instantiated by the model instance to be modified

    unlike the read query object, this is mutable
    NFc                 C   sL   || _ | j  | _|| _|| _|| _|| _|| _|| _|
| _|| _	|	| _
d S r@   )r   r   r   r   r   rb   r   r   r   r   rd   )r1   r   r   r  r\  rj   ra   r]  conditionalrl   r^  r(   r(   r)   r/   E  s   
zDMLQuery.__init__c                 C   s   | j r| j  n| j }| jr/| jjr%| jjs$|r$|| jjkr$tdn|| j_| j|S t| j|| j	| j
|d}| jsD| jsD| jrHt| |S )Nz:BatchQuery queries must be executed on the same connectionr   )r   r   r   r   rh   ri   r
   ro   r   rb   rd   r   r   r   r=   )r1   r   r   resultsr(   r(   r)   r   S  s   zDMLQuery._executec                 C   s$   |d urt |tstd|| _| S )Nr  )rG   r^   r
   r   )r1   r  r(   r(   r)   r  d  s   zDMLQuery.batchc                 C   s   t | j|| jd}d}d}| jj D ]9\}}|j}|jr+||j	 d}||j
M }qt|tjrLt|j	|j|j}| dkrL|| d}||j
O }q|ru|rU| jjn| jj}	|	 D ]\}
}||t t| j|
 q]| | dS dS )zU
        executes a delete query to remove columns that have changed to null
        )rg  r^  FTr   N)r   r   r   r   _valuesr   r'  deleted	add_fieldr#  staticrG   r	   r6  r    r1  previous_valueget_context_sizer   rJ  _primary_keys	add_wherer   getattrr   )r1   rg  r  deleted_fieldsstatic_only_r   r  ucr   r  r(   r(   r)   _delete_null_columnsj  s,   

zDMLQuery._delete_null_columnsc           	         s  | j du r	tdt| j | jksJ t| j jdkrdnd}d}t| j| j| j	| j
| jd}| j j D ]\}}|oD|t| j |d}q5t  | jj D ]@\}}|r\|js\|js\qO|jst| j |d}| j j| }|du rqqO|js{t|tjs{qO|o|j}|j|||jd  |j qO|jr| jj D ]\}}|s|r|jsq||t  t| j | q| !| |s| j
rƇ fdd	| j
D nd}| "| dS dS )
z
        updates a row.
        This is a blind update call.
        All validation and cleaning needs to happen
        prior to calling this.
        N#DML Query intance attribute is Noner   FT)r\  ra   rg  r^  )previousc                    r  r(   re  r  r  r(   r)   r    r  z#DMLQuery.update.<locals>.<listcomp>)#r   r
   rx   r   r   _clustering_keysr   r   r   r   r   r   r   _val_is_nullr  r   rP  r  r  r  r  changedrG   r	   r]   r  r  r7  r#  r  r  r  r   r   r  )	r1   null_clustering_keystatic_changed_onlyr   r  r  rI   val_mgrdelete_conditionalsr(   r  r)   r     sL   


zDMLQuery.updatec                 C   sn  | j du r	tdt| j | jksJ t }| j js| j  r,| j jr(tdt | 	 S t
| j| j| j| jd}t| j jdkrBdnd}| j j D ]\}}|oY|t| j |d}qJ| j j D ]C\}}|rn|jsn|jsnqat| j |d}||r| j j| jr||j qa|jr| j j| jsd| j j| _||t| j |d qa|js| | |s|    dS dS )z
        Creates / updates a row.
        This is a blind insert call.
        All validation and cleaning needs to happen
        prior to calling this.
        Nr  zy'create' and 'save' actions on Counters are deprecated. It will be disallowed in 4.0. Use the 'update' mechanism instead.)r\  ra   r]  r   FT)!r   r
   rx   r   r   r  _can_updater   r   r   r   r   r   r   r   r   r  r   r  r  rP  r  r  r  r  r7  r#  has_defaultexplicitadd_assignmentis_emptyr   r  )r1   nulled_fieldsinsertstatic_save_onlyr  r  rI   r(   r(   r)   r`    s<   


zDMLQuery.savec                 C   sz   | j du r	tdt| j| j| j| jd}| jj	 D ]\}}t
| j |}|du r-|js-q||t | q| | dS )z Deletes one instance Nz$DML Query instance attribute is None)ra   rg  r^  )r   r
   r   r   r   r   r   r   r  r   r  r  r  r   r   )r1   r  r  r  rI   r(   r(   r)   rj    s   
zDMLQuery.deleter@   )r%   r&   r'   r4   r   rb   r   r   r   r   r   r/   r   r  r  r   r`  rj  r(   r(   r(   r)   r  7  s     



3+r  c           	      C   s   |  }tt|||jd}| jr2|| j}tdd |D s2| |t	|j
}||_|  |_|p7|  }tj||||dS )N)consistency_levelr   c                 s   s    | ]}|d u V  qd S r@   r(   r+  r(   r(   r)   r     s    z%_execute_statement.<locals>.<genexpr>)rl   r   )r   r   rL   r   _partition_key_indexpartition_key_valuesr  _routing_key_from_valuesr   get_clusterprotocol_versionrouting_key_get_keyspacer   r   r   )	r   r   r  rl   r   paramsr   
key_valuespartsr(   r(   r)   r     s   
r   r@   )<r   r   r   	functoolsr   r   warningsr   cassandra.queryr   r   r   r   r   r	   r
   r   r   r   r   cassandra.cqlengine.functionsr   r   r   cassandra.cqlengine.operatorsr   r   r   r   r   r   r   r   cassandra.cqlengine.statementsr   r   r   r   r   r   r    r!   r#   r+   r,   r-   r6   r7   r=   r>   objectr^   r   r   r   ru  ry  rz  r  r   r(   r(   r(   r)   <module>   sJ   ((1 A     F   :