o
    DDiJ                     @  s8  d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	m
Z
 ddlmZmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ ddlmZ ddlmZ d)d*d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!ed"Z"ed#Z#d)d*d$d%Z$d)d+d'd(Z%dS ),z 
SQL composition utility module
    )annotationsN)ABCabstractmethod)Anyoverload)IterableIteratorSequence   )Escaping)AdaptContext)PyFormat)LiteralStringTemplate)conn_encoding)Transformerobjr   contextAdaptContext | Nonereturnstrc                 C  s   t | |S )a  
    Adapt a Python object to a quoted SQL string.

    Use this function only if you absolutely want to convert a Python string to
    an SQL quoted literal to use e.g. to generate batch SQL and you won't have
    a connection available when you will need to use it.

    This function is relatively inefficient, because it doesn't cache the
    adaptation rules. If you pass a `!context` you can adapt the adaptation
    rules used, otherwise only global rules are used.

    )Literal	as_string)r   r    r   D/var/www/Datamplify/venv/lib/python3.10/site-packages/psycopg/sql.pyquote   s   r   c                   @  sh   e Zd ZdZdddZd dd	Zed!d"ddZd!d#ddZd$ddZ	d%ddZ
d&ddZd&ddZd
S )'
ComposableaP  
    Abstract base class for objects that can be used to compose an SQL string.

    `!Composable` objects can be joined using the ``+`` operator: the result
    will be a `Composed` instance containing the objects joined. The operator
    ``*`` is also supported with an integer argument: the result is a
    `!Composed` instance containing the left argument repeated as many times as
    requested.

    `!SQL` and `!Composed` objects can be passed directly to
    `~psycopg.Cursor.execute()`, `~psycopg.Cursor.executemany()`,
    `~psycopg.Cursor.copy()` in place of the query string.
    r   r   c                 C  s
   || _ d S N_objselfr   r   r   r   __init__6      
zComposable.__init__r   r   c                 C  s   | j j d| jdS )N())	__class____name__r   r!   r   r   r   __repr__9   s   zComposable.__repr__Nr   r   bytesc                 C  s   t )a~  
        Return the value of the object as bytes.

        :param context: the context to evaluate the object into.
        :type context: `connection` or `cursor`

        The method is automatically invoked by `~psycopg.Cursor.execute()`,
        `~psycopg.Cursor.executemany()`, `~psycopg.Cursor.copy()` if a
        `!Composable` is passed instead of the query string.

        )NotImplementedErrorr!   r   r   r   r   as_bytes<   s   zComposable.as_bytesc                 C  sD   t |r|jnd}t| | }tr||S t||d S )z
        Return the value of the object as string.

        :param context: the context to evaluate the string into.
        :type context: `connection` or `cursor`

        Nr   )r   
connection
isinstancer-   r*   decodecodecslookup)r!   r   encbr   r   r   r   K   s   
zComposable.as_stringotherComposedc                 C  s:   t |trt| g| S t |trt| gt|g S tS r   )r/   r6   r   NotImplementedr!   r5   r   r   r   __add__Z   s
   

zComposable.__add__nintc                 C  s   t | g| S r   )r6   )r!   r:   r   r   r   __mul__b   s   zComposable.__mul__boolc                 C  s   t | t |u o| j|jkS r   )typer   r8   r   r   r   __eq__e   s   zComposable.__eq__c                 C  s   |  | S r   )r?   r8   r   r   r   __ne__h   s   zComposable.__ne__)r   r   r   r   r   r   r   r   r*   r   r   r   r   r5   r   r   r6   )r:   r;   r   r6   )r5   r   r   r=   )r'   
__module____qualname____doc__r"   r)   r   r-   r   r9   r<   r?   r@   r   r   r   r   r   '   s    




r   c                      sV   e Zd ZU dZded< d fddZddddZdddZdddZdddZ	  Z
S ) r6   a.  
    A `Composable` object made of a sequence of `!Composable`.

    The object is usually created using `!Composable` operators and methods
    (such as the `SQL.format()` method). `!Composed` objects can be passed
    directly to `~psycopg.Cursor.execute()`, `~psycopg.Cursor.executemany()`,
    `~psycopg.Cursor.copy()` in place of the query string.

    It is also possible to create a `!Composed` directly specifying a sequence
    of objects as arguments: if they are not `!Composable` they will be wrapped
    in a `Literal`.

    Example::

        >>> comp = sql.Composed(
        ...     [sql.SQL("INSERT INTO "), sql.Identifier("table")])
        >>> print(comp.as_string(conn))
        INSERT INTO "table"

    `!Composed` objects are iterable (so they can be used in `SQL.join` for
    instance).
    zlist[Composable]r   seqSequence[Any]c                   s   dd |D }t  | d S )Nc                 S  s"   g | ]}t |tr|nt|qS r   )r/   r   r   .0r   r   r   r   
<listcomp>   s   " z%Composed.__init__.<locals>.<listcomp>)superr"   r!   rH   r&   r   r   r"      s   zComposed.__init__Nr   r   r   r*   c                   s   d  fdd| jD S )N    c                 3  s    | ]}|  V  qd S r   r-   rJ   r   r   r   	<genexpr>   s    z$Composed.as_bytes.<locals>.<genexpr>)joinr   r,   r   rR   r   r-      s   zComposed.as_bytesIterator[Composable]c                 C  s
   t | jS r   )iterr   r(   r   r   r   __iter__   r#   zComposed.__iter__r5   r   c                 C  s8   t |trt| j|j S t |trt| j|g S tS r   )r/   r6   r   r   r7   r8   r   r   r   r9      s
   

zComposed.__add__joinerSQL | LiteralStringc                 C  s:   t |tr
t|}nt |tstd|d|| jS )a~  
        Return a new `!Composed` interposing the `!joiner` with the `!Composed` items.

        The `!joiner` must be a `SQL` or a string which will be interpreted as
        an `SQL`.

        Example::

            >>> fields = sql.Identifier('foo') + sql.Identifier('bar')  # a Composed
            >>> print(fields.join(', ').as_string(conn))
            "foo", "bar"

        z5Composed.join() argument must be strings or SQL, got  instead)r/   r   SQL	TypeErrorrT   r   )r!   rX   r   r   r   rT      s   


zComposed.join)rH   rI   r   rB   )r   rU   rD   )rX   rY   r   r6   )r'   rE   rF   rG   __annotations__r"   r-   rW   r9   rT   __classcell__r   r   rO   r   r6   l   s   
 

r6   c                      s|   e Zd ZU dZded< e Zd  fddZd!d"ddZ	d!d#ddZ
d$ddZed%ddZed&ddZd'ddZ  ZS )(r[   a  
    A `Composable` representing a snippet of SQL statement.

    `!SQL` exposes `join()` and `format()` methods useful to create a template
    where to merge variable parts of a query (for instance field or table
    names).

    The `!obj` string doesn't undergo any form of escaping, so it is not
    suitable to represent variable identifiers or values: you should only use
    it to pass constant strings representing templates or snippets of SQL
    statements; use other objects such as `Identifier` or `Literal` to
    represent variable parts.

    `!SQL` objects can be passed directly to `~psycopg.Cursor.execute()`,
    `~psycopg.Cursor.executemany()`, `~psycopg.Cursor.copy()` in place of the
    query string.

    Example::

        >>> query = sql.SQL("SELECT {0} FROM {1}").format(
        ...    sql.SQL(', ').join([sql.Identifier('foo'), sql.Identifier('bar')]),
        ...    sql.Identifier('table'))
        >>> print(query.as_string(conn))
        SELECT "foo", "bar" FROM "table"
    r   r   r   c                   s*   t  | t|tstd|dd S )Nz SQL values must be strings, got rZ   )rM   r"   r/   r   r\   r    rO   r   r   r"      s   
zSQL.__init__Nr   r   r   r   c                 C  s   | j S r   r   r,   r   r   r   r      s   zSQL.as_stringr*   c                 C  s"   |r|j nd }t|}| j|S r   )r.   r   r   encoder!   r   connr3   r   r   r   r-      s   zSQL.as_bytesargsr   kwargsr6   c           	      O  s   g }d}| j | jD ]S\}}}}|rtd|rtd|r&|t| |du r+q| rA|r5td||t|  d}q|sW|du rKtd|||  |d7 }q|||  qt|S )a  
        Merge `Composable` objects into a template.

        :param args: parameters to replace to numbered (``{0}``, ``{1}``) or
            auto-numbered (``{}``) placeholders
        :param kwargs: parameters to replace to named (``{name}``) placeholders
        :return: the union of the `!SQL` string with placeholders replaced
        :rtype: `Composed`

        The method is similar to the Python `str.format()` method: the string
        template supports auto-numbered (``{}``), numbered (``{0}``,
        ``{1}``...), and named placeholders (``{name}``), with positional
        arguments replacing the numbered placeholders and keywords replacing
        the named ones. However placeholder modifiers (``{0!r}``, ``{0:<10}``)
        are not supported.

        If a `!Composable` objects is passed to the template it will be merged
        according to its `as_string()` method. If any other Python object is
        passed, it will be wrapped in a `Literal` object and so escaped
        according to SQL rules.

        Example::

            >>> print(sql.SQL("SELECT * FROM {} WHERE {} = %s")
            ...     .format(sql.Identifier('people'), sql.Identifier('id'))
            ...     .as_string(conn))
            SELECT * FROM "people" WHERE "id" = %s

            >>> print(sql.SQL("SELECT * FROM {tbl} WHERE name = {name}")
            ...     .format(tbl=sql.Identifier('people'), name="O'Rourke"))
            ...     .as_string(conn))
            SELECT * FROM "people" WHERE name = 'O''Rourke'

        r   z(no format specification supported by SQLz%no format conversion supported by SQLNz6cannot switch from automatic field numbering to manualz6cannot switch from manual field numbering to automaticr
   )	
_formatterparser   
ValueErrorappendr[   isdigitr;   r6   )	r!   rb   rc   rvautonumprenamespecconvr   r   r   format   s6   #
z
SQL.formatrH   Iterable[Template]r   c                 C     d S r   r   rN   r   r   r   rT   $     zSQL.joinIterable[Any]c                 C  rq   r   r   rN   r   r   r   rT   '  rr   Composed | Templatec                 C  s   t |}zt|}W n ty   tg  Y S w t|trDt|}|D ]}t|ts4tdt|j	 |
| j || q#t| S |g}|D ]}t|trZtdt|j	 |
|  |
| qIt|S )a  
        Join a sequence of `Composable`.

        :param seq: the elements to join.

        Use the `!SQL` object's string to separate the elements in `!seq`.
        Elements that are not `Composable` will be considered `Literal`.

        If the arguments are `Template` instance, return a `Template` joining
        all the items. Note that arguments must either be all templates or
        none should be.

        Note that `Composed` objects are iterable too, so they can be used as
        argument for this method.

        Example::

            >>> snip = sql.SQL(', ').join(
            ...     sql.Identifier(n) for n in ['foo', 'bar', 'baz'])
            >>> print(snip.as_string(conn))
            "foo", "bar", "baz"
        zcan't mix Template and )rV   nextStopIterationr6   r/   r   listr\   r>   r'   rg   r   extend)r!   rH   itfirstitemstcsir   r   r   rT   *  s*   



)r   r   r   rC   rB   )rb   r   rc   r   r   r6   )rH   rp   r   r   )rH   rs   r   r6   )rH   rs   r   rt   )r'   rE   rF   rG   r]   string	Formatterrd   r"   r   r-   ro   r   rT   r^   r   r   rO   r   r[      s   
 
Hr[   c                      sL   e Zd ZU dZded< d fddZdd	d
ZddddZdddZ  Z	S )
Identifiera#  
    A `Composable` representing an SQL identifier or a dot-separated sequence.

    Identifiers usually represent names of database objects, such as tables or
    fields. PostgreSQL identifiers follow `different rules`__ than SQL string
    literals for escaping (e.g. they use double quotes instead of single).

    .. __: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#         SQL-SYNTAX-IDENTIFIERS

    Example::

        >>> t1 = sql.Identifier("foo")
        >>> t2 = sql.Identifier("ba'r")
        >>> t3 = sql.Identifier('ba"z')
        >>> print(sql.SQL(', ').join([t1, t2, t3]).as_string(conn))
        "foo", "ba'r", "ba""z"

    Multiple strings can be passed to the object to represent a qualified name,
    i.e. a dot-separated sequence of identifiers.

    Example::

        >>> query = sql.SQL("SELECT {} FROM {}").format(
        ...     sql.Identifier("table", "field"),
        ...     sql.Identifier("schema", "table"))
        >>> print(query.as_string(conn))
        SELECT "table"."field" FROM "schema"."table"

    zSequence[str]r   stringsr   c                   s@   t  | |std|D ]}t|tstd|dqd S )NzIdentifier cannot be emptyz*SQL identifier parts must be strings, got rZ   )rM   r"   r\   r/   r   )r!   r   srO   r   r   r"   }  s   

zIdentifier.__init__r   c                 C  s"   | j j ddtt| j dS )Nr$   , r%   )r&   r'   rT   mapreprr   r(   r   r   r   r)     s   "zIdentifier.__repr__Nr   r   r*   c                   sZ   |r|j nd  }rt|jt|  fddjD }n
fddjD }d|S )Nc                   s   g | ]
} | qS r   )escape_identifierr_   rK   r   )r3   escr   r   rL     s    z'Identifier.as_bytes.<locals>.<listcomp>c                   s   g | ]	}  | qS r   )_escape_identifierr_   r   r(   r   r   rL     s       .)r.   r   pgconnr   r   rT   )r!   r   ra   escsr   )r3   r   r!   r   r-     s   

zIdentifier.as_bytesr   c                 C  s   d| dd d S )zK
        Approximation of PQescapeIdentifier taking no connection.
           "s   "")replace)r!   r   r   r   r   r     s   zIdentifier._escape_identifier)r   r   rA   r   rB   )r   r*   r   r*   )
r'   rE   rF   rG   r]   r"   r)   r-   r   r^   r   r   rO   r   r   [  s   
 
	r   c                   @  s   e Zd ZdZd	d
ddZdS )r   a  
    A `Composable` representing an SQL value to include in a query.

    Usually you will want to include placeholders in the query and pass values
    as `~cursor.execute()` arguments. If however you really really need to
    include a literal value in the query you can use this object.

    The string returned by `!as_string()` follows the normal :ref:`adaptation
    rules <types-adaptation>` for Python objects.

    Example::

        >>> s1 = sql.Literal("fo'o")
        >>> s2 = sql.Literal(42)
        >>> s3 = sql.Literal(date(2000, 1, 1))
        >>> print(sql.SQL(', ').join([s1, s2, s3]).as_string(conn))
        'fo''o', 42, '2000-01-01'::date

    Nr   r   r   r*   c                 C  s   t |}|| jS r   )r   from_context
as_literalr   )r!   r   txr   r   r   r-     s   
zLiteral.as_bytesr   rB   )r'   rE   rF   rG   r-   r   r   r   r   r     s    r   c                      sL   e Zd ZdZdejfd fddZdd
dZddddZddddZ	  Z
S )Placeholdera	  A `Composable` representing a placeholder for query parameters.

    If the name is specified, generate a named placeholder (e.g. ``%(name)s``,
    ``%(name)b``), otherwise generate a positional placeholder (e.g. ``%s``,
    ``%b``).

    The object is useful to generate SQL queries with a variable number of
    arguments.

    Examples::

        >>> names = ['foo', 'bar', 'baz']

        >>> q1 = sql.SQL("INSERT INTO my_table ({}) VALUES ({})").format(
        ...     sql.SQL(', ').join(map(sql.Identifier, names)),
        ...     sql.SQL(', ').join(sql.Placeholder() * len(names)))
        >>> print(q1.as_string(conn))
        INSERT INTO my_table ("foo", "bar", "baz") VALUES (%s, %s, %s)

        >>> q2 = sql.SQL("INSERT INTO my_table ({}) VALUES ({})").format(
        ...     sql.SQL(', ').join(map(sql.Identifier, names)),
        ...     sql.SQL(', ').join(map(sql.Placeholder, names)))
        >>> print(q2.as_string(conn))
        INSERT INTO my_table ("foo", "bar", "baz") VALUES (%(foo)s, %(bar)s, %(baz)s)

     rl   r   ro   str | PyFormatc                   sv   t  | t|tstd|d|v rtd|t|tu r't|}t|ts6tdt|j|| _	d S )Nzexpected string as name, got r%   zinvalid name: z!expected PyFormat as format, got )
rM   r"   r/   r   r\   rf   r>   r   r'   _format)r!   rl   ro   rO   r   r   r"     s   


zPlaceholder.__init__r   c                 C  sT   g }| j r|t| j  | jtjur|d| jj  | jj dd	| dS )Nzformat=r$   r   r%   )
r   rg   r   r   r   AUTOrl   r&   r'   rT   )r!   partsr   r   r   r)     s   zPlaceholder.__repr__Nr   r   c                 C  s*   | j j}| jrd| j d| S d| S )Nz%(r%   %)r   valuer   )r!   r   coder   r   r   r     s   "zPlaceholder.as_stringr*   c                 C  s&   |r|j nd }t|}| ||S r   )r.   r   r   r_   r`   r   r   r   r-     s   zPlaceholder.as_bytes)rl   r   ro   r   rA   r   rC   rB   )r'   rE   rF   rG   r   r   r"   r)   r   r-   r^   r   r   rO   r   r     s    
	r   NULLDEFAULTc                 C  F   t | tr| j|dS t | trddlm} || |S t| j|dS )a  Convert an object to a string according to SQL rules.

    :param obj: the object to convert
    :param context: the context in which to convert the object
    :type context: `~psycopg.abc.AdaptContext` | `!None`

    Adaptation happens according to the type of `!obj`:

    - `Composable` objects are converted according to their
      `~Composable.as_string()` method;
    - `~string.templatelib.Template` strings are converted according to the
      rules documented in :ref:`template-strings`;
    - every other object is converted as it was :ref:`a parameter passed to a
      query <types-adaptation>`.

    If `!context` is specified then it is be used to customize the conversion.
    for example using the encoding of a connection or the dumpers registered.
    rR   r
   )r   )r/   r   r   r   	_tstringsr   )r   r   r   r   r   r   r     s   


r   r*   c                 C  r   )a  Convert an object to a bytes string according to SQL rules.

    :param obj: the object to convert
    :param context: the context in which to convert the object
    :type context: `~psycopg.abc.AdaptContext` | `!None`

    See `as_string()` for details.
    rR   r
   rQ   )r/   r   r-   r   r   r   )r   r   r-   r   r   r   r-     s   
	

r-   r   )r   r   r   r   r   r   )r   r   r   r   r   r*   )&rG   
__future__r   r1   r   abcr   r   typingr   r   collections.abcr   r   r	   pqr   r   _enumsr   _compatr   r   
_encodingsr   _transformerr   r   r   r6   r[   r   r   r   r   r   r   r-   r   r   r   r   <module>   s2    EE +BA