o
    i[                     @  s  U d dl mZ d dlZd dlmZmZ d dlmZ d dlm	Z	m
Z
 d dlmZmZmZ 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mZmZ d dlmZ d dlm Z m!Z! d dl"m#Z# d dl$m%Z% erd dl&Z&d dlm'Z'm(Z( d dl)m*Z* d dl+Z,d dlm-Z- e&j.dkrd dlm/Z/ nd dl0m/Z/ d dl1m2Z2 d dl3m4Z4 d dlm5Z5 d dl6m7Z7m8Z8m9Z9 h dZ:de;d< G dd dZ<G dd dZ=dS )     )annotationsN)	CoroutineSequence)suppress)	Parameter	signature)TYPE_CHECKINGAnyFinal)	functions)parse_versionqualified_type_name)
from_arrow)N_INFER_DEFAULT)DuplicateErrorModuleUpgradeRequiredErrorUnsuitableSQLError)ARROW_DRIVER_REGISTRY)ODBCCursorProxySurrealDBCursorProxy)dtype_from_cursor_description)
_run_async)IterableIterator)TracebackType)ArrowDriverProperties)      )Self
TextClause)
Selectable	DataFrame)ConnectionOrCursorCursor
SchemaDict>   ZUPDATEDELETEZVACUUMZINSERTZDROPZREVOKEZUPSERTZUSEZGRANTZREPLACEZCREATEZANALYZEZALTERzFinal[set[str]]_INVALID_QUERY_TYPESc                   @  s$   e Zd ZdZddd	ZdddZdS )CloseAfterFrameIterzDAllows cursor close to be deferred until the last batch is returned.framesr	   cursorr%   returnNonec                C  s   || _ || _d S N)_iter_frames_cursor)selfr*   r+    r2   S/home/app/Keep/.python/lib/python3.10/site-packages/polars/io/database/_executor.py__init__?   s   
zCloseAfterFrameIter.__init__Iterator[DataFrame]c                 c  s,    | j E d H  t| jdr| j  d S d S )Nclose)r/   hasattrr0   r6   r1   r2   r2   r3   __iter__C   s
   zCloseAfterFrameIter.__iter__N)r*   r	   r+   r%   r,   r-   )r,   r5   )__name__
__module____qualname____doc__r4   r9   r2   r2   r2   r3   r)   <   s    
r)   c                   @  s8  e Zd ZU dZdZded< dcd	d
ZddddZdeddZdfddZ	e
dgddZdhdd Ze
did#d$Zdjd+d,Ze
dkd1d2Zdld3d4Zdmd8d9Zdmd:d;Zdnd>d?Ze
dodBdCZe
dodDdEZe
dodFdGZe
dodHdIZe
dpdJdKZdqdLdMZdrdQdRZdsdVdWZdXdYdZdtd]d^ZddXdXed_dudadbZdXS )vConnectionExecutorzIAbstraction for querying databases with user-supplied connection objects.Fboolcan_close_cursor
connectionr$   r,   r-   c                 C  sT   t |trdnt|jddd  | _| jdkrt|d}| || _	d | _
d S )NZarrow_odbc_proxy.   r   Z	surrealdb)client)
isinstancer   typer;   splitlowerdriver_namer   _normalise_cursorr+   result)r1   rA   r2   r2   r3   r4   Q   s   


zConnectionExecutor.__init__r   c                 C  s   | S r.   r2   r8   r2   r2   r3   	__enter__]   s   zConnectionExecutor.__enter__exc_typetype[BaseException] | Noneexc_valBaseException | Noneexc_tbTracebackType | Nonec                 C  s`   |  | jrddlm} t| j|rt|   d S d S | jr,t| jdr.| j	  d S d S d S )Nr   )AsyncConnectionr6   )
_is_alchemy_asyncr+   sqlalchemy.ext.asynciorS   rE   r   _close_async_cursorr@   r7   r6   )r1   rM   rO   rQ   rS   r2   r2   r3   __exit__`   s   zConnectionExecutor.__exit__strc                 C  s   dt | j d| jdS )N<z module=>)rF   r:   rI   r8   r2   r2   r3   __repr__p   s   zConnectionExecutor.__repr__dfr#   schema_overridesr&   c                   s.   | j   fdd| D  }r| |} | S )z&Apply schema overrides to a DataFrame.c                   s4   g | ]\}}| v r| | krt ||qS r2   )Fcolcast).0r_   dtypeZexisting_schemar2   r3   
<listcomp>w   s
    z7ConnectionExecutor._apply_overrides.<locals>.<listcomp>)schemaitemsZwith_columns)r\   r]   Z	cast_colsr2   rc   r3   _apply_overridess   s   


z#ConnectionExecutor._apply_overridesc                   sf   | j r/t| jdr1ddlm} t| | j I d H  W d    d S 1 s(w   Y  d S d S d S )Nr6   r   )AsyncContextNotStarted)r@   r7   r+   Zsqlalchemy.ext.asyncio.excrh   r   r6   )r1   rh   r2   r2   r3   rV      s   
"z&ConnectionExecutor._close_async_cursormodule_nameminimum_versionc                 C  s   t | }tt= d}dD ]}tt||d }tr t|} nq|r5|t|k r=d|  d| }t|W d   dS W d   dS 1 sHw   Y  dS )z<Check the module version against a minimum required version.N)__version__versionz)`read_database` queries require at least z	 version )
__import__r   AttributeErrorrE   getattrrX   r   r   )ri   rj   modZmodule_versionZversion_attrvermsgr2   r2   r3   _check_module_version   s   
"z(ConnectionExecutor._check_module_versiondriver_propertiesr   
batch_size
int | Noneiter_batchesIterable[pa.RecordBatch]c          
      c  s    |d }|r|du r|d }t | j| V  dS |d r |gng }|d }t | j|}|s7|| E dH  dS 	 || }	|	s@dS |	V  q8)zGYield Arrow data as a generator of one or more RecordBatches or Tables.fetch_batchesNZ	fetch_allexact_batch_sizerepeat_batch_calls)ro   rK   )
r1   rt   ru   rw   ry   Zfetch_methodsizer{   Zfetchmany_arrowarrowr2   r2   r3   _fetch_arrow   s    zConnectionExecutor._fetch_arrowrK   r%   
is_alchemyIterable[Sequence[Any]]c                C  s6   |   }|r|st|d tttfr|S dd |D S )zCFetch row data in a single call, returning the complete result set.r   c                 S     g | ]}t |qS r2   tuplera   rowr2   r2   r3   rd          z5ConnectionExecutor._fetchall_rows.<locals>.<listcomp>)fetchallrE   listr   dict)rK   r   rowsr2   r2   r3   _fetchall_rows   s   z!ConnectionExecutor._fetchall_rowsc                c  sH    	 | |}|sdS |st|d tttfr|V  ndd |D V  q)zDFetch row data incrementally, yielding over the complete result set.Tr   c                 S  r   r2   r   r   r2   r2   r3   rd      r   z6ConnectionExecutor._fetchmany_rows.<locals>.<listcomp>N)Z	fetchmanyrE   r   r   r   )r1   rK   ru   r   r   r2   r2   r3   _fetchmany_rows   s   
z"ConnectionExecutor._fetchmany_rowsSchemaDict | Noneinfer_schema_length&DataFrame | Iterator[DataFrame] | Nonec             
     s@  ddl m  zxjdrdnj}t|g }t|ddD ]]\}}|d  }	rJ|dkr.dnj}
z|
|	 W n tyI   |t	|k rHY q w |r]|d	 r]|s]d
j d}t
| fddj|||dD }|ru|  W S t|  W S W dS  ty  zd}tfdd|D s W Y ddS dww )z5Return resultset data in Arrow format for frame init.r   r"   Zadbc_ZadbcrC   )startrj   Zadbc_driver_managerrz   zCannot set `iter_batches` for z- without also setting a non-zero `batch_size`c                 3  s6    | ]}t | r|pi nt|d V  qdS ))r]   N)rE   rg   r   )ra   batch)r#   r]   r1   r2   r3   	<genexpr>   s    

z1ConnectionExecutor._from_arrow.<locals>.<genexpr>)rw   ru   )zdoes not support Apache Arrowz$Apache Arrow format is not supportedc                 3  s    | ]	}|t  v V  qd S r.   )rX   )ra   e)errr2   r3   r      s    N)polarsr#   rI   
startswithr   get	enumeraters   r   len
ValueErrorr~   next	Exceptionany)r1   ru   rw   r]   r   driverZdriver_properties_listirt   rq   Zdriver_to_checkrr   r*   Zarrow_not_supportedr2   )r#   r   r]   r1   r3   _from_arrow   sT   	
.
zConnectionExecutor._from_arrowc                  sz  ddl m  |r|sd}t|t| j }t }r t| j| _zt| jdr| jdk }rZt| jdr?dd | jj	j
D }	n-t| jd	rPd
d | jjjD }	nd| j}t|t| jdrjdd | jj
D }	ng }	| j|	pri ddd |	D  fdd|r| j| j||dn| j| j|dgD }
|r|
nt|
W |r|  S S W |r|  dS dS |r|  w w )z.Return resultset data row-wise for frame init.r   r"   zFCannot set `iter_batches` without also setting a non-zero `batch_size`r   
sqlalchemyr+   c                 S      g | ]}|d  |dd fqS r   rC   Nr2   ra   dr2   r2   r3   rd     s    z1ConnectionExecutor._from_rows.<locals>.<listcomp>	_metadatac                 S  s   g | ]}|d fqS r.   r2   )ra   kr2   r2   r3   rd      r   z0Unable to determine metadata from query result; descriptionc                 S  r   r   r2   r   r2   r2   r3   rd   &  s     )r   r]   c                 S  s   g | ]\}}|qS r2   r2   )ra   nm_r2   r2   r3   rd   .  r   c                 3  s&    | ]} |p	d ddV  qd S )Nr   )datare   r]   r   Zorientr2   )ra   r   r#   r   Zresult_columnsr]   r2   r3   r   /  s    
z0ConnectionExecutor._from_rows.<locals>.<genexpr>)ru   r   )r   N)r   r#   r   rE   rK   r   r   r7   rI   r+   r   r   keys_inject_type_overridesr   r   r   r6   )r1   ru   rw   r]   r   rr   Zoriginal_resultis_asyncr   Zcursor_descr*   r2   r   r3   
_from_rows  sZ   	

zConnectionExecutor._from_rowsr   list[tuple[str, Any]]c                 C  sj   t  }|D ]-\}}||v rd|d}t||dur-||vr-t| j|}|dur-|||< || q|S )a  
        Attempt basic dtype inference from a cursor description.

        Notes
        -----
        This is limited; the `type_code` description attr may contain almost anything,
        from strings or python types to driver-specific codes, classes, enums, etc.
        We currently only do the additional inference from string/python type values.
        (Further refinement will require per-driver module knowledge and lookups).
        zcolumn z2 appears more than once in the query/result cursorN)setr   r   r+   add)r1   r   r]   Z
dupe_checkr   Zdescrr   rb   r2   r2   r3   r   G  s   z)ConnectionExecutor._inject_type_overridesconnr	   c                 C  s<   zddl m}m}m} t| |||fW S  ty   Y dS w )z2Check if the given connection is SQLALchemy async.r   )rS   AsyncSessionasync_sessionmakerF)rU   rS   r   r   rE   ImportError)r   rS   r   r   r2   r2   r3   rT   c  s   z$ConnectionExecutor._is_alchemy_asyncc                 C  sH   ddl m} t| |rdS zddlm} t| |W S  ty#   Y dS w )z5Check if the given connection is a SQLAlchemy Engine.r   )EngineT)AsyncEngineF)sqlalchemy.enginer   rE   rU   r   r   )r   r   r   r2   r2   r3   _is_alchemy_engineq  s   
z%ConnectionExecutor._is_alchemy_enginec                 C  s   t | jddd dkS )zCCheck if the given connection is a SQLAlchemy object (of any kind).rB   rC   r   r   )rF   r;   rG   )r   r2   r2   r3   _is_alchemy_object  s   z%ConnectionExecutor._is_alchemy_objectc                 C  s^   ddl m} ddlm}m} t| |||frdS zddl m} t| |W S  ty.   Y dS w )z=Check if the given connection is a SQLAlchemy Session object.r   )r   )SessionsessionmakerT)r   F)rU   r   sqlalchemy.ormr   r   rE   r   r   )r   r   r   r   r   r2   r2   r3   _is_alchemy_session  s   z&ConnectionExecutor._is_alchemy_sessionc                 C  sJ   zddl m} t| |rW dS ddlm} t| |W S  ty$   Y dS w )z8Check if the given result is a SQLAlchemy Result object.r   )CursorResultT)AsyncResultF)r   r   rE   rU   r   r   )rK   r   r   r2   r2   r3   _is_alchemy_result  s   
z%ConnectionExecutor._is_alchemy_resultc                 C  s   | j dkr5| |r|S |jjdkrd| _ |j  S |jjdkr'd| _ |S | |r3d| _| S |S t	|drKt
|j }rD| n|}d| _|S t	|drR|S d	t|d
}t|)zCNormalise a connection object such that we have the query executor.r   zdatabricks-sql-pythonZ
databricksZduckdb_engineduckdbTr+   executezUnrecognised connection type z!; no 'execute' or 'cursor' method)rI   r   Zenginer   Zraw_connectionr+   r   r@   connectr7   callabler   	TypeError)r1   r   r+   rr   r2   r2   r3   rJ     s,   




z$ConnectionExecutor._normalise_cursorqueryr    optionsc              	     s   |  | j}|r| j n| j}t|dddur%|j|fi |I dH S |4 I dH #}|r6t|ds6|j}|j|fi |I dH }|W  d  I dH  S 1 I dH sTw   Y  dS )z5Execute a query using an async SQLAlchemy connection.Zsync_connectionNr   )r   r+   beginro   r   r7   session)r1   r   r   Z
is_sessionr+   r   rK   r2   r2   r3   _sqlalchemy_async_execute  s   0z,ConnectionExecutor._sqlalchemy_async_executestr | TextClause | Selectabledict[str, Any]9tuple[Any, dict[str, Any], str | TextClause | Selectable]c           
      C  s  ddl m} ddlm} ddlm} d}d}t| j|r1d|v r1d|vr1| }|	d|d< d}|
|}| | j}	|	skt|trkt| jdrk| jj}t||rVt|}t|trjtd	d
 |D sjt|||< n	t|trt||}|du r|	r}| jn| jj}|||fS )z<Prepare a query for execution using a SQLAlchemy connection.r   )r   )textr   
parametersNparamsexec_driver_sqlc                 s  s    | ]
}t |ttfV  qd S r.   )rE   r   r   ra   pr2   r2   r3   r     s    
z7ConnectionExecutor._sqlalchemy_setup.<locals>.<genexpr>)r   r   Zsqlalchemy.sqlr   sqlalchemy.sql.elementsr    rE   r+   copypopr   rT   r   r7   r   rX   r   allr   r   r   )
r1   r   r   r   r   r    Z	param_keycursor_executer   r   r2   r2   r3   _sqlalchemy_setup  sD   





z$ConnectionExecutor._sqlalchemy_setupNT)r   select_queries_onlydict[str, Any] | Noner   c                  s6  |r(t |tr(tdtdd|}|sdn|d }tv r(| d}t| p+i  | | j	r<| 
| \} }n| j	j}zt|j}W n tyR   i }Y nw  r`tdd | D ri||fi  }	n fdd|pq D }
||g|
R  }	|	d	u s|	d
u r| j	n|	}	| jdkr| |	r|	j	}	|	| _| S )z-Execute a query and reference the result set.z\w{3,}z/\*(.|[\r\n])*?\*/ r   z( statements are not valid 'read' queriesc                 s  s"    | ]}|j tjtjfv V  qd S r.   )kindr   KEYWORD_ONLYPOSITIONAL_OR_KEYWORDr   r2   r2   r3   r     s
    
z-ConnectionExecutor.execute.<locals>.<genexpr>c                 3  s$    | ]} r
| v r | V  qd S r.   r2   )ra   or   r2   r3   r   $  s    NTr   )rE   rX   researchsubgroupr(   r   r   r+   r   r   r   r   r   r   valuesrI   r   rK   )r1   r   r   r   qZ
query_typerr   r   r   rK   Zpositional_optionsr2   r   r3   r     s6   

zConnectionExecutor.execute)rw   ru   r]   r   DataFrame | Iterator[DataFrame]c          
      C  s   | j du rd}t|| j}|o| }rd| _| j| jfD ] }|||||d}	|	dur=|r9dd t|	| j dD }	|	  S qd| jd	| j}t|)
z
        Convert the result set to a DataFrame.

        Wherever possible we try to return arrow-native data directly; only
        fall back to initialising with row-level data if no other option.
        Nz.cannot return a frame before executing a queryF)ru   rw   r]   r   c                 s  s    | ]}|V  qd S r.   r2   )ra   r\   r2   r2   r3   r   T  s
    
z/ConnectionExecutor.to_polars.<locals>.<genexpr>)r+   zCurrently no support for z connection )	rK   RuntimeErrorr@   r   r   r)   rI   r+   NotImplementedError)
r1   rw   ru   r]   r   rr   Z	can_closeZdefer_cursor_closeZ
frame_initframer2   r2   r3   	to_polars1  s8   
zConnectionExecutor.to_polars)rA   r$   r,   r-   )r,   r   )rM   rN   rO   rP   rQ   rR   r,   r-   )r,   rX   )r\   r#   r]   r&   r,   r#   )r,   r-   )ri   rX   rj   rX   r,   r-   )rt   r   ru   rv   rw   r?   r,   rx   )rK   r%   r   r?   r,   r   )rK   r%   ru   rv   r   r?   r,   r   )
ru   rv   rw   r?   r]   r   r   rv   r,   r   )r   r   r]   r&   r,   r&   )r   r	   r,   r?   )rK   r	   r,   r?   )r   r	   r,   r%   )r   r    r   r	   r,   r	   )r   r   r   r   r,   r   )r   r   r   r   r   r?   r,   r   )
rw   r?   ru   rv   r]   r   r   rv   r,   r   )r:   r;   r<   r=   r@   __annotations__r4   rL   rW   r[   staticmethodrg   rV   rs   r~   r   r   r   r   r   rT   r   r   r   r   rJ   r   r   r   r   r   r2   r2   r2   r3   r>   J   sP   
 






	

A
B

$
/2r>   )>
__future__r   r   collections.abcr   r   
contextlibr   inspectr   r   typingr   r	   r
   r   r   r^   Zpolars._utils.variousr   r   Zpolars.convertr   Zpolars.datatypesr   Zpolars.exceptionsr   r   r   Z"polars.io.database._arrow_registryr   Z"polars.io.database._cursor_proxiesr   r   Zpolars.io.database._inferencer   Zpolars.io.database._utilsr   sysr   r   typesr   Zpyarrowpar   version_infor   Ztyping_extensionsr   r    Zsqlalchemy.sql.expressionr!   r#   Zpolars._typingr$   r%   r&   r(   r   r)   r>   r2   r2   r2   r3   <module>   s>    
