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.

Files changed (159) hide show
  1. sqlspec/__init__.py +50 -25
  2. sqlspec/__main__.py +1 -1
  3. sqlspec/__metadata__.py +1 -3
  4. sqlspec/_serialization.py +1 -2
  5. sqlspec/_sql.py +480 -121
  6. sqlspec/_typing.py +278 -142
  7. sqlspec/adapters/adbc/__init__.py +4 -3
  8. sqlspec/adapters/adbc/_types.py +12 -0
  9. sqlspec/adapters/adbc/config.py +115 -260
  10. sqlspec/adapters/adbc/driver.py +462 -367
  11. sqlspec/adapters/aiosqlite/__init__.py +18 -3
  12. sqlspec/adapters/aiosqlite/_types.py +13 -0
  13. sqlspec/adapters/aiosqlite/config.py +199 -129
  14. sqlspec/adapters/aiosqlite/driver.py +230 -269
  15. sqlspec/adapters/asyncmy/__init__.py +18 -3
  16. sqlspec/adapters/asyncmy/_types.py +12 -0
  17. sqlspec/adapters/asyncmy/config.py +80 -168
  18. sqlspec/adapters/asyncmy/driver.py +260 -225
  19. sqlspec/adapters/asyncpg/__init__.py +19 -4
  20. sqlspec/adapters/asyncpg/_types.py +17 -0
  21. sqlspec/adapters/asyncpg/config.py +82 -181
  22. sqlspec/adapters/asyncpg/driver.py +285 -383
  23. sqlspec/adapters/bigquery/__init__.py +17 -3
  24. sqlspec/adapters/bigquery/_types.py +12 -0
  25. sqlspec/adapters/bigquery/config.py +191 -258
  26. sqlspec/adapters/bigquery/driver.py +474 -646
  27. sqlspec/adapters/duckdb/__init__.py +14 -3
  28. sqlspec/adapters/duckdb/_types.py +12 -0
  29. sqlspec/adapters/duckdb/config.py +415 -351
  30. sqlspec/adapters/duckdb/driver.py +343 -413
  31. sqlspec/adapters/oracledb/__init__.py +19 -5
  32. sqlspec/adapters/oracledb/_types.py +14 -0
  33. sqlspec/adapters/oracledb/config.py +123 -379
  34. sqlspec/adapters/oracledb/driver.py +507 -560
  35. sqlspec/adapters/psqlpy/__init__.py +13 -3
  36. sqlspec/adapters/psqlpy/_types.py +11 -0
  37. sqlspec/adapters/psqlpy/config.py +93 -254
  38. sqlspec/adapters/psqlpy/driver.py +505 -234
  39. sqlspec/adapters/psycopg/__init__.py +19 -5
  40. sqlspec/adapters/psycopg/_types.py +17 -0
  41. sqlspec/adapters/psycopg/config.py +143 -403
  42. sqlspec/adapters/psycopg/driver.py +706 -872
  43. sqlspec/adapters/sqlite/__init__.py +14 -3
  44. sqlspec/adapters/sqlite/_types.py +11 -0
  45. sqlspec/adapters/sqlite/config.py +202 -118
  46. sqlspec/adapters/sqlite/driver.py +264 -303
  47. sqlspec/base.py +105 -9
  48. sqlspec/{statement/builder → builder}/__init__.py +12 -14
  49. sqlspec/{statement/builder → builder}/_base.py +120 -55
  50. sqlspec/{statement/builder → builder}/_column.py +17 -6
  51. sqlspec/{statement/builder → builder}/_ddl.py +46 -79
  52. sqlspec/{statement/builder → builder}/_ddl_utils.py +5 -10
  53. sqlspec/{statement/builder → builder}/_delete.py +6 -25
  54. sqlspec/{statement/builder → builder}/_insert.py +18 -65
  55. sqlspec/builder/_merge.py +56 -0
  56. sqlspec/{statement/builder → builder}/_parsing_utils.py +8 -11
  57. sqlspec/{statement/builder → builder}/_select.py +11 -56
  58. sqlspec/{statement/builder → builder}/_update.py +12 -18
  59. sqlspec/{statement/builder → builder}/mixins/__init__.py +10 -14
  60. sqlspec/{statement/builder → builder}/mixins/_cte_and_set_ops.py +48 -59
  61. sqlspec/{statement/builder → builder}/mixins/_insert_operations.py +34 -18
  62. sqlspec/{statement/builder → builder}/mixins/_join_operations.py +1 -3
  63. sqlspec/{statement/builder → builder}/mixins/_merge_operations.py +19 -9
  64. sqlspec/{statement/builder → builder}/mixins/_order_limit_operations.py +3 -3
  65. sqlspec/{statement/builder → builder}/mixins/_pivot_operations.py +4 -8
  66. sqlspec/{statement/builder → builder}/mixins/_select_operations.py +25 -38
  67. sqlspec/{statement/builder → builder}/mixins/_update_operations.py +15 -16
  68. sqlspec/{statement/builder → builder}/mixins/_where_clause.py +210 -137
  69. sqlspec/cli.py +4 -5
  70. sqlspec/config.py +180 -133
  71. sqlspec/core/__init__.py +63 -0
  72. sqlspec/core/cache.py +873 -0
  73. sqlspec/core/compiler.py +396 -0
  74. sqlspec/core/filters.py +830 -0
  75. sqlspec/core/hashing.py +310 -0
  76. sqlspec/core/parameters.py +1209 -0
  77. sqlspec/core/result.py +664 -0
  78. sqlspec/{statement → core}/splitter.py +321 -191
  79. sqlspec/core/statement.py +666 -0
  80. sqlspec/driver/__init__.py +7 -10
  81. sqlspec/driver/_async.py +387 -176
  82. sqlspec/driver/_common.py +527 -289
  83. sqlspec/driver/_sync.py +390 -172
  84. sqlspec/driver/mixins/__init__.py +2 -19
  85. sqlspec/driver/mixins/_result_tools.py +164 -0
  86. sqlspec/driver/mixins/_sql_translator.py +6 -3
  87. sqlspec/exceptions.py +5 -252
  88. sqlspec/extensions/aiosql/adapter.py +93 -96
  89. sqlspec/extensions/litestar/cli.py +1 -1
  90. sqlspec/extensions/litestar/config.py +0 -1
  91. sqlspec/extensions/litestar/handlers.py +15 -26
  92. sqlspec/extensions/litestar/plugin.py +18 -16
  93. sqlspec/extensions/litestar/providers.py +17 -52
  94. sqlspec/loader.py +424 -105
  95. sqlspec/migrations/__init__.py +12 -0
  96. sqlspec/migrations/base.py +92 -68
  97. sqlspec/migrations/commands.py +24 -106
  98. sqlspec/migrations/loaders.py +402 -0
  99. sqlspec/migrations/runner.py +49 -51
  100. sqlspec/migrations/tracker.py +31 -44
  101. sqlspec/migrations/utils.py +64 -24
  102. sqlspec/protocols.py +7 -183
  103. sqlspec/storage/__init__.py +1 -1
  104. sqlspec/storage/backends/base.py +37 -40
  105. sqlspec/storage/backends/fsspec.py +136 -112
  106. sqlspec/storage/backends/obstore.py +138 -160
  107. sqlspec/storage/capabilities.py +5 -4
  108. sqlspec/storage/registry.py +57 -106
  109. sqlspec/typing.py +136 -115
  110. sqlspec/utils/__init__.py +2 -3
  111. sqlspec/utils/correlation.py +0 -3
  112. sqlspec/utils/deprecation.py +6 -6
  113. sqlspec/utils/fixtures.py +6 -6
  114. sqlspec/utils/logging.py +0 -2
  115. sqlspec/utils/module_loader.py +7 -12
  116. sqlspec/utils/singleton.py +0 -1
  117. sqlspec/utils/sync_tools.py +17 -38
  118. sqlspec/utils/text.py +12 -51
  119. sqlspec/utils/type_guards.py +443 -232
  120. {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/METADATA +7 -2
  121. sqlspec-0.16.0.dist-info/RECORD +134 -0
  122. sqlspec/adapters/adbc/transformers.py +0 -108
  123. sqlspec/driver/connection.py +0 -207
  124. sqlspec/driver/mixins/_cache.py +0 -114
  125. sqlspec/driver/mixins/_csv_writer.py +0 -91
  126. sqlspec/driver/mixins/_pipeline.py +0 -508
  127. sqlspec/driver/mixins/_query_tools.py +0 -796
  128. sqlspec/driver/mixins/_result_utils.py +0 -138
  129. sqlspec/driver/mixins/_storage.py +0 -912
  130. sqlspec/driver/mixins/_type_coercion.py +0 -128
  131. sqlspec/driver/parameters.py +0 -138
  132. sqlspec/statement/__init__.py +0 -21
  133. sqlspec/statement/builder/_merge.py +0 -95
  134. sqlspec/statement/cache.py +0 -50
  135. sqlspec/statement/filters.py +0 -625
  136. sqlspec/statement/parameters.py +0 -956
  137. sqlspec/statement/pipelines/__init__.py +0 -210
  138. sqlspec/statement/pipelines/analyzers/__init__.py +0 -9
  139. sqlspec/statement/pipelines/analyzers/_analyzer.py +0 -646
  140. sqlspec/statement/pipelines/context.py +0 -109
  141. sqlspec/statement/pipelines/transformers/__init__.py +0 -7
  142. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +0 -88
  143. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +0 -1247
  144. sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +0 -76
  145. sqlspec/statement/pipelines/validators/__init__.py +0 -23
  146. sqlspec/statement/pipelines/validators/_dml_safety.py +0 -290
  147. sqlspec/statement/pipelines/validators/_parameter_style.py +0 -370
  148. sqlspec/statement/pipelines/validators/_performance.py +0 -714
  149. sqlspec/statement/pipelines/validators/_security.py +0 -967
  150. sqlspec/statement/result.py +0 -435
  151. sqlspec/statement/sql.py +0 -1774
  152. sqlspec/utils/cached_property.py +0 -25
  153. sqlspec/utils/statement_hashing.py +0 -203
  154. sqlspec-0.14.1.dist-info/RECORD +0 -145
  155. /sqlspec/{statement/builder → builder}/mixins/_delete_operations.py +0 -0
  156. {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/WHEEL +0 -0
  157. {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/entry_points.txt +0 -0
  158. {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/licenses/LICENSE +0 -0
  159. {sqlspec-0.14.1.dist-info → sqlspec-0.16.0.dist-info}/licenses/NOTICE +0 -0
@@ -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 AsyncDriverAdapterProtocol, SyncDriverAdapterProtocol
12
+ from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
12
13
 
13
14
  __all__ = ("AsyncMigrationTracker", "SyncMigrationTracker")
14
15
 
15
16
 
16
- class SyncMigrationTracker(BaseMigrationTracker["SyncDriverAdapterProtocol[Any]"]):
17
- """Sync version - tracks applied migrations in the database."""
17
+ class SyncMigrationTracker(BaseMigrationTracker["SyncDriverAdapterBase"]):
18
+ """Tracks applied migrations in the database."""
18
19
 
19
- def ensure_tracking_table(self, driver: "SyncDriverAdapterProtocol[Any]") -> None:
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: "SyncDriverAdapterProtocol[Any]") -> Optional[str]:
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: "SyncDriverAdapterProtocol[Any]") -> "list[dict[str, Any]]":
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
- import os
70
-
71
- applied_by = os.environ.get("USER", "unknown")
72
-
73
- driver.execute(self._get_record_migration_sql(version, description, execution_time_ms, checksum, applied_by))
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: "SyncDriverAdapterProtocol[Any]", version: str) -> None:
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["AsyncDriverAdapterProtocol[Any]"]):
87
- """Async version - tracks applied migrations in the database."""
80
+ class AsyncMigrationTracker(BaseMigrationTracker["AsyncDriverAdapterBase"]):
81
+ """Tracks applied migrations in the database."""
88
82
 
89
- async def ensure_tracking_table(self, driver: "AsyncDriverAdapterProtocol[Any]") -> None:
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 async database driver to use.
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: "AsyncDriverAdapterProtocol[Any]") -> Optional[str]:
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 async database driver to use.
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: "AsyncDriverAdapterProtocol[Any]") -> "list[dict[str, Any]]":
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 async database driver to use.
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 async database driver to use.
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(version, description, execution_time_ms, checksum, applied_by)
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: "AsyncDriverAdapterProtocol[Any]", version: str) -> None:
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 async database driver to use.
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))
@@ -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 AsyncDriverAdapterProtocol
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
- filename = f"{version}_{safe_message}.sql"
35
- file_path = migrations_dir / filename
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
- # Generate template content
38
- template = f"""-- SQLSpec Migration
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
- -- TODO: Add your upgrade SQL statements here
46
- -- Example:
47
- -- CREATE TABLE example (
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
- -- TODO: Add your downgrade SQL statements here (optional)
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, as this requires database-specific logic.
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
- """Unified protocol for object storage operations.
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
- All methods use 'path' terminology for consistency with object store patterns.
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"
@@ -1,6 +1,6 @@
1
1
  """Storage abstraction layer for SQLSpec.
2
2
 
3
- This module provides a flexible storage system with:
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