sqlspec 0.14.1__py3-none-any.whl → 0.16.0__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 +50 -25
- sqlspec/__main__.py +1 -1
- sqlspec/__metadata__.py +1 -3
- sqlspec/_serialization.py +1 -2
- sqlspec/_sql.py +480 -121
- sqlspec/_typing.py +278 -142
- sqlspec/adapters/adbc/__init__.py +4 -3
- sqlspec/adapters/adbc/_types.py +12 -0
- sqlspec/adapters/adbc/config.py +115 -260
- sqlspec/adapters/adbc/driver.py +462 -367
- sqlspec/adapters/aiosqlite/__init__.py +18 -3
- sqlspec/adapters/aiosqlite/_types.py +13 -0
- sqlspec/adapters/aiosqlite/config.py +199 -129
- sqlspec/adapters/aiosqlite/driver.py +230 -269
- sqlspec/adapters/asyncmy/__init__.py +18 -3
- sqlspec/adapters/asyncmy/_types.py +12 -0
- sqlspec/adapters/asyncmy/config.py +80 -168
- sqlspec/adapters/asyncmy/driver.py +260 -225
- sqlspec/adapters/asyncpg/__init__.py +19 -4
- sqlspec/adapters/asyncpg/_types.py +17 -0
- sqlspec/adapters/asyncpg/config.py +82 -181
- sqlspec/adapters/asyncpg/driver.py +285 -383
- sqlspec/adapters/bigquery/__init__.py +17 -3
- sqlspec/adapters/bigquery/_types.py +12 -0
- sqlspec/adapters/bigquery/config.py +191 -258
- sqlspec/adapters/bigquery/driver.py +474 -646
- sqlspec/adapters/duckdb/__init__.py +14 -3
- sqlspec/adapters/duckdb/_types.py +12 -0
- sqlspec/adapters/duckdb/config.py +415 -351
- sqlspec/adapters/duckdb/driver.py +343 -413
- sqlspec/adapters/oracledb/__init__.py +19 -5
- sqlspec/adapters/oracledb/_types.py +14 -0
- sqlspec/adapters/oracledb/config.py +123 -379
- sqlspec/adapters/oracledb/driver.py +507 -560
- sqlspec/adapters/psqlpy/__init__.py +13 -3
- sqlspec/adapters/psqlpy/_types.py +11 -0
- sqlspec/adapters/psqlpy/config.py +93 -254
- sqlspec/adapters/psqlpy/driver.py +505 -234
- sqlspec/adapters/psycopg/__init__.py +19 -5
- sqlspec/adapters/psycopg/_types.py +17 -0
- sqlspec/adapters/psycopg/config.py +143 -403
- sqlspec/adapters/psycopg/driver.py +706 -872
- sqlspec/adapters/sqlite/__init__.py +14 -3
- sqlspec/adapters/sqlite/_types.py +11 -0
- sqlspec/adapters/sqlite/config.py +202 -118
- sqlspec/adapters/sqlite/driver.py +264 -303
- sqlspec/base.py +105 -9
- sqlspec/{statement/builder → builder}/__init__.py +12 -14
- sqlspec/{statement/builder → builder}/_base.py +120 -55
- sqlspec/{statement/builder → builder}/_column.py +17 -6
- sqlspec/{statement/builder → builder}/_ddl.py +46 -79
- sqlspec/{statement/builder → builder}/_ddl_utils.py +5 -10
- sqlspec/{statement/builder → builder}/_delete.py +6 -25
- sqlspec/{statement/builder → builder}/_insert.py +18 -65
- sqlspec/builder/_merge.py +56 -0
- sqlspec/{statement/builder → builder}/_parsing_utils.py +8 -11
- sqlspec/{statement/builder → builder}/_select.py +11 -56
- sqlspec/{statement/builder → builder}/_update.py +12 -18
- sqlspec/{statement/builder → builder}/mixins/__init__.py +10 -14
- sqlspec/{statement/builder → builder}/mixins/_cte_and_set_ops.py +48 -59
- sqlspec/{statement/builder → builder}/mixins/_insert_operations.py +34 -18
- sqlspec/{statement/builder → builder}/mixins/_join_operations.py +1 -3
- sqlspec/{statement/builder → builder}/mixins/_merge_operations.py +19 -9
- sqlspec/{statement/builder → builder}/mixins/_order_limit_operations.py +3 -3
- sqlspec/{statement/builder → builder}/mixins/_pivot_operations.py +4 -8
- sqlspec/{statement/builder → builder}/mixins/_select_operations.py +25 -38
- sqlspec/{statement/builder → builder}/mixins/_update_operations.py +15 -16
- sqlspec/{statement/builder → builder}/mixins/_where_clause.py +210 -137
- sqlspec/cli.py +4 -5
- sqlspec/config.py +180 -133
- sqlspec/core/__init__.py +63 -0
- sqlspec/core/cache.py +873 -0
- sqlspec/core/compiler.py +396 -0
- sqlspec/core/filters.py +830 -0
- sqlspec/core/hashing.py +310 -0
- sqlspec/core/parameters.py +1209 -0
- sqlspec/core/result.py +664 -0
- sqlspec/{statement → core}/splitter.py +321 -191
- sqlspec/core/statement.py +666 -0
- sqlspec/driver/__init__.py +7 -10
- sqlspec/driver/_async.py +387 -176
- sqlspec/driver/_common.py +527 -289
- sqlspec/driver/_sync.py +390 -172
- sqlspec/driver/mixins/__init__.py +2 -19
- sqlspec/driver/mixins/_result_tools.py +164 -0
- sqlspec/driver/mixins/_sql_translator.py +6 -3
- sqlspec/exceptions.py +5 -252
- sqlspec/extensions/aiosql/adapter.py +93 -96
- sqlspec/extensions/litestar/cli.py +1 -1
- sqlspec/extensions/litestar/config.py +0 -1
- sqlspec/extensions/litestar/handlers.py +15 -26
- sqlspec/extensions/litestar/plugin.py +18 -16
- sqlspec/extensions/litestar/providers.py +17 -52
- sqlspec/loader.py +424 -105
- sqlspec/migrations/__init__.py +12 -0
- sqlspec/migrations/base.py +92 -68
- sqlspec/migrations/commands.py +24 -106
- sqlspec/migrations/loaders.py +402 -0
- sqlspec/migrations/runner.py +49 -51
- sqlspec/migrations/tracker.py +31 -44
- sqlspec/migrations/utils.py +64 -24
- sqlspec/protocols.py +7 -183
- 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 -3
- 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 +443 -232
- {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/METADATA +7 -2
- sqlspec-0.16.0.dist-info/RECORD +134 -0
- sqlspec/adapters/adbc/transformers.py +0 -108
- sqlspec/driver/connection.py +0 -207
- sqlspec/driver/mixins/_cache.py +0 -114
- sqlspec/driver/mixins/_csv_writer.py +0 -91
- sqlspec/driver/mixins/_pipeline.py +0 -508
- sqlspec/driver/mixins/_query_tools.py +0 -796
- sqlspec/driver/mixins/_result_utils.py +0 -138
- sqlspec/driver/mixins/_storage.py +0 -912
- sqlspec/driver/mixins/_type_coercion.py +0 -128
- sqlspec/driver/parameters.py +0 -138
- sqlspec/statement/__init__.py +0 -21
- sqlspec/statement/builder/_merge.py +0 -95
- sqlspec/statement/cache.py +0 -50
- sqlspec/statement/filters.py +0 -625
- sqlspec/statement/parameters.py +0 -956
- 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 -109
- 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 -714
- sqlspec/statement/pipelines/validators/_security.py +0 -967
- sqlspec/statement/result.py +0 -435
- sqlspec/statement/sql.py +0 -1774
- sqlspec/utils/cached_property.py +0 -25
- sqlspec/utils/statement_hashing.py +0 -203
- sqlspec-0.14.1.dist-info/RECORD +0 -145
- /sqlspec/{statement/builder → builder}/mixins/_delete_operations.py +0 -0
- {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/migrations/tracker.py
CHANGED
|
@@ -3,20 +3,21 @@
|
|
|
3
3
|
This module provides functionality to track applied migrations in the database.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import os
|
|
6
7
|
from typing import TYPE_CHECKING, Any, Optional
|
|
7
8
|
|
|
8
9
|
from sqlspec.migrations.base import BaseMigrationTracker
|
|
9
10
|
|
|
10
11
|
if TYPE_CHECKING:
|
|
11
|
-
from sqlspec.driver import
|
|
12
|
+
from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
|
|
12
13
|
|
|
13
14
|
__all__ = ("AsyncMigrationTracker", "SyncMigrationTracker")
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
class SyncMigrationTracker(BaseMigrationTracker["
|
|
17
|
-
"""
|
|
17
|
+
class SyncMigrationTracker(BaseMigrationTracker["SyncDriverAdapterBase"]):
|
|
18
|
+
"""Tracks applied migrations in the database."""
|
|
18
19
|
|
|
19
|
-
def ensure_tracking_table(self, driver: "
|
|
20
|
+
def ensure_tracking_table(self, driver: "SyncDriverAdapterBase") -> None:
|
|
20
21
|
"""Create the migration tracking table if it doesn't exist.
|
|
21
22
|
|
|
22
23
|
Args:
|
|
@@ -24,7 +25,7 @@ class SyncMigrationTracker(BaseMigrationTracker["SyncDriverAdapterProtocol[Any]"
|
|
|
24
25
|
"""
|
|
25
26
|
driver.execute(self._get_create_table_sql())
|
|
26
27
|
|
|
27
|
-
def get_current_version(self, driver: "
|
|
28
|
+
def get_current_version(self, driver: "SyncDriverAdapterBase") -> Optional[str]:
|
|
28
29
|
"""Get the latest applied migration version.
|
|
29
30
|
|
|
30
31
|
Args:
|
|
@@ -36,7 +37,7 @@ class SyncMigrationTracker(BaseMigrationTracker["SyncDriverAdapterProtocol[Any]"
|
|
|
36
37
|
result = driver.execute(self._get_current_version_sql())
|
|
37
38
|
return result.data[0]["version_num"] if result.data else None
|
|
38
39
|
|
|
39
|
-
def get_applied_migrations(self, driver: "
|
|
40
|
+
def get_applied_migrations(self, driver: "SyncDriverAdapterBase") -> "list[dict[str, Any]]":
|
|
40
41
|
"""Get all applied migrations in order.
|
|
41
42
|
|
|
42
43
|
Args:
|
|
@@ -46,15 +47,10 @@ class SyncMigrationTracker(BaseMigrationTracker["SyncDriverAdapterProtocol[Any]"
|
|
|
46
47
|
List of migration records.
|
|
47
48
|
"""
|
|
48
49
|
result = driver.execute(self._get_applied_migrations_sql())
|
|
49
|
-
return result.data
|
|
50
|
+
return result.data or []
|
|
50
51
|
|
|
51
52
|
def record_migration(
|
|
52
|
-
self,
|
|
53
|
-
driver: "SyncDriverAdapterProtocol[Any]",
|
|
54
|
-
version: str,
|
|
55
|
-
description: str,
|
|
56
|
-
execution_time_ms: int,
|
|
57
|
-
checksum: str,
|
|
53
|
+
self, driver: "SyncDriverAdapterBase", version: str, description: str, execution_time_ms: int, checksum: str
|
|
58
54
|
) -> None:
|
|
59
55
|
"""Record a successfully applied migration.
|
|
60
56
|
|
|
@@ -64,41 +60,39 @@ class SyncMigrationTracker(BaseMigrationTracker["SyncDriverAdapterProtocol[Any]"
|
|
|
64
60
|
description: Description of the migration.
|
|
65
61
|
execution_time_ms: Execution time in milliseconds.
|
|
66
62
|
checksum: MD5 checksum of the migration content.
|
|
67
|
-
connection: Optional connection to use for the operation.
|
|
68
63
|
"""
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
64
|
+
driver.execute(
|
|
65
|
+
self._get_record_migration_sql(
|
|
66
|
+
version, description, execution_time_ms, checksum, os.environ.get("USER", "unknown")
|
|
67
|
+
)
|
|
68
|
+
)
|
|
74
69
|
|
|
75
|
-
def remove_migration(self, driver: "
|
|
70
|
+
def remove_migration(self, driver: "SyncDriverAdapterBase", version: str) -> None:
|
|
76
71
|
"""Remove a migration record (used during downgrade).
|
|
77
72
|
|
|
78
73
|
Args:
|
|
79
74
|
driver: The database driver to use.
|
|
80
75
|
version: Version number to remove.
|
|
81
|
-
connection: Optional connection to use for the operation.
|
|
82
76
|
"""
|
|
83
77
|
driver.execute(self._get_remove_migration_sql(version))
|
|
84
78
|
|
|
85
79
|
|
|
86
|
-
class AsyncMigrationTracker(BaseMigrationTracker["
|
|
87
|
-
"""
|
|
80
|
+
class AsyncMigrationTracker(BaseMigrationTracker["AsyncDriverAdapterBase"]):
|
|
81
|
+
"""Tracks applied migrations in the database."""
|
|
88
82
|
|
|
89
|
-
async def ensure_tracking_table(self, driver: "
|
|
83
|
+
async def ensure_tracking_table(self, driver: "AsyncDriverAdapterBase") -> None:
|
|
90
84
|
"""Create the migration tracking table if it doesn't exist.
|
|
91
85
|
|
|
92
86
|
Args:
|
|
93
|
-
driver: The
|
|
87
|
+
driver: The database driver to use.
|
|
94
88
|
"""
|
|
95
89
|
await driver.execute(self._get_create_table_sql())
|
|
96
90
|
|
|
97
|
-
async def get_current_version(self, driver: "
|
|
91
|
+
async def get_current_version(self, driver: "AsyncDriverAdapterBase") -> Optional[str]:
|
|
98
92
|
"""Get the latest applied migration version.
|
|
99
93
|
|
|
100
94
|
Args:
|
|
101
|
-
driver: The
|
|
95
|
+
driver: The database driver to use.
|
|
102
96
|
|
|
103
97
|
Returns:
|
|
104
98
|
The current version number or None if no migrations applied.
|
|
@@ -106,48 +100,41 @@ class AsyncMigrationTracker(BaseMigrationTracker["AsyncDriverAdapterProtocol[Any
|
|
|
106
100
|
result = await driver.execute(self._get_current_version_sql())
|
|
107
101
|
return result.data[0]["version_num"] if result.data else None
|
|
108
102
|
|
|
109
|
-
async def get_applied_migrations(self, driver: "
|
|
103
|
+
async def get_applied_migrations(self, driver: "AsyncDriverAdapterBase") -> "list[dict[str, Any]]":
|
|
110
104
|
"""Get all applied migrations in order.
|
|
111
105
|
|
|
112
106
|
Args:
|
|
113
|
-
driver: The
|
|
107
|
+
driver: The database driver to use.
|
|
114
108
|
|
|
115
109
|
Returns:
|
|
116
110
|
List of migration records.
|
|
117
111
|
"""
|
|
118
112
|
result = await driver.execute(self._get_applied_migrations_sql())
|
|
119
|
-
return result.data
|
|
113
|
+
return result.data or []
|
|
120
114
|
|
|
121
115
|
async def record_migration(
|
|
122
|
-
self,
|
|
123
|
-
driver: "AsyncDriverAdapterProtocol[Any]",
|
|
124
|
-
version: str,
|
|
125
|
-
description: str,
|
|
126
|
-
execution_time_ms: int,
|
|
127
|
-
checksum: str,
|
|
116
|
+
self, driver: "AsyncDriverAdapterBase", version: str, description: str, execution_time_ms: int, checksum: str
|
|
128
117
|
) -> None:
|
|
129
118
|
"""Record a successfully applied migration.
|
|
130
119
|
|
|
131
120
|
Args:
|
|
132
|
-
driver: The
|
|
121
|
+
driver: The database driver to use.
|
|
133
122
|
version: Version number of the migration.
|
|
134
123
|
description: Description of the migration.
|
|
135
124
|
execution_time_ms: Execution time in milliseconds.
|
|
136
125
|
checksum: MD5 checksum of the migration content.
|
|
137
126
|
"""
|
|
138
|
-
import os
|
|
139
|
-
|
|
140
|
-
applied_by = os.environ.get("USER", "unknown")
|
|
141
|
-
|
|
142
127
|
await driver.execute(
|
|
143
|
-
self._get_record_migration_sql(
|
|
128
|
+
self._get_record_migration_sql(
|
|
129
|
+
version, description, execution_time_ms, checksum, os.environ.get("USER", "unknown")
|
|
130
|
+
)
|
|
144
131
|
)
|
|
145
132
|
|
|
146
|
-
async def remove_migration(self, driver: "
|
|
133
|
+
async def remove_migration(self, driver: "AsyncDriverAdapterBase", version: str) -> None:
|
|
147
134
|
"""Remove a migration record (used during downgrade).
|
|
148
135
|
|
|
149
136
|
Args:
|
|
150
|
-
driver: The
|
|
137
|
+
driver: The database driver to use.
|
|
151
138
|
version: Version number to remove.
|
|
152
139
|
"""
|
|
153
140
|
await driver.execute(self._get_remove_migration_sql(version))
|
sqlspec/migrations/utils.py
CHANGED
|
@@ -9,50 +9,96 @@ from pathlib import Path
|
|
|
9
9
|
from typing import TYPE_CHECKING, Any, Optional
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
-
from sqlspec.driver import
|
|
12
|
+
from sqlspec.driver import AsyncDriverAdapterBase
|
|
13
13
|
|
|
14
14
|
__all__ = ("create_migration_file", "drop_all", "get_author")
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def create_migration_file(migrations_dir: Path, version: str, message: str) -> Path:
|
|
17
|
+
def create_migration_file(migrations_dir: Path, version: str, message: str, file_type: str = "sql") -> Path:
|
|
18
18
|
"""Create a new migration file from template.
|
|
19
19
|
|
|
20
20
|
Args:
|
|
21
21
|
migrations_dir: Directory to create the migration in.
|
|
22
22
|
version: Version number for the migration.
|
|
23
23
|
message: Description message for the migration.
|
|
24
|
+
file_type: Type of migration file to create ('sql' or 'py').
|
|
24
25
|
|
|
25
26
|
Returns:
|
|
26
27
|
Path to the created migration file.
|
|
27
28
|
"""
|
|
28
|
-
# Sanitize message for filename
|
|
29
29
|
safe_message = message.lower()
|
|
30
30
|
safe_message = "".join(c if c.isalnum() or c in " -" else "" for c in safe_message)
|
|
31
31
|
safe_message = safe_message.replace(" ", "_").replace("-", "_")
|
|
32
32
|
safe_message = "_".join(filter(None, safe_message.split("_")))[:50]
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
if file_type == "py":
|
|
35
|
+
filename = f"{version}_{safe_message}.py"
|
|
36
|
+
file_path = migrations_dir / filename
|
|
37
|
+
template = f'''"""SQLSpec Migration - {message}
|
|
36
38
|
|
|
37
|
-
|
|
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
|
|
39
90
|
-- Version: {version}
|
|
40
91
|
-- Description: {message}
|
|
41
92
|
-- Created: {datetime.now(timezone.utc).isoformat()}
|
|
42
93
|
-- Author: {get_author()}
|
|
43
94
|
|
|
44
95
|
-- name: migrate-{version}-up
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-- id INTEGER PRIMARY KEY,
|
|
49
|
-
-- name TEXT NOT NULL
|
|
50
|
-
-- );
|
|
96
|
+
CREATE TABLE placeholder (
|
|
97
|
+
id INTEGER PRIMARY KEY
|
|
98
|
+
);
|
|
51
99
|
|
|
52
100
|
-- name: migrate-{version}-down
|
|
53
|
-
|
|
54
|
-
-- Example:
|
|
55
|
-
-- DROP TABLE example;
|
|
101
|
+
DROP TABLE placeholder;
|
|
56
102
|
"""
|
|
57
103
|
|
|
58
104
|
file_path.write_text(template)
|
|
@@ -68,22 +114,16 @@ def get_author() -> str:
|
|
|
68
114
|
return os.environ.get("USER", "unknown")
|
|
69
115
|
|
|
70
116
|
|
|
71
|
-
async def drop_all(
|
|
72
|
-
engine: "AsyncDriverAdapterProtocol[Any]", version_table_name: str, metadata: Optional[Any] = None
|
|
73
|
-
) -> None:
|
|
117
|
+
async def drop_all(engine: "AsyncDriverAdapterBase", version_table_name: str, metadata: Optional[Any] = None) -> None:
|
|
74
118
|
"""Drop all tables from the database.
|
|
75
119
|
|
|
76
|
-
This is a placeholder for database-specific implementations.
|
|
77
|
-
|
|
78
120
|
Args:
|
|
79
121
|
engine: The database engine/driver.
|
|
80
122
|
version_table_name: Name of the version tracking table.
|
|
81
123
|
metadata: Optional metadata object.
|
|
82
124
|
|
|
83
125
|
Raises:
|
|
84
|
-
NotImplementedError: Always
|
|
126
|
+
NotImplementedError: Always raised.
|
|
85
127
|
"""
|
|
86
|
-
# This would need database-specific implementation
|
|
87
|
-
# For now, it's a placeholder
|
|
88
128
|
msg = "drop_all functionality requires database-specific implementation"
|
|
89
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,17 +14,10 @@ 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",
|
|
@@ -36,7 +28,6 @@ __all__ = (
|
|
|
36
28
|
"HasOffsetProtocol",
|
|
37
29
|
"HasOrderByProtocol",
|
|
38
30
|
"HasParameterBuilderProtocol",
|
|
39
|
-
"HasRiskLevelProtocol",
|
|
40
31
|
"HasSQLGlotExpressionProtocol",
|
|
41
32
|
"HasSQLMethodProtocol",
|
|
42
33
|
"HasToStatementProtocol",
|
|
@@ -46,14 +37,8 @@ __all__ = (
|
|
|
46
37
|
"ObjectStoreItemProtocol",
|
|
47
38
|
"ObjectStoreProtocol",
|
|
48
39
|
"ParameterValueProtocol",
|
|
49
|
-
"ProcessorProtocol",
|
|
50
40
|
"SQLBuilderProtocol",
|
|
51
41
|
"SelectBuilderProtocol",
|
|
52
|
-
"SyncCloseableConnectionProtocol",
|
|
53
|
-
"SyncCopyCapableConnectionProtocol",
|
|
54
|
-
"SyncPipelineCapableDriverProtocol",
|
|
55
|
-
"SyncTransactionCapableConnectionProtocol",
|
|
56
|
-
"SyncTransactionStateConnectionProtocol",
|
|
57
42
|
"WithMethodProtocol",
|
|
58
43
|
)
|
|
59
44
|
|
|
@@ -171,16 +156,6 @@ class ParameterValueProtocol(Protocol):
|
|
|
171
156
|
type_hint: str
|
|
172
157
|
|
|
173
158
|
|
|
174
|
-
@runtime_checkable
|
|
175
|
-
class HasRiskLevelProtocol(Protocol):
|
|
176
|
-
"""Protocol for objects with a risk_level attribute."""
|
|
177
|
-
|
|
178
|
-
@property
|
|
179
|
-
def risk_level(self) -> Any:
|
|
180
|
-
"""Get the risk level of this object."""
|
|
181
|
-
...
|
|
182
|
-
|
|
183
|
-
|
|
184
159
|
@runtime_checkable
|
|
185
160
|
class DictProtocol(Protocol):
|
|
186
161
|
"""Protocol for objects with a __dict__ attribute."""
|
|
@@ -188,25 +163,6 @@ class DictProtocol(Protocol):
|
|
|
188
163
|
__dict__: dict[str, Any]
|
|
189
164
|
|
|
190
165
|
|
|
191
|
-
class ProcessorProtocol(Protocol):
|
|
192
|
-
"""Defines the interface for a single processing step in the SQL pipeline."""
|
|
193
|
-
|
|
194
|
-
@abstractmethod
|
|
195
|
-
def process(
|
|
196
|
-
self, expression: "Optional[exp.Expression]", context: "SQLProcessingContext"
|
|
197
|
-
) -> "Optional[exp.Expression]":
|
|
198
|
-
"""Processes an SQL expression.
|
|
199
|
-
|
|
200
|
-
Args:
|
|
201
|
-
expression: The SQL expression to process.
|
|
202
|
-
context: The SQLProcessingContext holding the current state and config.
|
|
203
|
-
|
|
204
|
-
Returns:
|
|
205
|
-
The (possibly modified) SQL expression for transformers, or None for validators/analyzers.
|
|
206
|
-
"""
|
|
207
|
-
...
|
|
208
|
-
|
|
209
|
-
|
|
210
166
|
@runtime_checkable
|
|
211
167
|
class BytesConvertibleProtocol(Protocol):
|
|
212
168
|
"""Protocol for objects that can be converted to bytes."""
|
|
@@ -224,138 +180,20 @@ class ObjectStoreItemProtocol(Protocol):
|
|
|
224
180
|
key: "Optional[str]"
|
|
225
181
|
|
|
226
182
|
|
|
227
|
-
@runtime_checkable
|
|
228
|
-
class SyncTransactionCapableConnectionProtocol(Protocol):
|
|
229
|
-
"""Protocol for sync connections that support transactions."""
|
|
230
|
-
|
|
231
|
-
def commit(self) -> None:
|
|
232
|
-
"""Commit the current transaction."""
|
|
233
|
-
...
|
|
234
|
-
|
|
235
|
-
def rollback(self) -> None:
|
|
236
|
-
"""Rollback the current transaction."""
|
|
237
|
-
...
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
@runtime_checkable
|
|
241
|
-
class AsyncTransactionCapableConnectionProtocol(Protocol):
|
|
242
|
-
"""Protocol for async connections that support transactions."""
|
|
243
|
-
|
|
244
|
-
async def commit(self) -> None:
|
|
245
|
-
"""Commit the current transaction."""
|
|
246
|
-
...
|
|
247
|
-
|
|
248
|
-
async def rollback(self) -> None:
|
|
249
|
-
"""Rollback the current transaction."""
|
|
250
|
-
...
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
@runtime_checkable
|
|
254
|
-
class SyncTransactionStateConnectionProtocol(SyncTransactionCapableConnectionProtocol, Protocol):
|
|
255
|
-
"""Protocol for sync connections that can report transaction state."""
|
|
256
|
-
|
|
257
|
-
def in_transaction(self) -> bool:
|
|
258
|
-
"""Check if connection is currently in a transaction."""
|
|
259
|
-
...
|
|
260
|
-
|
|
261
|
-
def begin(self) -> None:
|
|
262
|
-
"""Begin a new transaction."""
|
|
263
|
-
...
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
@runtime_checkable
|
|
267
|
-
class AsyncTransactionStateConnectionProtocol(AsyncTransactionCapableConnectionProtocol, Protocol):
|
|
268
|
-
"""Protocol for async connections that can report transaction state."""
|
|
269
|
-
|
|
270
|
-
def in_transaction(self) -> bool:
|
|
271
|
-
"""Check if connection is currently in a transaction."""
|
|
272
|
-
...
|
|
273
|
-
|
|
274
|
-
async def begin(self) -> None:
|
|
275
|
-
"""Begin a new transaction."""
|
|
276
|
-
...
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
@runtime_checkable
|
|
280
|
-
class SyncCloseableConnectionProtocol(Protocol):
|
|
281
|
-
"""Protocol for sync connections that can be closed."""
|
|
282
|
-
|
|
283
|
-
def close(self) -> None:
|
|
284
|
-
"""Close the connection."""
|
|
285
|
-
...
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
@runtime_checkable
|
|
289
|
-
class AsyncCloseableConnectionProtocol(Protocol):
|
|
290
|
-
"""Protocol for async connections that can be closed."""
|
|
291
|
-
|
|
292
|
-
async def close(self) -> None:
|
|
293
|
-
"""Close the connection."""
|
|
294
|
-
...
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
@runtime_checkable
|
|
298
|
-
class SyncCopyCapableConnectionProtocol(Protocol):
|
|
299
|
-
"""Protocol for sync connections that support COPY operations."""
|
|
300
|
-
|
|
301
|
-
def copy_from(self, table: str, file: Any, **kwargs: Any) -> None:
|
|
302
|
-
"""Copy data from file to table."""
|
|
303
|
-
...
|
|
304
|
-
|
|
305
|
-
def copy_to(self, table: str, file: Any, **kwargs: Any) -> None:
|
|
306
|
-
"""Copy data from table to file."""
|
|
307
|
-
...
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
@runtime_checkable
|
|
311
|
-
class AsyncCopyCapableConnectionProtocol(Protocol):
|
|
312
|
-
"""Protocol for async connections that support COPY operations."""
|
|
313
|
-
|
|
314
|
-
async def copy_from(self, table: str, file: Any, **kwargs: Any) -> None:
|
|
315
|
-
"""Copy data from file to table."""
|
|
316
|
-
...
|
|
317
|
-
|
|
318
|
-
async def copy_to(self, table: str, file: Any, **kwargs: Any) -> None:
|
|
319
|
-
"""Copy data from table to file."""
|
|
320
|
-
...
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
@runtime_checkable
|
|
324
|
-
class SyncPipelineCapableDriverProtocol(Protocol):
|
|
325
|
-
"""Protocol for sync drivers that support native pipeline execution."""
|
|
326
|
-
|
|
327
|
-
def _execute_pipeline_native(self, operations: list[Any], **options: Any) -> list[Any]:
|
|
328
|
-
"""Execute pipeline operations natively."""
|
|
329
|
-
...
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
@runtime_checkable
|
|
333
|
-
class AsyncPipelineCapableDriverProtocol(Protocol):
|
|
334
|
-
"""Protocol for async drivers that support native pipeline execution."""
|
|
335
|
-
|
|
336
|
-
async def _execute_pipeline_native(self, operations: list[Any], **options: Any) -> list[Any]:
|
|
337
|
-
"""Execute pipeline operations natively."""
|
|
338
|
-
...
|
|
339
|
-
|
|
340
|
-
|
|
341
183
|
@runtime_checkable
|
|
342
184
|
class ObjectStoreProtocol(Protocol):
|
|
343
|
-
"""
|
|
344
|
-
|
|
345
|
-
This protocol defines the interface for all storage backends with built-in
|
|
346
|
-
instrumentation support. Backends must implement both sync and async operations
|
|
347
|
-
where possible, with async operations suffixed with _async.
|
|
185
|
+
"""Protocol for object storage operations.
|
|
348
186
|
|
|
349
|
-
|
|
187
|
+
Defines the interface for storage backends with both sync and async operations.
|
|
350
188
|
"""
|
|
351
189
|
|
|
352
|
-
# Class-level capability descriptor
|
|
353
190
|
capabilities: ClassVar["StorageCapabilities"]
|
|
354
191
|
|
|
192
|
+
protocol: str
|
|
193
|
+
|
|
355
194
|
def __init__(self, uri: str, **kwargs: Any) -> None:
|
|
356
195
|
return
|
|
357
196
|
|
|
358
|
-
# Core Operations (sync)
|
|
359
197
|
def read_bytes(self, path: "Union[str, Path]", **kwargs: Any) -> bytes:
|
|
360
198
|
"""Read bytes from an object."""
|
|
361
199
|
return b""
|
|
@@ -372,7 +210,6 @@ class ObjectStoreProtocol(Protocol):
|
|
|
372
210
|
"""Write text to an object."""
|
|
373
211
|
return
|
|
374
212
|
|
|
375
|
-
# Object Operations
|
|
376
213
|
def exists(self, path: "Union[str, Path]", **kwargs: Any) -> bool:
|
|
377
214
|
"""Check if an object exists."""
|
|
378
215
|
return False
|
|
@@ -389,7 +226,6 @@ class ObjectStoreProtocol(Protocol):
|
|
|
389
226
|
"""Move an object."""
|
|
390
227
|
return
|
|
391
228
|
|
|
392
|
-
# Listing Operations
|
|
393
229
|
def list_objects(self, prefix: str = "", recursive: bool = True, **kwargs: Any) -> list[str]:
|
|
394
230
|
"""List objects with optional prefix."""
|
|
395
231
|
return []
|
|
@@ -398,7 +234,6 @@ class ObjectStoreProtocol(Protocol):
|
|
|
398
234
|
"""Find objects matching a glob pattern."""
|
|
399
235
|
return []
|
|
400
236
|
|
|
401
|
-
# Path Operations
|
|
402
237
|
def is_object(self, path: "Union[str, Path]") -> bool:
|
|
403
238
|
"""Check if path points to an object."""
|
|
404
239
|
return False
|
|
@@ -411,32 +246,21 @@ class ObjectStoreProtocol(Protocol):
|
|
|
411
246
|
"""Get object metadata."""
|
|
412
247
|
return {}
|
|
413
248
|
|
|
414
|
-
# Arrow Operations
|
|
415
249
|
def read_arrow(self, path: "Union[str, Path]", **kwargs: Any) -> "ArrowTable":
|
|
416
|
-
"""Read an Arrow table from storage.
|
|
417
|
-
|
|
418
|
-
For obstore backend, this should use native arrow operations when available.
|
|
419
|
-
"""
|
|
250
|
+
"""Read an Arrow table from storage."""
|
|
420
251
|
msg = "Arrow reading not implemented"
|
|
421
252
|
raise NotImplementedError(msg)
|
|
422
253
|
|
|
423
254
|
def write_arrow(self, path: "Union[str, Path]", table: "ArrowTable", **kwargs: Any) -> None:
|
|
424
|
-
"""Write an Arrow table to storage.
|
|
425
|
-
|
|
426
|
-
For obstore backend, this should use native arrow operations when available.
|
|
427
|
-
"""
|
|
255
|
+
"""Write an Arrow table to storage."""
|
|
428
256
|
msg = "Arrow writing not implemented"
|
|
429
257
|
raise NotImplementedError(msg)
|
|
430
258
|
|
|
431
259
|
def stream_arrow(self, pattern: str, **kwargs: Any) -> "Iterator[ArrowRecordBatch]":
|
|
432
|
-
"""Stream Arrow record batches from matching objects.
|
|
433
|
-
|
|
434
|
-
For obstore backend, this should use native streaming when available.
|
|
435
|
-
"""
|
|
260
|
+
"""Stream Arrow record batches from matching objects."""
|
|
436
261
|
msg = "Arrow streaming not implemented"
|
|
437
262
|
raise NotImplementedError(msg)
|
|
438
263
|
|
|
439
|
-
# Async versions
|
|
440
264
|
async def read_bytes_async(self, path: "Union[str, Path]", **kwargs: Any) -> bytes:
|
|
441
265
|
"""Async read bytes from an object."""
|
|
442
266
|
msg = "Async operations not implemented"
|
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
|