"""{{module.name}}

This module has been generated with SqlPyGen from {{ src }}.
"""

from dataclasses import dataclass
from typing import Optional, Iterable

{% if typeguard %}
from typeguard import typechecked
{% endif %}

{% if dbcon == "apsw" %}
import apsw
ConnectionType = apsw.Connection
{% else %}
import sqlite3
ConnectionType = sqlite3.Connection
{% endif %}

SCHEMA = {}
{% for schema in schemas %}
SCHEMA["{{ schema.name }}"] = """
{{ schema.sql }}
"""

{% endfor %}

QUERY = {}
{% for query in queries %}
QUERY["{{ query.name }}"] = """
{{ query.sql }}
"""

{% endfor %}


{% for row_type in row_types %}
@dataclass(frozen=True)
class {{ row_type.name }}:
    {% for tv in row_type.typed_vars %}
    {{ tv.name }}: {{ tv.type | py_type }}
    {% endfor %}
    
{% endfor %}

def create_schema(connection: ConnectionType) -> None:
    """Create the table schema."""
    with connection:
        cursor = connection.cursor()

        {% for schema in schemas %}
        try:
            sql = SCHEMA["{{ schema.name }}"]

            cursor.execute(sql)
        except Exception as e:
            raise RuntimeError("An unexpected exception occurred when creating schema: {{ schema.name }}") from e
        {% endfor %}

{% for query in queries %}

{% if typeguard %}
@typechecked
{% endif %}
def {{ query.name }}({{ query.params | fn_params }}) -> {{ query.return_ | fn_return }}:
    """Query {{query.name}}."""
    cursor = connection.cursor()
    try:
        sql = QUERY["{{ query.name }}"]

        {% if query.params %}
        query_args = {{ query.params | query_args }}
        cursor.execute(sql, query_args)
        {% else %}
        cursor.execute(sql)
        {% endif %}

        {% if query.return_ %}
        {% if query.return_.returns_one %}
        row = cursor.fetchone()
        if row is None:
            return None
        return {{ query.return_ | ret_conversion }}
        {% else %}
        for row in cursor:
            row = {{ query.return_ | ret_conversion }}
            yield row
        {% endif %}
        {% endif %}
    except Exception as e:
        raise RuntimeError("An unexpected exception occurred while executing query: {{ query.name }}") from e

{% endfor %}

def explain_queries() -> None:
    {% if dbcon == "apsw" %}
    connection = apsw.Connection(":memory:")
    {% else %}
    connection = sqlite3.connect(":memory:")
    {% endif %}
    create_schema(connection)

    with connection:
        cursor = connection.cursor()

        {% for query in queries %}
        try:
            sql = QUERY["{{ query.name }}"]
            sql = "EXPLAIN " + sql

            {% if query.params %}
            query_args = {{ query.params | explain_args }}
            cursor.execute(sql, query_args)
            {% else %}
            cursor.execute(sql)
            {% endif %}

            print("Query {{ query.name }} is syntactically valid.")
        except Exception as e:
            raise RuntimeError("An unexpected exception occurred while executing query plan for: {{ query.name }}") from e

        {% endfor %}

if __name__ == "__main__":
    try:
        explain_queries()
    except RuntimeError as e:
        print(e)
        print(e.__cause__)
