
    2iJ                    f   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Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z  G d de      Z! ed      Z" ed      Z#dd dZ$dd!dZ%y)"z 
SQL composition utility module
    )annotationsN)ABCabstractmethod)Anyoverload)IterableIteratorSequence   )Escaping)AdaptContext)PyFormat)LiteralStringTemplate)conn_encoding)Transformerc                6    t        |       j                  |      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)objcontexts     J/var/www/html/secretsanta/venv/lib/python3.12/site-packages/psycopg/sql.pyquoter      s     3<!!'**    c                  ^    e Zd ZdZddZddZeddd       ZdddZddZ	ddZ
dd	Zdd
Zy)
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.
    c                    || _         y N_obj)selfr   s     r   __init__zComposable.__init__6   s	    	r   c                N    | j                   j                   d| j                  dS )N())	__class____name__r    r!   s    r   __repr__zComposable.__repr__9   s$    ..))*!DII=::r   Nc                    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   s     r   as_byteszComposable.as_bytes<   s
     "!r   c                    t        |r|j                  nd      }t        | j                  |      x}t              r|j                  |      S t        j                  |      j                  |      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-   bytesdecodecodecslookup)r!   r   encbs       r   r   zComposable.as_stringK   s_     'G..tDDMM'22qU;88C=  ==%,,Q/22r   c                    t        |t              rt        | g      |z   S t        |t              rt        | g      t        |g      z   S t        S r   )r0   Composedr   NotImplementedr!   others     r   __add__zComposable.__add__Z   sG    eX&TF#e++eZ(TF#hw&777!!r   c                     t        | g|z        S r   )r8   )r!   ns     r   __mul__zComposable.__mul__b   s    
##r   c                d    t        |       t        |      u xr | j                  |j                  k(  S r   )typer    r:   s     r   __eq__zComposable.__eq__e   s'    DzT%[(DTYY%**-DDr   c                &    | j                  |       S r   )rB   r:   s     r   __ne__zComposable.__ne__h   s    ;;u%%%r   )r   r   returnstrr   r   AdaptContext | NonerF   r1   r   rI   rF   rG   r;   r   rF   r8   )r>   intrF   r8   )r;   r   rF   bool)r'   
__module____qualname____doc__r"   r)   r   r-   r   r<   r?   rB   rD    r   r   r   r   '   s?    ; " "3"$E&r   r   c                  R     e Zd ZU dZded<   d	 fdZd
ddZddZddZddZ	 xZ
S )r8   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    c                    |D cg c]  }t        |t              r|n
t        |      ! }}t        |   |       y c c}w r   )r0   r   r   superr"   )r!   seqr   r&   s      r   r"   zComposed.__init__   s;    ORSjj1sws|CSS Ts   $<c                L    dj                  fd| j                  D              S )Nr   c              3  @   K   | ]  }|j                          y wr   r-   ).0r   r   s     r   	<genexpr>z$Composed.as_bytes.<locals>.<genexpr>   s     C#W-Cs   )joinr    r,   s    `r   r-   zComposed.as_bytes   s    xxCCCCr   c                ,    t        | j                        S r   )iterr    r(   s    r   __iter__zComposed.__iter__   s    DIIr   c                    t        |t              r"t        | j                  |j                  z         S t        |t              rt        | j                  |gz         S t        S r   )r0   r8   r    r   r9   r:   s     r   r<   zComposed.__add__   sJ    eX&DII

233eZ(DII/00!!r   c                    t        |t              rt        |      }nt        |t              st        d|d      |j	                  | 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)r0   rG   SQL	TypeErrorr[   r    )r!   joiners     r   r[   zComposed.join   sT     fc"[FFC(z+ 
 {{499%%r   )rU   zSequence[Any]r   rH   )rF   zIterator[Composable]rK   )rd   zSQL | LiteralStringrF   r8   )r'   rN   rO   rP   __annotations__r"   r-   r^   r<   r[   __classcell__r&   s   @r   r8   r8   l   s*    . D"&r   r8   c                       e Zd ZU dZded<    ej                         Zd fdZdddZ	dddZ
ddZedd       Zedd	       Zdd
Z xZS )rb   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    c                b    t         |   |       t        |t              st	        d|d      y )Nz SQL values must be strings, got ra   )rT   r"   r0   rG   rc   )r!   r   r&   s     r   r"   zSQL.__init__   s4    #s#>sgXNOO $r   c                    | j                   S r   r   r,   s     r   r   zSQL.as_string   s    yyr   c                n    |r|j                   nd }t        |      }| j                  j                  |      S r   )r/   r   r    encoder!   r   connr5   s       r   r-   zSQL.as_bytes   s0    %,w!!$D!yy$$r   c                   g }d}| j                   j                  | j                        D ]  \  }}}}|rt        d      |rt        d      |r|j	                  t        |             |A|j                         r-|rt        d      |j	                  |t        |                d}~|s'|t        d      |j	                  ||          |dz  }|j	                  ||           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appendrb   isdigitrL   r8   )	r!   argskwargsrvautonumprenamespecconvs	            r   formatz
SQL.format   s    F  " &*__%:%:499%E 	(!CtT !KLL !HII		#c(#|||~$P  		$s4y/*?$P  		$w-(1 		&,'9	(< |r   c                     y r   rQ   r!   rU   s     r   r[   zSQL.join$  s    9<r   c                     y r   rQ   r   s     r   r[   zSQL.join'  s    47r   c                B   t        |      }	 t        |      }t	        |t
              rwt        |      }|D ]_  }t	        |t
              s!t        dt        |      j                         |j                  | j                         |j                  |       a t        | S |g}|D ]U  }t	        |t
              r!t        dt        |      j                         |j                  |        |j                  |       W t        |      S # t        $ r t        g       cY S w xY w)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 )r]   nextStopIterationr8   r0   r   listrc   rA   r'   rs   r    extend)r!   rU   itfirstitemstcsis           r   r[   zSQL.join*  s
   0 #Y	 HE eX&KE  !!X.#&=d1g>N>N=O$PQQTYY'Q	 
 U##W 	A!X&"9$q':J:J9K LMMIIdOIIaL		 |'  	 B<	 s   D DD)r   r   r   rJ   rH   )ru   r   rv   r   rF   r8   )rU   zIterable[Template]rF   r   )rU   Iterable[Any]rF   r8   )rU   r   rF   zComposed | Template)r'   rN   rO   rP   re   string	Formatterrp   r"   r   r-   r}   r   r[   rf   rg   s   @r   rb   rb      sZ    4 !!!#JP
%
FP < <7 7.r   rb   c                  J     e Zd ZU dZded<   d fdZd	dZd
ddZddZ x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    c                    t         |   |       |st        d      |D ]!  }t        |t              rt        d|d       y )NzIdentifier cannot be emptyz*SQL identifier parts must be strings, got ra   )rT   r"   rc   r0   rG   )r!   stringssr&   s      r   r"   zIdentifier.__init__}  sQ    !899 	Aa%@XN 	r   c                    | j                   j                   ddj                  t        t        | j
                               dS )Nr$   , r%   )r&   r'   r[   mapreprr    r(   s    r   r)   zIdentifier.__repr__  s5    ..))*!DIIc$		6J,K+LANNr   c                x   |r|j                   nd x}rXt        |j                        }t        |      }| j                  D cg c]"  }|j                  |j                  |            $ }}n6| j                  D cg c]!  }| j                  |j                               # }}dj                  |      S c c}w c c}w )N   .)	r/   r   pgconnr   r    escape_identifierrl   _escape_identifierr[   )r!   r   rn   escr5   r   escss          r   r-   zIdentifier.as_bytes  s    *1G&&t<4<4;;'C%CBF))LQC))!((3-8LDLAEKAD++AHHJ7KDKyy MKs   'B29&B7c                2    d|j                  dd      z   dz   S )zK
        Approximation of PQescapeIdentifier taking no connection.
           "s   "")replace)r!   r   s     r   r   zIdentifier._escape_identifier  s     aiie,,t33r   )r   rG   rE   r   rH   )r   r1   rF   r1   )
r'   rN   rO   rP   re   r"   r)   r-   r   rf   rg   s   @r   r   r   [  s%    > O4r   r   c                      e Zd ZdZdddZy)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

    Nc                b    t        j                  |      }|j                  | j                        S r   )r   from_context
as_literalr    )r!   r   txs      r   r-   zLiteral.as_bytes  s%    %%g.}}TYY''r   r   rH   )r'   rN   rO   rP   r-   rQ   r   r   r   r     s    ((r   r   c                  Z     e Zd ZdZdej
                  fd fdZddZd	d
dZd	ddZ	 x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)

     c                ,   t         |   |       t        |t              st	        d|      d|v rt        d|      t        |      t        u rt        |      }t        |t              s!t	        dt        |      j                        || _	        y )Nzexpected string as name, got r%   zinvalid name: z!expected PyFormat as format, got )
rT   r"   r0   rG   rc   rr   rA   r   r'   _format)r!   rz   r}   r&   s      r   r"   zPlaceholder.__init__  s    $$;D8DEE$;~dX677<3f%F&(+3DL4I4I3LM  "(r   c                D   g }| j                   r$|j                  t        | j                                | j                  t        j
                  ur(|j                  d| j                  j                          | j                  j                   ddj                  |       dS )Nzformat=r$   r   r%   )
r    rs   r   r   r   AUTOrz   r&   r'   r[   )r!   partss     r   r)   zPlaceholder.__repr__  sx    99LLdii)<<x}},LL74<<#4#4"567..))*!DIIe,<+=Q??r   c                t    | j                   j                  }| j                  rd| j                   d| S d| S )Nz%(r%   %)r   valuer    )r!   r   codes      r   r   zPlaceholder.as_string  s9    ||!!*.))DII;av&C1TFCr   c                x    |r|j                   nd }t        |      }| j                  |      j                  |      S r   )r/   r   r   rl   rm   s       r   r-   zPlaceholder.as_bytes  s5    %,w!!$D!~~g&--c22r   )rz   rG   r}   zstr | PyFormatrE   r   rJ   rH   )r'   rN   rO   rP   r   r   r"   r)   r   r-   rf   rg   s   @r   r   r     s.    6 $& ("@D3 3r   r   NULLDEFAULTc                    t        | t              r| j                  |      S t        | t              rddlm}  || |      S t        |       j                  |      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.
    r   r   )r   )r0   r   r   r   	_tstringsr   )r   r   r   s      r   r   r     sQ    & #z"}}W}--	C	"(g&&s|%%g%66r   c                    t        | t              r| j                  |      S t        | t              rddlm}  || |      S t        |       j                  |      S )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.
    r   r   rX   )r0   r   r-   r   r   r   )r   r   r-   s      r   r-   r-     sQ     #z"||G|,,	C	"'W%%s|$$W$55r   r   )r   r   r   rI   rF   rG   )r   r   r   rI   rF   r1   )&rP   
__future__r   r3   r   abcr   r   typingr   r   collections.abcr   r	   r
   pqr   r   _enumsr   _compatr   r   
_encodingsr   _transformerr   r   r   r8   rb   r   r   r   r   r   r   r-   rQ   r   r   <module>r      s    #   #   8 8    , % %+ B& B&JB&z B&Jg* gT?4 ?4D(j (4=3* =3B 6{
i.7:6r   