from __future__ import annotations
import enum
from dataclasses import dataclass
from enum import auto
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import csql.dialect
__all__ = ["DefaultDialect", "DuckDB", "ParamStyle", "SQLDialect", "Snowflake"]
[docs]
class ParamStyle(enum.Enum):
"""
Enum to define how to render query parameter placeholders.
"""
numeric = auto()
"""
Use placeholders like ``:1``.
:meta hide-value:
"""
numeric_dollar = auto()
"""
Use placeholders like ``$1``.
:meta hide-value:
"""
qmark = auto()
"""
Use placeholders like ``?``.
:meta hide-value:
"""
clickhouse = auto()
"""
Use placeholders like ``{MyParam:String}``
"""
def __repr__(self) -> str:
return "ParamStyle." + self.name
[docs]
class Limit(enum.Enum):
"""
Enum to defines how to limit preview queries.
"""
limit = auto()
"""
Use a ``limit`` clause, e.g. ``select * from (query) limit 10``.
:meta hide-value:
"""
top_n = auto()
"""
Use a ``top n`` clause, e.g. ``select top(10) * from (query)``.'
:meta hide-value:
"""
ansi = auto()
"""
Use ANSI SQL ``fetch`` clause, e.g. ``select * from (query) fetch first 10 rows only``.
:meta hide-value:
"""
def __repr__(self) -> str:
return f"Limit.{self.name}"
[docs]
@dataclass(frozen=True)
class SQLDialect:
"""
Represents settings of a SQL Dialect.
>>> import functools
>>> from csql.dialect import SQLDialect, ParamStyle
>>> my_dialect=SQLDialect(paramstyle=ParamStyle.qmark)
>>> p = Parameters(value=123)
To use as a once-off, pass to :meth:`csql.Query.build`:
>>> q = Q(f"select {p['value']}")
>>> q.build() # builds normally
RenderedQuery('select :1', (123,))
>>> q.build(dialect=my_dialect) # builds with `my_dialect`
RenderedQuery('select ?', (123,))
To set as a default, use ``functools.partial``:
>>> Q = functools.partial(csql.Q, dialect=my_dialect)
>>> q = Q('select ...') # builds with `my_dialect`
"""
paramstyle: csql.dialect.ParamStyle = ParamStyle.numeric
limit: csql.dialect.Limit = Limit.limit
# experiments for doc gen
Snowflake = SQLDialect(paramstyle=ParamStyle.numeric, limit=Limit.limit)
"""A dialect for Snowflake"""
DuckDB = SQLDialect(paramstyle=ParamStyle.numeric_dollar, limit=Limit.limit)
"""A dialect for DuckDB"""
MSSQL = SQLDialect(paramstyle=ParamStyle.numeric, limit=Limit.top_n)
"""A dialect for MS SQL Server"""
SQLite = SQLDialect(paramstyle=ParamStyle.qmark, limit=Limit.limit)
"""A dialect for SQLite."""
ClickHouse = SQLDialect(paramstyle=ParamStyle.clickhouse, limit=Limit.limit)
# def __repr__(self) -> str:
# import inspect
# mod = inspect.getmodule(self)
# print('!!!')
# if mod is None:
# print('nomod')
# return super().__repr__()
# print('???')
# name = next(
# (
# name
# for name, obj in vars(mod).items()
# if obj is self
# ),
# None
# )
# print('!!!!')
# if name is None:
# print('nolocal')
# return super().__repr__()
# print(f'{name=}')
# return name
DefaultDialect = SQLDialect(paramstyle=ParamStyle.numeric, limit=Limit.limit)
"""The default dialect for CSQL."""
import dataclasses
[docs]
@dataclasses.dataclass(frozen=True)
class InferOrDefault:
"""A wrapper to flag that this query should use a previous query\'s dialect if not otherwise specified."""
dialect: csql.dialect.SQLDialect