o
    [h#                     @   sp   d Z ddlmZ ddlmZ ddlmZ ddlmZ ddgZG dd deZ	G d	d
 d
e
ZG dd deZd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.

   )inspect)util)Query)SessionShardedSessionShardedQueryc                       sT   e Zd Z fddZdd Zdd Zdd Z				d fd
d	Zd fdd	Z  Z	S )r   c                    s4   t t| j|i | | jj| _| jj| _d | _d S N)superr   __init__session
id_chooserquery_chooser	_shard_id)selfargskwargs	__class__ /home/ubuntu/experiments/live_experiments/Pythonexperiments/Otree/venv/lib/python3.10/site-packages/sqlalchemy/ext/horizontal_shard.pyr
      s   


zShardedQuery.__init__c                 C   s   |   }||_|S )zReturn 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.

        )Z_cloner   )r   shard_idqr   r   r   	set_shard!   s   zShardedQuery.set_shardc                    s`    fdd} j d ur| j S jd ur|jS g }D ]	}||| q"t|S )Nc                    s:   |   j d<  _j | d jj}| S )Nr   )mapperr   )
attributesidentity_token_connection_from_sessionZ_bind_mapperexecuteZ	statement_paramsZ	instances)r   resultcontextr   r   r   iter_for_shard.   s   z;ShardedQuery._execute_and_instances.<locals>.iter_for_shard)r   r   r   extenditer)r   r!   r"   partialr   r   r    r   _execute_and_instances-   s   



z#ShardedQuery._execute_and_instancesc                    sb    fdd}j d ur|j S d}g }D ]}||}||j7 }|| qt||S )Nc                    s$   j  | dd}|j}|S )NT)r   r   clauseZclose_with_result)r   r   r   )r   connr   r   r   stmtr   r   exec_for_shardC   s   z2ShardedQuery._execute_crud.<locals>.exec_for_shard    )r   r   rowcountappendShardedResult)r   r*   r   r+   r-   resultsr   r   r   r)   r   _execute_crudB   s   




zShardedQuery._execute_crudNc           	         s   |durt t| j||fd|i|S | j|}|r ||}| ||D ]}t t| j||fd|i|}|dur?|  S q&dS )zOverride the default Query._identity_lookup method so that we
        search for a given non-token primary key identity across all
        possible identity tokens (e.g. shard ids).

        Nr   )r	   r   _identity_lookupr   queryZ_set_lazyload_fromr   )	r   r   primary_key_identityr   Zlazy_loaded_fromkwr   r   objr   r   r   r2   Y   s0   


zShardedQuery._identity_lookupc                    s<    fdd}|du rj durj }ttj|||dS )zOverride the default Query._get_impl() method so that we emit
        a query to the DB for each possible identity token, if we don't
        have one already.

        c                    sX   j d ur
 |S t|}|D ]}|} ||}|d ur)|  S qd S r   )r   r   Zto_listr   r   )r3   r4   identr   r   o
db_load_fnr   r   r   _db_load_fn   s   




z+ShardedQuery._get_impl.<locals>._db_load_fnN)r   )r   r	   r   	_get_impl)r   r4   r:   r   r;   r   r9   r   r<   {   s   
zShardedQuery._get_impl)NNr   )
__name__
__module____qualname__r
   r   r&   r1   r2   r<   __classcell__r   r   r   r   r      s    "c                   @   s(   e Zd ZdZdZdd Zedd ZdS )r/   a  A value object that represents multiple :class:`_engine.ResultProxy`
    objects.

    This is used by the :meth:`.ShardedQuery._execute_crud` hook to return
    an object that takes the place of the single :class:`_engine.ResultProxy`.

    Attribute include ``result_proxies``, which is a sequence of the
    actual :class:`_engine.ResultProxy` objects,
    as well as ``aggregate_rowcount``
    or ``rowcount``, which is the sum of all the individual rowcount values.

    .. versionadded::  1.3

    result_proxiesaggregate_rowcountc                 C   s   || _ || _d S r   rA   )r   rB   rC   r   r   r   r
      s   
zShardedResult.__init__c                 C   s   | j S r   )rC   )r   r   r   r   r-      s   zShardedResult.rowcountN)r=   r>   r?   __doc__	__slots__r
   propertyr-   r   r   r   r   r/      s    r/   c                       sH   e Zd Zdef fdd	Zdd ZdddZ	ddd	Zd
d Z  Z	S )r   Nc                    sd   t t| jdd|i| || _|| _|| _i | _| j| _|dur.|D ]}| 	|||  q#d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 id_chooser: A callable, passed a query and a tuple of identity
          values, which should return a list of shard ids where the ID might
          reside.  The databases will be queried in the order of this listing.

        :param query_chooser: For a given Query, 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.

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

        	query_clsNr   )
r	   r   r
   shard_chooserr   r   _ShardedSession__binds
connectionZconnection_callable
bind_shard)r   rH   r   r   ZshardsrG   r   kr   r   r   r
      s   zShardedSession.__init__c                 K   sb   |d urt |}|jr|jd }|d usJ |S |jr|jS | j||fi |}|d ur/||_|S )Nr   )r   keyr   rH   )r   r   instancer5   statetokenr   r   r   r   _choose_shard_and_assign   s   
z'ShardedSession._choose_shard_and_assignc                 K   sJ   |d u r
|  ||}| jd ur| jj||dS | j|||djdi |S )N)r   )r   rN   r   )rQ   ZtransactionrJ   get_bindZ_contextual_connect)r   r   rN   r   r   r   r   r   rJ      s   
zShardedSession.connectionc                 K   s"   |d u r| j |||d}| j| S )N)r'   )rQ   rI   )r   r   r   rN   r'   r5   r   r   r   rR      s
   
zShardedSession.get_bindc                 C   s   || j |< d S r   )rI   )r   r   bindr   r   r   rK     s   zShardedSession.bind_shard)NNN)
r=   r>   r?   r   r
   rQ   rJ   rR   rK   r@   r   r   r   r   r      s    (

	N)rD    r   r   Z	orm.queryr   Zorm.sessionr   __all__r   objectr/   r   r   r   r   r   <module>   s   
 