o
    Šåg3A  ã                   @  sn  d 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
 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 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" ddl!m#Z# erú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. dd$l/m0Z0 dd%lm1Z1 dd&lm2Z2 dd'lm3Z3 dd(l4m5Z5 dd)l6m7Z7 dd*l8m9Z9 dd+l:m;Z; d,d-gZ<ed.ed/�Z=e>Z?G d0d1„ d1e"ƒZ@G d2d3„ d3e"ƒZAG d4d-„ d-ee= ƒZBG d5d,„ d,e ƒZCG d6d7„ d7eƒZDd?d<d=„ZEd>S )@aË  Horizontal sharding support.

Defines a rudimental 'horizontal sharding' system which allows a Session to
distribute queries and persistence operations across multiple databases.

For a usage example, see the :ref:`examples_sharding` example included in
the source distribution.

.. deepalchemy:: The horizontal sharding extension is an advanced feature,
   involving a complex statement -> database interaction as well as
   use of semi-public APIs for non-trivial cases.   Simpler approaches to
   refering to multiple database "shards", most commonly using a distinct
   :class:`_orm.Session` per "shard", should always be considered first
   before using this more complex and less-production-tested system.



é    )Úannotations)ÚAny)ÚCallable)ÚDict)ÚIterable)ÚOptional)ÚTuple)ÚType)ÚTYPE_CHECKING)ÚTypeVar)ÚUnioné   )Úevent)Úexc)Úinspect)Úutil)ÚPassiveFlag)ÚOrmExecuteOptionsParameter)Ú	ORMOption)ÚMapper)ÚQuery)Ú_BindArguments)Ú_PKIdentityArgument)ÚSession)ÚProtocol)ÚSelf)Ú
Connection)ÚEngine)ÚOptionEngine)ÚIteratorResult)ÚResult)ÚLoaderCallableStatus)Ú_O)ÚBulkUDCompileState)ÚQueryContext)Ú_EntityBindKey)Ú_SessionBind)ÚORMExecuteState)ÚInstanceState)Ú
Executable)Ú_TP)ÚClauseElementÚShardedSessionÚShardedQueryÚ_T)Úboundc                   @  s   e Zd Zddd	„Zd
S )ÚShardChooserÚmapperúOptional[Mapper[_T]]Úinstancer   ÚclauseúOptional[ClauseElement]Úreturnc                 C  ó   d S ©N© )Úselfr1   r3   r4   r9   r9   ú[/var/www/html/flaskapp/venv/lib/python3.10/site-packages/sqlalchemy/ext/horizontal_shard.pyÚ__call__Q   s   zShardChooser.__call__N)r1   r2   r3   r   r4   r5   r6   r   ©Ú__name__Ú
__module__Ú__qualname__r<   r9   r9   r9   r;   r0   P   ó    r0   c                   @  s   e Zd Zddd„ZdS )ÚIdentityChooserr1   ú
Mapper[_T]Úprimary_keyr   Úlazy_loaded_fromúOptional[InstanceState[Any]]Úexecution_optionsr   Úbind_argumentsr   Úkwr   r6   c                K  r7   r8   r9   )r:   r1   rD   rE   rG   rH   rI   r9   r9   r;   r<   Z   s   	zIdentityChooser.__call__N©r1   rC   rD   r   rE   rF   rG   r   rH   r   rI   r   r6   r   r=   r9   r9   r9   r;   rB   Y   rA   rB   c                      s,   e Zd ZdZd‡ fdd„Zddd„Z‡  ZS )r-   a  Query class used with :class:`.ShardedSession`.

    .. legacy:: The :class:`.ShardedQuery` is a subclass of the legacy
       :class:`.Query` class.   The :class:`.ShardedSession` now supports
       2.0 style execution via the :meth:`.ShardedSession.execute` method.

    Úargsr   Úkwargsr6   ÚNonec                   s@   t ƒ j|i |¤Ž t| jtƒsJ ‚| jj| _| jj| _d | _d S r8   )ÚsuperÚ__init__Ú
isinstanceÚsessionr,   Úidentity_chooserÚexecute_chooserÚ	_shard_id)r:   rK   rL   ©Ú	__class__r9   r;   rO   o   s
   


zShardedQuery.__init__Úshard_idÚShardIdentifierr   c                 C  s   | j |d�S )a•  Return a new query, limited to a single shard ID.

        All subsequent operations with the returned query will
        be against the single shard regardless of other state.

        The shard_id can be passed for a 2.0 style execution to the
        bind_arguments dictionary of :meth:`.Session.execute`::

            results = session.execute(stmt, bind_arguments={"shard_id": "my_shard"})

        )Ú_sa_shard_id)rG   )r:   rW   r9   r9   r;   Ú	set_shardw   s   zShardedQuery.set_shard)rK   r   rL   r   r6   rM   )rW   rX   r6   r   )r>   r?   r@   Ú__doc__rO   rZ   Ú__classcell__r9   r9   rU   r;   r-   f   s    c                      s¦   e Zd ZU ded< ded< ded< dddefdddœd@‡ fdd„Zdejdej	dfdA‡ fd)d*„Z
dBd-d.„Z			dCdDd3d4„Z	dEdddd5œdFd9d:„ZdGd>d?„Z‡  ZS )Hr,   r0   Úshard_chooserrB   rR   z*Callable[[ORMExecuteState], Iterable[Any]]rS   N)Ú
id_chooserÚquery_chooserúOptional[IdentityChooser]ú4Optional[Callable[[ORMExecuteState], Iterable[Any]]]ÚshardsúOptional[Dict[str, Any]]Ú	query_clsúType[Query[_T]]r^   ú<Optional[Callable[[Query[_T], Iterable[_T]], Iterable[Any]]]r_   ú/Optional[Callable[[Executable], Iterable[Any]]]rL   r   r6   rM   c                  sô   t ƒ jd!d|i|¤Ž tjˆdtdd� |ˆ_|r-|‰ t dd¡ d"‡ ‡fdd„}	|	ˆ_n|r3|ˆ_nt	 
d¡‚|rV|‰t dd¡ |rIt	 
d¡‚d#‡fdd„}
|du rV|
}|du r_t	 
d ¡‚|ˆ_i ˆ_|durv|D ]}ˆ ||| ¡ qkdS dS )$aî  Construct a ShardedSession.

        :param shard_chooser: A callable which, passed a Mapper, a mapped
          instance, and possibly a SQL clause, returns a shard ID.  This id
          may be based off of the attributes present within the object, or on
          some round-robin scheme. If the scheme is based on a selection, it
          should set whatever state on the instance to mark it in the future as
          participating in that shard.

        :param identity_chooser: A callable, passed a Mapper and primary key
         argument, which should return a list of shard ids where this
         primary key might reside.

          .. versionchanged:: 2.0  The ``identity_chooser`` parameter
             supersedes the ``id_chooser`` parameter.

        :param execute_chooser: For a given :class:`.ORMExecuteState`,
          returns the list of shard_ids
          where the query should be issued.  Results from all shards returned
          will be combined together into a single listing.

          .. versionchanged:: 1.4  The ``execute_chooser`` parameter
             supersedes the ``query_chooser`` parameter.

        :param shards: A dictionary of string shard names
          to :class:`~sqlalchemy.engine.Engine` objects.

        rd   Údo_orm_executeT)ÚretvalzLThe ``id_chooser`` parameter is deprecated; please use ``identity_chooser``.z2.0r1   rC   rD   r   rE   rF   rG   r   rH   r   rI   r   r6   c                  s"   ˆ  | ¡}|r| |¡}ˆ ||ƒS r8   )ÚqueryÚ_set_lazyload_from)r1   rD   rE   rG   rH   rI   Úq)Ú_id_chooserr:   r9   r;   Ú_legacy_identity_chooserÆ   s   
	

z9ShardedSession.__init__.<locals>._legacy_identity_chooserz*identity_chooser or id_chooser is requiredzNThe ``query_chooser`` parameter is deprecated; please use ``execute_chooser``.z1.4z>Can't pass query_chooser and execute_chooser at the same time.Úorm_contextr'   úIterable[Any]c                   s
   ˆ | j ƒS r8   )Ú	statement©ro   )Ú_query_chooserr9   r;   Ú_default_execute_chooseré   s   
z9ShardedSession.__init__.<locals>._default_execute_chooserNz,execute_chooser or query_chooser is requiredr9   rJ   )ro   r'   r6   rp   )rN   rO   r   ÚlistenÚexecute_and_instancesr]   r   Úwarn_deprecatedrR   r   ÚArgumentErrorrS   Ú_ShardedSession__shardsÚ
bind_shard)r:   r]   rR   rS   rb   rd   r^   r_   rL   rn   rt   ÚkrU   )rm   rs   r:   r;   rO   ‹   sT   ,ÿýÿýÿÿþzShardedSession.__init__r1   ú
Mapper[_O]Úprimary_key_identityúUnion[Any, Tuple[Any, ...]]Úidentity_tokenúOptional[Any]Úpassiver   rE   rF   rG   r   rH   úOptional[_BindArguments]rI   ú)Union[Optional[_O], LoaderCallableStatus]c                   s|   |durt ƒ j||fd|i|¤Ž}	|	S | j|||||rt|ƒni d�D ]}
t ƒ j||f|
|dœ|¤Ž}|dur;|  S q#dS )a_  override the default :meth:`.Session._identity_lookup` method so
        that we search for a given non-token primary key identity across all
        possible identity tokens (e.g. shard ids).

        .. versionchanged:: 1.4  Moved :meth:`.Session._identity_lookup` from
           the :class:`_query.Query` object to the :class:`.Session`.

        Nr   )rE   rG   rH   )r   rE   )rN   Ú_identity_lookuprR   Údict)r:   r1   r}   r   r�   rE   rG   rH   rI   ÚobjrW   Úobj2rU   r9   r;   r„   û   s<   þýü
ûþüûÿzShardedSession._identity_lookupúOptional[_EntityBindKey[_O]]r3   c                 K  sp   |d urt |ƒ}|jr|jd }|d usJ ‚|S |jr|jS t|tƒs%J ‚| j||fi |¤Ž}|d ur6||_|S )Nr   )r   Úkeyr   rP   r   r]   )r:   r1   r3   rI   ÚstateÚtokenrW   r9   r9   r;   Ú_choose_shard_and_assign,  s   
z'ShardedSession._choose_shard_and_assignr2   rW   úOptional[ShardIdentifier]r   c                 K  sz   |du r
|   ||¡}|  ¡ r|  ¡ }|dusJ ‚|j||d�S | j|||d�}t|tƒr4|jdi |¤ŽS t|tƒs;J ‚|S )zaProvide a :class:`_engine.Connection` to use in the unit of work
        flush process.

        N)rW   )r1   rW   r3   r9   )	rŒ   Úin_transactionÚget_transactionÚ
connectionÚget_bindrP   r   Úconnectr   )r:   r1   r3   rW   rI   ÚtransÚbindr9   r9   r;   Úconnection_callableA  s   ÿ
z"ShardedSession.connection_callable)rW   r3   r4   r4   r5   r&   c                K  s.   |d u r| j |||d�}|d usJ ‚| j| S )N)r3   r4   )rŒ   ry   )r:   r1   rW   r3   r4   rI   r9   r9   r;   r‘   _  s   	ÿ
zShardedSession.get_bindrX   r”   úUnion[Engine, OptionEngine]c                 C  s   || j |< d S r8   )ry   )r:   rW   r”   r9   r9   r;   rz   o  s   zShardedSession.bind_shard)r]   r0   rR   r`   rS   ra   rb   rc   rd   re   r^   rf   r_   rg   rL   r   r6   rM   )r1   r|   r}   r~   r   r€   r�   r   rE   rF   rG   r   rH   r‚   rI   r   r6   rƒ   )r1   rˆ   r3   r   rI   r   r6   r   )NNN)
r1   r2   r3   r€   rW   r�   rI   r   r6   r   r8   )r1   rˆ   rW   r�   r3   r€   r4   r5   rI   r   r6   r&   )rW   rX   r”   r–   r6   rM   )r>   r?   r@   Ú__annotations__r-   rO   r   ÚPASSIVE_OFFr   Ú
EMPTY_DICTr„   rŒ   r•   r‘   rz   r\   r9   r9   rU   r;   r,   †   s<   
 øótø
1ü þúc                   @  s"   e Zd ZdZdZ	dddd	„Zd
S )Úset_shard_ida  a loader option for statements to apply a specific shard id to the
    primary query as well as for additional relationship and column
    loaders.

    The :class:`_horizontal.set_shard_id` option may be applied using
    the :meth:`_sql.Executable.options` method of any executable statement::

        stmt = (
            select(MyObject)
            .where(MyObject.name == "some name")
            .options(set_shard_id("shard1"))
        )

    Above, the statement when invoked will limit to the "shard1" shard
    identifier for the primary query as well as for all relationship and
    column loading strategies, including eager loaders such as
    :func:`_orm.selectinload`, deferred column loaders like :func:`_orm.defer`,
    and the lazy relationship loader :func:`_orm.lazyload`.

    In this way, the :class:`_horizontal.set_shard_id` option has much wider
    scope than using the "shard_id" argument within the
    :paramref:`_orm.Session.execute.bind_arguments` dictionary.


    .. versionadded:: 2.0.0

    ©rW   Úpropagate_to_loadersTrW   rX   rœ   Úboolc                 C  s   || _ || _dS )aH  Construct a :class:`_horizontal.set_shard_id` option.

        :param shard_id: shard identifier
        :param propagate_to_loaders: if left at its default of ``True``, the
         shard option will take place for lazy loaders such as
         :func:`_orm.lazyload` and :func:`_orm.defer`; if False, the option
         will not be propagated to loaded objects. Note that :func:`_orm.defer`
         always limits to the shard_id of the parent row in any case, so the
         parameter only has a net effect on the behavior of the
         :func:`_orm.lazyload` strategy.

        Nr›   )r:   rW   rœ   r9   r9   r;   rO   ”  s   
zset_shard_id.__init__N)T)rW   rX   rœ   r�   )r>   r?   r@   r[   Ú	__slots__rO   r9   r9   r9   r;   rš   u  s
    ÿrš   ro   r'   r6   ú&Union[Result[_T], IteratorResult[_TP]]c                   sú   ˆ j rˆ j}nˆ jsˆ jrˆ j}nd }ˆ j}t|tƒsJ ‚d
‡ fdd„}ˆ jD ]}t|t	ƒr3|j
} n$q'|r?|jd ur?|j}ndˆ jv rJˆ jd }ndˆ jv rUˆ jd }nd }|d ur_||ƒS g }| ˆ ¡D ]}||ƒ}| |¡ qf|d j|d	d … Ž S )NrW   rX   r6   rŸ   c                   s*   t ˆ jƒ}| |d< ˆ j| d� ˆ j|d�S )NrW   )r   )rH   )r…   rH   Úupdate_execution_optionsÚinvoke_statement)rW   rH   rr   r9   r;   Úiter_for_shard½  s   
z-execute_and_instances.<locals>.iter_for_shardrY   r   é   )rW   rX   r6   rŸ   )Ú	is_selectÚload_optionsÚ	is_updateÚ	is_deleteÚupdate_delete_optionsrQ   rP   r,   Ú_non_compile_orm_optionsrš   rW   Ú_identity_tokenrG   rH   rS   ÚappendÚmerge)ro   Úactive_optionsrQ   r¢   Úorm_optrW   ÚpartialÚresult_r9   rr   r;   rv   §  s6   
	
þ

rv   N)ro   r'   r6   rŸ   )Fr[   Ú
__future__r   Útypingr   r   r   r   r   r   r	   r
   r   r   Ú r   r   r   r   Úormr   Úorm._typingr   Úorm.interfacesr   Ú
orm.mapperr   Ú	orm.queryr   Úorm.sessionr   r   r   Úutil.typingr   r   Úengine.baser   r   r   Úengine.resultr   r    r!   r"   Úorm.bulk_persistencer#   Úorm.contextr$   r%   r&   r'   Ú	orm.stater(   Úsqlr)   Úsql._typingr*   Úsql.elementsr+   Ú__all__r.   ÚstrrX   r0   rB   r-   r,   rš   rv   r9   r9   r9   r;   Ú<module>   sj   	  p2