U
    cc"                     @   s   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	gZ
G d
d	 d	eZG dd de	Zdd 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.

   )event)exc)inspect)util)Query)SessionShardedSessionShardedQueryc                       s$   e Zd Z fddZdd Z  ZS )r	   c                    s:   t t| j|| | jj| _| jj| _| jj| _d | _d S N)superr	   __init__session
id_chooserquery_chooserexecute_chooserZ	_shard_id)selfargskwargs	__class__ C/tmp/pip-unpacked-wheel-8u86ls_i/sqlalchemy/ext/horizontal_shard.pyr      s
    


zShardedQuery.__init__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)execution_options)r   shard_idr   r   r   	set_shard$   s    zShardedQuery.set_shard)__name__
__module____qualname__r   r   __classcell__r   r   r   r   r	      s   c                       sV   e Zd Zddef fdd	Zd fdd	Zdd Zddd	Zdd
dZdd Z	  Z
S )r   Nc                    s   | dd tt| jf d|i| tj| dtdd || _|| _ rvt	
dd |rbtd	 fd
d}|| _n|| _ | _i | _|dk	r|D ]}| |||  qd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 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   N	query_clsZdo_orm_executeT)retvalzMThe ``query_choser`` parameter is deprecated; please use ``execute_chooser``.z1.4z>Can't pass query_chooser and execute_chooser at the same time.c                    s
    | j S r
   )Z	statementorm_contextr   r   r   r   n   s    z0ShardedSession.__init__.<locals>.execute_chooser)popr   r   r   r   listenexecute_and_instancesshard_chooserr   r   Zwarn_deprecatedr   ArgumentErrorr   r   _ShardedSession__binds
bind_shard)r   r(   r   r   Zshardsr    r   kr   r$   r   r   7   s6    "   zShardedSession.__init__c           	         s   |dk	r&t t| j||fd|i|S | |}|r>||}| ||D ]4}t t| j||f||d|}|dk	rJ|  S qJdS 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`.

        Nidentity_token)r-   lazy_loaded_from)r   r   _identity_lookupqueryZ_set_lazyload_fromr   )	r   mapperZprimary_key_identityr-   r.   kwqr   objr   r   r   r/   z   s2    




zShardedSession._identity_lookupc                 K   s^   |d k	r<t |}|jr0|jd }|d k	s,t|S |jr<|jS | j||f|}|d k	rZ||_|S )Nr   )r   keyAssertionErrorr-   r(   )r   r1   instancer2   statetokenr   r   r   r   _choose_shard_and_assign   s    
z'ShardedSession._choose_shard_and_assignc                 K   sJ   |dkr|  ||}|  r.|  j||dS | j|||djf |S dS )zaProvide a :class:`_engine.Connection` to use in the unit of work
        flush process.

        N)r   )r   r7   )r:   Zin_transactionZget_transaction
connectionget_bindconnect)r   r1   r7   r   r   r   r   r   connection_callable   s      z"ShardedSession.connection_callablec                 K   s"   |d kr| j |||d}| j| S )N)clause)r:   r*   )r   r1   r   r7   r?   r2   r   r   r   r<      s      zShardedSession.get_bindc                 C   s   || j |< d S r
   )r*   )r   r   bindr   r   r   r+      s    zShardedSession.bind_shard)NN)NNN)NNNN)r   r   r   r	   r   r/   r:   r>   r<   r+   r   r   r   r   r   r   6   s$   G  )     
       
	c           	         s    j r j }}d }n( js" jr2d } j }}nd  } }} j} fdd}|rf|jd k	rf|j}n0d jkr| jd }nd jkr jd }nd }|d k	r||||S g }|	 D ]}||||}|
| q|d j|dd   S d S )Nc                    sf   t  j}t  j}| |d<  jr8|d| i7 }||d< n  jsD jrX|d| i7 }||d<  j||dS )Nr   _refresh_identity_tokenZ_sa_orm_load_optionsZ_sa_orm_update_options)bind_argumentsr   )dictZlocal_execution_optionsrB   	is_select	is_update	is_deleteZinvoke_statement)r   load_optionsupdate_optionsr   rB   r"   r   r   iter_for_shard   s    


 z-execute_and_instances.<locals>.iter_for_shardr   r          )rD   rG   rE   rF   Zupdate_delete_optionsr   rA   r   rB   r   appendmerge)	r#   rG   Zactive_optionsrH   r   rI   r   partialZresult_r   r"   r   r'      s.    


r'   N)__doc__ r   r   r   r   Z	orm.queryr   Zorm.sessionr   __all__r	   r   r'   r   r   r   r   <module>   s   
 