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rd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   Y/var/www/html/api-tag/env/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