o
    ŠågYE  ã                   @   s¶   d Z ddlm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dlmZ ddlmZ dd	lmZ ddlmZ e e¡ZG d
d„ dƒZG dd„ dƒZG dd„ dƒZejZdS )zÎBaked query extension.

Provides a creational pattern for the :class:`.query.Query` object which
allows the fully constructed object, Core select statement, and string
compiled result to be fully cached.


é    Né   )Úexc)Úutil)ÚQuery)ÚSession)Úfunc)Úliteral_columnc                   @   s$   e Zd ZdZdZdd„ Zdd„ ZdS )ÚBakeryzêCallable which returns a :class:`.BakedQuery`.

    This object is returned by the class method
    :meth:`.BakedQuery.bakery`.  It exists as an object
    so that the "cache" can be easily inspected.

    .. versionadded:: 1.2


    ©ÚclsÚcachec                 C   s   || _ || _d S ©Nr
   )ÚselfÚcls_r   © r   úP/var/www/html/flaskapp/venv/lib/python3.10/site-packages/sqlalchemy/ext/baked.pyÚ__init__1   s   
zBakery.__init__c                 G   s   |   | j||¡S r   r
   )r   Ú
initial_fnÚargsr   r   r   Ú__call__5   s   zBakery.__call__N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú	__slots__r   r   r   r   r   r   r	   #   s
    r	   c                   @   s´   e Zd ZdZdZd+dd„Zed,dd	„ƒZd
d„ Zd+dd„Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd-dd„Zdd„ Zd.dd „Zd.d!d"„Zd#d$„ Zd%d&„ Zd'd(„ Zd)d*„ ZdS )/Ú
BakedQueryz3A builder object for :class:`.query.Query` objects.)ÚstepsÚ_bakeryÚ
_cache_keyÚ_spoiledr   c                 C   s*   d| _ |  ||¡ |g| _d| _|| _d S )Nr   F)r   Ú_update_cache_keyr   r   r   )r   Úbakeryr   r   r   r   r   r   >   s
   
zBakedQuery.__init__éÈ   Nc                 C   s   t | tj||d�ƒS )zSConstruct a new bakery.

        :return: an instance of :class:`.Bakery`

        )Ú
size_alert)r	   r   ÚLRUCache)r   ÚsizeÚ_size_alertr   r   r   r!   E   s   zBakedQuery.bakeryc                 C   s2   t  t ¡}| j|_t| jƒ|_| j|_| j|_|S r   )r   Ú__new__r   Úlistr   r   r   )r   Úb1r   r   r   Ú_cloneO   s   
zBakedQuery._clonec                 C   s   |  j |jf| 7  _ d S r   )r   Ú__code__©r   Úfnr   r   r   r   r    W   s   zBakedQuery._update_cache_keyc                 C   s&   t |tƒr| j|Ž  | S |  |¡ | S r   )Ú
isinstanceÚtupleÚadd_criteria©r   Úotherr   r   r   Ú__iadd__Z   s
   


ÿzBakedQuery.__iadd__c                 C   s   t |tƒr
| j|Ž S |  |¡S r   )r.   r/   Úwith_criteriar1   r   r   r   Ú__add__a   s   


zBakedQuery.__add__c                 G   s   |   ||¡ | j |¡ | S )z«Add a criteria function to this :class:`.BakedQuery`.

        This is equivalent to using the ``+=`` operator to
        modify a :class:`.BakedQuery` in-place.

        )r    r   Úappendr,   r   r   r   r0   g   s   zBakedQuery.add_criteriac                 G   s   |   ¡ j|g|¢R Ž S )zÓAdd a criteria function to a :class:`.BakedQuery` cloned from this
        one.

        This is equivalent to using the ``+`` operator to
        produce a new :class:`.BakedQuery` with modifications.

        )r*   r0   r,   r   r   r   r4   r   s   zBakedQuery.with_criteriac                 C   s
   t | |ƒS )zàReturn a :class:`_baked.Result` object for this
        :class:`.BakedQuery`.

        This is equivalent to calling the :class:`.BakedQuery` as a
        Python callable, e.g. ``result = my_baked_query(session)``.

        )ÚResult©r   Úsessionr   r   r   Úfor_session|   s   
zBakedQuery.for_sessionc                 C   s
   |   |¡S r   )r:   r8   r   r   r   r   †   s   
zBakedQuery.__call__Fc                 C   s4   |s| j s|  ¡ }| jd7  _|jg| _d| _ | S )a€  Cancel any query caching that will occur on this BakedQuery object.

        The BakedQuery can continue to be used normally, however additional
        creational functions will not be cached; they will be called
        on every invocation.

        This is to support the case where a particular step in constructing
        a baked query disqualifies the query from being cacheable, such
        as a variant that relies upon some uncacheable value.

        :param full: if False, only functions added to this
         :class:`.BakedQuery` object subsequent to the spoil step will be
         non-cached; the state of the :class:`.BakedQuery` up until
         this point will be pulled from the cache.   If True, then the
         entire :class:`_query.Query` object is built from scratch each
         time, with all creational functions being called on each
         invocation.

        )Ú_query_onlyT)r   r*   r   Ú_retrieve_baked_queryr   )r   ÚfullÚ_spoil_pointr   r   r   Úspoil‰   s   

zBakedQuery.spoilc                 C   s   | j |jf S )a«  Return the key that actually goes into the cache dictionary for
        this :class:`.BakedQuery`, taking into account the given
        :class:`.Session`.

        This basically means we also will include the session's query_class,
        as the actual :class:`_query.Query` object is part of what's cached
        and needs to match the type of :class:`_query.Query` that a later
        session will want to use.

        )r   Ú
_query_clsr8   r   r   r   Ú_effective_key¤   s   zBakedQuery._effective_keyc                 C   s   |   ¡ }|j|||d� |S )z)Cloning version of _add_lazyload_options.)Ú
cache_path)r*   Ú_add_lazyload_options)r   ÚoptionsÚeffective_pathrB   Úqr   r   r   Ú_with_lazyload_options±   s   z!BakedQuery._with_lazyload_optionsc                    sz   d}|sˆ }ˆD ]%}|j s|jr-| ¡ }|du r| jdd� q|d r'J dƒ‚||d 7 }q|  ‡ ‡fdd	„|j|¡ dS )
a*  Used by per-state lazy loaders to add options to the
        "lazy load" query from a parent query.

        Creates a cache key based on given load path and query options;
        if a repeatable cache key cannot be generated, the query is
        "spoiled" so that it won't use caching.

        r   NT)r=   é   z‘loader options with variable bound parameters not supported with baked queries.  Please use new-style select() statements for cached ORM queries.r   c                    s   |   ˆ ¡jˆŽ S r   )Ú_with_current_pathrD   ©rF   ©rE   rD   r   r   Ú<lambda>Õ   s    z2BakedQuery._add_lazyload_options.<locals>.<lambda>)Ú_is_legacy_optionÚ_is_compile_stateÚ_generate_cache_keyr?   r0   Úpath)r   rD   rE   rB   ÚkeyÚoptÚckr   rK   r   rC   ·   s$   

ÿ€ýz BakedQuery._add_lazyload_optionsc                 C   sF   | j  |  |¡d ¡}|d u r|  |¡}| d ¡| j |  |¡< | |¡S r   )r   ÚgetrA   Ú	_as_queryÚwith_session)r   r9   Úqueryr   r   r   r<   Ú   s   
ÿ
z BakedQuery._retrieve_baked_queryc                 C   s<   |   |¡}d |_| ¡ }|jjr||f| j|  |¡< ||fS r   )rU   r9   Ú_statement_20Ú_compile_optionsÚ_bake_okr   rA   )r   r9   rW   Ú	statementr   r   r   Ú_bakeã   s   
þzBakedQuery._bakec                 C   sN   t |tƒr|}nt |tƒr|j}|du rt d¡‚ntdt|ƒ ƒ‚|  |¡S )a  Return the :class:`_query.Query` object for use as a subquery.

        This method should be used within the lambda callable being used
        to generate a step of an enclosing :class:`.BakedQuery`.   The
        parameter should normally be the :class:`_query.Query` object that
        is passed to the lambda::

            sub_bq = self.bakery(lambda s: s.query(User.name))
            sub_bq += lambda q: q.filter(User.id == Address.user_id).correlate(Address)

            main_bq = self.bakery(lambda s: s.query(Address))
            main_bq += lambda q: q.filter(sub_bq.to_query(q).exists())

        In the case where the subquery is used in the first callable against
        a :class:`.Session`, the :class:`.Session` is also accepted::

            sub_bq = self.bakery(lambda s: s.query(User.name))
            sub_bq += lambda q: q.filter(User.id == Address.user_id).correlate(Address)

            main_bq = self.bakery(
                lambda s: s.query(Address.id, sub_bq.to_query(q).scalar_subquery())
            )

        :param query_or_session: a :class:`_query.Query` object or a class
         :class:`.Session` object, that is assumed to be within the context
         of an enclosing :class:`.BakedQuery` callable.


         .. versionadded:: 1.3


        Nz1Given Query needs to be associated with a Sessionz)Query or Session object expected, got %r.)	r.   r   r   r9   Úsa_excÚArgumentErrorÚ	TypeErrorÚtyperU   )r   Úquery_or_sessionr9   r   r   r   Úto_queryü   s   
"
ÿÿÿÿ
zBakedQuery.to_queryc                 C   s.   | j d |ƒ}| j dd … D ]}||ƒ}q|S ©Nr   rH   )r   )r   r9   rW   Ústepr   r   r   rU   -  s   
zBakedQuery._as_query)r   )r"   N)Fr   )r   r   r   r   r   r   Úclassmethodr!   r*   r    r3   r5   r0   r4   r:   r   r?   rA   rG   rC   r<   r\   rb   rU   r   r   r   r   r   9   s,    
	





#	1r   c                   @   s”   e Zd 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d„ Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ Zd#S )$r7   a  Invokes a :class:`.BakedQuery` against a :class:`.Session`.

    The :class:`_baked.Result` object is where the actual :class:`.query.Query`
    object gets created, or retrieved from the cache,
    against a target :class:`.Session`, and is then invoked for results.

    ©Úbqr9   Ú_paramsÚ_post_criteriac                 C   s   || _ || _i | _g | _d S r   rf   )r   rg   r9   r   r   r   r   A  s   
zResult.__init__c                 O   sB   t |ƒdkr| |d ¡ nt |ƒdkrt d¡‚| j |¡ | S )z@Specify parameters to be replaced into the string SQL statement.rH   r   zFparams() takes zero or one positional argument, which is a dictionary.)ÚlenÚupdater]   r^   rh   )r   r   Úkwr   r   r   ÚparamsG  s   ÿzResult.paramsc                 C   s   |r| j  |¡ | S r   )ri   Úextend)r   Úfnsr   r   r   Ú_using_post_criteriaT  s   zResult._using_post_criteriac                 C   s   |   |g¡S )aô  Add a criteria function that will be applied post-cache.

        This adds a function that will be run against the
        :class:`_query.Query` object after it is retrieved from the
        cache.    This currently includes **only** the
        :meth:`_query.Query.params` and :meth:`_query.Query.execution_options`
        methods.

        .. warning::  :meth:`_baked.Result.with_post_criteria`
           functions are applied
           to the :class:`_query.Query`
           object **after** the query's SQL statement
           object has been retrieved from the cache.   Only
           :meth:`_query.Query.params` and
           :meth:`_query.Query.execution_options`
           methods should be used.


        .. versionadded:: 1.2


        )rp   )r   r-   r   r   r   Úwith_post_criteriaY  s   zResult.with_post_criteriac                 C   s.   | j  | j¡ | j¡}| jD ]}||ƒ}q|S r   )rg   rU   r9   rm   rh   ri   )r   rF   r-   r   r   r   rU   r  s   

zResult._as_queryc                 C   s   t |  ¡ ƒS r   )ÚstrrU   ©r   r   r   r   Ú__str__x  ó   zResult.__str__c                 C   ó   |   ¡  ¡ S r   )Ú_iterÚ__iter__rs   r   r   r   rx   {  ru   zResult.__iter__c           	      C   sä   | j }| jjr
|jr|  ¡  ¡ S |j | | j¡d¡\}}|d u r)| 	| j¡\}}| j
r3| | j
¡}n|}| jD ]}||ƒ}q8|j
}t|jƒ}| |j|jdœ¡ | jj|||d�}|j dd¡re| ¡ }|j dd¡rp| ¡ }|S )N)NN)Ú_sa_orm_load_optionsÚcompiled_cache)Úexecution_optionsÚis_single_entityFÚfiltered)rg   r9   Úenable_baked_queriesr   rU   rw   r   rT   rA   r\   rh   rm   ri   ÚdictÚ_execution_optionsrk   Úload_optionsÚexecuteÚ_attributesÚscalarsÚunique)	r   rg   rW   r[   rF   r-   rm   r{   Úresultr   r   r   rw   ~  s8   ÿ


þÿÿzResult._iterc                    s:   t  tdƒ¡‰ | j ‡ fdd„¡}| | j¡ | j¡ 	¡ S )zÎreturn the 'count'.

        Equivalent to :meth:`_query.Query.count`.

        Note this uses a subquery to ensure an accurate count regardless
        of the structure of the original statement.

        Ú*c                    s
   |   ˆ ¡S r   )Ú_legacy_from_selfrJ   ©Úcolr   r   rL   °  s   
 zResult.count.<locals>.<lambda>)
r   Úcountr   rg   r4   r:   r9   rm   rh   Úscalar©r   rg   r   r‰   r   r‹   ¥  s   
zResult.countc                 C   s<   z|   ¡ }t|tjƒs|W S |d W S  tjy   Y dS w )zÓReturn the first element of the first result or None
        if no rows present.  If multiple rows are returned,
        raises MultipleResultsFound.

        Equivalent to :meth:`_query.Query.scalar`.

        r   N)Úoner.   Úcollections_abcÚSequenceÚorm_excÚNoResultFound)r   Úretr   r   r   rŒ   ³  s   
ÿzResult.scalarc                 C   s4   | j  dd„ ¡}| | j¡ | j¡ | j¡ ¡  	¡ S )zRReturn the first row.

        Equivalent to :meth:`_query.Query.first`.

        c                 S   s   |   dd¡S rc   )ÚslicerJ   r   r   r   rL   Ê  s    zResult.first.<locals>.<lambda>)
rg   r4   r:   r9   rm   rh   rp   ri   rw   Úfirstr�   r   r   r   r•   Ã  s   
ûzResult.firstc                 C   rv   )zkReturn exactly one result or raise an exception.

        Equivalent to :meth:`_query.Query.one`.

        )rw   rŽ   rs   r   r   r   rŽ   Ó  ó   z
Result.onec                 C   rv   )z�Return one or zero results, or raise an exception for multiple
        rows.

        Equivalent to :meth:`_query.Query.one_or_none`.

        )rw   Úone_or_noners   r   r   r   r—   Û  s   zResult.one_or_nonec                 C   rv   )zKReturn all rows.

        Equivalent to :meth:`_query.Query.all`.

        )rw   Úallrs   r   r   r   r˜   ä  r–   z
Result.allc                 C   s    | j jd | jƒ}| || j¡S )z`Retrieve an object based on identity.

        Equivalent to :meth:`_query.Query.get`.

        r   )rg   r   r9   Ú	_get_implÚ_load_on_pk_identity)r   ÚidentrW   r   r   r   rT   ì  s   z
Result.getc           
         sÄ   |j d jd ‰ˆj\‰ ‰‡ ‡‡‡‡fdd„}ˆj}| ¡ }| jˆ f7  _| |tdd„ ˆD ƒƒ¡}‡fdd„tˆˆj	ƒD ƒ}t
| ˆj¡jdi |¤Žƒ}t|ƒ}	|	d	krZt ¡ ‚|	r`|d S d
S )z6Load the given primary key identity from the database.r   Úparententityc                    st   ˆ }|   ¡ }| ¡  d |_d ˆv r$‡fdd„tˆjˆƒD ƒ}t ||¡}t |ddi¡f|_ˆj	D ]}||ƒ}q1|S )Nc                    s"   h | ]\}}|d u rˆ | j ’qS r   ©rQ   )Ú.0rŠ   Úvalue©Ú_get_paramsr   r   Ú	<setcomp>  s
    üz=Result._load_on_pk_identity.<locals>.setup.<locals>.<setcomp>Ú
_orm_adaptT)
r*   Ú_get_conditionÚ	_order_byÚzipÚprimary_keyÚsql_utilÚadapt_criterion_to_nullÚ_deep_annotateÚ_where_criteriari   )rW   Ú_lcl_get_clauserF   Únonesr-   ©Ú_get_clauser¡   ÚmapperÚprimary_key_identityr   r   r   Úsetupý  s$   
ÿþÿÿ

z*Result._load_on_pk_identity.<locals>.setupc                 s   s   � | ]}|d u V  qd S r   r   )rž   Úelemr   r   r   Ú	<genexpr>&  s   € z.Result._load_on_pk_identity.<locals>.<genexpr>c                    s   i | ]
\}}ˆ | j |“qS r   r�   )rž   Úid_valr§   r    r   r   Ú
<dictcomp>)  s    
ÿÿz/Result._load_on_pk_identity.<locals>.<dictcomp>rH   Nr   )Ú_raw_columnsÚ_annotationsr¯   rg   r*   r   r4   r/   r¦   r§   r(   r:   r9   rm   rj   r‘   ÚMultipleResultsFound)
r   r9   rW   r±   rl   r²   rg   rm   r†   Úlr   r®   r   rš   ö  s*   
 ÿ
ÿþzResult._load_on_pk_identityN)r   r   r   r   r   r   rm   rp   rq   rU   rt   rx   rw   r‹   rŒ   r•   rŽ   r—   r˜   rT   rš   r   r   r   r   r7   6  s&    '	
r7   )r   Úcollections.abcÚabcr�   ÚloggingÚ r   r]   r   Úormr‘   Ú	orm.queryr   Úorm.sessionr   Úsqlr   r   r¨   Ú	getLoggerr   Úlogr	   r   r7   r!   r   r   r   r   Ú<module>   s&   		
 ~  
