U
    4Jec                     @  s4  d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	m
Z
mZmZmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZmZmZ ddl m!Z!m"Z"m#Z#m$Z$m%Z%m&Z& dZ'G dd dZ(dddddZ)dDddddddZ*dEddddddZ+dFddddd d!Z,dGdddd"d#d$d%Z-G d&d' d'Z.G d(d) d)e.Z/G d*d+ d+e.Z0G d,d- d-e.Z1G d.d/ d/e1Z2G d0d1 d1Z3G d2d3 d3e/Z4G d4d5 d5e/Z5G d6d7 d7e5Z6G d8d9 d9e5Z7G d:d; d;e1Z8G d<d= d=e/Z9G d>d? d?e/Z:G d@dA dAe/Z;G dBdC dCe.Z<dS )HzImplementation of Statements.    )annotationsN)AnyDictIterableListOptionalTupleUnion   )LockContention)DbDoc)NotSupportedErrorProgrammingError)
ExprParser)
deprecated)mysqlxpb_enum)	DocResultResult	RowResult	SqlResult)ConnectionTypeDatabaseTargetTypeMessageTypeProtobufMessageCextTypeProtobufMessageType
SchemaTypez&The given index name "{}" is not validc                   @  s    e Zd ZdZdddddZdS )ExprzExpression wrapper.r   None)exprreturnc                 C  s
   || _ d S N)r   )selfr    r"   4/tmp/pip-unpacked-wheel-7_167w8m/mysqlx/statement.py__init__?   s    zExpr.__init__N)__name__
__module____qualname____doc__r$   r"   r"   r"   r#   r   <   s   r   r   zUnion[List, Tuple]valuesr   c                  G  s*   t | dkr&t| d ttfr&| d S | S )zParse flexible parameters.r
   r   )len
isinstancelisttuple)r*   r"   r"   r#   flexible_paramsC   s    r/    strbool)
identifiersql_moder   c                 C  sP   d|kr8| d dkr | d dkp6| d dko6| d dkS | d dkoN| d dkS )zCheck if the given identifier is quoted.

    Args:
        identifier (string): Identifier to check.
        sql_mode (Optional[string]): SQL mode.

    Returns:
        `True` if the identifier has backtick quotes, and False otherwise.
    ANSI_QUOTESr   `"r"   )r3   r4   r"   r"   r#   is_quoted_identifierJ   s
    
r9   c                 C  sH   t | dkrdS d|kr0| dd}d| dS | dd}d| dS )a@  Quote the given identifier with backticks, converting backticks (`) in
    the identifier name with the correct escape sequence (``).

    Args:
        identifier (string): Identifier to quote.
        sql_mode (Optional[string]): SQL mode.

    Returns:
        A string with the identifier quoted with backticks.
    r   z``r5   r8   z""r6   )r+   replace)r3   r4   quotedr"   r"   r#   quote_identifier[   s    r<   zIterable[str])identifiersr4   r   c                   s   d  fdd| D S )a  Quote the given multi-part identifier with backticks.

    Args:
        identifiers (iterable): List of identifiers to quote.
        sql_mode (Optional[string]): SQL mode.

    Returns:
        A string with the multi-part identifier quoted with backticks.
    .c                   s   g | ]}t | qS r"   )r<   ).0r3   r4   r"   r#   
<listcomp>z   s     z.quote_multipart_identifier.<locals>.<listcomp>)join)r=   r4   r"   r@   r#   quote_multipart_identifiero   s    
rC   zTuple[str, str])default_schema
table_namer4   r   c                 C  s^   d|krdnd}||kr"d| nd}| |d}t|dkrB| n|d ||d |fS )zParse table name.

    Args:
        default_schema (str): The default schema.
        table_name (str): The table name.
        sql_mode(Optional[str]): The SQL mode.

    Returns:
        str: The parsed table name.
    r5   r8   r6   r>   r
   r   r7   )splitr+   strip)rD   rE   r4   quote	delimitertempr"   r"   r#   parse_table_name~   s    rK   c                   @  sD  e Zd ZdZd+ddddddZedd	d
dZedd	ddZedd	ddZej	dddddZedd	ddZ
edd	ddZej	dddddZedd	ddZej	dddddZedd	ddZedd	ddZej	dddd dZdd	d!d"Zdd	d#d$Zdd	d%d&Zd'd	d(d)Zd*S ),	Statementa	  Provides base functionality for statement objects.

    Args:
        target (object): The target database object, it can be
                         :class:`mysqlx.Collection` or :class:`mysqlx.Table`.
        doc_based (bool): `True` if it is document based.
    Tr   r2   r   target	doc_basedr   c                 C  s@   || _ || _|r| nd | _d | _d| _d| _d| _d| _d S )Nr   TF)	_target
_doc_basedget_connection_connection_stmt_id_exec_counter_changed	_prepared_deallocate_prepare_executer!   rN   rO   r"   r"   r#   r$      s    zStatement.__init__r   c                 C  s   | j S )z#object: The database object target.)rP   r!   r"   r"   r#   rN      s    zStatement.targetr   c                 C  s   | j jS )z*:class:`mysqlx.Schema`: The Schema object.)rP   schemar[   r"   r"   r#   r\      s    zStatement.schemaintc                 C  s   | j S )zXReturns this statement ID.

        Returns:
            int: The statement ID.
        rT   r[   r"   r"   r#   stmt_id   s    zStatement.stmt_idvaluer   c                 C  s
   || _ d S r    r^   r!   ra   r"   r"   r#   r_      s    c                 C  s   | j S )z5int: The number of times this statement was executed.rU   r[   r"   r"   r#   exec_counter   s    zStatement.exec_counterc                 C  s   | j S )z+bool: `True` if this statement has changes.rV   r[   r"   r"   r#   changed   s    zStatement.changedc                 C  s
   || _ d S r    re   rb   r"   r"   r#   rf      s    c                 C  s   | j S )z1bool: `True` if this statement has been prepared.rW   r[   r"   r"   r#   prepared   s    zStatement.preparedc                 C  s
   || _ d S r    rg   rb   r"   r"   r#   rh      s    c                 C  s
   | j dkS )z;bool: `True` if this statement was executed more than once.r
   rc   r[   r"   r"   r#   repeated   s    zStatement.repeatedc                 C  s   | j S )z9bool: `True` to deallocate + prepare + execute statement.rX   r[   r"   r"   r#   deallocate_prepare_execute   s    z$Statement.deallocate_prepare_executec                 C  s
   || _ d S r    rj   rb   r"   r"   r#   rk      s    c                 C  s   | j S )zkCheck if it is document based.

        Returns:
            bool: `True` if it is document based.
        )rQ   r[   r"   r"   r#   is_doc_based   s    zStatement.is_doc_basedc                 C  s   |  j d7  _ dS )z@Increments the number of times this statement has been executed.r
   Nrc   r[   r"   r"   r#   increment_exec_counter   s    z Statement.increment_exec_counterc                 C  s
   d| _ dS )z<Resets the number of times this statement has been executed.r   Nrc   r[   r"   r"   r#   reset_exec_counter   s    zStatement.reset_exec_counterr   c                 C  s   t dS zqExecute the statement.

        Raises:
           NotImplementedError: This method must be implemented.
        NNotImplementedErrorr[   r"   r"   r#   execute   s    zStatement.executeN)T)r%   r&   r'   r(   r$   propertyrN   r\   r_   setterrd   rf   rh   ri   rk   rl   rm   rn   rr   r"   r"   r"   r#   rL      s<   rL   c                      s~  e Zd ZdZdGddddd fd	d
ZdddddZdd dddZdd dddZdddddZdddddZ	dd dddZ
dddd Zd!dd"d#Zd$dd%d&Zd'dd(d)Zd*dd+d,Zd*dd-d.Zd'dd/d0Zd$dd1d2Zd$dd3d4Zed5dd dd6d7Zed5dd dd8d9ZdHd*d:d d;d<d=Zd*d d>d?d@ZdAd dBdCdDZdAddEdFZ  ZS )IFilterableStatementa  A statement to be used with filterable statements.

    Args:
        target (object): The target database object, it can be
                         :class:`mysqlx.Collection` or :class:`mysqlx.Table`.
        doc_based (Optional[bool]): `True` if it is document based
                                    (default: `True`).
        condition (Optional[str]): Sets the search condition to filter
                                   documents or records.
    TNr   r2   Optional[str]r   rN   rO   	conditionr   c                   s   t  j||d i | _i | _d | _d| _d | _d| _d | _d| _	d | _
d| _d | _d| _d | _d| _d| _d| _d| _d| _d| _d| _|r| | d S )NrN   rO   r0   r   F)superr$   _binding_map	_bindings_having_grouping_str	_grouping_limit_offset_limit_row_count_projection_str_projection_expr	_sort_str
_sort_expr
_where_str_where_exprhas_bindings	has_limithas_group_by
has_havinghas_projectionhas_sort	has_where
_set_wherer!   rN   rO   rx   	__class__r"   r#   r$   
  s4    zFilterableStatement.__init__z!Union[DbDoc, Dict[str, Any], str])objr   c              
   C  s   t |tr| t|  nt |tr8| |  n|t |trzt|}t |ts\tW n, tk
r } zt	d|W 5 d}~X Y nX |
 D ]}| |||  qnt	ddS )a  Bind single object.

        Args:
            obj (:class:`mysqlx.DbDoc` or str): DbDoc or JSON string object.

        Raises:
            :class:`mysqlx.ProgrammingError`: If invalid JSON string to bind.
            ValueError: If JSON loaded is not a dictionary.
        zInvalid JSON string to bindNz%Invalid JSON string or object to bind)r,   dictbindr   Zas_strr1   jsonloads
ValueErrorr   keys)r!   r   reserrkeyr"   r"   r#   _bind_single.  s    





z FilterableStatement._bind_singler1   clausesr   c                 G  s6   d| _ dt| | _t| j| j  | _d| _| S )zSets the sorting criteria.

        Args:
            *clauses: The expression strings defining the sort criteria.

        Returns:
            mysqlx.FilterableStatement: FilterableStatement object.
        T,)	r   rB   r/   r   r   rQ   Zparse_order_specr   rV   r!   r   r"   r"   r#   _sortH  s    	 
zFilterableStatement._sortrx   r   c              
   C  sh   d| _ || _zt|| j }| | _W n, tk
rT } ztd|W 5 d}~X Y nX |j| _	d| _
| S )a  Sets the search condition to filter.

        Args:
            condition (str): Sets the search condition to filter documents or
                             records.

        Returns:
            mysqlx.FilterableStatement: FilterableStatement object.
        TzInvalid conditionN)r   r   r   rQ   r   r   r   r   Zplaceholder_name_to_positionr{   rV   )r!   rx   r   r   r"   r"   r#   r   Y  s    
zFilterableStatement._set_wherefieldsr   c                 G  s:   t | }d| _d|| _t| j| j  | _d| _dS )zJSet group by.

        Args:
            *fields: List of fields.
        Tr   N)	r/   r   rB   r~   r   rQ   Zparse_expr_listr   rV   r!   r   r"   r"   r#   _set_group_byn  s     
z!FilterableStatement._set_group_byc                 C  s$   d| _ t|| j  | _d| _dS )zOSet having.

        Args:
            condition (str): The condition.
        TN)r   r   rQ   r   r}   rV   r!   rx   r"   r"   r#   _set_having|  s    zFilterableStatement._set_havingc                 G  s:   t | }d| _d|| _t| j| j  | _d| _| S )zSet the projection.

        Args:
            *fields: List of fields.

        Returns:
            :class:`mysqlx.FilterableStatement`: Returns self.
        Tr   )	r/   r   rB   r   r   rQ   Zparse_table_select_projectionr   rV   r   r"   r"   r#   _set_projection  s    	 
z#FilterableStatement._set_projectionDict[str, Any]rZ   c                 C  s   | j S zlReturns the binding map dictionary.

        Returns:
            dict: The binding map dictionary.
        r{   r[   r"   r"   r#   get_binding_map  s    z#FilterableStatement.get_binding_mapzUnion[Dict[str, Any], List]c                 C  s   | j S z\Returns the bindings list.

        Returns:
            `list`: The bindings list.
        r|   r[   r"   r"   r#   get_bindings  s    z FilterableStatement.get_bindingsz9List[Union[ProtobufMessageType, ProtobufMessageCextType]]c                 C  s   | j S )zrReturns the grouping expression list.

        Returns:
            `list`: The grouping expression list.
        )r   r[   r"   r"   r#   get_grouping  s    z FilterableStatement.get_groupingr   c                 C  s   | j S )zdReturns the having expression.

        Returns:
            object: The having expression.
        )r}   r[   r"   r"   r#   
get_having  s    zFilterableStatement.get_havingr]   c                 C  s   | j S )z]Returns the limit row count.

        Returns:
            int: The limit row count.
        )r   r[   r"   r"   r#   get_limit_row_count  s    z'FilterableStatement.get_limit_row_countc                 C  s   | j S )zWReturns the limit offset.

        Returns:
            int: The limit offset.
        )r   r[   r"   r"   r#   get_limit_offset  s    z$FilterableStatement.get_limit_offsetc                 C  s   | j S )zbReturns the where expression.

        Returns:
            object: The where expression.
        )r   r[   r"   r"   r#   get_where_expr  s    z"FilterableStatement.get_where_exprc                 C  s   | j S )zlReturns the projection expression.

        Returns:
            object: The projection expression.
        )r   r[   r"   r"   r#   get_projection_expr  s    z'FilterableStatement.get_projection_exprc                 C  s   | j S )z`Returns the sort expression.

        Returns:
            object: The sort expression.
        )r   r[   r"   r"   r#   get_sort_expr  s    z!FilterableStatement.get_sort_expr8.0.12c                 C  s
   |  |S )a&  Sets the search condition to filter.

        Args:
            condition (str): Sets the search condition to filter documents or
                             records.

        Returns:
            mysqlx.FilterableStatement: FilterableStatement object.

        .. deprecated:: 8.0.12
        r   r   r"   r"   r#   where  s    zFilterableStatement.wherec                 G  s
   | j | S )zSets the sorting criteria.

        Args:
            *clauses: The expression strings defining the sort criteria.

        Returns:
            mysqlx.FilterableStatement: FilterableStatement object.

        .. deprecated:: 8.0.12
        r   r   r"   r"   r#   sort  s    zFilterableStatement.sortzOptional[int])	row_countoffsetr   c                 C  sn   t |tr|dk rtd| jsBt| jdk| _t| jdk | _|| _d| _|rj| 	| t
jdtd | S )a  Sets the maximum number of items to be returned.

        Args:
            row_count (int): The maximum number of items.

        Returns:
            mysqlx.FilterableStatement: FilterableStatement object.

        Raises:
            ValueError: If ``row_count`` is not a positive integer.

        .. versionchanged:: 8.0.12
           The usage of ``offset`` was deprecated.
        r   z0The 'row_count' value must be a positive integerTzh'limit(row_count, offset)' is deprecated, please use 'offset(offset)' to set the number of items to skip)category)r,   r]   r   r   r2   rU   rV   rX   r   r   warningswarnDeprecationWarning)r!   r   r   r"   r"   r#   limit  s    
zFilterableStatement.limit)r   r   c                 C  s$   t |tr|dk rtd|| _| S )a:  Sets the number of items to skip.

        Args:
            offset (int): The number of items to skip.

        Returns:
            mysqlx.FilterableStatement: FilterableStatement object.

        Raises:
            ValueError: If ``offset`` is not a positive integer.

        .. versionadded:: 8.0.12
        r   z-The 'offset' value must be a positive integer)r,   r]   r   r   )r!   r   r"   r"   r#   r   $  s    zFilterableStatement.offsetr   argsr   c                 G  sN   d| _ t|}|dkr&| |d  n$|dkrB|d | j|d < ntd| S )a  Binds value(s) to a specific placeholder(s).

        Args:
            *args: The name of the placeholder and the value to bind.
                   A :class:`mysqlx.DbDoc` object or a JSON string
                   representation can be used.

        Returns:
            mysqlx.FilterableStatement: FilterableStatement object.

        Raises:
            ProgrammingError: If the number of arguments is invalid.
        Tr
   r      #Invalid number of arguments to bind)r   r+   r   r|   r   )r!   r   countr"   r"   r#   r   7  s    zFilterableStatement.bindc                 C  s   t dS ro   rp   r[   r"   r"   r#   rr   O  s    zFilterableStatement.execute)TN)N)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   rr   __classcell__r"   r"   r   r#   ru      s8     $


 #ru   c                      sv   e Zd ZdZdddd fddZeddd	d
ZddddZddddZdd dddZ	ddddZ
  ZS )SqlStatementzA statement for SQL execution.

    Args:
        connection (mysqlx.connection.Connection): Connection object.
        sql (string): The sql statement to be executed.
    r   r1   r   )
connectionsqlr   c                   s8   t  jd dd || _|| _d | _g | _d| _d| _d S NFry   )rz   r$   rS   _sqlr{   r|   r   r   )r!   r   r   r   r"   r#   r$   `  s    zSqlStatement.__init__rZ   c                 C  s   | j S )zstring: The SQL text statement.)r   r[   r"   r"   r#   r   i  s    zSqlStatement.sqlr   c                 C  s   | j S r   r   r[   r"   r"   r#   r   n  s    zSqlStatement.get_binding_mapzUnion[Tuple, List]c                 C  s   | j S r   r   r[   r"   r"   r#   r   v  s    zSqlStatement.get_bindingsr   r   c                 G  sH   t |dkrtdd| _t| }t|ttfr8|| _n| j| | S )zBinds value(s) to a specific placeholder(s).

        Args:
            *args: The value(s) to bind.

        Returns:
            mysqlx.SqlStatement: SqlStatement object.
        r   r   T)	r+   r   r   r/   r,   r-   r.   r|   append)r!   r   Zbindingsr"   r"   r#   r   ~  s    	zSqlStatement.bindr   c                 C  s   | j | S )zaExecute the statement.

        Returns:
            mysqlx.SqlResult: SqlResult object.
        )rS   Zsend_sqlr[   r"   r"   r#   rr     s    zSqlStatement.execute)r%   r&   r'   r(   r$   rs   r   r   r   r   rr   r   r"   r"   r   r#   r   X  s   	r   c                      sF   e Zd ZdZdddd fddZdd	d
dZdd	ddZ  ZS )WriteStatementz*Provide common write operation attributes.r   r2   r   rM   c                   s   t  || g | _d S r    )rz   r$   _valuesrY   r   r"   r#   r$     s    	zWriteStatement.__init__zpList[Union[int, str, DbDoc, Dict[str, Any], List[Optional[Union[str, int, float, ExprParser, Dict[str, Any]]]]]]rZ   c                 C  s   | j S )z^Returns the list of values.

        Returns:
            `list`: The list of values.
        )r   r[   r"   r"   r#   
get_values  s    zWriteStatement.get_valuesr   c                 C  s   t dS ro   rp   r[   r"   r"   r#   rr     s    zWriteStatement.execute)r%   r&   r'   r(   r$   r   rr   r   r"   r"   r   r#   r     s   r   c                      sf   e Zd ZdZddd fddZddd	d
Zddd dddZdd dddZddddZ  Z	S )AddStatementzA statement for document addition on a collection.

    Args:
        collection (mysqlx.Collection): The Collection object.
    r   r   )
collectionr   c                   s   t  |d d| _g | _d S )NTF)rz   r$   _upsertids)r!   r   r   r"   r#   r$     s    zAddStatement.__init__r2   rZ   c                 C  s   | j S )zhReturns `True` if it's an upsert.

        Returns:
            bool: `True` if it's an upsert.
        r   r[   r"   r"   r#   	is_upsert  s    zAddStatement.is_upsertTr`   c                 C  s
   || _ | S )zSets the upset flag to the boolean of the value provided.
        Setting of this flag allows updating of the matched rows/documents
        with the provided value.

        Args:
            value (optional[bool]): Set or unset the upsert flag.
        r   rb   r"   r"   r#   upsert  s    zAddStatement.upsertr   r)   c                 G  s:   t | D ],}t|tr$| j| q| jt| q| S )zAdds a list of documents into a collection.

        Args:
            *values: The documents to be added into the collection.

        Returns:
            mysqlx.AddStatement: AddStatement object.
        )r/   r,   r   r   r   )r!   r*   valr"   r"   r#   add  s
    	
zAddStatement.addr   c                 C  s    t | jdkrt S | j| S )[Execute the statement.

        Returns:
            mysqlx.Result: Result object.
        r   )r+   r   r   rS   send_insertr[   r"   r"   r#   rr     s    zAddStatement.execute)T)
r%   r&   r'   r(   r$   r   r   r   rr   r   r"   r"   r   r#   r     s   r   c                   @  s8   e Zd ZdZdddddddd	Zdddd
ddZdS )
UpdateSpeczUpdate specification class implementation.

    Args:
        update_type (int): The update type.
        source (str): The source.
        value (Optional[str]): The value.

    Raises:
        ProgrammingError: If `source` is invalid.
    Nr]   r1   r   r   )update_typesourcera   r   c              
   C  sp   |t dkr| || nR|| _zt|d j| _W n. tk
rd } zt| |W 5 d }~X Y nX || _	d S )N*Mysqlx.Crud.UpdateOperation.UpdateType.SETF)
r   
_table_setr   r   Zdocument_fieldr3   r   r   r   ra   )r!   r   r   ra   r   r"   r"   r#   r$     s    zUpdateSpec.__init__)r   ra   r   c                 C  s$   t d| _t|d | _|| _dS )zlTable set.

        Args:
            source (str): The source.
            value (str): The value.
        r   TN)r   r   r   Zparse_table_update_fieldr   ra   )r!   r   ra   r"   r"   r#   r     s    
zUpdateSpec._table_set)N)r%   r&   r'   r(   r$   r   r"   r"   r"   r#   r     s   r   c                      s   e Zd ZdZdddd fddZdd dd	d
ZddddZddd dddZedddd dddZ	dd dddZ
ddd dddZddd dddZdd dd d!Zd"dd#d$Z  ZS )%ModifyStatementaU  A statement for document update operations on a Collection.

    Args:
        collection (mysqlx.Collection): The Collection object.
        condition (str): Sets the search condition to identify the documents
                         to be modified.

    .. versionchanged:: 8.0.12
       The ``condition`` parameter is now mandatory.
    r   r1   r   r   rx   r   c                   s   t  j||d i | _d S N)rN   rx   rz   r$   _update_opsr!   r   rx   r   r"   r#   r$   .  s    zModifyStatement.__init__r   c                 G  s
   | j | S )zSets the sorting criteria.

        Args:
            *clauses: The expression strings defining the sort criteria.

        Returns:
            mysqlx.ModifyStatement: ModifyStatement object.
        r   r   r"   r"   r#   r   2  s    	zModifyStatement.sortr   rZ   c                 C  s   | j S ztReturns the list of update operations.

        Returns:
            `list`: The list of update operations.
        r   r[   r"   r"   r#   get_update_ops=  s    zModifyStatement.get_update_opsr   )doc_pathra   r   c                 C  s    t td||| j|< d| _| S )a2  Sets or updates attributes on documents in a collection.

        Args:
            doc_path (string): The document path of the item to be set.
            value (string): The value to be set on the specified attribute.

        Returns:
            mysqlx.ModifyStatement: ModifyStatement object.
        z/Mysqlx.Crud.UpdateOperation.UpdateType.ITEM_SETTr   r   r   rV   r!   r   ra   r"   r"   r#   setE  s    

zModifyStatement.setr   c                 C  s    t td||| j|< d| _| S )a  Add an update to the statement setting the field, if it exists at
        the document path, to the given value.

        Args:
            doc_path (string): The document path of the item to be set.
            value (object): The value to be set on the specified attribute.

        Returns:
            mysqlx.ModifyStatement: ModifyStatement object.

        .. deprecated:: 8.0.12
        z3Mysqlx.Crud.UpdateOperation.UpdateType.ITEM_REPLACETr   r   r"   r"   r#   changeW  s    
zModifyStatement.change)	doc_pathsr   c                 G  s,   t | D ]}ttd|| j|< qd| _| S )a  Removes attributes from documents in a collection.

        Args:
            doc_paths (list): The list of document paths of the attributes to be
                              removed.

        Returns:
            mysqlx.ModifyStatement: ModifyStatement object.
        z2Mysqlx.Crud.UpdateOperation.UpdateType.ITEM_REMOVET)r/   r   r   r   rV   )r!   r   itemr"   r"   r#   unsetm  s    
zModifyStatement.unsetfieldra   r   c                 C  s    t td||| j|< d| _| S )a  Insert a value into the specified array in documents of a
        collection.

        Args:
            field (string): A document path that identifies the array attribute
                            and position where the value will be inserted.
            value (object): The value to be inserted.

        Returns:
            mysqlx.ModifyStatement: ModifyStatement object.
        z3Mysqlx.Crud.UpdateOperation.UpdateType.ARRAY_INSERTTr   r!   r   ra   r"   r"   r#   array_insert  s    
zModifyStatement.array_insertc                 C  s    t td||| j|< d| _| S )a  Inserts a value into a specific position in an array attribute in
        documents of a collection.

        Args:
            doc_path (string): A document path that identifies the array
                               attribute and position where the value will be
                               inserted.
            value (object): The value to be inserted.

        Returns:
            mysqlx.ModifyStatement: ModifyStatement object.
        z3Mysqlx.Crud.UpdateOperation.UpdateType.ARRAY_APPENDTr   r   r"   r"   r#   array_append  s    
zModifyStatement.array_appendz#Union[Dict, DbDoc, ExprParser, str])docr   c                 C  sX   |dkrd}t |ttttfs&tdttddt |trB| n|| j	d< d| _
| S )a  Takes a :class:`mysqlx.DbDoc`, string JSON format or a dict with the
        changes and applies it on all matching documents.

        Args:
            doc (object): A generic document (DbDoc), string in JSON format or
                          dict, with the changes to apply to the matching
                          documents.

        Returns:
            mysqlx.ModifyStatement: ModifyStatement object.
        Nr0   z>Invalid data for update operation on document collection tablez2Mysqlx.Crud.UpdateOperation.UpdateType.MERGE_PATCH$patchT)r,   r   r   r   r1   r   r   r   r   r   rV   )r!   r   r"   r"   r#   r     s    
zModifyStatement.patchr   c                 C  s   | j std| j| S )Execute the statement.

        Returns:
            mysqlx.Result: Result object.

        Raises:
            ProgrammingError: If condition was not set.
        z!No condition was found for modifyr   r   rS   Zsend_updater[   r"   r"   r#   rr     s    	zModifyStatement.execute)r%   r&   r'   r(   r$   r   r   r   r   r   r   r   r   r   rr   r   r"   r"   r   r#   r   "  s   r   c                      s   e Zd ZdZd$ddddd fd	d
ZeddddZdddddZddddZddddZ	e
jfdd dddZe
jfdd dddZdd dddZdd ddd Zd!dd"d#Z  ZS )%ReadStatementa  Provide base functionality for Read operations

    Args:
        target (object): The target database object, it can be
                         :class:`mysqlx.Collection` or :class:`mysqlx.Table`.
        doc_based (Optional[bool]): `True` if it is document based
                                    (default: `True`).
        condition (Optional[str]): Sets the search condition to filter
                                   documents or records.
    TNr   r2   rv   r   rw   c                   s(   t  ||| d| _d| _tj| _d S NF)rz   r$   _lock_exclusive_lock_sharedr   DEFAULT_lock_contentionr   r   r"   r#   r$     s    zReadStatement.__init__r   rZ   c                 C  s   | j S )z::class:`mysqlx.LockContention`: The lock contention value.)r  r[   r"   r"   r#   lock_contention  s    zReadStatement.lock_contention)r  r   c              
   C  sF   zt |j}W n, tk
r: } ztd|W 5 d}~X Y nX || _dS )zSet the lock contention.

        Args:
            lock_contention (:class:`mysqlx.LockContention`): Lock contention.

        Raises:
            ProgrammingError: If is an invalid lock contention value.
        z;Invalid lock contention mode. Use 'NOWAIT' or 'SKIP_LOCKED'N)r   ra   r   r   r  )r!   r  _r   r"   r"   r#   _set_lock_contention  s    	z"ReadStatement._set_lock_contentionc                 C  s   | j S )zrReturns `True` if is `EXCLUSIVE LOCK`.

        Returns:
            bool: `True` if is `EXCLUSIVE LOCK`.
        )r  r[   r"   r"   r#   is_lock_exclusive  s    zReadStatement.is_lock_exclusivec                 C  s   | j S )zlReturns `True` if is `SHARED LOCK`.

        Returns:
            bool: `True` if is `SHARED LOCK`.
        )r  r[   r"   r"   r#   is_lock_shared  s    zReadStatement.is_lock_sharedc                 C  s   d| _ d| _| | | S )zExecute a read operation with `SHARED LOCK`. Only one lock can be
           active at a time.

        Args:
            lock_contention (:class:`mysqlx.LockContention`): Lock contention.
        FTr  r  r  r!   r  r"   r"   r#   lock_shared  s    	
zReadStatement.lock_sharedc                 C  s   d| _ d| _| | | S )zExecute a read operation with `EXCLUSIVE LOCK`. Only one lock can be
           active at a time.

        Args:
            lock_contention (:class:`mysqlx.LockContention`): Lock contention.
        TFr
  r  r"   r"   r#   lock_exclusive  s    	
zReadStatement.lock_exclusiver1   r   c                 G  s   | j |  | S )zSets a grouping criteria for the resultset.

        Args:
            *fields: The string expressions identifying the grouping criteria.

        Returns:
            mysqlx.ReadStatement: ReadStatement object.
        )r   r   r"   r"   r#   group_by*  s    	
zReadStatement.group_byr   c                 C  s   |  | | S )a=  Sets a condition for records to be considered in agregate function
        operations.

        Args:
            condition (string): A condition on the agregate functions used on
                                the grouping criteria.

        Returns:
            mysqlx.ReadStatement: ReadStatement object.
        )r   r   r"   r"   r#   having6  s    
zReadStatement.havingzUnion[DocResult, RowResult]c                 C  s   | j | S r   )rS   Z	send_findr[   r"   r"   r#   rr   D  s    zReadStatement.execute)TN)r%   r&   r'   r(   r$   rs   r  r  r  r	  r   r  r  r  r  r  rr   r   r"   r"   r   r#   r     s      	r   c                      sL   e Zd ZdZddddd fddZd	d d
ddZd	d dddZ  ZS )FindStatementa  A statement document selection on a Collection.

    Args:
        collection (mysqlx.Collection): The Collection object.
        condition (Optional[str]): An optional expression to identify the
                                   documents to be retrieved. If not specified
                                   all the documents will be included on the
                                   result unless a limit is set.
    Nr   rv   r   r   c                   s   t  |d| d S )NTrz   r$   r   r   r"   r#   r$   X  s    zFindStatement.__init__r1   r   c                 G  s
   | j | S )zSets a document field filter.

        Args:
            *fields: The string expressions identifying the fields to be
                     extracted.

        Returns:
            mysqlx.FindStatement: FindStatement object.
        )r   r   r"   r"   r#   r   ]  s    
zFindStatement.fieldsr   c                 G  s
   | j | S zSets the sorting criteria.

        Args:
            *clauses: The expression strings defining the sort criteria.

        Returns:
            mysqlx.FindStatement: FindStatement object.
        r   r   r"   r"   r#   r   i  s    	zFindStatement.sort)N)r%   r&   r'   r(   r$   r   r   r   r"   r"   r   r#   r  M  s
    r  c                      sX   e Zd ZdZdddd fddZdd dd	d
Zdd dddZddddZ  ZS )SelectStatementzA statement for record retrieval operations on a Table.

    Args:
        table (mysqlx.Table): The Table object.
        *fields: The fields to be retrieved.
    r   r1   r   tabler   r   c                   s   t  |d | j|  d S r   )rz   r$   r   r!   r  r   r   r"   r#   r$   }  s    zSelectStatement.__init__r   c                 C  s
   |  |S )zSets the search condition to filter.

        Args:
            condition (str): Sets the search condition to filter records.

        Returns:
            mysqlx.SelectStatement: SelectStatement object.
        r   r   r"   r"   r#   r     s    	zSelectStatement.wherer   c                 G  s
   | j | S )zSets the order by criteria.

        Args:
            *clauses: The expression strings defining the order by criteria.

        Returns:
            mysqlx.SelectStatement: SelectStatement object.
        r   r   r"   r"   r#   order_by  s    	zSelectStatement.order_byrZ   c                 C  s   | j rd| j nd}| jr(d| j nd}| jr>d| j nd}| jrTd| j nd}| jrrd| j	 d| j
 nd}d| jpd	 d
| jj d| jj | | | | | }|S )zYReturns the generated SQL.

        Returns:
            str: The generated SQL.
        z WHERE r0   z
 GROUP BY z HAVING z
 ORDER BY z LIMIT z OFFSET zSELECT *z FROM r>   )r   r   r   r~   r   r}   r   r   r   r   r   r   r\   namerN   )r!   r   r  r  r  r   Zstmtr"   r"   r#   get_sql  s    6zSelectStatement.get_sql)	r%   r&   r'   r(   r$   r   r  r  r   r"   r"   r   r#   r  u  s
   r  c                      sH   e Zd ZdZdddd fddZdd dd	d
ZddddZ  ZS )InsertStatementzA statement for insert operations on Table.

    Args:
        table (mysqlx.Table): The Table object.
        *fields: The fields to be inserted.
    r   r   r   r  c                   s   t  |d t| | _d S r   )rz   r$   r/   _fieldsr  r   r"   r#   r$     s    zInsertStatement.__init__r)   c                 G  s   | j tt|  | S )zSet the values to be inserted.

        Args:
            *values: The values of the columns to be inserted.

        Returns:
            mysqlx.InsertStatement: InsertStatement object.
        )r   r   r-   r/   )r!   r*   r"   r"   r#   r*     s    	zInsertStatement.valuesr   rZ   c                 C  s   | j | S r  )rS   r   r[   r"   r"   r#   rr     s    zInsertStatement.execute)r%   r&   r'   r(   r$   r*   rr   r   r"   r"   r   r#   r    s   r  c                      sv   e Zd ZdZddd fddZdd dd	d
Zdd dddZddddZddd dddZddddZ	  Z
S )UpdateStatementzA statement for record update operations on a Table.

    Args:
        table (mysqlx.Table): The Table object.

    .. versionchanged:: 8.0.12
       The ``fields`` parameters were removed.
    r   r   r  r   c                   s   t  j|dd i | _d S r   r   r!   r  r   r"   r#   r$     s    zUpdateStatement.__init__r1   r   c                 C  s
   |  |S )zSets the search condition to filter.

        Args:
            condition (str): Sets the search condition to filter records.

        Returns:
            mysqlx.UpdateStatement: UpdateStatement object.
        r   r   r"   r"   r#   r     s    	zUpdateStatement.wherer   c                 G  s
   | j | S )zSets the order by criteria.

        Args:
            *clauses: The expression strings defining the order by criteria.

        Returns:
            mysqlx.UpdateStatement: UpdateStatement object.
        r   r   r"   r"   r#   r    s    	zUpdateStatement.order_byr   rZ   c                 C  s   | j S r   r   r[   r"   r"   r#   r     s    zUpdateStatement.get_update_opsr   r   c                 C  s    t td||| j|< d| _| S )a  Updates the column value on records in a table.

        Args:
            field (string): The column name to be updated.
            value (object): The value to be set on the specified column.

        Returns:
            mysqlx.UpdateStatement: UpdateStatement object.
        r   Tr   r   r"   r"   r#   r     s    

zUpdateStatement.setr   c                 C  s   | j std| j| S )zExecute the statement.

        Returns:
            mysqlx.Result: Result object

        Raises:
            ProgrammingError: If condition was not set.
        z!No condition was found for updater   r[   r"   r"   r#   rr     s    	zUpdateStatement.execute)r%   r&   r'   r(   r$   r   r  r   r   rr   r   r"   r"   r   r#   r    s   	r  c                      sH   e Zd ZdZdddd fddZdd dd	d
ZddddZ  ZS )RemoveStatementaE  A statement for document removal from a collection.

    Args:
        collection (mysqlx.Collection): The Collection object.
        condition (str): Sets the search condition to identify the documents
                         to be removed.

    .. versionchanged:: 8.0.12
       The ``condition`` parameter was added.
    r   r1   r   r   c                   s   t  j||d d S r   r  r   r   r"   r#   r$   '  s    zRemoveStatement.__init__r   c                 G  s
   | j | S r  r   r   r"   r"   r#   r   *  s    	zRemoveStatement.sortr   rZ   c                 C  s   | j std| j| S )r   z!No condition was found for remover   r   rS   Zsend_deleter[   r"   r"   r#   rr   5  s    	zRemoveStatement.execute)r%   r&   r'   r(   r$   r   rr   r   r"   r"   r   r#   r!    s   r!  c                      sV   e Zd ZdZddd fddZdd dd	d
Zdd dddZddddZ  ZS )DeleteStatementzA statement that drops a table.

    Args:
        table (mysqlx.Table): The Table object.

    .. versionchanged:: 8.0.12
       The ``condition`` parameter was removed.
    r   r   r  c                   s   t  j|dd d S r   r  r   r   r"   r#   r$   M  s    zDeleteStatement.__init__r1   r   c                 C  s
   |  |S )zSets the search condition to filter.

        Args:
            condition (str): Sets the search condition to filter records.

        Returns:
            mysqlx.DeleteStatement: DeleteStatement object.
        r   r   r"   r"   r#   r   P  s    	zDeleteStatement.wherer   c                 G  s
   | j | S )zSets the order by criteria.

        Args:
            *clauses: The expression strings defining the order by criteria.

        Returns:
            mysqlx.DeleteStatement: DeleteStatement object.
        r   r   r"   r"   r#   r  [  s    	zDeleteStatement.order_byr   rZ   c                 C  s   | j std| j| S )r   z!No condition was found for deleter"  r[   r"   r"   r#   rr   f  s    	zDeleteStatement.execute)	r%   r&   r'   r(   r$   r   r  rr   r   r"   r"   r   r#   r#  C  s
   	r#  c                      s:   e Zd ZdZddddd fddZd	d
ddZ  ZS )CreateCollectionIndexStatementa)  A statement that creates an index on a collection.

    Args:
        collection (mysqlx.Collection): Collection.
        index_name (string): Index name.
        index_desc (dict): A dictionary containing the fields members that
                           constraints the index to be created. It must have
                           the form as shown in the following::

                               {"fields": [{"field": member_path,
                                            "type": member_type,
                                            "required": member_required,
                                            "collation": collation,
                                            "options": options,
                                            "srid": srid},
                                            # {... more members,
                                            #      repeated as many times
                                            #      as needed}
                                            ],
                                "type": type}
    r   r1   r   r   )r   
index_name
index_descr   c                   s4   t  j|d t|| _|| _| jdg | _d S )N)rN   r   )rz   r$   copydeepcopy_index_desc_index_namepop_fields_desc)r!   r   r%  r&  r   r"   r#   r$     s    z'CreateCollectionIndexStatement.__init__r   rZ   c              
   C  sh  | j dkrtt| j z`t| j   }t|trZ|d t	dkrxtt| j n|j
t	dkrxtt| j W n8 ttfk
r } ztt| j |W 5 d}~X Y nX | jstd| j t| jtstdi }| j |d< | jj|d< | jjj|d< d| jkr$| jd|d< nd	|d< | jd
d|d
< |d
 rPtdg |d< | jrptd| j z| jD ]x}i }|d|d< |d|d< |dd|d< |dd|d< t|d tstdt|d tstd|d  dkr|d std|d  d	kr<|d dkr<tdd|kr|d  dsrtd|d   d|d|d< d|kr|d  dkrtd|d|d< d|kr|d  dkrtd |d|d< |d | qzW n: tk
r2 } ztd!| d"| |W 5 d}~X Y nX | jD ]}|r:td#| q:| jd$d%d&|S )'r   NtypezMysqlx.Expr.Expr.Type.IDENTzCRequired member 'fields' not found in the given index description: z,Required member 'fields' must contain a listr  r   r\   ZINDEXuniqueFz!Unique indexes are not supported.
constraintzUnidentified fields: r   memberrequiredarrayz'Field member 'required' must be Booleanz$Field member 'array' must be BooleanZSPATIALzQField member 'required' must be set to 'True' when index type is set to 'SPATIAL'ZGEOJSONzIIndex 'type' must be set to 'SPATIAL' when field type is set to 'GEOJSON'Z	collationZTEXTzCThe 'collation' member can only be used when field type is set to ''optionszIThe 'options' member can only be used when index type is set to 'GEOJSON'ZsridzFThe 'srid' member can only be used when index type is set to 'GEOJSON'zRequired inner member z not found in constraint: zUnidentified inner fields: ZmysqlxZcreate_collection_indexT)r*  r   ERR_INVALID_INDEX_NAMEformatr   r   Zget_messager,   r   r   r-  r   AttributeErrorr,  r)  r-   rP   r  r\   r+  r   r2   	TypeErrorupper
startswithr   KeyErrorrS   Zexecute_nonquery)r!   Zparsed_identr   r   Z
field_descr/  r"   r"   r#   rr     s    







 



   z&CreateCollectionIndexStatement.execute)r%   r&   r'   r(   r$   rr   r   r"   r"   r   r#   r$  t  s   r$  )r0   )r0   )r0   )r0   )=r(   
__future__r   r'  r   r   typingr   r   r   r   r   r   r	   	constantsr   Zdbdocr   errorsr   r   r   r   Zhelpersr   Zprotobufr   resultr   r   r   r   typesr   r   r   r   r   r   r5  r   r/   r9   r<   rC   rK   rL   ru   r   r   r   r   r   r   r  r  r  r  r!  r#  r$  r"   r"   r"   r#   <module>   sN   $ 	 j  \B*;# /}(9!L(1