U kfE@sdZddlmZddlZddlmZddlmZddl mZ ddl m Z ddl mZddlmZdd lmZddlmZeeZGd d d ZGd d d ZGdddZejZdS)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@s$eZdZdZdZddZddZdS)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 clscachecCs||_||_dSNr )selfZcls_r rD/opt/hc_python/lib64/python3.8/site-packages/sqlalchemy/ext/baked.py__init__1szBakery.__init__cGs||j||Sr r )r initial_fnargsrrr__call__5szBakery.__call__N)__name__ __module__ __qualname____doc__ __slots__rrrrrrr #s r c@seZdZdZdZd+ddZed,dd Zd d Zd-d d Z ddZ ddZ ddZ ddZ ddZddZd.ddZddZd/dd Zd0d!d"Zd#d$Zd%d&Zd'd(Zd)d*ZdS)1 BakedQueryz3A builder object for :class:`.query.Query` objects.)steps_bakery _cache_key_spoiledrcCs*d|_||||g|_d|_||_dS)NrF)r_update_cache_keyrrr)rbakeryrrrrrr>s  zBakedQuery.__init__NcCst|tj||dS)zSConstruct a new bakery. :return: an instance of :class:`.Bakery` )Z size_alert)r rZLRUCache)r sizeZ _size_alertrrrr EszBakedQuery.bakerycCs2tt}|j|_t|j|_|j|_|j|_|Sr )r__new__rlistrrr)rb1rrr_cloneOs   zBakedQuery._clonecCs|j|jf|7_dSr )r__code__rfnrrrrrWszBakedQuery._update_cache_keycCs$t|tr|j|n |||Sr ) isinstancetuple add_criteriarotherrrr__iadd__Zs   zBakedQuery.__iadd__cCs"t|tr|j|S||SdSr )r*r+ with_criteriar-rrr__add__as  zBakedQuery.__add__cGs||||j||S)zAdd a criteria function to this :class:`.BakedQuery`. This is equivalent to using the ``+=`` operator to modify a :class:`.BakedQuery` in-place. )rrappendr(rrrr,gs  zBakedQuery.add_criteriacGs|j|f|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. )r&r,r(rrrr0rszBakedQuery.with_criteriacCs 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)``. )Resultrsessionrrr for_session|szBakedQuery.for_sessioncCs ||Sr )r6r4rrrrszBakedQuery.__call__FcCs4|s*|js*|}|jd7_|jg|_d|_|S)aCancel 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. )Z _query_onlyT)rr&r_retrieve_baked_queryr)rfullZ _spoil_pointrrrspoils   zBakedQuery.spoilcCs|j|jfS)aReturn 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. )rZ _query_clsr4rrr_effective_keys zBakedQuery._effective_keycCs|}|j|||d|S)z)Cloning version of _add_lazyload_options.) cache_path)r&_add_lazyload_options)roptionseffective_pathr;qrrr_with_lazyload_optionssz!BakedQuery._with_lazyload_optionscszd}|s }D]J}|js |jr|}|dkr>|jddq|drNtd||d7}q|fdd |j|dS) 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. rNT)r8zloader options with variable bound parameters not supported with baked queries. Please use new-style select() statements for cached ORM queries.rcs|jSr )Z_with_current_pathr=r?r>r=rrz2BakedQuery._add_lazyload_options..)Z_is_legacy_optionZ_is_compile_stateZ_generate_cache_keyr9AssertionErrorr,path)rr=r>r;keyoptZckrrCrr<s"    z BakedQuery._add_lazyload_optionscCsF|j||d}|dkr<||}|d|j||<||Sr )rgetr: _as_queryZ with_session)rr5queryrrrr7s z BakedQuery._retrieve_baked_querycCs<||}d|_|}|jjr4||f|j||<||fSr )rKr5Z _statement_20Z_compile_optionsZ_bake_okrr:)rr5rL statementrrr_bakes  zBakedQuery._bakecCsNt|tr|}n4t|tr4|j}|dkrDtdntdt|||S)aLReturn 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*rrr5sa_exc ArgumentError TypeErrortyperK)rZquery_or_sessionr5rrrto_querys&  zBakedQuery.to_querycCs.|jd|}|jddD] }||}q|SNrrA)r)rr5rLsteprrrrK1s zBakedQuery._as_query)r)r!N)r)F)N)N)rrrrrr classmethodr r&rr/r1r,r0r6rr9r:r@r<r7rNrSrKrrrrr9s*         # 5rc@seZdZdZdZddZddZddZd d Zd d Z d dZ ddZ ddZ ddZ ddZddZddZddZddZdd Zd!d"Zd#S)$r3aInvokes 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. bqr5_params_post_criteriacCs||_||_i|_g|_dSr rW)rrXr5rrrrEszResult.__init__cOsBt|dkr||dnt|dkr2td|j||S)z@Specify parameters to be replaced into the string SQL statement.rArzFparams() takes zero or one positional argument, which is a dictionary.)lenupdaterOrPrY)rrkwrrrparamsKs   z Result.paramscCs|r|j||Sr )rZextend)rZfnsrrr_using_post_criteriaXs zResult._using_post_criteriacCs ||gS)aAdd 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`)rr)rrrwith_post_criteria]szResult.with_post_criteriacCs.|j|j|j}|jD] }||}q|Sr )rXrKr5r^rYrZ)rr?r)rrrrKvs  zResult._as_querycCs t|Sr )strrKrrrr__str__|szResult.__str__cCs |Sr )_iter__iter__rcrrrrfszResult.__iter__c Cs|j}|jjr|jr |S|j||jd\}}|dkrR| |j\}}|j rf| |j }n|}|j D] }||}qp|j }t |j}||j|jd|jj|||d}|jddr|}|jddr|}|S)N)NN)Z_sa_orm_load_optionsZcompiled_cache)execution_optionsZis_single_entityFfiltered)rXr5Zenable_baked_queriesrrKrerrJr:rNrYr^rZdictZ_execution_optionsr\Z load_optionsexecute _attributesZscalarsunique) rrXrLrMr?r)r^rgresultrrrres>     z Result._itercs:ttd|jfdd}||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. *cs |Sr )Z_legacy_from_selfrBcolrrrDrEzResult.count..) rcountrrXr0r6r5r^rYscalarrrXrrorrqs z Result.countcCsBz$|}t|tjs|WS|dWStjk r<YdSXdS)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`. rN)oner*collections_abcSequenceorm_excZ NoResultFound)rretrrrrrs  z Result.scalarcCs4|jdd}||j|j|j S)zRReturn the first row. Equivalent to :meth:`_query.Query.first`. cSs |ddSrT)slicerBrrrrDrEzResult.first..) rXr0r6r5r^rYr`rZrefirstrsrrrrzs  z Result.firstcCs |S)zkReturn exactly one result or raise an exception. Equivalent to :meth:`_query.Query.one`. )rertrcrrrrtsz Result.onecCs |S)zReturn one or zero results, or raise an exception for multiple rows. Equivalent to :meth:`_query.Query.one_or_none`. )re one_or_nonercrrrr{szResult.one_or_nonecCs |S)zKReturn all rows. Equivalent to :meth:`_query.Query.all`. )reallrcrrrr|sz Result.allcCs |jjd|j}|||jS)z`Retrieve an object based on identity. Equivalent to :meth:`_query.Query.get`. r)rXrr5Z _get_impl_load_on_pk_identity)ridentrLrrrrJsz Result.getc  s|jdjdj\fdd}j}|}|jf7_||tddD}fddtj D}t | j j f|}t|} | d krtn| r|dSd Sd S) z6Load the given primary key identity from the database.rZ parententitycst}|}|d|_dkrHfddtjD}t||}t|ddif|_j D] }||}qb|S)Ncs"h|]\}}|dkr|jqSr rH).0rpvalue _get_paramsrr sz=Result._load_on_pk_identity..setup..Z _orm_adaptT) r&Z_get_conditionZ _order_byzip primary_keysql_utilZadapt_criterion_to_nullZ_deep_annotateZ_where_criteriarZ)rLZ_lcl_get_clauser?Znonesr) _get_clauserZmapperprimary_key_identityrrrsetups(   z*Result._load_on_pk_identity..setupcss|]}|dkVqdSr r)relemrrr *sz.Result._load_on_pk_identity..csi|]\}}|j|qSrr)rZid_valrrrr -sz/Result._load_on_pk_identity..rAN)Z _raw_columnsZ _annotationsrrXr&rr0r+rrr$r6r5r^r[rwZMultipleResultsFound) rr5rLrr]rrXr^rmlrrrr}s.    zResult._load_on_pk_identityN)rrrrrrr^r`rarKrdrfrerqrrrzrtr{r|rJr}rrrrr3:s$ '  r3)rcollections.abcabcruloggingrrOrZormrwZ orm.queryrZ orm.sessionrsqlrrr getLoggerrlogr rr3r rrrr s&