
    gYE                         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j&                  e      Z G d
 d      Z G d d      Z G d d      Zej2                  Zy)zBaked 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                        e Zd ZdZdZd Zd Zy)BakeryzCallable 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                      || _         || _        y Nr   )selfcls_r   s      S/var/www/html/AdoubleTech/venv/lib/python3.12/site-packages/sqlalchemy/ext/baked.py__init__zBakery.__init__1   s    
    c                 <    | j                  | j                  ||      S r   r   )r   
initial_fnargss      r   __call__zBakery.__call__5   s    xx

J55r   N)__name__
__module____qualname____doc__	__slots__r   r    r   r   r   r   #   s    	 I6r   r   c                       e Zd ZdZdZddZedd       Zd ZddZ	d Z
d	 Zd
 Zd Zd Zd ZddZd ZddZddZd Zd Zd Zd Zy)
BakedQueryz3A builder object for :class:`.query.Query` objects.)steps_bakery
_cache_key_spoiledc                 b    d| _         | j                  ||       |g| _        d| _        || _        y )Nr   F)r$   _update_cache_keyr"   r%   r#   )r   bakeryr   r   s       r   r   zBakedQuery.__init__>   s0    z40 \
r   Nc                 D    t        | t        j                  ||            S )zSConstruct a new bakery.

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

        )
size_alert)r   r   LRUCache)r   size_size_alerts      r   r(   zBakedQuery.bakeryE   s     c4==+FGGr   c                     t         j                  t               }| j                  |_        t        | j                        |_        | j
                  |_        | j                  |_        |S r   )r!   __new__r$   listr"   r#   r%   )r   b1s     r   _clonezBakedQuery._cloneO   sH    
+

#\\
mm	r   c                 J    | xj                   |j                  f|z   z  c_         y r   )r$   __code__r   fnr   s      r   r'   zBakedQuery._update_cache_keyW   s    BKK>D00r   c                 j    t        |t              r | j                  |  | S | j                  |       | S r   )
isinstancetupleadd_criteriar   others     r   __iadd__zBakedQuery.__iadd__Z   s8    eU#Du%  e$r   c                 b    t        |t              r | j                  | S | j                  |      S r   )r8   r9   with_criteriar;   s     r   __add__zBakedQuery.__add__a   s0    eU#%4%%u--%%e,,r   c                 `    | j                  ||       | j                  j                  |       | S )zAdd a criteria function to this :class:`.BakedQuery`.

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

        )r'   r"   appendr5   s      r   r:   zBakedQuery.add_criteriag   s+     	r4(

"r   c                 D     | j                         j                  |g| S )zAdd 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.

        )r2   r:   r5   s      r   r?   zBakedQuery.with_criteriar   s"     *t{{}))"4t44r   c                     t        | |      S )zReturn 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   sessions     r   for_sessionzBakedQuery.for_session|   s     dG$$r   c                 $    | j                  |      S r   )rH   rF   s     r   r   zBakedQuery.__call__   s    ((r   c                     |sC| j                   s7| j                         }|xj                  dz  c_        |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%   r2   r$   _retrieve_baked_queryr"   )r   full_spoil_points      r   spoilzBakedQuery.spoil   sF    ( DMM;;=L##'77#&<<=DJr   c                 6    | j                   |j                  fz   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_clsrF   s     r   _effective_keyzBakedQuery._effective_key   s     '"4"4!666r   c                 N    | j                         }|j                  |||       |S )z)Cloning version of _add_lazyload_options.)
cache_path)r2   _add_lazyload_options)r   optionseffective_pathrT   qs        r   _with_lazyload_optionsz!BakedQuery._with_lazyload_options   s'    KKM	JOr   c                    d}|s}D ]T  }|j                   s|j                  s|j                         }|| j                  d       A|d   rJ d       ||d   z  }V | j	                  fd|j
                  |       y)	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)rM      zloader options with variable bound parameters not supported with baked queries.  Please use new-style select() statements for cached ORM queries.r   c                 @     | j                        j                   S r   )_with_current_pathrV   )rX   rW   rV   s    r   <lambda>z2BakedQuery._add_lazyload_options.<locals>.<lambda>   s     Ba**>:BBGL r   )_is_legacy_option_is_compile_state_generate_cache_keyrO   r:   path)r   rV   rW   rT   keyoptcks    ``    r   rU   z BakedQuery._add_lazyload_options   s     'J 	!C$$(=(=,,.:JJDJ)!!u '9 2a5LC	! 	LOO	
r   c                     | j                   j                  | j                  |      d       }|>| j                  |      }|j	                  d       | j                   | j                  |      <   |j	                  |      S r   )r#   getrR   	_as_querywith_session)r   rG   querys      r   rL   z BakedQuery._retrieve_baked_query   sp      !4!4W!=tD=NN7+E9>9K9K:DLL,,W56 !!'**r   c                     | j                  |      }d |_        |j                         }|j                  j                  r ||f| j
                  | j                  |      <   ||fS r   )rh   rG   _statement_20_compile_options_bake_okr#   rR   )r   rG   rj   	statements       r   _bakezBakedQuery._bake   sf    w' '')	 %%..:DLL,,W56
 ir   c                     t        |t              r|}nJt        |t              r#|j                  }|,t	        j
                  d      t        dt        |      z        | j                  |      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


        z1Given Query needs to be associated with a Sessionz)Query or Session object expected, got %r.)	r8   r   r   rG   sa_excArgumentError	TypeErrortyperh   )r   query_or_sessionrG   s      r   to_queryzBakedQuery.to_query   sw    D &0&G(%0&..G**G  ;'()  ~~g&&r   c                 h     | j                   d   |      }| j                   dd  D ]
  } ||      } |S Nr   r[   )r"   )r   rG   rj   steps       r   rh   zBakedQuery._as_query-  s?    

1g&JJqrN 	 DKE	  r   )r   )   N)Fr   )r   r   r   r   r   r   classmethodr(   r2   r'   r=   r@   r:   r?   rH   r   rO   rR   rY   rU   rL   rp   rw   rh   r   r   r   r!   r!   9   sw    =<I H H1-	5%)67!
F+ 2/'br   r!   c                   t    e Zd ZdZdZd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zy)rE   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.

    bqrG   _params_post_criteriac                 <    || _         || _        i | _        g | _        y r   r~   )r   r   rG   s      r   r   zResult.__init__A  s     r   c                     t        |      dk(  r|j                  |d          n#t        |      dkD  rt        j                  d      | j                  j                  |       | S )z@Specify parameters to be replaced into the string SQL statement.r[   r   zFparams() takes zero or one positional argument, which is a dictionary.)lenupdaterr   rs   r   )r   r   kws      r   paramszResult.paramsG  s[     t9>IId1gY]&&)  	Br   c                 @    |r| j                   j                  |       | S r   )r   extend)r   fnss     r   _using_post_criteriazResult._using_post_criteriaT  s    &&s+r   c                 &    | j                  |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


        )r   )r   r6   s     r   with_post_criteriazResult.with_post_criteriaY  s    . (("..r   c                     | j                   j                  | j                        j                  | j                        }| j
                  D ]
  } ||      } |S r   )r   rh   rG   r   r   r   )r   rX   r6   s      r   rh   zResult._as_queryr  sL    GGdll+224<<@%% 	B1A	r   c                 4    t        | j                               S r   )strrh   r   s    r   __str__zResult.__str__x  s    4>>#$$r   c                 >    | j                         j                         S r   )_iter__iter__r   s    r   r   zResult.__iter__{  s    zz|$$&&r   c                 R   | j                   }| j                  j                  r|j                  r| j	                         j                         S |j                  j                  |j                  | j                        d      \  }}||j                  | j                        \  }}| j                  r|j                  | j                        }n|}| j                  D ]
  } ||      } |j                  }t        |j                        }|j                  |j                   |j                  d       | j                  j#                  |||      }|j$                  j                  dd      r|j'                         }|j$                  j                  dd      r|j)                         }|S )N)NN)_sa_orm_load_optionscompiled_cache)execution_optionsis_single_entityFfiltered)r   rG   enable_baked_queriesr%   rh   r   r#   rg   rR   rp   r   r   r   dict_execution_optionsr   load_optionsexecute_attributesscalarsunique)	r   r   rj   ro   rX   r6   r   r   results	            r   r   zResult._iter~  sd   WW||00BKK>>#))++::>>dll+\
y =!xx5E9<<T\\*AA%% 	B1A	  !5!56  ()"$**	
 %%v1B & 
 !!"4e<^^%F!!*e4]]_Fr   c                     t        j                  t        d            | j                  j	                  fd      }|j                  | j                        j                  | j                        j                         S )zreturn 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                 &    | j                        S r   )_legacy_from_self)rX   cols    r   r^   zResult.count.<locals>.<lambda>  s    Q-@-@-E r   )
r   countr	   r   r?   rH   rG   r   r   scalar)r   r   r   s     @r   r   zResult.count  sX     jj,-WW""#EF~~dll+224<<@GGIIr   c                     	 | j                         }t        |t        j                        s|S |d   S # t        j
                  $ r Y yw xY w)zReturn 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)oner8   collections_abcSequenceorm_excNoResultFound)r   rets     r   r   zResult.scalar  sH    	((*Cc?#;#;<
q6M$$ 		s   +3 3 A	A	c                    | j                   j                  d       }|j                  | j                        j	                  | j
                        j                  | j                        j                         j                         S )zRReturn the first row.

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

        c                 &    | j                  dd      S ry   )slice)rX   s    r   r^   zResult.first.<locals>.<lambda>  s    QWWQ] r   )
r   r?   rH   rG   r   r   r   r   r   first)r   r   s     r   r   zResult.first  s[     WW""#:;NN4<<(VDLL!!!$"5"56UWUW	
r   c                 >    | j                         j                         S )zkReturn exactly one result or raise an exception.

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

        )r   r   r   s    r   r   z
Result.one       zz|!!r   c                 >    | j                         j                         S )zReturn one or zero results, or raise an exception for multiple
        rows.

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

        )r   one_or_noner   s    r   r   zResult.one_or_none  s     zz|''))r   c                 >    | j                         j                         S )zKReturn all rows.

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

        )r   allr   s    r   r   z
Result.all  r   r   c                      | j                   j                  d   | j                        }|j                  || j                        S )z`Retrieve an object based on identity.

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

        r   )r   r"   rG   	_get_impl_load_on_pk_identity)r   identrj   s      r   rg   z
Result.get  s8     !a .ud&?&?@@r   c                 T    |j                   d   j                  d   j                  \   fd} j                  }|j	                         }|xj
                  fz  c_        |j                  |t        d D                    }t        j                        D ci c]  \  }}|   j                  | }	}}t         |j                   j                        j                  di |	      }
t        |
      }|dkD  rt!        j"                         |r|
d   S yc c}}w )z6Load the given primary key identity from the database.r   parententityc                 v   }| j                         }|j                          d |_        d 
v rMt        	j                  
      D ch c]  \  }}||   j
                   }}}t        j                  ||      }t        j                  |ddi      f|_	        j                  D ]
  } ||      } |S c c}}w )N
_orm_adaptT)r2   _get_condition	_order_byzipprimary_keyrc   sql_utiladapt_criterion_to_null_deep_annotate_where_criteriar   )rj   _lcl_get_clauserX   r   valuenonesr6   _get_clause_get_paramsmapperprimary_key_identityr   s          r   setupz*Result._load_on_pk_identity.<locals>.setup  s    )OAAK ++ '***,@'"U }	  $((  #+"B"B#U# '',9MN!A )) qEH%s   B5c              3   $   K   | ]  }|d u  
 y wr   r   ).0elems     r   	<genexpr>z.Result._load_on_pk_identity.<locals>.<genexpr>&  s     G$Gs   r[   Nr   )_raw_columns_annotationsr   r   r2   r$   r?   r9   r   r   rc   r0   rH   rG   r   r   r   MultipleResultsFound)r   rG   rj   r   r   r   r   id_valr   r   r   lr   r   r   s   `  `        @@@r   r   zResult._load_on_pk_identity  s%    ##A&33NC#)#5#5 [	 	@ WW
 YY[
+'5G2FGG
 (+$f&8&8(
# $((&0
 
 9bnnT\\299CFCDKq5..00!9
s   'D$N)r   r   r   r   r   r   r   r   r   rh   r   r   r   r   r   r   r   r   r   rg   r   r   r   r   rE   rE   6  sb     =I!
/2%'%NJ 
 "*"AAr   rE   )r   collections.abcabcr   logging r   rr   r   ormr   	orm.queryr   orm.sessionr   sqlr   r	   r   	getLoggerr   logr   r!   rE   r(   r   r   r   <module>r      so    *       !    " g!6 6,z zzA AH 
		r   