ó
¿b›]c           @   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 g Z d e f d „  ƒ  YZ	 d	 e
 f d
 „  ƒ  YZ d e f d „  ƒ  YZ d S(   s  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.

i   (   t   inspect(   t   util(   t   Query(   t   Sessiont   ShardedSessiont   ShardedQueryc           B   sG   e  Z d  „  Z d „  Z d „  Z d „  Z d d d „ Z d d „ Z RS(   c         O   sD   t  t |  ƒ j | | Ž  |  j j |  _ |  j j |  _ d  |  _ d  S(   N(   t   superR   t   __init__t   sessiont
   id_choosert   query_choosert   Nonet	   _shard_id(   t   selft   argst   kwargs(    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR      s    c         C   s   |  j  ƒ  } | | _ | S(   s¹   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.
        (   t   _cloneR   (   R   t   shard_idt   q(    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyt	   set_shard"   s    	c            s‹   ‡  ‡ f d †  } ˆ  j  d  k	 r. | ˆ  j  ƒ Sˆ j d  k	 rJ | ˆ j ƒ Sg  } x* ˆ j ˆ ƒ D] } | j | | ƒ ƒ q` Wt | ƒ Sd  S(   Nc            sT   |  ˆ  j  d <ˆ  _ ˆ j d ˆ j ƒ  d |  ƒ j ˆ  j ˆ j ƒ } ˆ j | ˆ  ƒ S(   NR   t   mapper(   t
   attributest   identity_tokent   _connection_from_sessiont   _bind_mappert   executet	   statementt   _paramst	   instances(   R   t   result(   t   contextR   (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyt   iter_for_shard.   s
    	(   R   R   R   R
   t   extendt   iter(   R   R   R   t   partialR   (    (   R   R   s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyt   _execute_and_instances-   s    c            sŽ   ‡  ‡ ‡ f d †  } ˆ j  d  k	 r1 | ˆ j  ƒ Sd } g  } x= ˆ j ˆ ƒ D], } | | ƒ } | | j 7} | j | ƒ qM Wt | | ƒ Sd  S(   Nc      	      s=   ˆ j  d ˆ  d |  d ˆ d t ƒ } | j ˆ ˆ j ƒ } | S(   NR   R   t   clauset   close_with_result(   R   t   TrueR   R   (   R   t   connR   (   R   R   t   stmt(    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyt   exec_for_shardC   s    		i    (   R   R   R
   t   rowcountt   appendt   ShardedResult(   R   R(   R   R)   R*   t   resultsR   R   (    (   R   R   R(   s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyt   _execute_crudB   s    
c   	      K   s±   | d k	 r. t t |  ƒ j | | d | | S|  j j | ƒ } | rX | j | ƒ } n  xN |  j | | ƒ D]: } t t |  ƒ j | | d | | } | d k	 rk | Sqk Wd Sd S(   s¿   override 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).

        R   N(   R   R   R   t   _identity_lookupR   t   queryt   _set_lazyload_fromR	   (	   R   R   t   primary_key_identityR   t   lazy_loaded_fromt   kwR   R   t   obj(    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR/   Y   s    c            sX   ‡  ‡ f d †  } | d k r9 ˆ j d k	 r9 ˆ j } n  t t ˆ ƒ j | | d | ƒS(   s©   Override 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            s~   ˆ j  d  k	 r ˆ  ˆ | ƒ St j | ƒ } xL ˆ j ˆ | ƒ D]4 } ˆ j | ƒ } ˆ  | | ƒ } | d  k	 r> | Sq> Wd  Sd  S(   N(   R   R   R   t   to_listR	   R   (   R0   R2   t   identR   R   t   o(   t
   db_load_fnR   (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyt   _db_load_fn‚   s    R   N(   R   R   R   R   t	   _get_impl(   R   R2   R9   R   R:   (    (   R9   R   s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR;   {   s
    N(	   t   __name__t
   __module__R   R   R#   R.   R   R/   R;   (    (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR      s   				R,   c           B   s,   e  Z d  Z d Z d „  Z e d „  ƒ Z RS(   sÚ  A value object that represents multiple :class:`.ResultProxy` objects.

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

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

    .. versionadded::  1.3
    t   result_proxiest   aggregate_rowcountc         C   s   | |  _  | |  _ d  S(   N(   R>   R?   (   R   R>   R?   (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR   «   s    	c         C   s   |  j  S(   N(   R?   (   R   (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR*   ¯   s    (   R>   R?   (   R<   R=   t   __doc__t	   __slots__R   t   propertyR*   (    (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR,   œ   s   	c           B   sM   e  Z d e d  „ Z d „  Z d d d d „ Z d d d d „ Z d „  Z RS(   c         K   s„   t  t |  ƒ j d | |  | |  _ | |  _ | |  _ i  |  _ |  j |  _ | d k	 r€ x% | D] } |  j
 | | | ƒ q_ Wn  d S(   s  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.

        t	   query_clsN(   R   R   R   t   shard_chooserR	   R
   t   _ShardedSession__bindst
   connectiont   connection_callableR   t
   bind_shard(   R   RD   R	   R
   t   shardsRC   R   t   k(    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR   µ   s    				c         K   sˆ   | d  k	 rW t | ƒ } | j rD | j d } | d  k	 s@ t ‚ | S| j rW | j Sn  |  j | | |  } | d  k	 r„ | | _ n  | S(   Ni   (   R   R    t   keyt   AssertionErrorR   RD   (   R   R   t   instanceR4   t   statet   tokenR   (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyt   _choose_shard_and_assignÝ   s    		
c         K   sl   | d  k r! |  j | | ƒ } n  |  j d  k	 rF |  j j | d | ƒS|  j | d | d | ƒj |   Sd  S(   NR   RM   (   R   RP   t   transactionRF   t   get_bindt   _contextual_connect(   R   R   RM   R   R   (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyRF   ì   s    c         K   s2   | d  k r' |  j | | d | ƒ} n  |  j | S(   NR$   (   R   RP   RE   (   R   R   R   RM   R$   R4   (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyRR   ÷   s    c         C   s   | |  j  | <d  S(   N(   RE   (   R   R   t   bind(    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyRH      s    N(	   R<   R=   R   R   R   RP   RF   RR   RH   (    (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyR   ´   s   "	N(   R@   t    R    R   t	   orm.queryR   t   orm.sessionR   t   __all__R   t   objectR,   R   (    (    (    s>   lib/python2.7/site-packages/sqlalchemy/ext/horizontal_shard.pyt   <module>   s   