sqlspec 0.16.2__cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sqlspec might be problematic. Click here for more details.
- 51ff5a9eadfdefd49f98__mypyc.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/__init__.py +92 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_serialization.py +77 -0
- sqlspec/_sql.py +1782 -0
- sqlspec/_typing.py +680 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +5 -0
- sqlspec/adapters/adbc/_types.py +12 -0
- sqlspec/adapters/adbc/config.py +361 -0
- sqlspec/adapters/adbc/driver.py +512 -0
- sqlspec/adapters/aiosqlite/__init__.py +19 -0
- sqlspec/adapters/aiosqlite/_types.py +13 -0
- sqlspec/adapters/aiosqlite/config.py +253 -0
- sqlspec/adapters/aiosqlite/driver.py +248 -0
- sqlspec/adapters/asyncmy/__init__.py +19 -0
- sqlspec/adapters/asyncmy/_types.py +12 -0
- sqlspec/adapters/asyncmy/config.py +180 -0
- sqlspec/adapters/asyncmy/driver.py +274 -0
- sqlspec/adapters/asyncpg/__init__.py +21 -0
- sqlspec/adapters/asyncpg/_types.py +17 -0
- sqlspec/adapters/asyncpg/config.py +229 -0
- sqlspec/adapters/asyncpg/driver.py +344 -0
- sqlspec/adapters/bigquery/__init__.py +18 -0
- sqlspec/adapters/bigquery/_types.py +12 -0
- sqlspec/adapters/bigquery/config.py +298 -0
- sqlspec/adapters/bigquery/driver.py +558 -0
- sqlspec/adapters/duckdb/__init__.py +22 -0
- sqlspec/adapters/duckdb/_types.py +12 -0
- sqlspec/adapters/duckdb/config.py +504 -0
- sqlspec/adapters/duckdb/driver.py +368 -0
- sqlspec/adapters/oracledb/__init__.py +32 -0
- sqlspec/adapters/oracledb/_types.py +14 -0
- sqlspec/adapters/oracledb/config.py +317 -0
- sqlspec/adapters/oracledb/driver.py +538 -0
- sqlspec/adapters/psqlpy/__init__.py +16 -0
- sqlspec/adapters/psqlpy/_types.py +11 -0
- sqlspec/adapters/psqlpy/config.py +214 -0
- sqlspec/adapters/psqlpy/driver.py +530 -0
- sqlspec/adapters/psycopg/__init__.py +32 -0
- sqlspec/adapters/psycopg/_types.py +17 -0
- sqlspec/adapters/psycopg/config.py +426 -0
- sqlspec/adapters/psycopg/driver.py +796 -0
- sqlspec/adapters/sqlite/__init__.py +15 -0
- sqlspec/adapters/sqlite/_types.py +11 -0
- sqlspec/adapters/sqlite/config.py +240 -0
- sqlspec/adapters/sqlite/driver.py +294 -0
- sqlspec/base.py +571 -0
- sqlspec/builder/__init__.py +62 -0
- sqlspec/builder/_base.py +473 -0
- sqlspec/builder/_column.py +320 -0
- sqlspec/builder/_ddl.py +1346 -0
- sqlspec/builder/_ddl_utils.py +103 -0
- sqlspec/builder/_delete.py +76 -0
- sqlspec/builder/_insert.py +421 -0
- sqlspec/builder/_merge.py +71 -0
- sqlspec/builder/_parsing_utils.py +164 -0
- sqlspec/builder/_select.py +170 -0
- sqlspec/builder/_update.py +188 -0
- sqlspec/builder/mixins/__init__.py +55 -0
- sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
- sqlspec/builder/mixins/_delete_operations.py +41 -0
- sqlspec/builder/mixins/_insert_operations.py +244 -0
- sqlspec/builder/mixins/_join_operations.py +149 -0
- sqlspec/builder/mixins/_merge_operations.py +562 -0
- sqlspec/builder/mixins/_order_limit_operations.py +135 -0
- sqlspec/builder/mixins/_pivot_operations.py +153 -0
- sqlspec/builder/mixins/_select_operations.py +604 -0
- sqlspec/builder/mixins/_update_operations.py +202 -0
- sqlspec/builder/mixins/_where_clause.py +644 -0
- sqlspec/cli.py +247 -0
- sqlspec/config.py +395 -0
- sqlspec/core/__init__.py +63 -0
- sqlspec/core/cache.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/cache.py +871 -0
- sqlspec/core/compiler.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/compiler.py +417 -0
- sqlspec/core/filters.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/filters.py +830 -0
- sqlspec/core/hashing.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/hashing.py +310 -0
- sqlspec/core/parameters.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters.py +1237 -0
- sqlspec/core/result.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result.py +677 -0
- sqlspec/core/splitter.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/splitter.py +819 -0
- sqlspec/core/statement.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/statement.py +676 -0
- sqlspec/driver/__init__.py +19 -0
- sqlspec/driver/_async.py +502 -0
- sqlspec/driver/_common.py +631 -0
- sqlspec/driver/_sync.py +503 -0
- sqlspec/driver/mixins/__init__.py +6 -0
- sqlspec/driver/mixins/_result_tools.py +193 -0
- sqlspec/driver/mixins/_sql_translator.py +86 -0
- sqlspec/exceptions.py +193 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/aiosql/__init__.py +10 -0
- sqlspec/extensions/aiosql/adapter.py +461 -0
- sqlspec/extensions/litestar/__init__.py +6 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/cli.py +48 -0
- sqlspec/extensions/litestar/config.py +92 -0
- sqlspec/extensions/litestar/handlers.py +260 -0
- sqlspec/extensions/litestar/plugin.py +145 -0
- sqlspec/extensions/litestar/providers.py +454 -0
- sqlspec/loader.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/loader.py +760 -0
- sqlspec/migrations/__init__.py +35 -0
- sqlspec/migrations/base.py +414 -0
- sqlspec/migrations/commands.py +443 -0
- sqlspec/migrations/loaders.py +402 -0
- sqlspec/migrations/runner.py +213 -0
- sqlspec/migrations/tracker.py +140 -0
- sqlspec/migrations/utils.py +129 -0
- sqlspec/protocols.py +407 -0
- sqlspec/py.typed +0 -0
- sqlspec/storage/__init__.py +23 -0
- sqlspec/storage/backends/__init__.py +0 -0
- sqlspec/storage/backends/base.py +163 -0
- sqlspec/storage/backends/fsspec.py +386 -0
- sqlspec/storage/backends/obstore.py +459 -0
- sqlspec/storage/capabilities.py +102 -0
- sqlspec/storage/registry.py +239 -0
- sqlspec/typing.py +299 -0
- sqlspec/utils/__init__.py +3 -0
- sqlspec/utils/correlation.py +150 -0
- sqlspec/utils/deprecation.py +106 -0
- sqlspec/utils/fixtures.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/fixtures.py +58 -0
- sqlspec/utils/logging.py +127 -0
- sqlspec/utils/module_loader.py +89 -0
- sqlspec/utils/serializers.py +4 -0
- sqlspec/utils/singleton.py +32 -0
- sqlspec/utils/sync_tools.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/sync_tools.py +237 -0
- sqlspec/utils/text.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/text.py +96 -0
- sqlspec/utils/type_guards.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_guards.py +1139 -0
- sqlspec-0.16.2.dist-info/METADATA +365 -0
- sqlspec-0.16.2.dist-info/RECORD +148 -0
- sqlspec-0.16.2.dist-info/WHEEL +7 -0
- sqlspec-0.16.2.dist-info/entry_points.txt +2 -0
- sqlspec-0.16.2.dist-info/licenses/LICENSE +21 -0
- sqlspec-0.16.2.dist-info/licenses/NOTICE +29 -0
sqlspec/cli.py
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from collections.abc import Sequence
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from click import Group
|
|
7
|
+
|
|
8
|
+
from sqlspec.config import AsyncDatabaseConfig, SyncDatabaseConfig
|
|
9
|
+
|
|
10
|
+
__all__ = ("add_migration_commands", "get_sqlspec_group")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_sqlspec_group() -> "Group":
|
|
14
|
+
"""Get the SQLSpec CLI group.
|
|
15
|
+
|
|
16
|
+
Raises:
|
|
17
|
+
MissingDependencyError: If the `click` package is not installed.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
The SQLSpec CLI group.
|
|
21
|
+
"""
|
|
22
|
+
from sqlspec.exceptions import MissingDependencyError
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
import rich_click as click
|
|
26
|
+
except ImportError:
|
|
27
|
+
try:
|
|
28
|
+
import click # type: ignore[no-redef]
|
|
29
|
+
except ImportError as e:
|
|
30
|
+
raise MissingDependencyError(package="click", install_package="cli") from e
|
|
31
|
+
|
|
32
|
+
@click.group(name="sqlspec")
|
|
33
|
+
@click.option(
|
|
34
|
+
"--config",
|
|
35
|
+
help="Dotted path to SQLSpec config(s) (e.g. 'myapp.config.sqlspec_configs')",
|
|
36
|
+
required=True,
|
|
37
|
+
type=str,
|
|
38
|
+
)
|
|
39
|
+
@click.pass_context
|
|
40
|
+
def sqlspec_group(ctx: "click.Context", config: str) -> None:
|
|
41
|
+
"""SQLSpec CLI commands."""
|
|
42
|
+
from rich import get_console
|
|
43
|
+
|
|
44
|
+
from sqlspec.utils import module_loader
|
|
45
|
+
|
|
46
|
+
console = get_console()
|
|
47
|
+
ctx.ensure_object(dict)
|
|
48
|
+
try:
|
|
49
|
+
config_instance = module_loader.import_string(config)
|
|
50
|
+
if isinstance(config_instance, Sequence):
|
|
51
|
+
ctx.obj["configs"] = config_instance
|
|
52
|
+
else:
|
|
53
|
+
ctx.obj["configs"] = [config_instance]
|
|
54
|
+
except ImportError as e:
|
|
55
|
+
console.print(f"[red]Error loading config: {e}[/]")
|
|
56
|
+
ctx.exit(1)
|
|
57
|
+
|
|
58
|
+
return sqlspec_group
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def add_migration_commands(database_group: Optional["Group"] = None) -> "Group":
|
|
62
|
+
"""Add migration commands to the database group.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
database_group: The database group to add the commands to.
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
MissingDependencyError: If the `click` package is not installed.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The database group with the migration commands added.
|
|
72
|
+
"""
|
|
73
|
+
from sqlspec.exceptions import MissingDependencyError
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
import rich_click as click
|
|
77
|
+
except ImportError:
|
|
78
|
+
try:
|
|
79
|
+
import click # type: ignore[no-redef]
|
|
80
|
+
except ImportError as e:
|
|
81
|
+
raise MissingDependencyError(package="click", install_package="cli") from e
|
|
82
|
+
from rich import get_console
|
|
83
|
+
|
|
84
|
+
console = get_console()
|
|
85
|
+
|
|
86
|
+
if database_group is None:
|
|
87
|
+
database_group = get_sqlspec_group()
|
|
88
|
+
|
|
89
|
+
bind_key_option = click.option(
|
|
90
|
+
"--bind-key", help="Specify which SQLSpec config to use by bind key", type=str, default=None
|
|
91
|
+
)
|
|
92
|
+
verbose_option = click.option("--verbose", help="Enable verbose output.", type=bool, default=False, is_flag=True)
|
|
93
|
+
no_prompt_option = click.option(
|
|
94
|
+
"--no-prompt",
|
|
95
|
+
help="Do not prompt for confirmation before executing the command.",
|
|
96
|
+
type=bool,
|
|
97
|
+
default=False,
|
|
98
|
+
required=False,
|
|
99
|
+
show_default=True,
|
|
100
|
+
is_flag=True,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def get_config_by_bind_key(
|
|
104
|
+
ctx: "click.Context", bind_key: Optional[str]
|
|
105
|
+
) -> "Union[AsyncDatabaseConfig[Any, Any, Any], SyncDatabaseConfig[Any, Any, Any]]":
|
|
106
|
+
"""Get the SQLSpec config for the specified bind key.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
ctx: The click context.
|
|
110
|
+
bind_key: The bind key to get the config for.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
The SQLSpec config for the specified bind key.
|
|
114
|
+
"""
|
|
115
|
+
configs = ctx.obj["configs"]
|
|
116
|
+
if bind_key is None:
|
|
117
|
+
return cast("Union[AsyncDatabaseConfig[Any, Any, Any], SyncDatabaseConfig[Any, Any, Any]]", configs[0])
|
|
118
|
+
|
|
119
|
+
for config in configs:
|
|
120
|
+
config_name = getattr(config, "name", None) or getattr(config, "bind_key", None)
|
|
121
|
+
if config_name == bind_key:
|
|
122
|
+
return cast("Union[AsyncDatabaseConfig[Any, Any, Any], SyncDatabaseConfig[Any, Any, Any]]", config)
|
|
123
|
+
|
|
124
|
+
console.print(f"[red]No config found for bind key: {bind_key}[/]")
|
|
125
|
+
sys.exit(1)
|
|
126
|
+
|
|
127
|
+
@database_group.command(name="show-current-revision", help="Shows the current revision for the database.")
|
|
128
|
+
@bind_key_option
|
|
129
|
+
@verbose_option
|
|
130
|
+
def show_database_revision(bind_key: Optional[str], verbose: bool) -> None: # pyright: ignore[reportUnusedFunction]
|
|
131
|
+
"""Show current database revision."""
|
|
132
|
+
from sqlspec.migrations.commands import MigrationCommands
|
|
133
|
+
|
|
134
|
+
ctx = click.get_current_context()
|
|
135
|
+
console.rule("[yellow]Listing current revision[/]", align="left")
|
|
136
|
+
sqlspec_config = get_config_by_bind_key(ctx, bind_key)
|
|
137
|
+
migration_commands = MigrationCommands(config=sqlspec_config)
|
|
138
|
+
migration_commands.current(verbose=verbose)
|
|
139
|
+
|
|
140
|
+
@database_group.command(name="downgrade", help="Downgrade database to a specific revision.")
|
|
141
|
+
@bind_key_option
|
|
142
|
+
@no_prompt_option
|
|
143
|
+
@click.argument("revision", type=str, default="-1")
|
|
144
|
+
def downgrade_database( # pyright: ignore[reportUnusedFunction]
|
|
145
|
+
bind_key: Optional[str], revision: str, no_prompt: bool
|
|
146
|
+
) -> None:
|
|
147
|
+
"""Downgrade the database to the latest revision."""
|
|
148
|
+
from rich.prompt import Confirm
|
|
149
|
+
|
|
150
|
+
from sqlspec.migrations.commands import MigrationCommands
|
|
151
|
+
|
|
152
|
+
ctx = click.get_current_context()
|
|
153
|
+
console.rule("[yellow]Starting database downgrade process[/]", align="left")
|
|
154
|
+
input_confirmed = (
|
|
155
|
+
True
|
|
156
|
+
if no_prompt
|
|
157
|
+
else Confirm.ask(f"Are you sure you want to downgrade the database to the `{revision}` revision?")
|
|
158
|
+
)
|
|
159
|
+
if input_confirmed:
|
|
160
|
+
sqlspec_config = get_config_by_bind_key(ctx, bind_key)
|
|
161
|
+
migration_commands = MigrationCommands(config=sqlspec_config)
|
|
162
|
+
migration_commands.downgrade(revision=revision)
|
|
163
|
+
|
|
164
|
+
@database_group.command(name="upgrade", help="Upgrade database to a specific revision.")
|
|
165
|
+
@bind_key_option
|
|
166
|
+
@no_prompt_option
|
|
167
|
+
@click.argument("revision", type=str, default="head")
|
|
168
|
+
def upgrade_database( # pyright: ignore[reportUnusedFunction]
|
|
169
|
+
bind_key: Optional[str], revision: str, no_prompt: bool
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Upgrade the database to the latest revision."""
|
|
172
|
+
from rich.prompt import Confirm
|
|
173
|
+
|
|
174
|
+
from sqlspec.migrations.commands import MigrationCommands
|
|
175
|
+
|
|
176
|
+
ctx = click.get_current_context()
|
|
177
|
+
console.rule("[yellow]Starting database upgrade process[/]", align="left")
|
|
178
|
+
input_confirmed = (
|
|
179
|
+
True
|
|
180
|
+
if no_prompt
|
|
181
|
+
else Confirm.ask(f"[bold]Are you sure you want migrate the database to the `{revision}` revision?[/]")
|
|
182
|
+
)
|
|
183
|
+
if input_confirmed:
|
|
184
|
+
sqlspec_config = get_config_by_bind_key(ctx, bind_key)
|
|
185
|
+
migration_commands = MigrationCommands(config=sqlspec_config)
|
|
186
|
+
migration_commands.upgrade(revision=revision)
|
|
187
|
+
|
|
188
|
+
@database_group.command(help="Stamp the revision table with the given revision")
|
|
189
|
+
@click.argument("revision", type=str)
|
|
190
|
+
@bind_key_option
|
|
191
|
+
def stamp(bind_key: Optional[str], revision: str) -> None: # pyright: ignore[reportUnusedFunction]
|
|
192
|
+
"""Stamp the revision table with the given revision."""
|
|
193
|
+
from sqlspec.migrations.commands import MigrationCommands
|
|
194
|
+
|
|
195
|
+
ctx = click.get_current_context()
|
|
196
|
+
sqlspec_config = get_config_by_bind_key(ctx, bind_key)
|
|
197
|
+
migration_commands = MigrationCommands(config=sqlspec_config)
|
|
198
|
+
migration_commands.stamp(revision=revision)
|
|
199
|
+
|
|
200
|
+
@database_group.command(name="init", help="Initialize migrations for the project.")
|
|
201
|
+
@bind_key_option
|
|
202
|
+
@click.argument("directory", default=None, required=False)
|
|
203
|
+
@click.option("--package", is_flag=True, default=True, help="Create `__init__.py` for created folder")
|
|
204
|
+
@no_prompt_option
|
|
205
|
+
def init_sqlspec( # pyright: ignore[reportUnusedFunction]
|
|
206
|
+
bind_key: Optional[str], directory: Optional[str], package: bool, no_prompt: bool
|
|
207
|
+
) -> None:
|
|
208
|
+
"""Initialize the database migrations."""
|
|
209
|
+
from rich.prompt import Confirm
|
|
210
|
+
|
|
211
|
+
from sqlspec.migrations.commands import MigrationCommands
|
|
212
|
+
|
|
213
|
+
ctx = click.get_current_context()
|
|
214
|
+
console.rule("[yellow]Initializing database migrations.", align="left")
|
|
215
|
+
input_confirmed = (
|
|
216
|
+
True if no_prompt else Confirm.ask("[bold]Are you sure you want initialize migrations for the project?[/]")
|
|
217
|
+
)
|
|
218
|
+
if input_confirmed:
|
|
219
|
+
configs = [get_config_by_bind_key(ctx, bind_key)] if bind_key is not None else ctx.obj["configs"]
|
|
220
|
+
for config in configs:
|
|
221
|
+
migration_config = getattr(config, "migration_config", {})
|
|
222
|
+
directory = migration_config.get("script_location", "migrations") if directory is None else directory
|
|
223
|
+
migration_commands = MigrationCommands(config=config)
|
|
224
|
+
migration_commands.init(directory=cast("str", directory), package=package)
|
|
225
|
+
|
|
226
|
+
@database_group.command(name="make-migrations", help="Create a new migration revision.")
|
|
227
|
+
@bind_key_option
|
|
228
|
+
@click.option("-m", "--message", default=None, help="Revision message")
|
|
229
|
+
@no_prompt_option
|
|
230
|
+
def create_revision( # pyright: ignore[reportUnusedFunction]
|
|
231
|
+
bind_key: Optional[str], message: Optional[str], no_prompt: bool
|
|
232
|
+
) -> None:
|
|
233
|
+
"""Create a new database revision."""
|
|
234
|
+
from rich.prompt import Prompt
|
|
235
|
+
|
|
236
|
+
from sqlspec.migrations.commands import MigrationCommands
|
|
237
|
+
|
|
238
|
+
ctx = click.get_current_context()
|
|
239
|
+
console.rule("[yellow]Creating new migration revision[/]", align="left")
|
|
240
|
+
if message is None:
|
|
241
|
+
message = "new migration" if no_prompt else Prompt.ask("Please enter a message describing this revision")
|
|
242
|
+
|
|
243
|
+
sqlspec_config = get_config_by_bind_key(ctx, bind_key)
|
|
244
|
+
migration_commands = MigrationCommands(config=sqlspec_config)
|
|
245
|
+
migration_commands.revision(message=message)
|
|
246
|
+
|
|
247
|
+
return database_group
|
sqlspec/config.py
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Generic, Optional, TypeVar, Union
|
|
3
|
+
|
|
4
|
+
from typing_extensions import NotRequired, TypedDict
|
|
5
|
+
|
|
6
|
+
from sqlspec.core.parameters import ParameterStyle, ParameterStyleConfig
|
|
7
|
+
from sqlspec.core.statement import StatementConfig
|
|
8
|
+
from sqlspec.utils.logging import get_logger
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Awaitable
|
|
12
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager
|
|
13
|
+
|
|
14
|
+
from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__all__ = (
|
|
18
|
+
"AsyncConfigT",
|
|
19
|
+
"AsyncDatabaseConfig",
|
|
20
|
+
"ConfigT",
|
|
21
|
+
"DatabaseConfigProtocol",
|
|
22
|
+
"DriverT",
|
|
23
|
+
"LifecycleConfig",
|
|
24
|
+
"NoPoolAsyncConfig",
|
|
25
|
+
"NoPoolSyncConfig",
|
|
26
|
+
"SyncConfigT",
|
|
27
|
+
"SyncDatabaseConfig",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
AsyncConfigT = TypeVar("AsyncConfigT", bound="Union[AsyncDatabaseConfig[Any, Any, Any], NoPoolAsyncConfig[Any, Any]]")
|
|
31
|
+
SyncConfigT = TypeVar("SyncConfigT", bound="Union[SyncDatabaseConfig[Any, Any, Any], NoPoolSyncConfig[Any, Any]]")
|
|
32
|
+
ConfigT = TypeVar(
|
|
33
|
+
"ConfigT",
|
|
34
|
+
bound="Union[Union[AsyncDatabaseConfig[Any, Any, Any], NoPoolAsyncConfig[Any, Any]], SyncDatabaseConfig[Any, Any, Any], NoPoolSyncConfig[Any, Any]]",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Define TypeVars for Generic classes
|
|
38
|
+
ConnectionT = TypeVar("ConnectionT")
|
|
39
|
+
PoolT = TypeVar("PoolT")
|
|
40
|
+
DriverT = TypeVar("DriverT", bound="Union[SyncDriverAdapterBase, AsyncDriverAdapterBase]")
|
|
41
|
+
|
|
42
|
+
logger = get_logger("config")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class LifecycleConfig(TypedDict, total=False):
|
|
46
|
+
"""Universal lifecycle hooks for all adapters.
|
|
47
|
+
|
|
48
|
+
Each hook accepts a list of callables to support multiple handlers.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
on_connection_create: NotRequired[list[Callable[[Any], None]]]
|
|
52
|
+
on_connection_destroy: NotRequired[list[Callable[[Any], None]]]
|
|
53
|
+
on_pool_create: NotRequired[list[Callable[[Any], None]]]
|
|
54
|
+
on_pool_destroy: NotRequired[list[Callable[[Any], None]]]
|
|
55
|
+
on_session_start: NotRequired[list[Callable[[Any], None]]]
|
|
56
|
+
on_session_end: NotRequired[list[Callable[[Any], None]]]
|
|
57
|
+
on_query_start: NotRequired[list[Callable[[str, dict], None]]]
|
|
58
|
+
on_query_complete: NotRequired[list[Callable[[str, dict, Any], None]]]
|
|
59
|
+
on_error: NotRequired[list[Callable[[Exception, str, dict], None]]]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
|
|
63
|
+
"""Protocol defining the interface for database configurations."""
|
|
64
|
+
|
|
65
|
+
__slots__ = ("driver_features", "migration_config", "pool_instance", "statement_config")
|
|
66
|
+
driver_type: "ClassVar[type[Any]]"
|
|
67
|
+
connection_type: "ClassVar[type[Any]]"
|
|
68
|
+
is_async: "ClassVar[bool]" = False
|
|
69
|
+
supports_connection_pooling: "ClassVar[bool]" = False
|
|
70
|
+
supports_native_arrow_import: "ClassVar[bool]" = False
|
|
71
|
+
supports_native_arrow_export: "ClassVar[bool]" = False
|
|
72
|
+
supports_native_parquet_import: "ClassVar[bool]" = False
|
|
73
|
+
supports_native_parquet_export: "ClassVar[bool]" = False
|
|
74
|
+
statement_config: "StatementConfig"
|
|
75
|
+
pool_instance: "Optional[PoolT]"
|
|
76
|
+
migration_config: "dict[str, Any]"
|
|
77
|
+
|
|
78
|
+
def __hash__(self) -> int:
|
|
79
|
+
return id(self)
|
|
80
|
+
|
|
81
|
+
def __eq__(self, other: object) -> bool:
|
|
82
|
+
if not isinstance(other, type(self)):
|
|
83
|
+
return False
|
|
84
|
+
return bool(self.pool_instance == other.pool_instance and self.migration_config == other.migration_config)
|
|
85
|
+
|
|
86
|
+
def __repr__(self) -> str:
|
|
87
|
+
parts = ", ".join([f"pool_instance={self.pool_instance!r}", f"migration_config={self.migration_config!r}"])
|
|
88
|
+
return f"{type(self).__name__}({parts})"
|
|
89
|
+
|
|
90
|
+
@abstractmethod
|
|
91
|
+
def create_connection(self) -> "Union[ConnectionT, Awaitable[ConnectionT]]":
|
|
92
|
+
"""Create and return a new database connection."""
|
|
93
|
+
raise NotImplementedError
|
|
94
|
+
|
|
95
|
+
@abstractmethod
|
|
96
|
+
def provide_connection(
|
|
97
|
+
self, *args: Any, **kwargs: Any
|
|
98
|
+
) -> "Union[AbstractContextManager[ConnectionT], AbstractAsyncContextManager[ConnectionT]]":
|
|
99
|
+
"""Provide a database connection context manager."""
|
|
100
|
+
raise NotImplementedError
|
|
101
|
+
|
|
102
|
+
@abstractmethod
|
|
103
|
+
def provide_session(
|
|
104
|
+
self, *args: Any, **kwargs: Any
|
|
105
|
+
) -> "Union[AbstractContextManager[DriverT], AbstractAsyncContextManager[DriverT]]":
|
|
106
|
+
"""Provide a database session context manager."""
|
|
107
|
+
raise NotImplementedError
|
|
108
|
+
|
|
109
|
+
@abstractmethod
|
|
110
|
+
def create_pool(self) -> "Union[PoolT, Awaitable[PoolT]]":
|
|
111
|
+
"""Create and return connection pool."""
|
|
112
|
+
raise NotImplementedError
|
|
113
|
+
|
|
114
|
+
@abstractmethod
|
|
115
|
+
def close_pool(self) -> "Optional[Awaitable[None]]":
|
|
116
|
+
"""Terminate the connection pool."""
|
|
117
|
+
raise NotImplementedError
|
|
118
|
+
|
|
119
|
+
@abstractmethod
|
|
120
|
+
def provide_pool(
|
|
121
|
+
self, *args: Any, **kwargs: Any
|
|
122
|
+
) -> "Union[PoolT, Awaitable[PoolT], AbstractContextManager[PoolT], AbstractAsyncContextManager[PoolT]]":
|
|
123
|
+
"""Provide pool instance."""
|
|
124
|
+
raise NotImplementedError
|
|
125
|
+
|
|
126
|
+
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
127
|
+
"""Get the signature namespace for this database configuration.
|
|
128
|
+
|
|
129
|
+
This method returns a dictionary of type names to types that should be
|
|
130
|
+
registered with Litestar's signature namespace to prevent serialization
|
|
131
|
+
attempts on database-specific types.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Dictionary mapping type names to types.
|
|
135
|
+
"""
|
|
136
|
+
return {}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class NoPoolSyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
|
|
140
|
+
"""Base class for a sync database configurations that do not implement a pool."""
|
|
141
|
+
|
|
142
|
+
__slots__ = ("connection_config",)
|
|
143
|
+
is_async: "ClassVar[bool]" = False
|
|
144
|
+
supports_connection_pooling: "ClassVar[bool]" = False
|
|
145
|
+
|
|
146
|
+
def __init__(
|
|
147
|
+
self,
|
|
148
|
+
*,
|
|
149
|
+
connection_config: Optional[dict[str, Any]] = None,
|
|
150
|
+
migration_config: "Optional[dict[str, Any]]" = None,
|
|
151
|
+
statement_config: "Optional[StatementConfig]" = None,
|
|
152
|
+
driver_features: "Optional[dict[str, Any]]" = None,
|
|
153
|
+
) -> None:
|
|
154
|
+
self.pool_instance = None
|
|
155
|
+
self.connection_config = connection_config or {}
|
|
156
|
+
self.migration_config: dict[str, Any] = migration_config if migration_config is not None else {}
|
|
157
|
+
|
|
158
|
+
if statement_config is None:
|
|
159
|
+
default_parameter_config = ParameterStyleConfig(
|
|
160
|
+
default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
|
|
161
|
+
)
|
|
162
|
+
self.statement_config = StatementConfig(dialect="sqlite", parameter_config=default_parameter_config)
|
|
163
|
+
else:
|
|
164
|
+
self.statement_config = statement_config
|
|
165
|
+
self.driver_features = driver_features or {}
|
|
166
|
+
|
|
167
|
+
def create_connection(self) -> ConnectionT:
|
|
168
|
+
"""Create a database connection."""
|
|
169
|
+
raise NotImplementedError
|
|
170
|
+
|
|
171
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "AbstractContextManager[ConnectionT]":
|
|
172
|
+
"""Provide a database connection context manager."""
|
|
173
|
+
raise NotImplementedError
|
|
174
|
+
|
|
175
|
+
def provide_session(
|
|
176
|
+
self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
|
|
177
|
+
) -> "AbstractContextManager[DriverT]":
|
|
178
|
+
"""Provide a database session context manager."""
|
|
179
|
+
raise NotImplementedError
|
|
180
|
+
|
|
181
|
+
def create_pool(self) -> None:
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
def close_pool(self) -> None:
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
def provide_pool(self, *args: Any, **kwargs: Any) -> None:
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class NoPoolAsyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
|
|
192
|
+
"""Base class for an async database configurations that do not implement a pool."""
|
|
193
|
+
|
|
194
|
+
__slots__ = ("connection_config",)
|
|
195
|
+
|
|
196
|
+
is_async: "ClassVar[bool]" = True
|
|
197
|
+
supports_connection_pooling: "ClassVar[bool]" = False
|
|
198
|
+
|
|
199
|
+
def __init__(
|
|
200
|
+
self,
|
|
201
|
+
*,
|
|
202
|
+
connection_config: "Optional[dict[str, Any]]" = None,
|
|
203
|
+
migration_config: "Optional[dict[str, Any]]" = None,
|
|
204
|
+
statement_config: "Optional[StatementConfig]" = None,
|
|
205
|
+
driver_features: "Optional[dict[str, Any]]" = None,
|
|
206
|
+
) -> None:
|
|
207
|
+
self.pool_instance = None
|
|
208
|
+
self.connection_config = connection_config or {}
|
|
209
|
+
self.migration_config: dict[str, Any] = migration_config if migration_config is not None else {}
|
|
210
|
+
|
|
211
|
+
if statement_config is None:
|
|
212
|
+
default_parameter_config = ParameterStyleConfig(
|
|
213
|
+
default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
|
|
214
|
+
)
|
|
215
|
+
self.statement_config = StatementConfig(dialect="sqlite", parameter_config=default_parameter_config)
|
|
216
|
+
else:
|
|
217
|
+
self.statement_config = statement_config
|
|
218
|
+
self.driver_features = driver_features or {}
|
|
219
|
+
|
|
220
|
+
async def create_connection(self) -> ConnectionT:
|
|
221
|
+
"""Create a database connection."""
|
|
222
|
+
raise NotImplementedError
|
|
223
|
+
|
|
224
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "AbstractAsyncContextManager[ConnectionT]":
|
|
225
|
+
"""Provide a database connection context manager."""
|
|
226
|
+
raise NotImplementedError
|
|
227
|
+
|
|
228
|
+
def provide_session(
|
|
229
|
+
self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
|
|
230
|
+
) -> "AbstractAsyncContextManager[DriverT]":
|
|
231
|
+
"""Provide a database session context manager."""
|
|
232
|
+
raise NotImplementedError
|
|
233
|
+
|
|
234
|
+
async def create_pool(self) -> None:
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
async def close_pool(self) -> None:
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
def provide_pool(self, *args: Any, **kwargs: Any) -> None:
|
|
241
|
+
return None
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class SyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
|
|
245
|
+
"""Generic Sync Database Configuration."""
|
|
246
|
+
|
|
247
|
+
__slots__ = ("pool_config",)
|
|
248
|
+
|
|
249
|
+
is_async: "ClassVar[bool]" = False
|
|
250
|
+
supports_connection_pooling: "ClassVar[bool]" = True
|
|
251
|
+
|
|
252
|
+
def __init__(
|
|
253
|
+
self,
|
|
254
|
+
*,
|
|
255
|
+
pool_config: "Optional[dict[str, Any]]" = None,
|
|
256
|
+
pool_instance: "Optional[PoolT]" = None,
|
|
257
|
+
migration_config: "Optional[dict[str, Any]]" = None,
|
|
258
|
+
statement_config: "Optional[StatementConfig]" = None,
|
|
259
|
+
driver_features: "Optional[dict[str, Any]]" = None,
|
|
260
|
+
) -> None:
|
|
261
|
+
self.pool_instance = pool_instance
|
|
262
|
+
self.pool_config = pool_config or {}
|
|
263
|
+
self.migration_config: dict[str, Any] = migration_config if migration_config is not None else {}
|
|
264
|
+
|
|
265
|
+
if statement_config is None:
|
|
266
|
+
default_parameter_config = ParameterStyleConfig(
|
|
267
|
+
default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
|
|
268
|
+
)
|
|
269
|
+
self.statement_config = StatementConfig(dialect="postgres", parameter_config=default_parameter_config)
|
|
270
|
+
else:
|
|
271
|
+
self.statement_config = statement_config
|
|
272
|
+
self.driver_features = driver_features or {}
|
|
273
|
+
|
|
274
|
+
def create_pool(self) -> PoolT:
|
|
275
|
+
"""Create and return the connection pool.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
The created pool.
|
|
279
|
+
"""
|
|
280
|
+
if self.pool_instance is not None:
|
|
281
|
+
return self.pool_instance
|
|
282
|
+
self.pool_instance = self._create_pool()
|
|
283
|
+
return self.pool_instance
|
|
284
|
+
|
|
285
|
+
def close_pool(self) -> None:
|
|
286
|
+
"""Close the connection pool."""
|
|
287
|
+
self._close_pool()
|
|
288
|
+
|
|
289
|
+
def provide_pool(self, *args: Any, **kwargs: Any) -> PoolT:
|
|
290
|
+
"""Provide pool instance."""
|
|
291
|
+
if self.pool_instance is None:
|
|
292
|
+
self.pool_instance = self.create_pool()
|
|
293
|
+
return self.pool_instance
|
|
294
|
+
|
|
295
|
+
def create_connection(self) -> ConnectionT:
|
|
296
|
+
"""Create a database connection."""
|
|
297
|
+
raise NotImplementedError
|
|
298
|
+
|
|
299
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "AbstractContextManager[ConnectionT]":
|
|
300
|
+
"""Provide a database connection context manager."""
|
|
301
|
+
raise NotImplementedError
|
|
302
|
+
|
|
303
|
+
def provide_session(
|
|
304
|
+
self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
|
|
305
|
+
) -> "AbstractContextManager[DriverT]":
|
|
306
|
+
"""Provide a database session context manager."""
|
|
307
|
+
raise NotImplementedError
|
|
308
|
+
|
|
309
|
+
@abstractmethod
|
|
310
|
+
def _create_pool(self) -> PoolT:
|
|
311
|
+
"""Actual pool creation implementation."""
|
|
312
|
+
raise NotImplementedError
|
|
313
|
+
|
|
314
|
+
@abstractmethod
|
|
315
|
+
def _close_pool(self) -> None:
|
|
316
|
+
"""Actual pool destruction implementation."""
|
|
317
|
+
raise NotImplementedError
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class AsyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
|
|
321
|
+
"""Generic Async Database Configuration."""
|
|
322
|
+
|
|
323
|
+
__slots__ = ("pool_config",)
|
|
324
|
+
|
|
325
|
+
is_async: "ClassVar[bool]" = True
|
|
326
|
+
supports_connection_pooling: "ClassVar[bool]" = True
|
|
327
|
+
|
|
328
|
+
def __init__(
|
|
329
|
+
self,
|
|
330
|
+
*,
|
|
331
|
+
pool_config: "Optional[dict[str, Any]]" = None,
|
|
332
|
+
pool_instance: "Optional[PoolT]" = None,
|
|
333
|
+
migration_config: "Optional[dict[str, Any]]" = None,
|
|
334
|
+
statement_config: "Optional[StatementConfig]" = None,
|
|
335
|
+
driver_features: "Optional[dict[str, Any]]" = None,
|
|
336
|
+
) -> None:
|
|
337
|
+
self.pool_instance = pool_instance
|
|
338
|
+
self.pool_config = pool_config or {}
|
|
339
|
+
self.migration_config: dict[str, Any] = migration_config if migration_config is not None else {}
|
|
340
|
+
|
|
341
|
+
if statement_config is None:
|
|
342
|
+
self.statement_config = StatementConfig(
|
|
343
|
+
parameter_config=ParameterStyleConfig(
|
|
344
|
+
default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
|
|
345
|
+
),
|
|
346
|
+
dialect="postgres",
|
|
347
|
+
)
|
|
348
|
+
else:
|
|
349
|
+
self.statement_config = statement_config
|
|
350
|
+
self.driver_features = driver_features or {}
|
|
351
|
+
|
|
352
|
+
async def create_pool(self) -> PoolT:
|
|
353
|
+
"""Create and return the connection pool.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
The created pool.
|
|
357
|
+
"""
|
|
358
|
+
if self.pool_instance is not None:
|
|
359
|
+
return self.pool_instance
|
|
360
|
+
self.pool_instance = await self._create_pool()
|
|
361
|
+
return self.pool_instance
|
|
362
|
+
|
|
363
|
+
async def close_pool(self) -> None:
|
|
364
|
+
"""Close the connection pool."""
|
|
365
|
+
await self._close_pool()
|
|
366
|
+
|
|
367
|
+
async def provide_pool(self, *args: Any, **kwargs: Any) -> PoolT:
|
|
368
|
+
"""Provide pool instance."""
|
|
369
|
+
if self.pool_instance is None:
|
|
370
|
+
self.pool_instance = await self.create_pool()
|
|
371
|
+
return self.pool_instance
|
|
372
|
+
|
|
373
|
+
async def create_connection(self) -> ConnectionT:
|
|
374
|
+
"""Create a database connection."""
|
|
375
|
+
raise NotImplementedError
|
|
376
|
+
|
|
377
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "AbstractAsyncContextManager[ConnectionT]":
|
|
378
|
+
"""Provide a database connection context manager."""
|
|
379
|
+
raise NotImplementedError
|
|
380
|
+
|
|
381
|
+
def provide_session(
|
|
382
|
+
self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
|
|
383
|
+
) -> "AbstractAsyncContextManager[DriverT]":
|
|
384
|
+
"""Provide a database session context manager."""
|
|
385
|
+
raise NotImplementedError
|
|
386
|
+
|
|
387
|
+
@abstractmethod
|
|
388
|
+
async def _create_pool(self) -> PoolT:
|
|
389
|
+
"""Actual async pool creation implementation."""
|
|
390
|
+
raise NotImplementedError
|
|
391
|
+
|
|
392
|
+
@abstractmethod
|
|
393
|
+
async def _close_pool(self) -> None:
|
|
394
|
+
"""Actual async pool destruction implementation."""
|
|
395
|
+
raise NotImplementedError
|