U aP@s@dZddlZddlmZddlmZddlmZddlmZddl m Z ddl m Z dd l mZdd l mZddl mZdd lmZeeZGd d d eZGdddeZGdddeZeddddZeddddZeddZejeddddZejeddddZ ej!Ze j"Z ej#Z#dS)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)strategy_options)Query)Session)func)literal_column)collections_abcc@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_rrUC:\Users\vtejo\AppData\Local\Temp\pip-unpacked-wheel-nyjtotrf\sqlalchemy\ext\baked.py__init__/szBakery.__init__cGs||j||Srr )r initial_fnargsrrr__call__3szBakery.__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_keyrr r)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"CszBakedQuery.bakerycCs2tt}|j|_t|j|_|j|_|j|_|Sr)r__new__rlistrrr )rZb1rrr_cloneMs   zBakedQuery._clonecCs|j|jf|7_dSr)r__code__rfnrrrrr!UszBakedQuery._update_cache_keycCs$t|tr|j|n |||Sr) isinstancetuple add_criteriarotherrrr__iadd__Xs   zBakedQuery.__iadd__cCs"t|tr|j|S||SdSr)r+r, with_criteriar.rrr__add___s  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. )r!rappendr)rrrr-es  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)rrrr1pszBakedQuery.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_sessionzszBakedQuery.for_sessioncCs ||Sr)r7r5rrrrszBakedQuery.__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)r r'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_clsr5rrr_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)r9zloader 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_keyr:AssertionErrorr-path)rr>r?r<keyoptZckrrDrr=s"    z BakedQuery._add_lazyload_optionscCsF|j||d}|dkr<||}|d|j||<||Sr)rgetr; _as_queryZ with_session)rr6queryrrrr8s z BakedQuery._retrieve_baked_querycCs<||}d|_|}|jjr4||f|j||<||fSr)rLr6Z _statement_20Z_compile_optionsZ_bake_okrr;)rr6rM 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+rrr6sa_exc ArgumentError TypeErrortyperL)rZquery_or_sessionr6rrrto_querys&  zBakedQuery.to_querycCs.|jd|}|jddD] }||}q|SNrrB)r)rr6rMsteprrrrL/s zBakedQuery._as_query)r)r#N)r)F)N)N)rrrrrr classmethodr"r'r!r0r2r-r1r7rr:r;rAr=r8rOrTrLrrrrr7s*         # 5rc@seZdZdZdZddZddZddZd d Zd d Z d dZ ddZ ddZ ddZ ddZddZddZddZddZdd Zd!d"Zd#S)$r4aInvokes 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. bqr6_params_post_criteriacCs||_||_i|_g|_dSrrX)rrYr6rrrrCszResult.__init__cOsBt|dkr||dnt|dkr2td|j||S)z@Specify parameters to be replaced into the string SQL statement.rBrzFparams() takes zero or one positional argument, which is a dictionary.)lenupdaterPrQrZ)rrkwrrrparamsIs   z Result.paramscCs|r|j||Sr)r[extend)rfnsrrr_using_post_criteriaVs 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 )rb)rr*rrrwith_post_criteria[szResult.with_post_criteriacCs.|j|j|j}|jD] }||}q|Sr)rYrLr6r_rZr[)rr@r*rrrrLts  zResult._as_querycCs t|Sr)strrLrrrr__str__zszResult.__str__cCs |Sr)_iter__iter__rerrrrh}szResult.__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)rYr6Zenable_baked_queriesr rLrgrrKr;rOrZr_r[dictZ_execution_optionsr]Z load_optionsexecute _attributesZscalarsunique) rrYrMrNr@r*r_riresultrrrrgs>     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. .. versionadded:: 1.1.6 *cs |Sr)Z _from_selfrCcolrrrErFzResult.count..) rcountr rYr1r7r6r_rZscalarrrYrrqrrss 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`. .. versionadded:: 1.1.6 rN)oner+r Sequenceorm_excZ NoResultFound)rretrrrrts   z Result.scalarcCs4|jdd}||j|j|j S)zRReturn the first row. Equivalent to :meth:`_query.Query.first`. cSs |ddSrU)slicerCrrrrErFzResult.first..) rYr1r7r6r_rZrbr[rgfirstrurrrr{s  z Result.firstcCs |S)zkReturn exactly one result or raise an exception. Equivalent to :meth:`_query.Query.one`. )rgrvrerrrrvsz Result.onecCs |S)zReturn one or zero results, or raise an exception for multiple rows. Equivalent to :meth:`_query.Query.one_or_none`. .. versionadded:: 1.0.9 )rg one_or_nonererrrr|s zResult.one_or_nonecCs |S)zKReturn all rows. Equivalent to :meth:`_query.Query.all`. )rgallrerrrr}sz Result.allcCs |jjd|j}|||jS)z`Retrieve an object based on identity. Equivalent to :meth:`_query.Query.get`. r)rYrr6Z _get_impl_load_on_pk_identity)ridentrMrrrrKsz Result.getc  s|jdjdj\fdd}j}|}|jf7_||tddD}tfddt j D}t | j jf|}t|} | d krtn| r|dSd Sd S) z6Load the given primary key identity from the database.rZ parententitycsx}|}|d|_dkrLtfddtjD}t||}t|ddif|_ j D] }||}qf|S)Ncs"g|]\}}|dkr|jqSrrI).0rrvalue _get_paramsrr sz>Result._load_on_pk_identity..setup..Z _orm_adaptT) r'Z_get_conditionZ _order_bysetzip primary_keysql_utilZadapt_criterion_to_nullZ_deep_annotateZ_where_criteriar[)rMZ_lcl_get_clauser@Znonesr* _get_clauserZmapperprimary_key_identityrrrsetups,    z*Result._load_on_pk_identity..setupcss|]}|dkVqdSrr)relemrrr 0sz.Result._load_on_pk_identity..csg|]\}}|j|fqSrr)rZid_valrrrrr4sz/Result._load_on_pk_identity..rBN)Z _raw_columnsZ _annotationsrrYr'rr1r,rkrrr&r7r6r_r\rxZMultipleResultsFound) rr6rMrr^rrYr_rolrrrr~s2 "   zResult._load_on_pk_identityN)rrrrrrr_rbrcrLrfrhrgrsrtr{rvr|r}rKr~rrrrr48s$ '  r4z1.2z5Baked lazy loading is now the default implementation.cCsdS)zEnable the use of baked queries for all lazyloaders systemwide. The "baked" implementation of lazy loading is now the sole implementation for the base lazy loader; this method has no effect except for a warning. Nrrrrrbake_lazy_loadersFs rcCs tddS)aHDisable the use of baked queries for all lazyloaders systemwide. This method now raises NotImplementedError() as the "baked" implementation is the only lazy load implementation. The :paramref:`_orm.relationship.bake_queries` flag may be used to disable the caching of queries on a per-relationship basis. z4Baked lazy loading is now the default implementationN)NotImplementedErrorrrrrunbake_lazy_loadersSs rcCs||ddiS)zxIndicate that the given attribute should be loaded using "lazy" loading with a "baked" query used in the load. ZlazyZ baked_select)Zset_relationship_strategy)Zloadoptattrrrrbaked_lazyloaddsrzFBaked lazy loading is now the default implementation for lazy loading.cGstjtjj|diS)NFrZ _UnboundLoadZ _from_keysrkeysrrrrms cGstjtjj|diS)NTrrrrrbaked_lazyload_allys r)$rloggingrrPrZormrxrZ orm.queryrZ orm.sessionrZsqlrr rr getLoggerrlogobjectr rr4 deprecatedrrZ loader_optionrZ_add_unbound_fnZ_add_unbound_all_fnrZ _unbound_fnZ_unbound_all_fnr"rrrrs\