1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
U
¸ý°dcCã@svdZddlmZddlmZddlmZddlmZddlmZddlmZddlm    Z    dd    lm
Z
dd
lm Z dd lm Z dd lm Z d dlmZd dlmZd dlmZd dlmZd dlmZd dlmZd dlmZd dlmZd dlmZd dlmZd dlmZd dlm Z d dl!m"Z"d dl!m#Z#e röd dl$m%Z%d dl$m&Z&d dl$m'Z'd dl(m)Z)d d l(m*Z*d d!lm+Z+d d"lm,Z,d d#l-m.Z.d d$l/m0Z0d d%lm1Z1d d&lm2Z2d d'lm3Z3d d(l4m5Z5d d)l6m7Z7d d*l8m9Z9d d+l:m;Z;d,d-gZ<e d.ed/Z=e>Z?Gd0d1„d1e"ƒZ@Gd2d3„d3e"ƒZAGd4d-„d-ee=ƒZBGd5d,„d,e ƒZCGd6d7„d7eƒZDd8d9d:œ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 eZdZdddddœdd„ZdS)Ú ShardChooserúOptional[Mapper[_T]]rúOptional[ClauseElement])ÚmapperÚinstanceÚclauseÚreturncCsdS©N©)Úselfr3r4r5r8r8úVd:\z\workplace\vscode\pyvenv\venv\Lib\site-packages\sqlalchemy/ext/horizontal_shard.pyÚ__call__QszShardChooser.__call__N©Ú__name__Ú
__module__Ú __qualname__r;r8r8r8r:r0Psr0c@s&eZdZddddddddœdd    „Zd
S) ÚIdentityChooserú
Mapper[_T]rúOptional[InstanceState[Any]]rrr©r3Ú primary_keyÚlazy_loaded_fromÚexecution_optionsÚbind_argumentsÚkwr6cKsdSr7r8)r9r3rDrErFrGrHr8r8r:r;[s
zIdentityChooser.__call__Nr<r8r8r8r:r@Zsr@cs:eZdZdZddddœ‡fdd„ Zddd    œd
d „Z‡ZS) r-aQuery 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.
 
    rÚNone)ÚargsÚkwargsr6cs<tƒj||Žt|jtƒst‚|jj|_|jj|_d|_dSr7)    ÚsuperÚ__init__Ú
isinstanceÚsessionr,ÚAssertionErrorÚidentity_chooserÚexecute_chooserZ    _shard_id)r9rJrK©Ú    __class__r8r:rMqs
 
 
zShardedQuery.__init__ÚShardIdentifierr©Úshard_idr6cCs |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)rF)r9rWr8r8r:Ú    set_shardyszShardedQuery.set_shard)r=r>r?Ú__doc__rMrYÚ __classcell__r8r8rSr:r-hsc sòeZdZUded<ded<ded<dddefdddœdd    d
d d d ddddœ    ‡fdd„Zdejdej    dfddddddddddœ    ‡fdd„ Z
ddddd œd!d"„Z d4d#dd$dd%d&œd'd(„Z d5dddd)œdd$dd*dd+d,œd-d.„Z d/d0dd1œd2d3„Z‡ZS)6r,r0Ú shard_chooserr@rQz*Callable[[ORMExecuteState], Iterable[Any]]rRN)Ú
id_chooserÚ query_chooserzOptional[IdentityChooser]z4Optional[Callable[[ORMExecuteState], Iterable[Any]]]zOptional[Dict[str, Any]]zType[Query[_T]]z<Optional[Callable[[Query[_T], Iterable[_T]], Iterable[Any]]]z/Optional[Callable[[Executable], Iterable[Any]]]rrI)    r\rQrRÚshardsÚ    query_clsr]r^rKr6c  stƒjfd|i|—Žtjˆdtdd|ˆ_|rj|‰t dd¡ddd    d
d d d d œ‡‡fdd„ }    |    ˆ_n|rv|ˆ_n
t     
d¡‚|rÂ|‰t dd¡|r¢t     
d¡‚dddœ‡fdd„ }
|dkrÂ|
}|dkrÔt     
d¡‚|ˆ_ iˆ_ |dk    r|D]} ˆ  | || ¡qîdS)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.
 
        r`Zdo_orm_executeT)ÚretvalzLThe ``id_chooser`` parameter is deprecated; please use ``identity_chooser``.z2.0rArrBrrrrCcs"ˆ |¡}|r| |¡}ˆ||ƒSr7)ÚqueryZ_set_lazyload_from)r3rDrErFrGrHÚq)Ú _id_chooserr9r8r:Ú_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``.z1.4z>Can't pass query_chooser and execute_chooser at the same time.r'z Iterable[Any]©Ú orm_contextr6cs
ˆ|jƒSr7)Z    statement©rg)Ú_query_chooserr8r:Ú_default_execute_chooserîsz9ShardedSession.__init__.<locals>._default_execute_chooserNz,execute_chooser or query_chooser is required)rLrMrÚlistenÚexecute_and_instancesr\rZwarn_deprecatedrQrÚ ArgumentErrorrRÚ_ShardedSession__shardsÚ
bind_shard) r9r\rQrRr_r`r]r^rKrerjÚkrS)rdrir9r:rMsV,ÿý ÿýÿÿ
zShardedSession.__init__z
Mapper[_O]zUnion[Any, Tuple[Any, ...]]z Optional[Any]rrBrzOptional[_BindArguments]z)Union[Optional[_O], LoaderCallableStatus])    r3Úprimary_key_identityÚidentity_tokenÚpassiverErFrGrHr6c  s€|dk    r&tƒj||fd|i|—Ž}    |    S|j|||||r>t|ƒnidD]0}
tƒj||f|
|dœ|—Ž} | dk    rF| SqFdSdS)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`.
 
        Nrr)rErFrG)rrrE)rLÚ_identity_lookuprQÚdict) r9r3rqrrrsrErFrGrHÚobjrWÚobj2rSr8r:rts:þýüû
þüû
zShardedSession._identity_lookupzOptional[_EntityBindKey[_O]])r3r4rHr6cKsl|dk    r<t|ƒ}|jr0|jd}|dk    s,t‚|S|jr<|jSt|tƒsJt‚|j||f|Ž}|dk    rh||_|S)Nr )rÚkeyrPrrrNrr\)r9r3r4rHÚstateÚtokenrWr8r8r:Ú_choose_shard_and_assign1s
 z'ShardedSession._choose_shard_and_assignr1zOptional[ShardIdentifier]r)r3r4rWrHr6cKsz|dkr| ||¡}| ¡r>| ¡}|dk    s0t‚|j||dS|j|||d}t|tƒrd|jf|ŽSt|t    ƒsrt‚|SdS)zaProvide a :class:`_engine.Connection` to use in the unit of work
        flush process.
 
        N)rW)r3rWr4)
r{Zin_transactionZget_transactionrPÚ
connectionÚget_bindrNrÚconnectr)r9r3r4rWrHZtransÚbindr8r8r:Úconnection_callableFs   ÿ
 z"ShardedSession.connection_callable)rWr4r5r2r&)r3rWr4r5rHr6cKs.|dkr$|j|||d}|dk    s$t‚|j|S)N)r4r5)r{rPrn)r9r3rWr4r5rHr8r8r:r}ds    ÿ zShardedSession.get_bindrUzUnion[Engine, OptionEngine])rWrr6cCs||j|<dSr7)rn)r9rWrr8r8r:rotszShardedSession.bind_shard)NNN)N)r=r>r?Ú__annotations__r-rMrZ PASSIVE_OFFrÚ
EMPTY_DICTrtr{r€r}ror[r8r8rSr:r,‹s:
ø ó&tø$1ü þúc@s&eZdZdZdZd    dddœdd„ZdS)
Ú set_shard_idaa 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_loadersTrUÚboolcCs||_||_dS)aHConstruct 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„)r9rWr…r8r8r:rM™szset_shard_id.__init__N)T)r=r>r?rZÚ    __slots__rMr8r8r8r:rƒzsÿrƒr'ú&Union[Result[_T], IteratorResult[_TP]]rfcsˆjrˆj}nˆjsˆjr"ˆj}nd}ˆj}t|tƒs:t‚dddœ‡fdd„ }ˆj    D]}t|t
ƒrT|j }q´qT|r„|j dk    r„|j }n0dˆj kršˆj d}ndˆjkr°ˆjd}nd}|dk    rÄ||ƒSg}| ˆ¡D]}||ƒ}| |¡qÒ|dj|d    d…ŽSdS)
NrUrˆrVcs*tˆjƒ}||d<ˆj|dˆj|dS)NrW)rr)rG)rurGZupdate_execution_optionsZinvoke_statement)rWrGrhr8r:Úiter_for_shardÂs
 z-execute_and_instances.<locals>.iter_for_shardrXrWré)Z    is_selectZ load_optionsZ    is_updateZ    is_deleteZupdate_delete_optionsrOrNr,rPZ_non_compile_orm_optionsrƒrWZ_identity_tokenrFrGrRÚappendÚmerge)rgZactive_optionsrOr‰Zorm_optrWÚpartialZresult_r8rhr:rl¬s4  
 
 
 
 
  rlN)FrZÚ
__future__rÚtypingrrrrrrr    r
r r ÚrrrrZormrZ orm._typingrZorm.interfacesrZ
orm.mapperrZ    orm.queryrZ orm.sessionrrrZ util.typingrrZ engine.baserrrZ engine.resultrr r!r"Zorm.bulk_persistencer#Z orm.contextr$r%r&r'Z    orm.stater(Zsqlr)Z sql._typingr*Z sql.elementsr+Ú__all__r.ÚstrrUr0r@r-r,rƒrlr8r8r8r:Ú<module>sh                                          
#p2