Source code for postgast.deparse

"""SQL query deparsing via libpg_query."""

from __future__ import annotations

import ctypes
from typing import TYPE_CHECKING

from postgast.errors import check_error
from postgast.native import PgQueryProtobuf, lib
from postgast.nodes.base import AstNode

if TYPE_CHECKING:
    from google.protobuf.message import Message

    from postgast.pg_query_pb2 import ParseResult


[docs] def deparse(tree: ParseResult | AstNode) -> str: """Convert a protobuf parse tree back into a SQL string. Calls libpg_query's ``pg_query_deparse_protobuf`` to convert a ``ParseResult`` AST back into SQL text. This is the inverse of :func:`postgast.parse`. Note: The deparsed SQL is canonicalized by libpg_query and may differ from the original query in whitespace, casing, or parenthesization while remaining semantically equivalent. Args: tree: A ``ParseResult`` protobuf message (as returned by :func:`postgast.parse`), or a typed ``AstNode`` wrapper. Returns: The deparsed SQL string. Raises: PgQueryError: If the parse tree cannot be deparsed. Example: >>> from postgast import parse, deparse >>> tree = parse("SELECT id FROM users") >>> deparse(tree) 'SELECT id FROM users' """ pb: Message = tree._pb if isinstance(tree, AstNode) else tree # pyright: ignore[reportPrivateUsage] data = pb.SerializeToString() buf = ctypes.create_string_buffer(data) pbuf = PgQueryProtobuf(len=len(data), data=ctypes.cast(buf, ctypes.c_void_p).value) result = lib.pg_query_deparse_protobuf(pbuf) try: check_error(result) query: bytes = result.query return query.decode("utf-8") finally: lib.pg_query_free_deparse_result(result)