3
(h)E                 @   s  d Z ddlZddlmZmZ ddlmZmZmZ ddlm	Z	m
Z
mZ ddlmZ G dd deZd0d
dZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZeee eeeddddZej  eeeddd dZej  eeed!d"d#dZej  ed$ed%d&d'dZej  ed(ed)d*d+dZej  ed,ed-d.d/dZej  dS )1z1Implementation of the Range type and adaptation

    N)ProgrammingErrorInterfaceError)	ISQLQuoteadaptregister_adapter)new_typenew_array_typeregister_type)string_typesc               @   s   e Zd ZdZd4Zd5dd	Zd
d Zdd Zedd Z	edd Z
edd Zedd Zedd Zedd Zedd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2d3 ZdS )6Rangea  Python representation for a PostgreSQL |range|_ type.

    :param lower: lower bound for the range. `!None` means unbound
    :param upper: upper bound for the range. `!None` means unbound
    :param bounds: one of the literal strings ``()``, ``[)``, ``(]``, ``[]``,
        representing whether the lower or upper bounds are included
    :param empty: if `!True`, the range is empty

    _lower_upper_boundsN[)Fc             C   sB   |s,|dkrt d| || _|| _|| _nd  | _ | _| _d S )N[)(]()[]zbound flags not valid: %r)r   r   r   r   )
ValueErrorr   r   r   )selflowerupperboundsempty r   </tmp/pip-install-q3hcpn_q/psycopg2-binary/psycopg2/_range.py__init__0   s    zRange.__init__c             C   s4   | j d krd| jj S d| jj| j| j| j f S d S )Nz%s(empty=True)z%s(%r, %r, %r))r   	__class____name__r   r   )r   r   r   r   __repr__;   s    
zRange.__repr__c             C   s>   | j d krdS | j d t| jdt| j| j d g}dj|S )Nr   r   z,     )r   strr   r   join)r   itemsr   r   r   __str__B   s    
zRange.__str__c             C   s   | j S )z:The lower bound of the range. `!None` if empty or unbound.)r   )r   r   r   r   r   O   s    zRange.lowerc             C   s   | j S )z:The upper bound of the range. `!None` if empty or unbound.)r   )r   r   r   r   r   T   s    zRange.upperc             C   s
   | j dkS )z`!True` if the range is empty.N)r   )r   r   r   r   isemptyY   s    zRange.isemptyc             C   s   | j dkrdS | jdkS )z0`!True` if the range doesn't have a lower bound.NF)r   r   )r   r   r   r   	lower_inf^   s    
zRange.lower_infc             C   s   | j dkrdS | jdkS )z1`!True` if the range doesn't have an upper bound.NF)r   r   )r   r   r   r   	upper_infe   s    
zRange.upper_infc             C   s&   | j dks| jdkrdS | j d dkS )z4`!True` if the lower bound is included in the range.NFr   [)r   r   )r   r   r   r   	lower_incl   s    zRange.lower_incc             C   s&   | j dks| jdkrdS | j d dkS )z4`!True` if the upper bound is included in the range.NFr    ])r   r   )r   r   r   r   	upper_incs   s    zRange.upper_incc             C   s~   | j d krdS | jd k	rD| j d dkr6|| jk rDdS n|| jkrDdS | jd k	rz| j d dkrl|| jkrzdS n|| jkrzdS dS )NFr   r)   r    r+   T)r   r   r   )r   xr   r   r   __contains__z   s    






zRange.__contains__c             C   s
   | j d k	S )N)r   )r   r   r   r   __bool__   s    zRange.__bool__c             C   s   t | j| S )N)typer/   )r   r   r   r   __nonzero__   s    zRange.__nonzero__c             C   s2   t |tsdS | j|jko0| j|jko0| j|jkS )NF)
isinstancer   r   r   r   )r   otherr   r   r   __eq__   s
    
zRange.__eq__c             C   s   | j | S )N)r4   )r   r3   r   r   r   __ne__   s    zRange.__ne__c             C   s   t | j| j| jfS )N)hashr   r   r   )r   r   r   r   __hash__   s    zRange.__hash__c             C   s^   t |tstS xJdD ]B}t| |}t||}||kr6q|d krBdS |d krNdS ||k S qW dS )Nr   r   r   TF)r   r   r   )r2   r   NotImplementedgetattr)r   r3   attrZ
self_valueZother_valuer   r   r   __lt__   s    



zRange.__lt__c             C   s   | |krdS | j |S d S )NT)r;   )r   r3   r   r   r   __le__   s    zRange.__le__c             C   s   t |tr|j| S tS d S )N)r2   r   r;   r8   )r   r3   r   r   r   __gt__   s    

zRange.__gt__c             C   s   | |krdS | j |S d S )NT)r=   )r   r3   r   r   r   __ge__   s    zRange.__ge__c                s    fdd j D S )Nc                s"   i | ]}t  |rt ||qS r   )hasattrr9   ).0slot)r   r   r   
<dictcomp>   s   z&Range.__getstate__.<locals>.<dictcomp>)	__slots__)r   r   )r   r   __getstate__   s    
zRange.__getstate__c             C   s&   x |j  D ]\}}t| || q
W d S )N)r$   setattr)r   staterA   valuer   r   r   __setstate__   s    zRange.__setstate__)r   r   r   )NNr   F)r   
__module____qualname____doc__rC   r   r   r%   propertyr   r   r&   r'   r(   r*   r,   r.   r/   r1   r4   r5   r7   r;   r<   r=   r>   rD   rH   r   r   r   r   r   $   s0   	
r   Fc             C   s&   t j| ||}|j| r|pd |S )a  Create and register an adapter and the typecasters to convert between
    a PostgreSQL |range|_ type and a PostgreSQL `Range` subclass.

    :param pgrange: the name of the PostgreSQL |range| type. Can be
        schema-qualified
    :param pyrange: a `Range` strict subclass, or just a name to give to a new
        class
    :param conn_or_curs: a connection or cursor used to find the oid of the
        range and its subtype; the typecaster is registered in a scope limited
        to this object, unless *globally* is set to `!True`
    :param globally: if `!False` (default) register the typecaster only on
        *conn_or_curs*, otherwise register it globally
    :return: `RangeCaster` instance responsible for the conversion

    If a string is passed to *pyrange*, a new `Range` subclass is created
    with such name and will be available as the `~RangeCaster.range` attribute
    of the returned `RangeCaster` object.

    The function queries the database on *conn_or_curs* to inspect the
    *pgrange* type and raises `~psycopg2.ProgrammingError` if the type is not
    found.  If querying the database is not advisable, use directly the
    `RangeCaster` class and register the adapter and typecasters using the
    provided functions.

    N)RangeCaster_from_db	_register)pgrangepyrangeconn_or_cursZgloballyZcasterr   r   r   register_range   s    rS   c               @   s4   e Zd ZdZdZdd Zdd Zdd Zd	d
 ZdS )RangeAdapterz`ISQLQuote` adapter for `Range` subclasses.

    This is an abstract class: concrete classes must set a `name` class
    attribute or override `getquoted()`.
    Nc             C   s
   || _ d S )N)adapted)r   rU   r   r   r   r      s    zRangeAdapter.__init__c             C   s   | j tkr| S d S )N)Z_protor   )r   protor   r   r   __conform__   s    
zRangeAdapter.__conform__c             C   s
   || _ d S )N)_conn)r   connr   r   r   prepare  s    zRangeAdapter.preparec             C   s   | j d krtd| j}|jr.d| j jd S |jd k	rbt|j}t|drX|j| j	 |j
 }nd}|jd k	rt|j}t|dr|j| j	 |j
 }nd}| j jdd | d | d |jjd d	 S )
NzMRangeAdapter must be subclassed overriding its name or the getquoted() methods	   'empty'::utf8rZ   s   NULL   (s   , s   , 's   '))nameNotImplementedErrorrU   r&   encoder   r   r?   rZ   rX   	getquotedr   r   )r   rar   r   r   r   r   r`     s&    








zRangeAdapter.getquoted)	r   rI   rJ   rK   r]   r   rW   rZ   r`   r   r   r   r   rT      s   rT   c               @   sZ   e Zd ZdZdddZdd Zedd Zej	d	ej
Zej	d
ZdddZdddZdS )rM   a	  Helper class to convert between `Range` and PostgreSQL range types.

    Objects of this class are usually created by `register_range()`. Manual
    creation could be useful if querying the database is not advisable: in
    this case the oids must be provided.
    Nc             C   s`   || _ | j|| | jjp"| jjj}t|f|| j| _|d k	rVt	|f|d | j| _
nd | _
d S )NARRAY)subtype_oid_create_rangesadapterr]   r   r   r   parse
typecasterr   array_typecaster)r   rP   rQ   oidrd   	array_oidr]   r   r   r   r   )  s    zRangeCaster.__init__c             C   s   d| _ t|tr*t|tfi | _ || j _n2yt|trD|tk	rD|| _ W n tk
rZ   Y nX | j dkrntdd| _y6t|trt|t	fi | _t|t	r|t	k	r|| _W n tk
r   Y nX | jdkrtddS )z0Create Range and RangeAdapter classes if needed.Nz:pgrange must be a string or a RangeAdapter strict subclassz1pyrange must be a type or a Range strict subclass)
rf   r2   r
   r0   rT   r]   
issubclass	TypeErrorranger   )r   rP   rQ   r   r   r   re   7  s0    







zRangeCaster._create_rangesc             C   s   ddl m} ddlm} ||\}}|jjdk r@td|jj |j}d|kr`|jdd\}	}
n|}
d}	y|j	d	|
|	f W n$ tk
r   |j
s|j   Y n"X |j }||kr|j
 r|j  |std
| |\}}}t|||||dS )z|Return a `RangeCaster` instance for the type *pgrange*.

        Raise `ProgrammingError` if the type is not found.
        r   )STATUS_IN_TRANSACTION)_solve_conn_cursiX` z'range types not available in version %s.r    publiczselect rngtypid, rngsubtype,
    (select typarray from pg_type where oid = rngtypid)
from pg_range r
join pg_type t on t.oid = rngtypid
join pg_namespace ns on ns.oid = typnamespace
where typname = %s and ns.nspname = %s;
zPostgreSQL type '%s' not found)rj   rd   rk   )psycopg2.extensionsro   Zpsycopg2.extrasrp   infoZserver_versionr   statussplitexecuteZ
autocommitrollbackZfetchonerM   )r   r]   rQ   rR   ro   rp   rY   ZcursZconn_statusZschematnameZrecr0   subtypearrayr   r   r   rN   Z  s8    

zRangeCaster._from_dba]  
        ( \(|\[ )                   # lower bound flag
        (?:                         # lower bound:
          " ( (?: [^"] | "")* ) "   #   - a quoted string
          | ( [^",]+ )              #   - or an unquoted string
        )?                          #   - or empty (not catched)
        ,
        (?:                         # upper bound:
          " ( (?: [^"] | "")* ) "   #   - a quoted string
          | ( [^"\)\]]+ )           #   - or an unquoted string
        )?                          #   - or empty (not catched)
        ( \)|\] )                   # upper bound flag
        z	(["\\])\1c             C   s   |d krd S |dkr | j ddS | jj|}|d kr@td| |jd}|d krr|jd}|d k	rr| jjd|}|jd}|d kr|jd	}|d k	r| jjd|}|d k	r|j| j|}|j| j|}|jd
|jd }| j |||S )Nr   T)r   zfailed to parse range: '%s'      z\1      r       )	rn   	_re_rangematchr   group_re_undoublesubcastrd   )r   scurmr   r   r   r   r   r   rg     s,    



zRangeCaster.parsec             C   s4   t | j| | jd k	r"t | j| t| j| j d S )N)r	   rh   ri   r   rn   rf   )r   scoper   r   r   rO     s    
zRangeCaster._register)N)N)N)r   rI   rJ   rK   r   re   classmethodrN   recompileVERBOSEr   r   rg   rO   r   r   r   r   rM   "  s   
#8


rM   c               @   s   e Zd ZdZdS )NumericRangezA `Range` suitable to pass Python numeric types to a PostgreSQL range.

    PostgreSQL types :sql:`int4range`, :sql:`int8range`, :sql:`numrange` are
    casted into `!NumericRange` instances.
    N)r   rI   rJ   rK   r   r   r   r   r     s   r   c               @   s   e Zd ZdZdS )	DateRangez#Represents :sql:`daterange` values.N)r   rI   rJ   rK   r   r   r   r   r     s   r   c               @   s   e Zd ZdZdS )DateTimeRangez!Represents :sql:`tsrange` values.N)r   rI   rJ   rK   r   r   r   r   r     s   r   c               @   s   e Zd ZdZdS )DateTimeTZRangez#Represents :sql:`tstzrange` values.N)r   rI   rJ   rK   r   r   r   r   r     s   r   c               @   s   e Zd ZdZdd ZdS )NumberRangeAdapterz1Adapt a range if the subtype doesn't need quotes.c             C   sr   | j }|jrdS |js,t|jj jd}nd}|jsLt|jj jd}nd}d|j	d |||j	d f j
dS )Ns   'empty'asciir!   z'%s%s,%s%s'r   r    )rU   r&   r'   r   r   r`   decoder(   r   r   r_   )r   ra   r   r   r   r   r   r`     s    zNumberRangeAdapter.getquotedN)r   rI   rJ   rK   r`   r   r   r   r   r     s   r   i@     iA  )rj   rd   rk   iV     iW  iB  i  iC  Z	daterangeiH  i:  iI  ZtsrangeiD  iZ  iE  Z	tstzrangeiF  i  iG  )F)rK   r   Zpsycopg2._psycopgr   r   rs   r   r   r   r   r   r	   Zpsycopg2.compatr
   objectr   rS   rT   rM   r   r   r   r   r   Zint4range_casterrO   Zint8range_casterZnumrange_casterZdaterange_casterZtsrange_casterZtstzrange_casterr   r   r   r   <module>   sF    0
0 (	

