sqlspec 0.17.1__py3-none-any.whl → 0.19.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 (77) hide show
  1. sqlspec/__init__.py +1 -1
  2. sqlspec/_sql.py +54 -159
  3. sqlspec/adapters/adbc/config.py +24 -30
  4. sqlspec/adapters/adbc/driver.py +42 -61
  5. sqlspec/adapters/aiosqlite/config.py +5 -10
  6. sqlspec/adapters/aiosqlite/driver.py +9 -25
  7. sqlspec/adapters/aiosqlite/pool.py +43 -35
  8. sqlspec/adapters/asyncmy/config.py +10 -7
  9. sqlspec/adapters/asyncmy/driver.py +18 -39
  10. sqlspec/adapters/asyncpg/config.py +4 -0
  11. sqlspec/adapters/asyncpg/driver.py +32 -79
  12. sqlspec/adapters/bigquery/config.py +12 -65
  13. sqlspec/adapters/bigquery/driver.py +39 -133
  14. sqlspec/adapters/duckdb/config.py +11 -15
  15. sqlspec/adapters/duckdb/driver.py +61 -85
  16. sqlspec/adapters/duckdb/pool.py +2 -5
  17. sqlspec/adapters/oracledb/_types.py +8 -1
  18. sqlspec/adapters/oracledb/config.py +55 -38
  19. sqlspec/adapters/oracledb/driver.py +35 -92
  20. sqlspec/adapters/oracledb/migrations.py +257 -0
  21. sqlspec/adapters/psqlpy/config.py +13 -9
  22. sqlspec/adapters/psqlpy/driver.py +28 -103
  23. sqlspec/adapters/psycopg/config.py +9 -5
  24. sqlspec/adapters/psycopg/driver.py +107 -175
  25. sqlspec/adapters/sqlite/config.py +7 -5
  26. sqlspec/adapters/sqlite/driver.py +37 -73
  27. sqlspec/adapters/sqlite/pool.py +3 -12
  28. sqlspec/base.py +19 -22
  29. sqlspec/builder/__init__.py +1 -1
  30. sqlspec/builder/_base.py +34 -20
  31. sqlspec/builder/_ddl.py +407 -183
  32. sqlspec/builder/_insert.py +1 -1
  33. sqlspec/builder/mixins/_insert_operations.py +26 -6
  34. sqlspec/builder/mixins/_merge_operations.py +1 -1
  35. sqlspec/builder/mixins/_select_operations.py +1 -5
  36. sqlspec/cli.py +281 -33
  37. sqlspec/config.py +183 -14
  38. sqlspec/core/__init__.py +89 -14
  39. sqlspec/core/cache.py +57 -104
  40. sqlspec/core/compiler.py +57 -112
  41. sqlspec/core/filters.py +1 -21
  42. sqlspec/core/hashing.py +13 -47
  43. sqlspec/core/parameters.py +272 -261
  44. sqlspec/core/result.py +12 -27
  45. sqlspec/core/splitter.py +17 -21
  46. sqlspec/core/statement.py +150 -159
  47. sqlspec/driver/_async.py +2 -15
  48. sqlspec/driver/_common.py +16 -95
  49. sqlspec/driver/_sync.py +2 -15
  50. sqlspec/driver/mixins/_result_tools.py +8 -29
  51. sqlspec/driver/mixins/_sql_translator.py +6 -8
  52. sqlspec/exceptions.py +1 -2
  53. sqlspec/extensions/litestar/plugin.py +15 -8
  54. sqlspec/loader.py +43 -115
  55. sqlspec/migrations/__init__.py +1 -1
  56. sqlspec/migrations/base.py +34 -45
  57. sqlspec/migrations/commands.py +34 -15
  58. sqlspec/migrations/loaders.py +1 -1
  59. sqlspec/migrations/runner.py +104 -19
  60. sqlspec/migrations/tracker.py +49 -2
  61. sqlspec/protocols.py +3 -6
  62. sqlspec/storage/__init__.py +4 -4
  63. sqlspec/storage/backends/fsspec.py +5 -6
  64. sqlspec/storage/backends/obstore.py +7 -8
  65. sqlspec/storage/registry.py +3 -3
  66. sqlspec/utils/__init__.py +2 -2
  67. sqlspec/utils/logging.py +6 -10
  68. sqlspec/utils/sync_tools.py +27 -4
  69. sqlspec/utils/text.py +6 -1
  70. {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/METADATA +1 -1
  71. sqlspec-0.19.0.dist-info/RECORD +138 -0
  72. sqlspec/builder/_ddl_utils.py +0 -103
  73. sqlspec-0.17.1.dist-info/RECORD +0 -138
  74. {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/WHEEL +0 -0
  75. {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/entry_points.txt +0 -0
  76. {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/licenses/LICENSE +0 -0
  77. {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/licenses/NOTICE +0 -0
@@ -1,18 +1,7 @@
1
- """Enhanced Psqlpy driver with CORE_ROUND_3 architecture integration.
2
-
3
- This driver implements the complete CORE_ROUND_3 architecture for:
4
- - 5-10x faster SQL compilation through single-pass processing
5
- - 40-60% memory reduction through __slots__ optimization
6
- - Enhanced caching for repeated statement execution
7
- - Complete backward compatibility with existing functionality
8
-
9
- Architecture Features:
10
- - Direct integration with sqlspec.core modules
11
- - Enhanced parameter processing with type coercion
12
- - Psqlpy-optimized async resource management
13
- - MyPyC-optimized performance patterns
14
- - Zero-copy data access where possible
15
- - Native PostgreSQL parameter styles
1
+ """Psqlpy driver implementation.
2
+
3
+ Provides PostgreSQL connectivity with parameter style conversion,
4
+ type coercion, error handling, and transaction management.
16
5
  """
17
6
 
18
7
  import datetime
@@ -65,7 +54,7 @@ PSQLPY_STATUS_REGEX: Final[re.Pattern[str]] = re.compile(r"^([A-Z]+)(?:\s+(\d+))
65
54
 
66
55
  SPECIAL_TYPE_REGEX: Final[re.Pattern[str]] = re.compile(
67
56
  r"^(?:"
68
- r"(?P<uuid>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|[0-9a-f]{32})|"
57
+ r"(?P<uuid>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})|"
69
58
  r"(?P<ipv4>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:/(?:3[0-2]|[12]?[0-9]))?)|"
70
59
  r"(?P<ipv6>(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|:(?::[0-9a-f]{1,4}){1,7}|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|::(?:ffff:)?(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?)|"
71
60
  r"(?P<mac>(?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2}|[0-9a-f]{12})|"
@@ -81,23 +70,13 @@ SPECIAL_TYPE_REGEX: Final[re.Pattern[str]] = re.compile(
81
70
 
82
71
 
83
72
  def _detect_postgresql_type(value: str) -> Optional[str]:
84
- """Detect PostgreSQL data type from string value using enhanced regex.
85
-
86
- The SPECIAL_TYPE_REGEX pattern matches the following PostgreSQL types:
87
- - uuid: Standard UUID format (with dashes) or 32 hex characters (without dashes)
88
- - ipv4: IPv4 addresses with optional CIDR notation (e.g., 192.168.1.1/24)
89
- - ipv6: All IPv6 formats including compressed forms and IPv4-mapped addresses
90
- - mac: MAC addresses in colon/dash separated or continuous format
91
- - iso_datetime: ISO 8601 datetime strings with optional timezone
92
- - iso_date: ISO 8601 date strings (YYYY-MM-DD)
93
- - iso_time: Time strings with optional microseconds and timezone
94
- - interval: PostgreSQL interval format or ISO 8601 duration format
95
- - json: JSON objects ({...}) or arrays ([...])
96
- - pg_array: PostgreSQL array literals ({...})
73
+ """Detect PostgreSQL data type from string value.
74
+
75
+ Detects common PostgreSQL types including UUID, IP addresses,
76
+ timestamps, JSON, and arrays.
97
77
 
98
78
  Returns:
99
- Type name if detected ('uuid', 'ipv4', 'ipv6', 'mac', 'iso_datetime', etc.)
100
- None if no special type detected
79
+ Type name if detected, None otherwise.
101
80
  """
102
81
  match = SPECIAL_TYPE_REGEX.match(value)
103
82
  if not match:
@@ -182,12 +161,9 @@ _PSQLPY_TYPE_CONVERTERS: dict[str, Any] = {
182
161
 
183
162
 
184
163
  def _convert_psqlpy_parameters(value: Any) -> Any:
185
- """Convert parameters for Psqlpy compatibility using enhanced type detection.
164
+ """Convert parameters for Psqlpy compatibility.
186
165
 
187
- This function performs intelligent type conversions based on detected PostgreSQL types.
188
- Uses a hash map for O(1) type conversion dispatch. Works in conjunction with
189
- the type_coercion_map for optimal performance - basic type coercion happens in
190
- the core pipeline, while PostgreSQL-specific string type detection happens here.
166
+ Performs type conversions based on detected PostgreSQL types.
191
167
 
192
168
  Args:
193
169
  value: Parameter value to convert
@@ -212,7 +188,7 @@ def _convert_psqlpy_parameters(value: Any) -> Any:
212
188
 
213
189
 
214
190
  class PsqlpyCursor:
215
- """Context manager for Psqlpy cursor management with enhanced error handling."""
191
+ """Context manager for Psqlpy cursor management."""
216
192
 
217
193
  __slots__ = ("_in_use", "connection")
218
194
 
@@ -221,12 +197,12 @@ class PsqlpyCursor:
221
197
  self._in_use = False
222
198
 
223
199
  async def __aenter__(self) -> "PsqlpyConnection":
224
- """Enter cursor context with proper lifecycle tracking."""
200
+ """Enter cursor context."""
225
201
  self._in_use = True
226
202
  return self.connection
227
203
 
228
204
  async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
229
- """Exit cursor context with proper cleanup."""
205
+ """Exit cursor context."""
230
206
  _ = (exc_type, exc_val, exc_tb)
231
207
  self._in_use = False
232
208
 
@@ -274,34 +250,10 @@ class PsqlpyExceptionHandler:
274
250
 
275
251
 
276
252
  class PsqlpyDriver(AsyncDriverAdapterBase):
277
- """Enhanced Psqlpy driver with CORE_ROUND_3 architecture integration.
278
-
279
- This driver leverages the complete core module system for maximum performance:
280
-
281
- Performance Improvements:
282
- - 5-10x faster SQL compilation through single-pass processing
283
- - 40-60% memory reduction through __slots__ optimization
284
- - Enhanced caching for repeated statement execution
285
- - Zero-copy parameter processing where possible
286
- - Psqlpy-optimized async resource management
287
-
288
- Core Integration Features:
289
- - sqlspec.core.statement for enhanced SQL processing
290
- - sqlspec.core.parameters for optimized parameter handling
291
- - sqlspec.core.cache for unified statement caching
292
- - sqlspec.core.config for centralized configuration management
293
-
294
- Psqlpy Features:
295
- - Native PostgreSQL parameter styles (NUMERIC, NAMED_DOLLAR)
296
- - Enhanced async execution with proper transaction management
297
- - Optimized batch operations with psqlpy execute_many
298
- - PostgreSQL-specific exception handling and command tag parsing
299
-
300
- Compatibility:
301
- - 100% backward compatibility with existing psqlpy driver interface
302
- - All existing tests pass without modification
303
- - Complete StatementConfig API compatibility
304
- - Preserved async patterns and transaction management
253
+ """Psqlpy driver implementation.
254
+
255
+ Provides PostgreSQL connectivity through psqlpy with parameter style
256
+ conversion, type coercion, error handling, and transaction management.
305
257
  """
306
258
 
307
259
  __slots__ = ()
@@ -315,18 +267,17 @@ class PsqlpyDriver(AsyncDriverAdapterBase):
315
267
  ) -> None:
316
268
  if statement_config is None:
317
269
  cache_config = get_cache_config()
318
- enhanced_config = psqlpy_statement_config.replace(
270
+ statement_config = psqlpy_statement_config.replace(
319
271
  enable_caching=cache_config.compiled_cache_enabled,
320
272
  enable_parsing=True,
321
273
  enable_validation=True,
322
274
  dialect="postgres",
323
275
  )
324
- statement_config = enhanced_config
325
276
 
326
277
  super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
327
278
 
328
279
  def with_cursor(self, connection: "PsqlpyConnection") -> "PsqlpyCursor":
329
- """Create context manager for psqlpy cursor with enhanced resource management."""
280
+ """Create context manager for psqlpy cursor."""
330
281
  return PsqlpyCursor(connection)
331
282
 
332
283
  def handle_database_exceptions(self) -> "AbstractAsyncContextManager[None]":
@@ -336,30 +287,18 @@ class PsqlpyDriver(AsyncDriverAdapterBase):
336
287
  async def _try_special_handling(self, cursor: "PsqlpyConnection", statement: SQL) -> "Optional[SQLResult]":
337
288
  """Hook for psqlpy-specific special operations.
338
289
 
339
- Psqlpy has some specific optimizations we could leverage in the future:
340
- - Native transaction management with connection pooling
341
- - Batch execution optimization for scripts
342
- - Cursor-based iteration for large result sets
343
- - Connection pool management
344
-
345
- For now, we proceed with standard execution but this provides
346
- a clean extension point for psqlpy-specific optimizations.
347
-
348
290
  Args:
349
291
  cursor: Psqlpy connection object
350
292
  statement: SQL statement to analyze
351
293
 
352
294
  Returns:
353
- None for standard execution (no special operations implemented yet)
295
+ None for standard execution
354
296
  """
355
297
  _ = (cursor, statement)
356
298
  return None
357
299
 
358
300
  async def _execute_script(self, cursor: "PsqlpyConnection", statement: SQL) -> "ExecutionResult":
359
- """Execute SQL script using enhanced statement splitting and parameter handling.
360
-
361
- Uses core module optimization for statement parsing and parameter processing.
362
- Leverages psqlpy's execute_batch for optimal script execution when possible.
301
+ """Execute SQL script with statement splitting and parameter handling.
363
302
 
364
303
  Args:
365
304
  cursor: Psqlpy connection object
@@ -390,17 +329,14 @@ class PsqlpyDriver(AsyncDriverAdapterBase):
390
329
  )
391
330
 
392
331
  async def _execute_many(self, cursor: "PsqlpyConnection", statement: SQL) -> "ExecutionResult":
393
- """Execute SQL with multiple parameter sets using optimized batch processing.
394
-
395
- Leverages psqlpy's execute_many for efficient batch operations with
396
- enhanced parameter format handling for PostgreSQL.
332
+ """Execute SQL with multiple parameter sets using batch processing.
397
333
 
398
334
  Args:
399
335
  cursor: Psqlpy connection object
400
336
  statement: SQL statement with multiple parameter sets
401
337
 
402
338
  Returns:
403
- ExecutionResult with accurate batch execution metadata
339
+ ExecutionResult with batch execution metadata
404
340
  """
405
341
  sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
406
342
 
@@ -422,17 +358,14 @@ class PsqlpyDriver(AsyncDriverAdapterBase):
422
358
  return self.create_execution_result(cursor, rowcount_override=rows_affected, is_many_result=True)
423
359
 
424
360
  async def _execute_statement(self, cursor: "PsqlpyConnection", statement: SQL) -> "ExecutionResult":
425
- """Execute single SQL statement with enhanced data handling and performance optimization.
426
-
427
- Uses core processing for optimal parameter handling and result processing.
428
- Leverages psqlpy's fetch for SELECT queries and execute for other operations.
361
+ """Execute single SQL statement with data handling.
429
362
 
430
363
  Args:
431
364
  cursor: Psqlpy connection object
432
365
  statement: SQL statement to execute
433
366
 
434
367
  Returns:
435
- ExecutionResult with comprehensive execution metadata
368
+ ExecutionResult with execution metadata
436
369
  """
437
370
  sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
438
371
 
@@ -457,10 +390,7 @@ class PsqlpyDriver(AsyncDriverAdapterBase):
457
390
  return self.create_execution_result(cursor, rowcount_override=rows_affected)
458
391
 
459
392
  def _extract_rows_affected(self, result: Any) -> int:
460
- """Extract rows affected from psqlpy result using PostgreSQL command tag parsing.
461
-
462
- Psqlpy may return command tag information that we can parse for accurate
463
- row count reporting in INSERT/UPDATE/DELETE operations.
393
+ """Extract rows affected from psqlpy result.
464
394
 
465
395
  Args:
466
396
  result: Psqlpy execution result object
@@ -482,11 +412,6 @@ class PsqlpyDriver(AsyncDriverAdapterBase):
482
412
  def _parse_command_tag(self, tag: str) -> int:
483
413
  """Parse PostgreSQL command tag to extract rows affected.
484
414
 
485
- PostgreSQL command tags have formats like:
486
- - 'INSERT 0 1' (INSERT with 1 row)
487
- - 'UPDATE 5' (UPDATE with 5 rows)
488
- - 'DELETE 3' (DELETE with 3 rows)
489
-
490
415
  Args:
491
416
  tag: PostgreSQL command tag string
492
417
 
@@ -85,17 +85,18 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
85
85
  *,
86
86
  pool_config: "Optional[Union[PsycopgPoolParams, dict[str, Any]]]" = None,
87
87
  pool_instance: Optional["ConnectionPool"] = None,
88
- statement_config: "Optional[StatementConfig]" = None,
89
88
  migration_config: Optional[dict[str, Any]] = None,
89
+ statement_config: "Optional[StatementConfig]" = None,
90
+ driver_features: "Optional[dict[str, Any]]" = None,
90
91
  ) -> None:
91
92
  """Initialize Psycopg synchronous configuration.
92
93
 
93
94
  Args:
94
95
  pool_config: Pool configuration parameters (TypedDict or dict)
95
96
  pool_instance: Existing pool instance to use
96
- statement_config: Default SQL statement configuration
97
97
  migration_config: Migration configuration
98
-
98
+ statement_config: Default SQL statement configuration
99
+ driver_features: Optional driver feature configuration
99
100
  """
100
101
  processed_pool_config: dict[str, Any] = dict(pool_config) if pool_config else {}
101
102
  if "extra" in processed_pool_config:
@@ -107,6 +108,7 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
107
108
  pool_instance=pool_instance,
108
109
  migration_config=migration_config,
109
110
  statement_config=statement_config or psycopg_statement_config,
111
+ driver_features=driver_features or {},
110
112
  )
111
113
 
112
114
  def _create_pool(self) -> "ConnectionPool":
@@ -268,14 +270,16 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
268
270
  pool_instance: "Optional[AsyncConnectionPool]" = None,
269
271
  migration_config: "Optional[dict[str, Any]]" = None,
270
272
  statement_config: "Optional[StatementConfig]" = None,
273
+ driver_features: "Optional[dict[str, Any]]" = None,
271
274
  ) -> None:
272
275
  """Initialize Psycopg asynchronous configuration.
273
276
 
274
277
  Args:
275
278
  pool_config: Pool configuration parameters (TypedDict or dict)
276
279
  pool_instance: Existing pool instance to use
277
- statement_config: Default SQL statement configuration
278
280
  migration_config: Migration configuration
281
+ statement_config: Default SQL statement configuration
282
+ driver_features: Optional driver feature configuration
279
283
  """
280
284
  processed_pool_config: dict[str, Any] = dict(pool_config) if pool_config else {}
281
285
  if "extra" in processed_pool_config:
@@ -287,6 +291,7 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
287
291
  pool_instance=pool_instance,
288
292
  migration_config=migration_config,
289
293
  statement_config=statement_config or psycopg_statement_config,
294
+ driver_features=driver_features or {},
290
295
  )
291
296
 
292
297
  async def _create_pool(self) -> "AsyncConnectionPool":
@@ -306,7 +311,6 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
306
311
  "num_workers": all_config.pop("num_workers", 3),
307
312
  }
308
313
 
309
- # Capture autocommit setting before configuring the pool
310
314
  autocommit_setting = all_config.get("autocommit")
311
315
 
312
316
  async def configure_connection(conn: "PsycopgAsyncConnection") -> None: