sqlspec 0.13.1__py3-none-any.whl → 0.16.2__py3-none-any.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.
- sqlspec/__init__.py +71 -8
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +1 -3
- sqlspec/_serialization.py +1 -2
- sqlspec/_sql.py +930 -136
- sqlspec/_typing.py +278 -142
- sqlspec/adapters/adbc/__init__.py +4 -3
- sqlspec/adapters/adbc/_types.py +12 -0
- sqlspec/adapters/adbc/config.py +116 -285
- sqlspec/adapters/adbc/driver.py +462 -340
- sqlspec/adapters/aiosqlite/__init__.py +18 -3
- sqlspec/adapters/aiosqlite/_types.py +13 -0
- sqlspec/adapters/aiosqlite/config.py +202 -150
- sqlspec/adapters/aiosqlite/driver.py +226 -247
- sqlspec/adapters/asyncmy/__init__.py +18 -3
- sqlspec/adapters/asyncmy/_types.py +12 -0
- sqlspec/adapters/asyncmy/config.py +80 -199
- sqlspec/adapters/asyncmy/driver.py +257 -215
- sqlspec/adapters/asyncpg/__init__.py +19 -4
- sqlspec/adapters/asyncpg/_types.py +17 -0
- sqlspec/adapters/asyncpg/config.py +81 -214
- sqlspec/adapters/asyncpg/driver.py +284 -359
- sqlspec/adapters/bigquery/__init__.py +17 -3
- sqlspec/adapters/bigquery/_types.py +12 -0
- sqlspec/adapters/bigquery/config.py +191 -299
- sqlspec/adapters/bigquery/driver.py +474 -634
- sqlspec/adapters/duckdb/__init__.py +14 -3
- sqlspec/adapters/duckdb/_types.py +12 -0
- sqlspec/adapters/duckdb/config.py +414 -397
- sqlspec/adapters/duckdb/driver.py +342 -393
- sqlspec/adapters/oracledb/__init__.py +19 -5
- sqlspec/adapters/oracledb/_types.py +14 -0
- sqlspec/adapters/oracledb/config.py +123 -458
- sqlspec/adapters/oracledb/driver.py +505 -531
- sqlspec/adapters/psqlpy/__init__.py +13 -3
- sqlspec/adapters/psqlpy/_types.py +11 -0
- sqlspec/adapters/psqlpy/config.py +93 -307
- sqlspec/adapters/psqlpy/driver.py +504 -213
- sqlspec/adapters/psycopg/__init__.py +19 -5
- sqlspec/adapters/psycopg/_types.py +17 -0
- sqlspec/adapters/psycopg/config.py +143 -472
- sqlspec/adapters/psycopg/driver.py +704 -825
- sqlspec/adapters/sqlite/__init__.py +14 -3
- sqlspec/adapters/sqlite/_types.py +11 -0
- sqlspec/adapters/sqlite/config.py +208 -142
- sqlspec/adapters/sqlite/driver.py +263 -278
- sqlspec/base.py +105 -9
- sqlspec/{statement/builder → builder}/__init__.py +12 -14
- sqlspec/{statement/builder/base.py → builder/_base.py} +184 -86
- sqlspec/{statement/builder/column.py → builder/_column.py} +97 -60
- sqlspec/{statement/builder/ddl.py → builder/_ddl.py} +61 -131
- sqlspec/{statement/builder → builder}/_ddl_utils.py +4 -10
- sqlspec/{statement/builder/delete.py → builder/_delete.py} +10 -30
- sqlspec/builder/_insert.py +421 -0
- sqlspec/builder/_merge.py +71 -0
- sqlspec/{statement/builder → builder}/_parsing_utils.py +49 -26
- sqlspec/builder/_select.py +170 -0
- sqlspec/{statement/builder/update.py → builder/_update.py} +16 -20
- sqlspec/builder/mixins/__init__.py +55 -0
- sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
- sqlspec/{statement/builder/mixins/_delete_from.py → builder/mixins/_delete_operations.py} +8 -1
- sqlspec/builder/mixins/_insert_operations.py +244 -0
- sqlspec/{statement/builder/mixins/_join.py → builder/mixins/_join_operations.py} +45 -13
- sqlspec/{statement/builder/mixins/_merge_clauses.py → builder/mixins/_merge_operations.py} +188 -30
- 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 +183 -138
- sqlspec/core/__init__.py +63 -0
- sqlspec/core/cache.py +871 -0
- sqlspec/core/compiler.py +417 -0
- sqlspec/core/filters.py +830 -0
- sqlspec/core/hashing.py +310 -0
- sqlspec/core/parameters.py +1237 -0
- sqlspec/core/result.py +677 -0
- sqlspec/{statement → core}/splitter.py +321 -191
- sqlspec/core/statement.py +676 -0
- sqlspec/driver/__init__.py +7 -10
- sqlspec/driver/_async.py +422 -163
- sqlspec/driver/_common.py +545 -287
- sqlspec/driver/_sync.py +426 -160
- sqlspec/driver/mixins/__init__.py +2 -13
- sqlspec/driver/mixins/_result_tools.py +193 -0
- sqlspec/driver/mixins/_sql_translator.py +65 -14
- sqlspec/exceptions.py +5 -252
- sqlspec/extensions/aiosql/adapter.py +93 -96
- sqlspec/extensions/litestar/__init__.py +2 -1
- sqlspec/extensions/litestar/cli.py +48 -0
- sqlspec/extensions/litestar/config.py +0 -1
- sqlspec/extensions/litestar/handlers.py +15 -26
- sqlspec/extensions/litestar/plugin.py +21 -16
- sqlspec/extensions/litestar/providers.py +17 -52
- sqlspec/loader.py +423 -104
- 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 +51 -186
- sqlspec/storage/__init__.py +1 -1
- sqlspec/storage/backends/base.py +37 -40
- sqlspec/storage/backends/fsspec.py +136 -112
- sqlspec/storage/backends/obstore.py +138 -160
- sqlspec/storage/capabilities.py +5 -4
- sqlspec/storage/registry.py +57 -106
- sqlspec/typing.py +136 -115
- sqlspec/utils/__init__.py +2 -2
- sqlspec/utils/correlation.py +0 -3
- sqlspec/utils/deprecation.py +6 -6
- sqlspec/utils/fixtures.py +6 -6
- sqlspec/utils/logging.py +0 -2
- sqlspec/utils/module_loader.py +7 -12
- sqlspec/utils/singleton.py +0 -1
- sqlspec/utils/sync_tools.py +17 -38
- sqlspec/utils/text.py +12 -51
- sqlspec/utils/type_guards.py +482 -235
- {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/METADATA +7 -2
- sqlspec-0.16.2.dist-info/RECORD +134 -0
- sqlspec-0.16.2.dist-info/entry_points.txt +2 -0
- sqlspec/driver/connection.py +0 -207
- sqlspec/driver/mixins/_csv_writer.py +0 -91
- sqlspec/driver/mixins/_pipeline.py +0 -512
- sqlspec/driver/mixins/_result_utils.py +0 -140
- sqlspec/driver/mixins/_storage.py +0 -926
- sqlspec/driver/mixins/_type_coercion.py +0 -130
- sqlspec/driver/parameters.py +0 -138
- sqlspec/service/__init__.py +0 -4
- sqlspec/service/_util.py +0 -147
- sqlspec/service/base.py +0 -1131
- sqlspec/service/pagination.py +0 -26
- sqlspec/statement/__init__.py +0 -21
- sqlspec/statement/builder/insert.py +0 -288
- sqlspec/statement/builder/merge.py +0 -95
- sqlspec/statement/builder/mixins/__init__.py +0 -65
- sqlspec/statement/builder/mixins/_aggregate_functions.py +0 -250
- sqlspec/statement/builder/mixins/_case_builder.py +0 -91
- sqlspec/statement/builder/mixins/_common_table_expr.py +0 -90
- sqlspec/statement/builder/mixins/_from.py +0 -63
- sqlspec/statement/builder/mixins/_group_by.py +0 -118
- sqlspec/statement/builder/mixins/_having.py +0 -35
- sqlspec/statement/builder/mixins/_insert_from_select.py +0 -47
- sqlspec/statement/builder/mixins/_insert_into.py +0 -36
- sqlspec/statement/builder/mixins/_insert_values.py +0 -67
- sqlspec/statement/builder/mixins/_limit_offset.py +0 -53
- sqlspec/statement/builder/mixins/_order_by.py +0 -46
- sqlspec/statement/builder/mixins/_pivot.py +0 -79
- sqlspec/statement/builder/mixins/_returning.py +0 -37
- sqlspec/statement/builder/mixins/_select_columns.py +0 -61
- sqlspec/statement/builder/mixins/_set_ops.py +0 -122
- sqlspec/statement/builder/mixins/_unpivot.py +0 -77
- sqlspec/statement/builder/mixins/_update_from.py +0 -55
- sqlspec/statement/builder/mixins/_update_set.py +0 -94
- sqlspec/statement/builder/mixins/_update_table.py +0 -29
- sqlspec/statement/builder/mixins/_where.py +0 -401
- sqlspec/statement/builder/mixins/_window_functions.py +0 -86
- sqlspec/statement/builder/select.py +0 -221
- sqlspec/statement/filters.py +0 -596
- sqlspec/statement/parameter_manager.py +0 -220
- sqlspec/statement/parameters.py +0 -867
- sqlspec/statement/pipelines/__init__.py +0 -210
- sqlspec/statement/pipelines/analyzers/__init__.py +0 -9
- sqlspec/statement/pipelines/analyzers/_analyzer.py +0 -646
- sqlspec/statement/pipelines/context.py +0 -115
- sqlspec/statement/pipelines/transformers/__init__.py +0 -7
- sqlspec/statement/pipelines/transformers/_expression_simplifier.py +0 -88
- sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +0 -1247
- sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +0 -76
- sqlspec/statement/pipelines/validators/__init__.py +0 -23
- sqlspec/statement/pipelines/validators/_dml_safety.py +0 -290
- sqlspec/statement/pipelines/validators/_parameter_style.py +0 -370
- sqlspec/statement/pipelines/validators/_performance.py +0 -718
- sqlspec/statement/pipelines/validators/_security.py +0 -967
- sqlspec/statement/result.py +0 -435
- sqlspec/statement/sql.py +0 -1704
- sqlspec/statement/sql_compiler.py +0 -140
- sqlspec/utils/cached_property.py +0 -25
- sqlspec-0.13.1.dist-info/RECORD +0 -150
- {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/WHEEL +0 -0
- {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/NOTICE +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Migration version tracking for SQLSpec.
|
|
2
|
+
|
|
3
|
+
This module provides functionality to track applied migrations in the database.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
8
|
+
|
|
9
|
+
from sqlspec.migrations.base import BaseMigrationTracker
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
|
|
13
|
+
|
|
14
|
+
__all__ = ("AsyncMigrationTracker", "SyncMigrationTracker")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SyncMigrationTracker(BaseMigrationTracker["SyncDriverAdapterBase"]):
|
|
18
|
+
"""Tracks applied migrations in the database."""
|
|
19
|
+
|
|
20
|
+
def ensure_tracking_table(self, driver: "SyncDriverAdapterBase") -> None:
|
|
21
|
+
"""Create the migration tracking table if it doesn't exist.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
driver: The database driver to use.
|
|
25
|
+
"""
|
|
26
|
+
driver.execute(self._get_create_table_sql())
|
|
27
|
+
|
|
28
|
+
def get_current_version(self, driver: "SyncDriverAdapterBase") -> Optional[str]:
|
|
29
|
+
"""Get the latest applied migration version.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
driver: The database driver to use.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
The current version number or None if no migrations applied.
|
|
36
|
+
"""
|
|
37
|
+
result = driver.execute(self._get_current_version_sql())
|
|
38
|
+
return result.data[0]["version_num"] if result.data else None
|
|
39
|
+
|
|
40
|
+
def get_applied_migrations(self, driver: "SyncDriverAdapterBase") -> "list[dict[str, Any]]":
|
|
41
|
+
"""Get all applied migrations in order.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
driver: The database driver to use.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
List of migration records.
|
|
48
|
+
"""
|
|
49
|
+
result = driver.execute(self._get_applied_migrations_sql())
|
|
50
|
+
return result.data or []
|
|
51
|
+
|
|
52
|
+
def record_migration(
|
|
53
|
+
self, driver: "SyncDriverAdapterBase", version: str, description: str, execution_time_ms: int, checksum: str
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Record a successfully applied migration.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
driver: The database driver to use.
|
|
59
|
+
version: Version number of the migration.
|
|
60
|
+
description: Description of the migration.
|
|
61
|
+
execution_time_ms: Execution time in milliseconds.
|
|
62
|
+
checksum: MD5 checksum of the migration content.
|
|
63
|
+
"""
|
|
64
|
+
driver.execute(
|
|
65
|
+
self._get_record_migration_sql(
|
|
66
|
+
version, description, execution_time_ms, checksum, os.environ.get("USER", "unknown")
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def remove_migration(self, driver: "SyncDriverAdapterBase", version: str) -> None:
|
|
71
|
+
"""Remove a migration record (used during downgrade).
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
driver: The database driver to use.
|
|
75
|
+
version: Version number to remove.
|
|
76
|
+
"""
|
|
77
|
+
driver.execute(self._get_remove_migration_sql(version))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class AsyncMigrationTracker(BaseMigrationTracker["AsyncDriverAdapterBase"]):
|
|
81
|
+
"""Tracks applied migrations in the database."""
|
|
82
|
+
|
|
83
|
+
async def ensure_tracking_table(self, driver: "AsyncDriverAdapterBase") -> None:
|
|
84
|
+
"""Create the migration tracking table if it doesn't exist.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
driver: The database driver to use.
|
|
88
|
+
"""
|
|
89
|
+
await driver.execute(self._get_create_table_sql())
|
|
90
|
+
|
|
91
|
+
async def get_current_version(self, driver: "AsyncDriverAdapterBase") -> Optional[str]:
|
|
92
|
+
"""Get the latest applied migration version.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
driver: The database driver to use.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
The current version number or None if no migrations applied.
|
|
99
|
+
"""
|
|
100
|
+
result = await driver.execute(self._get_current_version_sql())
|
|
101
|
+
return result.data[0]["version_num"] if result.data else None
|
|
102
|
+
|
|
103
|
+
async def get_applied_migrations(self, driver: "AsyncDriverAdapterBase") -> "list[dict[str, Any]]":
|
|
104
|
+
"""Get all applied migrations in order.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
driver: The database driver to use.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
List of migration records.
|
|
111
|
+
"""
|
|
112
|
+
result = await driver.execute(self._get_applied_migrations_sql())
|
|
113
|
+
return result.data or []
|
|
114
|
+
|
|
115
|
+
async def record_migration(
|
|
116
|
+
self, driver: "AsyncDriverAdapterBase", version: str, description: str, execution_time_ms: int, checksum: str
|
|
117
|
+
) -> None:
|
|
118
|
+
"""Record a successfully applied migration.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
driver: The database driver to use.
|
|
122
|
+
version: Version number of the migration.
|
|
123
|
+
description: Description of the migration.
|
|
124
|
+
execution_time_ms: Execution time in milliseconds.
|
|
125
|
+
checksum: MD5 checksum of the migration content.
|
|
126
|
+
"""
|
|
127
|
+
await driver.execute(
|
|
128
|
+
self._get_record_migration_sql(
|
|
129
|
+
version, description, execution_time_ms, checksum, os.environ.get("USER", "unknown")
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
async def remove_migration(self, driver: "AsyncDriverAdapterBase", version: str) -> None:
|
|
134
|
+
"""Remove a migration record (used during downgrade).
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
driver: The database driver to use.
|
|
138
|
+
version: Version number to remove.
|
|
139
|
+
"""
|
|
140
|
+
await driver.execute(self._get_remove_migration_sql(version))
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Utility functions for SQLSpec migrations.
|
|
2
|
+
|
|
3
|
+
This module provides helper functions for migration operations.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from sqlspec.driver import AsyncDriverAdapterBase
|
|
13
|
+
|
|
14
|
+
__all__ = ("create_migration_file", "drop_all", "get_author")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_migration_file(migrations_dir: Path, version: str, message: str, file_type: str = "sql") -> Path:
|
|
18
|
+
"""Create a new migration file from template.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
migrations_dir: Directory to create the migration in.
|
|
22
|
+
version: Version number for the migration.
|
|
23
|
+
message: Description message for the migration.
|
|
24
|
+
file_type: Type of migration file to create ('sql' or 'py').
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Path to the created migration file.
|
|
28
|
+
"""
|
|
29
|
+
safe_message = message.lower()
|
|
30
|
+
safe_message = "".join(c if c.isalnum() or c in " -" else "" for c in safe_message)
|
|
31
|
+
safe_message = safe_message.replace(" ", "_").replace("-", "_")
|
|
32
|
+
safe_message = "_".join(filter(None, safe_message.split("_")))[:50]
|
|
33
|
+
|
|
34
|
+
if file_type == "py":
|
|
35
|
+
filename = f"{version}_{safe_message}.py"
|
|
36
|
+
file_path = migrations_dir / filename
|
|
37
|
+
template = f'''"""SQLSpec Migration - {message}
|
|
38
|
+
|
|
39
|
+
Version: {version}
|
|
40
|
+
Created: {datetime.now(timezone.utc).isoformat()}
|
|
41
|
+
Author: {get_author()}
|
|
42
|
+
|
|
43
|
+
Migration functions can use either naming convention:
|
|
44
|
+
- Preferred: up()/down()
|
|
45
|
+
- Legacy: migrate_up()/migrate_down()
|
|
46
|
+
|
|
47
|
+
Both can be synchronous or asynchronous:
|
|
48
|
+
- def up(): ...
|
|
49
|
+
- async def up(): ...
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
from typing import List, Union
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def up() -> Union[str, List[str]]:
|
|
56
|
+
"""Apply the migration (upgrade).
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
SQL statement(s) to execute for upgrade.
|
|
60
|
+
Can return a single string or list of strings.
|
|
61
|
+
|
|
62
|
+
Note: You can use either 'up()' or 'migrate_up()' for function names.
|
|
63
|
+
Both support async versions: 'async def up()' or 'async def migrate_up()'
|
|
64
|
+
"""
|
|
65
|
+
return """
|
|
66
|
+
CREATE TABLE example (
|
|
67
|
+
id INTEGER PRIMARY KEY,
|
|
68
|
+
name TEXT NOT NULL
|
|
69
|
+
);
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def down() -> Union[str, List[str]]:
|
|
74
|
+
"""Reverse the migration (downgrade).
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
SQL statement(s) to execute for downgrade.
|
|
78
|
+
Can return a single string or list of strings.
|
|
79
|
+
Return empty string or empty list if downgrade is not supported.
|
|
80
|
+
|
|
81
|
+
Note: You can use either 'down()' or 'migrate_down()' for function names.
|
|
82
|
+
Both support async versions: 'async def down()' or 'async def migrate_down()'
|
|
83
|
+
"""
|
|
84
|
+
return "DROP TABLE example;"
|
|
85
|
+
'''
|
|
86
|
+
else:
|
|
87
|
+
filename = f"{version}_{safe_message}.sql"
|
|
88
|
+
file_path = migrations_dir / filename
|
|
89
|
+
template = f"""-- SQLSpec Migration
|
|
90
|
+
-- Version: {version}
|
|
91
|
+
-- Description: {message}
|
|
92
|
+
-- Created: {datetime.now(timezone.utc).isoformat()}
|
|
93
|
+
-- Author: {get_author()}
|
|
94
|
+
|
|
95
|
+
-- name: migrate-{version}-up
|
|
96
|
+
CREATE TABLE placeholder (
|
|
97
|
+
id INTEGER PRIMARY KEY
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
-- name: migrate-{version}-down
|
|
101
|
+
DROP TABLE placeholder;
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
file_path.write_text(template)
|
|
105
|
+
return file_path
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_author() -> str:
|
|
109
|
+
"""Get current user for migration metadata.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Username from environment or 'unknown'.
|
|
113
|
+
"""
|
|
114
|
+
return os.environ.get("USER", "unknown")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
async def drop_all(engine: "AsyncDriverAdapterBase", version_table_name: str, metadata: Optional[Any] = None) -> None:
|
|
118
|
+
"""Drop all tables from the database.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
engine: The database engine/driver.
|
|
122
|
+
version_table_name: Name of the version tracking table.
|
|
123
|
+
metadata: Optional metadata object.
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
NotImplementedError: Always raised.
|
|
127
|
+
"""
|
|
128
|
+
msg = "drop_all functionality requires database-specific implementation"
|
|
129
|
+
raise NotImplementedError(msg)
|
sqlspec/protocols.py
CHANGED
|
@@ -4,7 +4,6 @@ This module provides protocols that can be used for static type checking
|
|
|
4
4
|
and runtime isinstance() checks, replacing defensive hasattr() patterns.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from abc import abstractmethod
|
|
8
7
|
from typing import TYPE_CHECKING, Any, ClassVar, Optional, Protocol, Union, runtime_checkable
|
|
9
8
|
|
|
10
9
|
from typing_extensions import Self
|
|
@@ -15,41 +14,31 @@ if TYPE_CHECKING:
|
|
|
15
14
|
|
|
16
15
|
from sqlglot import exp
|
|
17
16
|
|
|
18
|
-
from sqlspec.statement.pipelines.context import SQLProcessingContext
|
|
19
17
|
from sqlspec.storage.capabilities import StorageCapabilities
|
|
20
18
|
from sqlspec.typing import ArrowRecordBatch, ArrowTable
|
|
21
19
|
|
|
22
20
|
__all__ = (
|
|
23
|
-
# Database Connection Protocols
|
|
24
|
-
"AsyncCloseableConnectionProtocol",
|
|
25
|
-
"AsyncCopyCapableConnectionProtocol",
|
|
26
|
-
"AsyncPipelineCapableDriverProtocol",
|
|
27
|
-
"AsyncTransactionCapableConnectionProtocol",
|
|
28
|
-
"AsyncTransactionStateConnectionProtocol",
|
|
29
21
|
"BytesConvertibleProtocol",
|
|
30
22
|
"DictProtocol",
|
|
31
23
|
"FilterAppenderProtocol",
|
|
32
24
|
"FilterParameterProtocol",
|
|
25
|
+
"HasExpressionProtocol",
|
|
33
26
|
"HasExpressionsProtocol",
|
|
34
27
|
"HasLimitProtocol",
|
|
35
28
|
"HasOffsetProtocol",
|
|
36
29
|
"HasOrderByProtocol",
|
|
37
|
-
"
|
|
30
|
+
"HasParameterBuilderProtocol",
|
|
31
|
+
"HasSQLGlotExpressionProtocol",
|
|
38
32
|
"HasSQLMethodProtocol",
|
|
33
|
+
"HasToStatementProtocol",
|
|
39
34
|
"HasWhereProtocol",
|
|
40
35
|
"IndexableRow",
|
|
41
36
|
"IterableParameters",
|
|
42
37
|
"ObjectStoreItemProtocol",
|
|
43
38
|
"ObjectStoreProtocol",
|
|
44
39
|
"ParameterValueProtocol",
|
|
45
|
-
"ProcessorProtocol",
|
|
46
40
|
"SQLBuilderProtocol",
|
|
47
41
|
"SelectBuilderProtocol",
|
|
48
|
-
"SyncCloseableConnectionProtocol",
|
|
49
|
-
"SyncCopyCapableConnectionProtocol",
|
|
50
|
-
"SyncPipelineCapableDriverProtocol",
|
|
51
|
-
"SyncTransactionCapableConnectionProtocol",
|
|
52
|
-
"SyncTransactionStateConnectionProtocol",
|
|
53
42
|
"WithMethodProtocol",
|
|
54
43
|
)
|
|
55
44
|
|
|
@@ -167,16 +156,6 @@ class ParameterValueProtocol(Protocol):
|
|
|
167
156
|
type_hint: str
|
|
168
157
|
|
|
169
158
|
|
|
170
|
-
@runtime_checkable
|
|
171
|
-
class HasRiskLevelProtocol(Protocol):
|
|
172
|
-
"""Protocol for objects with a risk_level attribute."""
|
|
173
|
-
|
|
174
|
-
@property
|
|
175
|
-
def risk_level(self) -> Any:
|
|
176
|
-
"""Get the risk level of this object."""
|
|
177
|
-
...
|
|
178
|
-
|
|
179
|
-
|
|
180
159
|
@runtime_checkable
|
|
181
160
|
class DictProtocol(Protocol):
|
|
182
161
|
"""Protocol for objects with a __dict__ attribute."""
|
|
@@ -184,25 +163,6 @@ class DictProtocol(Protocol):
|
|
|
184
163
|
__dict__: dict[str, Any]
|
|
185
164
|
|
|
186
165
|
|
|
187
|
-
class ProcessorProtocol(Protocol):
|
|
188
|
-
"""Defines the interface for a single processing step in the SQL pipeline."""
|
|
189
|
-
|
|
190
|
-
@abstractmethod
|
|
191
|
-
def process(
|
|
192
|
-
self, expression: "Optional[exp.Expression]", context: "SQLProcessingContext"
|
|
193
|
-
) -> "Optional[exp.Expression]":
|
|
194
|
-
"""Processes an SQL expression.
|
|
195
|
-
|
|
196
|
-
Args:
|
|
197
|
-
expression: The SQL expression to process.
|
|
198
|
-
context: The SQLProcessingContext holding the current state and config.
|
|
199
|
-
|
|
200
|
-
Returns:
|
|
201
|
-
The (possibly modified) SQL expression for transformers, or None for validators/analyzers.
|
|
202
|
-
"""
|
|
203
|
-
...
|
|
204
|
-
|
|
205
|
-
|
|
206
166
|
@runtime_checkable
|
|
207
167
|
class BytesConvertibleProtocol(Protocol):
|
|
208
168
|
"""Protocol for objects that can be converted to bytes."""
|
|
@@ -220,138 +180,20 @@ class ObjectStoreItemProtocol(Protocol):
|
|
|
220
180
|
key: "Optional[str]"
|
|
221
181
|
|
|
222
182
|
|
|
223
|
-
@runtime_checkable
|
|
224
|
-
class SyncTransactionCapableConnectionProtocol(Protocol):
|
|
225
|
-
"""Protocol for sync connections that support transactions."""
|
|
226
|
-
|
|
227
|
-
def commit(self) -> None:
|
|
228
|
-
"""Commit the current transaction."""
|
|
229
|
-
...
|
|
230
|
-
|
|
231
|
-
def rollback(self) -> None:
|
|
232
|
-
"""Rollback the current transaction."""
|
|
233
|
-
...
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
@runtime_checkable
|
|
237
|
-
class AsyncTransactionCapableConnectionProtocol(Protocol):
|
|
238
|
-
"""Protocol for async connections that support transactions."""
|
|
239
|
-
|
|
240
|
-
async def commit(self) -> None:
|
|
241
|
-
"""Commit the current transaction."""
|
|
242
|
-
...
|
|
243
|
-
|
|
244
|
-
async def rollback(self) -> None:
|
|
245
|
-
"""Rollback the current transaction."""
|
|
246
|
-
...
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
@runtime_checkable
|
|
250
|
-
class SyncTransactionStateConnectionProtocol(SyncTransactionCapableConnectionProtocol, Protocol):
|
|
251
|
-
"""Protocol for sync connections that can report transaction state."""
|
|
252
|
-
|
|
253
|
-
def in_transaction(self) -> bool:
|
|
254
|
-
"""Check if connection is currently in a transaction."""
|
|
255
|
-
...
|
|
256
|
-
|
|
257
|
-
def begin(self) -> None:
|
|
258
|
-
"""Begin a new transaction."""
|
|
259
|
-
...
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
@runtime_checkable
|
|
263
|
-
class AsyncTransactionStateConnectionProtocol(AsyncTransactionCapableConnectionProtocol, Protocol):
|
|
264
|
-
"""Protocol for async connections that can report transaction state."""
|
|
265
|
-
|
|
266
|
-
def in_transaction(self) -> bool:
|
|
267
|
-
"""Check if connection is currently in a transaction."""
|
|
268
|
-
...
|
|
269
|
-
|
|
270
|
-
async def begin(self) -> None:
|
|
271
|
-
"""Begin a new transaction."""
|
|
272
|
-
...
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
@runtime_checkable
|
|
276
|
-
class SyncCloseableConnectionProtocol(Protocol):
|
|
277
|
-
"""Protocol for sync connections that can be closed."""
|
|
278
|
-
|
|
279
|
-
def close(self) -> None:
|
|
280
|
-
"""Close the connection."""
|
|
281
|
-
...
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
@runtime_checkable
|
|
285
|
-
class AsyncCloseableConnectionProtocol(Protocol):
|
|
286
|
-
"""Protocol for async connections that can be closed."""
|
|
287
|
-
|
|
288
|
-
async def close(self) -> None:
|
|
289
|
-
"""Close the connection."""
|
|
290
|
-
...
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
@runtime_checkable
|
|
294
|
-
class SyncCopyCapableConnectionProtocol(Protocol):
|
|
295
|
-
"""Protocol for sync connections that support COPY operations."""
|
|
296
|
-
|
|
297
|
-
def copy_from(self, table: str, file: Any, **kwargs: Any) -> None:
|
|
298
|
-
"""Copy data from file to table."""
|
|
299
|
-
...
|
|
300
|
-
|
|
301
|
-
def copy_to(self, table: str, file: Any, **kwargs: Any) -> None:
|
|
302
|
-
"""Copy data from table to file."""
|
|
303
|
-
...
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
@runtime_checkable
|
|
307
|
-
class AsyncCopyCapableConnectionProtocol(Protocol):
|
|
308
|
-
"""Protocol for async connections that support COPY operations."""
|
|
309
|
-
|
|
310
|
-
async def copy_from(self, table: str, file: Any, **kwargs: Any) -> None:
|
|
311
|
-
"""Copy data from file to table."""
|
|
312
|
-
...
|
|
313
|
-
|
|
314
|
-
async def copy_to(self, table: str, file: Any, **kwargs: Any) -> None:
|
|
315
|
-
"""Copy data from table to file."""
|
|
316
|
-
...
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
@runtime_checkable
|
|
320
|
-
class SyncPipelineCapableDriverProtocol(Protocol):
|
|
321
|
-
"""Protocol for sync drivers that support native pipeline execution."""
|
|
322
|
-
|
|
323
|
-
def _execute_pipeline_native(self, operations: list[Any], **options: Any) -> list[Any]:
|
|
324
|
-
"""Execute pipeline operations natively."""
|
|
325
|
-
...
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
@runtime_checkable
|
|
329
|
-
class AsyncPipelineCapableDriverProtocol(Protocol):
|
|
330
|
-
"""Protocol for async drivers that support native pipeline execution."""
|
|
331
|
-
|
|
332
|
-
async def _execute_pipeline_native(self, operations: list[Any], **options: Any) -> list[Any]:
|
|
333
|
-
"""Execute pipeline operations natively."""
|
|
334
|
-
...
|
|
335
|
-
|
|
336
|
-
|
|
337
183
|
@runtime_checkable
|
|
338
184
|
class ObjectStoreProtocol(Protocol):
|
|
339
|
-
"""
|
|
185
|
+
"""Protocol for object storage operations.
|
|
340
186
|
|
|
341
|
-
|
|
342
|
-
instrumentation support. Backends must implement both sync and async operations
|
|
343
|
-
where possible, with async operations suffixed with _async.
|
|
344
|
-
|
|
345
|
-
All methods use 'path' terminology for consistency with object store patterns.
|
|
187
|
+
Defines the interface for storage backends with both sync and async operations.
|
|
346
188
|
"""
|
|
347
189
|
|
|
348
|
-
# Class-level capability descriptor
|
|
349
190
|
capabilities: ClassVar["StorageCapabilities"]
|
|
350
191
|
|
|
192
|
+
protocol: str
|
|
193
|
+
|
|
351
194
|
def __init__(self, uri: str, **kwargs: Any) -> None:
|
|
352
195
|
return
|
|
353
196
|
|
|
354
|
-
# Core Operations (sync)
|
|
355
197
|
def read_bytes(self, path: "Union[str, Path]", **kwargs: Any) -> bytes:
|
|
356
198
|
"""Read bytes from an object."""
|
|
357
199
|
return b""
|
|
@@ -368,7 +210,6 @@ class ObjectStoreProtocol(Protocol):
|
|
|
368
210
|
"""Write text to an object."""
|
|
369
211
|
return
|
|
370
212
|
|
|
371
|
-
# Object Operations
|
|
372
213
|
def exists(self, path: "Union[str, Path]", **kwargs: Any) -> bool:
|
|
373
214
|
"""Check if an object exists."""
|
|
374
215
|
return False
|
|
@@ -385,7 +226,6 @@ class ObjectStoreProtocol(Protocol):
|
|
|
385
226
|
"""Move an object."""
|
|
386
227
|
return
|
|
387
228
|
|
|
388
|
-
# Listing Operations
|
|
389
229
|
def list_objects(self, prefix: str = "", recursive: bool = True, **kwargs: Any) -> list[str]:
|
|
390
230
|
"""List objects with optional prefix."""
|
|
391
231
|
return []
|
|
@@ -394,7 +234,6 @@ class ObjectStoreProtocol(Protocol):
|
|
|
394
234
|
"""Find objects matching a glob pattern."""
|
|
395
235
|
return []
|
|
396
236
|
|
|
397
|
-
# Path Operations
|
|
398
237
|
def is_object(self, path: "Union[str, Path]") -> bool:
|
|
399
238
|
"""Check if path points to an object."""
|
|
400
239
|
return False
|
|
@@ -407,32 +246,21 @@ class ObjectStoreProtocol(Protocol):
|
|
|
407
246
|
"""Get object metadata."""
|
|
408
247
|
return {}
|
|
409
248
|
|
|
410
|
-
# Arrow Operations
|
|
411
249
|
def read_arrow(self, path: "Union[str, Path]", **kwargs: Any) -> "ArrowTable":
|
|
412
|
-
"""Read an Arrow table from storage.
|
|
413
|
-
|
|
414
|
-
For obstore backend, this should use native arrow operations when available.
|
|
415
|
-
"""
|
|
250
|
+
"""Read an Arrow table from storage."""
|
|
416
251
|
msg = "Arrow reading not implemented"
|
|
417
252
|
raise NotImplementedError(msg)
|
|
418
253
|
|
|
419
254
|
def write_arrow(self, path: "Union[str, Path]", table: "ArrowTable", **kwargs: Any) -> None:
|
|
420
|
-
"""Write an Arrow table to storage.
|
|
421
|
-
|
|
422
|
-
For obstore backend, this should use native arrow operations when available.
|
|
423
|
-
"""
|
|
255
|
+
"""Write an Arrow table to storage."""
|
|
424
256
|
msg = "Arrow writing not implemented"
|
|
425
257
|
raise NotImplementedError(msg)
|
|
426
258
|
|
|
427
259
|
def stream_arrow(self, pattern: str, **kwargs: Any) -> "Iterator[ArrowRecordBatch]":
|
|
428
|
-
"""Stream Arrow record batches from matching objects.
|
|
429
|
-
|
|
430
|
-
For obstore backend, this should use native streaming when available.
|
|
431
|
-
"""
|
|
260
|
+
"""Stream Arrow record batches from matching objects."""
|
|
432
261
|
msg = "Arrow streaming not implemented"
|
|
433
262
|
raise NotImplementedError(msg)
|
|
434
263
|
|
|
435
|
-
# Async versions
|
|
436
264
|
async def read_bytes_async(self, path: "Union[str, Path]", **kwargs: Any) -> bytes:
|
|
437
265
|
"""Async read bytes from an object."""
|
|
438
266
|
msg = "Async operations not implemented"
|
|
@@ -501,9 +329,39 @@ class ObjectStoreProtocol(Protocol):
|
|
|
501
329
|
raise NotImplementedError(msg)
|
|
502
330
|
|
|
503
331
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
332
|
+
@runtime_checkable
|
|
333
|
+
class HasSQLGlotExpressionProtocol(Protocol):
|
|
334
|
+
"""Protocol for objects with a sqlglot_expression property."""
|
|
335
|
+
|
|
336
|
+
@property
|
|
337
|
+
def sqlglot_expression(self) -> "Optional[exp.Expression]":
|
|
338
|
+
"""Return the SQLGlot expression for this object."""
|
|
339
|
+
...
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@runtime_checkable
|
|
343
|
+
class HasParameterBuilderProtocol(Protocol):
|
|
344
|
+
"""Protocol for objects that can add parameters."""
|
|
345
|
+
|
|
346
|
+
def add_parameter(self, value: Any, name: "Optional[str]" = None) -> tuple[Any, str]:
|
|
347
|
+
"""Add a parameter to the builder."""
|
|
348
|
+
...
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
@runtime_checkable
|
|
352
|
+
class HasExpressionProtocol(Protocol):
|
|
353
|
+
"""Protocol for objects with an _expression attribute."""
|
|
354
|
+
|
|
355
|
+
_expression: "Optional[exp.Expression]"
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@runtime_checkable
|
|
359
|
+
class HasToStatementProtocol(Protocol):
|
|
360
|
+
"""Protocol for objects with a to_statement method."""
|
|
361
|
+
|
|
362
|
+
def to_statement(self) -> Any:
|
|
363
|
+
"""Convert to SQL statement."""
|
|
364
|
+
...
|
|
507
365
|
|
|
508
366
|
|
|
509
367
|
@runtime_checkable
|
|
@@ -513,6 +371,9 @@ class SQLBuilderProtocol(Protocol):
|
|
|
513
371
|
_expression: "Optional[exp.Expression]"
|
|
514
372
|
_parameters: dict[str, Any]
|
|
515
373
|
_parameter_counter: int
|
|
374
|
+
_columns: Any # Optional attribute for some builders
|
|
375
|
+
_table: Any # Optional attribute for some builders
|
|
376
|
+
_with_ctes: Any # Optional attribute for some builders
|
|
516
377
|
dialect: Any
|
|
517
378
|
dialect_name: "Optional[str]"
|
|
518
379
|
|
|
@@ -525,6 +386,10 @@ class SQLBuilderProtocol(Protocol):
|
|
|
525
386
|
"""Add a parameter to the builder."""
|
|
526
387
|
...
|
|
527
388
|
|
|
389
|
+
def _generate_unique_parameter_name(self, base_name: str) -> str:
|
|
390
|
+
"""Generate a unique parameter name."""
|
|
391
|
+
...
|
|
392
|
+
|
|
528
393
|
def _parameterize_expression(self, expression: "exp.Expression") -> "exp.Expression":
|
|
529
394
|
"""Replace literal values in an expression with bound parameters."""
|
|
530
395
|
...
|
sqlspec/storage/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Storage abstraction layer for SQLSpec.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Provides a flexible storage system with:
|
|
4
4
|
- Multiple backend support (local, fsspec, obstore)
|
|
5
5
|
- Lazy loading and configuration-based registration
|
|
6
6
|
- URI scheme-based automatic backend resolution
|