Ë
    5¾ªj¡E  ã                   ó   — d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	m
Z
mZmZmZmZmZmZ ddlZddlZddlmZ ddlmZ ddlmZ ddlmZ d	Zd
ZddddddœZd	Z dee!   de!fd„Z"ededee#e$e%e%f         fd„«       Z&	 d1dede%deddfd„Z'de%fd„Z(d2de
e%ge)f   de*de%fd„Z+de	dee%ee	   f   fd„Z,dedejZ                  fd „Z.ded!e%d"e%dejZ                  fd#„Z/ded!e%d"e%de)fd$„Z0ded!e%d"e%ddfd%„Z1	 d1ded!e%d"e%d&ejZ                  d'ee%e%f   ddfd(„Z2ded!e%d&ejZ                  dee%e%f   fd)„Z3d*e%de%fd+„Z4dede%fd,„Z5ded!e%d"e%de)fd-„Z6	 d3d.eeejZ                  ejn                  ejp                  f      d/e%deejZ                     fd0„Z9y)4a.  General utilities for AI features in MySQL Connector/Python.

Includes helpers for:
- defensive dict copying
- temporary table lifecycle management
- SQL execution and result conversions
- DataFrame to/from SQL table utilities
- schema/table/column name validation
- array-like to DataFrame conversion
é    N)Úcontextmanager)ÚAnyÚCallableÚDictÚIteratorÚListÚOptionalÚTupleÚUnion)Úatomic_transaction)ÚMySQLConnectionAbstract)ÚMySQLCursorAbstract)ÚParamsSequenceOrDictTypeÚmysql_aié    ÚBIGINTÚDOUBLEÚLONGTEXTÚBOOLEANÚDATETIME)Úint64Úfloat64ÚobjectÚboolzdatetime64[ns]ÚoptionsÚreturnc                 ó4   — | €i S t        j                  | «      S )z›
    Make a defensive copy of a dictionary, or return an empty dict if None.

    Args:
        options: param dict or None

    Returns:
        dict
    )ÚcopyÚdeepcopy)r   s    úS/var/www/html/serviGia/entorno/lib/python3.12/site-packages/mysql/ai/utils/utils.pyÚ	copy_dictr!   I   s   € ð €Øˆ	ä�=‰=˜Ó!Ð!ó    Údb_connectionc           	   #   ó  K  — g }	 |–— t        | «      5 }|D ]  \  }}t        |||«       Œ 	 ddd«       y# 1 sw Y   yxY w# t        | «      5 }|D ]  \  }}t        |||«       Œ 	 ddd«       w # 1 sw Y   w xY wxY w­w)a  
    Context manager to track and automatically clean up temporary SQL tables.

    Args:
        db_connection: Database connection object used to create and delete tables.

    Returns:
        None

    Raises:
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.

    Yields:
        temporary_tables: List of (schema_name, table_name) tuples created during the
            context. All tables in this list are deleted on context exit.
    N)r   Údelete_sql_table)r#   Útemporary_tablesÚcursorÚschema_nameÚ
table_names        r    Útemporary_sql_tablesr*   Y   s£   è ø€ ð, /1ÐðBØÒä Ó.ð 	B°&Ø+;ò BÑ'�˜ZÜ  ¨°jÕAñB÷	B÷ 	Bñ 	BûÔ Ó.ð 	B°&Ø+;ò BÑ'�˜ZÜ  ¨°jÕAñB÷	B÷ 	Bñ 	BÿsF   ‚B †A ŠB •7®	B ·A ¼B ÁA=ÁA1Á(	A=Á1A:Á6A=Á=B r'   ÚqueryÚparamsc                 ó0   — | j                  ||xs d«       y)aB  
    Execute an SQL query with optional parameters using the given cursor.

    Args:
        cursor: MySQLCursorAbstract object to execute the query.
        query: SQL query string to execute.
        params: Optional sequence or dict providing parameters for the query.

    Raises:
        DatabaseError:
            If the provided SQL query/params are invalid
            If the query is valid but the sql raises as an exception
            If a database connection issue occurs.
            If an operational error occurs during execution.

    Returns:
        None
    © N)Úexecute)r'   r+   r,   s      r    Úexecute_sqlr0   x   s   € ð* ‡N�N�5˜&š, BÕ'r"   c                  óv   — t         j                  } dj                  t        j                  | t
        ¬«      «      S )z•
    Generate a random uppercase string of fixed length for table names.

    Returns:
        Random string of length RANDOM_TABLE_NAME_LENGTH.
    Ú )Úk)ÚstringÚascii_uppercaseÚjoinÚrandomÚchoicesÚRANDOM_TABLE_NAME_LENGTH)Úchar_sets    r    Ú	_get_namer;   �   s*   € ô ×%Ñ%€HØ�7‰7”6—>‘> (Ô.FÔGÓHÐHr"   Ú	conditionÚ	max_callsc                 ód   — t        |«      D ]  } | t        «       x}«      sŒ|c S  t        d«      ‚)a¨  
    Generate a random string name that satisfies a given condition.

    Args:
        condition: Callable that takes a generated name and returns True if it is valid.
        max_calls: Maximum number of attempts before giving up (default 100).

    Returns:
        A random string that fulfills the provided condition.

    Raises:
        RuntimeError: If the maximum number of attempts is reached without success.
    z<Reached max tries without successfully finding a unique name)Úranger;   ÚRuntimeError)r<   r=   Ú_Únames       r    Úget_random_namerC   ›   s:   € ô �9Óò ˆÙœY›[Ð(�TÕ)ØŠKðô ÐUÓ
VÐVr"   Úvaluec                 óŽ   — t        | t        t        f«      r+t        | «      dk(  rddgfS dt	        j
                  | «      gfS d| gfS )a.  
    Convert a Python value into its SQL-compatible string representation and parameters.

    Args:
        value: The value to format.

    Returns:
        Tuple containing:
            - A string for substitution into a SQL query.
            - A list of parameters to be bound into the query.
    r   z%sNzCAST(%s as JSON))Ú
isinstanceÚdictÚlistÚlenÚjsonÚdumps)rD   s    r    Úformat_value_sqlrL   ³   sL   € ô �%œ$¤˜Ô&Üˆu‹:˜Š?Ø˜$˜�<ÐØ!¤D§J¡J¨uÓ$5Ð#6Ð6Ð6Ø�%�ˆ=Ðr"   c                 ó°  — dt         t           dt         t           fd„}dt        dt        fd„}i }t	        | j
                  «      D ]  \  }}|d   dk(  r|||<   Œ|||<   Œ | j                  «       }g }|D ]?  }t        |«      }	t	        |«      D ]  \  }}
 ||   |
«      |	|<   Œ |j                  |	«       ŒA t        j                  || j                  ¬«      S )a³  
    Convert the results of a cursor's last executed query to a pandas DataFrame.

    Args:
        cursor: MySQLCursorAbstract with a completed query.

    Returns:
        DataFrame with data from the cursor.

    Raises:
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
            If a compatible SELECT query wasn't the last statement ran
    Úelemr   c                 ó4   — | �t        j                  | «      S d S ©N)rJ   Úloads©rN   s    r    Ú_json_processorz+sql_response_to_df.<locals>._json_processor×   s   € Ø#'Ð#3Œt�z‰z˜$ÓÐ=¸Ð=r"   c                 ó   — | S rP   r.   rR   s    r    Ú_default_processorz.sql_response_to_df.<locals>._default_processorÚ   s   € Øˆr"   é   éõ   )Úcolumns)r	   ÚstrrG   r   Ú	enumerateÚdescriptionÚfetchallrH   ÚappendÚpdÚ	DataFrameÚcolumn_names)r'   rS   rU   Úidx_to_processorÚidxÚcolÚrowsÚprocessed_rowsÚrowÚprocessed_rowrN   s              r    Úsql_response_to_dfrh   Æ   sû   € ð">œh¤s™mð >´¼±ó >ð¤ð ¬ó ð ÐÜ˜f×0Ñ0Ó1ò 7‰ˆˆSØˆq‰6�SŠ=à$3Ð˜SÒ!à$6Ð˜SÒ!ð7ð �?‰?Ó€Dð €NØò -ˆÜ˜S›	ˆä" 3›ò 	=‰IˆC�Ø!6Ð!1°#Ñ!6°tÓ!<ˆM˜#Òð	=ð 	×Ñ˜mÕ,ð-ô �<‰<˜°×0CÑ0CÔDÐDr"   r(   r)   c                 óh   — t        |«       t        |«       t        | d|› d|› �«       t        | «      S )aD  
    Load the entire contents of a SQL table into a pandas DataFrame.

    Args:
        cursor: MySQLCursorAbstract to execute the query.
        schema_name: Name of the schema containing the table.
        table_name: Name of the table to fetch.

    Returns:
        DataFrame containing all rows from the specified table.

    Raises:
        DatabaseError:
            If the table does not exist
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    zSELECT * FROM ú.)Úvalidate_namer0   rh   ©r'   r(   r)   s      r    Úsql_table_to_dfrm   ô   s6   € ô* �+ÔÜ�*Ôä�˜.¨¨°Q°z°lÐCÔDÜ˜fÓ%Ð%r"   c                 óz   — t        |«       t        |«       | j                  d||f«       | j                  «       duS )aó  
    Check whether a table exists in a specific schema.

    Args:
        cursor: MySQLCursorAbstract object to execute the query.
        schema_name: Name of the database schema.
        table_name: Name of the table.

    Returns:
        True if the table exists, False otherwise.

    Raises:
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    z…
        SELECT 1
        FROM information_schema.tables
        WHERE table_schema = %s AND table_name = %s
        LIMIT 1
        N©rk   r/   Úfetchonerl   s      r    Útable_existsrq     sC   € ô( �+ÔÜ�*Ôà
‡N�Nð	ð 
�jÐ!ôð �?‰?Ó DÐ(Ð(r"   c                 óT   — t        |«       t        |«       t        | d|› d|› �«       y)aÌ  
    Drop a table from the SQL database if it exists.

    Args:
        cursor: MySQLCursorAbstract to execute the drop command.
        schema_name: Name of the schema.
        table_name: Name of the table to delete.

    Returns:
        None

    Raises:
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    zDROP TABLE IF EXISTS rj   N)rk   r0   rl   s      r    r%   r%   6  s,   € ô( �+ÔÜ�*Ôä�Ð/°¨}¸A¸j¸\ÐJÕKr"   ÚdfÚcol_name_to_placeholder_stringc           	      ó‚  — |€i }t        |«       t        |«       |j                  D ]  }t        t        |«      «       Œ |› d|› �}|j                  D ]å  }g g }	}t	        ||j                  «      D ]i  \  }
}t        |
d«      r|
j                  «       n|
}
||v r||   t        |
«      g}}nt        |
«      \  }}|j                  |«       |	j                  |«       Œk dj                  |j                  D �cg c]  }t        |«      ‘Œ c}«      }dj                  |«      }d|› d|› d|› d�}t        | ||	¬	«       Œç yc c}w )
aõ  
    Insert all rows from a pandas DataFrame into an existing SQL table.

    Args:
        cursor: MySQLCursorAbstract for execution.
        schema_name: Name of the database schema.
        table_name: Table to insert new rows into.
        df: DataFrame containing the rows to insert.
        col_name_to_placeholder_string:
            Optional mapping of column names to custom SQL value/placeholder
            strings.

    Returns:
        None

    Raises:
        DatabaseError:
            If the rows could not be inserted into the table, e.g., a type or shape issue
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    Nrj   Úitemú, zINSERT INTO ú (z
) VALUES (ú))r,   )rk   rX   rY   ÚvaluesÚzipÚhasattrrv   rL   r]   Úextendr6   r0   )r'   r(   r)   rs   rt   rc   Úqualified_table_namerf   Úplaceholdersr,   rN   Úelem_placeholderÚelem_paramsÚcols_sqlÚplaceholders_sqlÚ
insert_sqls                   r    Úextend_sql_tabler…   P  sa  € ð: &Ð-Ø)+Ð&ä�+ÔÜ�*ÔØ�z‰zò  ˆÜ”c˜#“hÕð ð *˜]¨!¨J¨<Ð8Ðð �y‰yò 7ˆØ! 2�fˆÜ˜S "§*¡*Ó-ò 	'‰IˆD�#Ü")¨$°Ô"7�4—9‘9”;¸TˆDàÐ4Ñ4Ø0NÈsÑ0SÜ˜“IðV +Ñ ô 1AÀÓ0FÑ-Ð  +à×ÑÐ 0Ô1Ø�M‰M˜+Õ&ð	'ð —9‘9°"·*±*Ö=¨3œc #�hÒ=Ó>ˆØŸ9™9 \Ó2ÐàÐ/Ð0ð 1Øˆz˜Ð$4Ð#5°Qð8ð 	ô 	�F˜J¨vÖ6ñ+7ùò >s   Ã5D<
c                 óp  ‡ ‡— t        ˆ ˆfd„«      }‰› d|› �}t        ‰«       t        |«       |j                  D ]  }t        t        |«      «       Œ g }|j                  j                  «       D ]N  \  }}t        j                  t        |«      d«      }t        t        |«      «       |j                  |› d|› �«       ŒP dj                  |«      }	t        d„ |j                  D «       «      }
|
r|	dz  }	d|› d	|	› d
�}t        ‰ |«       	 t        ‰ ‰||«       ||fS # t        $ r t        ‰ ‰|«       ‚ w xY w)a  
    Create a new SQL table with a random name, and populate it with data from a DataFrame.

    If an 'id' column is defined in the dataframe, it will be used as the primary key.

    Args:
        cursor: MySQLCursorAbstract for executing SQL.
        schema_name: Schema in which to create the table.
        df: DataFrame containing the data to be inserted.

    Returns:
        Tuple (qualified_table_name, table_name): The schema-qualified and
        unqualified table names.

    Raises:
        RuntimeError: If a random available table name could not be found.
        ValueError: If any schema, table, or a column name is invalid.
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
    c                 ó    •— t        ‰‰| «       S rP   )rq   )r)   r'   r(   s    €€r    ú<lambda>z#sql_table_from_df.<locals>.<lambda>©  s   ø€ œ|¨F°KÀÓLÐL€ r"   rj   r   ú rw   c              3   óB   K  — | ]  }|j                  «       d k(  –— Œ y­w)ÚidN)Úlower)Ú.0rc   s     r    ú	<genexpr>z$sql_table_from_df.<locals>.<genexpr>»  s   è ø€ Ò?¨S�S—Y‘Y“[ DÕ(Ñ?ùs   ‚z, PRIMARY KEY (id)zCREATE TABLE rx   ry   )rC   rk   rX   rY   ÚdtypesÚitemsÚPD_TO_SQL_DTYPE_MAPPINGÚgetr]   r6   Úanyr0   r…   Ú	Exceptionr%   )r'   r(   rs   r)   r~   rc   Úcolumns_sqlÚdtypeÚsql_typeÚcolumns_strÚ
has_id_colÚcreate_table_sqls   ``          r    Úsql_table_from_dfr›   �  sJ  ù€ ô0 !ÜLó€Jð *˜]¨!¨J¨<Ð8Ðä�+ÔÜ�*ÔØ�z‰zò  ˆÜ”c˜#“hÕð ð €KØ—i‘i—o‘oÓ'ò 0‰
ˆˆUä*×.Ñ.¬s°5«z¸:ÓFˆÜ”c˜#“hÔØ×Ñ˜c˜U ! H :Ð.Õ/ð	0ð —)‘)˜KÓ(€KäÑ?°B·J±JÔ?Ó?€JÙØÐ+Ñ+ˆð 'Ð';Ð&<¸B¸{¸mÈ1ÐMÐÜ�Ð(Ô)ðä˜ ¨j¸"Ô=ð
   Ð+Ð+øô	 ò ä˜ ¨jÔ9Øðús   ÄD ÄD5rB   c                 ón   — t        | t        «      rt        j                  d| «      st	        d| › �«      ‚| S )a  
    Validate that the string is a legal SQL identifier (letters, digits, underscores).

    Args:
        name: Name (schema, table, or column) to validate.

    Returns:
        The validated name.

    Raises:
        ValueError: If the name does not meet format requirements.
    z^[A-Za-z0-9_]+$zUnsupported name format )rF   rY   ÚreÚmatchÚ
ValueError)rB   s    r    rk   rk   Í  s4   € ô �tœSÔ!¤b§h¡hÐ/AÀ4Ô&HÜÐ3°D°6Ð:Ó;Ð;à€Kr"   c                 ó¦   — | j                   }|€+t        }t        | «      5 }d|› �}t        ||«       ddd«       t	        |«       |S # 1 sw Y   ŒxY w)aµ  
    Retrieve the name of the currently selected schema, or set and ensure the default schema.

    Args:
        db_connection: MySQL connector database connection object.

    Returns:
        Name of the schema (database in use).

    Raises:
        ValueError: If the schema name is not valid
        DatabaseError:
            If a database connection issue occurs.
            If an operational error occurs during execution.
    NzCREATE DATABASE IF NOT EXISTS )ÚdatabaseÚDEFAULT_SCHEMAr   r0   rk   )r#   Úschemar'   Úcreate_database_stmts       r    Úsource_schemar¥   á  s_   € ð  ×#Ñ#€FØ€~Üˆä Ó.ð 	6°&Ø%CÀFÀ8Ð#LÐ Ü˜Ð 4Ô5÷	6ô �&Ôà€M÷	6ð 	6ús    AÁAc                 ó‚   — t        |«       t        |«       | j                  d|› d|› d�«       | j                  «       du S )a+  
    Determine if a given SQL table is empty.

    Args:
        cursor: MySQLCursorAbstract with access to the database.
        schema_name: Name of the schema containing the table.
        table_name: Name of the table to check.

    Returns:
        True if the table has no rows, False otherwise.

    Raises:
        DatabaseError:
            If the table does not exist
            If a database connection issue occurs.
            If an operational error occurs during execution.
        ValueError: If the schema or table name is not valid
    zSELECT 1 FROM rj   z LIMIT 1Nro   rl   s      r    Úis_table_emptyr§   þ  sA   € ô* �+ÔÜ�*Ôà
‡N�N�^ K =°°*°¸XÐFÔGØ�?‰?Ó Ð$Ð$r"   ÚarrÚ
col_prefixc                 óŠ  — | €yt        | t        j                  «      rt        j                  | «      S t        | t        j                  «      r| j	                  «       S | j
                  dk(  r| j                  dd«      } t        | j                  d   «      D �cg c]	  }|› d|› �‘Œ }}t        j                  | |d¬«      S c c}w )a$  
    Convert input data to a pandas DataFrame if necessary.

    Args:
        arr: Input data as a pandas DataFrame, NumPy ndarray, pandas Series, or None.

    Returns:
        If the input is None, returns None.
        Otherwise, returns a DataFrame backed by the same underlying data whenever
        possible (except in cases where pandas or NumPy must copy, such as for
        certain views or non-contiguous arrays).

    Notes:
        - If an ndarray is passed, column names will be integer indices (0, 1, ...).
        - If a DataFrame is passed, column names and indices are preserved.
        - The returned DataFrame is a shallow copy and shares data with the original
          input when possible; however, copies may still occur for certain input
          types or memory layouts.
    NrV   éÿÿÿÿrA   F)rX   r   )	rF   r^   r_   ÚSeriesÚto_frameÚndimÚreshaper?   Úshape)r¨   r©   rb   Ú	col_namess       r    Úconvert_to_dfr²     s¢   € ð. €{Øä�#”r—|‘|Ô$Ü�|‰|˜CÓ Ð Ü�#”r—y‘yÔ!Ø�|‰|‹~Ðà
‡x�x�1‚}Ø�k‰k˜"˜aÓ ˆÜ27¸¿	¹	À!¹Ó2EÖF¨3�J�<˜q  Ò&ÐF€IÐFä�<‰<˜ Y°UÔ;Ð;ùò Gs   ÂC rP   )éd   )Úfeature):Ú__doc__r   rJ   r7   r�   r4   Ú
contextlibr   Útypingr   r   r   r   r   r	   r
   r   ÚnumpyÚnpÚpandasr^   Úmysql.ai.utils.atomic_cursorr   Úmysql.connector.abstractsr   Úmysql.connector.cursorr   Úmysql.connector.typesr   ÚVAR_NAME_SPACEr9   r‘   r¢   rG   r!   rH   ÚtuplerY   r*   r0   r;   r   ÚintrC   rL   r_   rh   rm   rq   r%   r…   r›   rk   r¥   r§   r¬   Úndarrayr²   r.   r"   r    ú<module>rÃ      sä  ðñ8	ó Û Û Û 	Û å %ß N× NÓ Nã Û å ;å =Ý 6Ý :à€ØÐ ð ØØØØ ñÐ ð €ð
"�x ‘~ð "¨$ó "ð  ðBØ*ðBàˆd�5˜˜c˜‘?Ñ#Ñ$òBó ðBð> QUñ(Øð(Ø(+ð(Ø5Mð(à	ó(ð0I�3ó IñW˜x¨¨¨t¨Ñ4ð WÀð WÈsó Wð0˜Cð  E¨#¨t°C©y¨.Ñ$9ó ð&+EÐ2ð +E°r·|±|ó +Eð\&Øð&Ø.1ð&Ø?Bð&à‡\�\ó&ð> )Øð )Ø.1ð )Ø?Bð )à	ó )ðFLØðLØ.1ðLØ?BðLà	óLð> 6:ñ=7Øð=7àð=7ð ð=7ð 	�‰ð	=7ð
 %)¨¨c¨¡Nð=7ð 
ó=7ð@:,Øð:,Ø.1ð:,Ø79·|±|ð:,à
ˆ3�ˆ8�_ó:,ðz˜ð  ó ð(Ð!8ð ¸Só ð:%Øð%Ø.1ð%Ø?Bð%à	ó%ð<  ñ#<Ø	�%˜Ÿ™ b§i¡i°·±Ð;Ñ<Ñ	=ð#<àð#<ð ˆb�l‰lÑô#<r"   