sqlspec 0.17.0__py3-none-any.whl → 0.18.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 (80) hide show
  1. sqlspec/__init__.py +1 -1
  2. sqlspec/_sql.py +188 -234
  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 +1 -8
  29. sqlspec/builder/__init__.py +1 -1
  30. sqlspec/builder/_base.py +34 -20
  31. sqlspec/builder/_column.py +5 -1
  32. sqlspec/builder/_ddl.py +407 -183
  33. sqlspec/builder/_expression_wrappers.py +46 -0
  34. sqlspec/builder/_insert.py +2 -4
  35. sqlspec/builder/_update.py +5 -5
  36. sqlspec/builder/mixins/_insert_operations.py +26 -6
  37. sqlspec/builder/mixins/_merge_operations.py +1 -1
  38. sqlspec/builder/mixins/_order_limit_operations.py +16 -4
  39. sqlspec/builder/mixins/_select_operations.py +3 -7
  40. sqlspec/builder/mixins/_update_operations.py +4 -4
  41. sqlspec/config.py +32 -13
  42. sqlspec/core/__init__.py +89 -14
  43. sqlspec/core/cache.py +57 -104
  44. sqlspec/core/compiler.py +57 -112
  45. sqlspec/core/filters.py +1 -21
  46. sqlspec/core/hashing.py +13 -47
  47. sqlspec/core/parameters.py +272 -261
  48. sqlspec/core/result.py +12 -27
  49. sqlspec/core/splitter.py +17 -21
  50. sqlspec/core/statement.py +150 -159
  51. sqlspec/driver/_async.py +2 -15
  52. sqlspec/driver/_common.py +16 -95
  53. sqlspec/driver/_sync.py +2 -15
  54. sqlspec/driver/mixins/_result_tools.py +8 -29
  55. sqlspec/driver/mixins/_sql_translator.py +6 -8
  56. sqlspec/exceptions.py +1 -2
  57. sqlspec/loader.py +43 -115
  58. sqlspec/migrations/__init__.py +1 -1
  59. sqlspec/migrations/base.py +34 -45
  60. sqlspec/migrations/commands.py +34 -15
  61. sqlspec/migrations/loaders.py +1 -1
  62. sqlspec/migrations/runner.py +104 -19
  63. sqlspec/migrations/tracker.py +49 -2
  64. sqlspec/protocols.py +13 -6
  65. sqlspec/storage/__init__.py +4 -4
  66. sqlspec/storage/backends/fsspec.py +5 -6
  67. sqlspec/storage/backends/obstore.py +7 -8
  68. sqlspec/storage/registry.py +3 -3
  69. sqlspec/utils/__init__.py +2 -2
  70. sqlspec/utils/logging.py +6 -10
  71. sqlspec/utils/sync_tools.py +27 -4
  72. sqlspec/utils/text.py +6 -1
  73. {sqlspec-0.17.0.dist-info → sqlspec-0.18.0.dist-info}/METADATA +1 -1
  74. sqlspec-0.18.0.dist-info/RECORD +138 -0
  75. sqlspec/builder/_ddl_utils.py +0 -103
  76. sqlspec-0.17.0.dist-info/RECORD +0 -137
  77. {sqlspec-0.17.0.dist-info → sqlspec-0.18.0.dist-info}/WHEEL +0 -0
  78. {sqlspec-0.17.0.dist-info → sqlspec-0.18.0.dist-info}/entry_points.txt +0 -0
  79. {sqlspec-0.17.0.dist-info → sqlspec-0.18.0.dist-info}/licenses/LICENSE +0 -0
  80. {sqlspec-0.17.0.dist-info → sqlspec-0.18.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/core/compiler.py CHANGED
@@ -1,18 +1,9 @@
1
- """SQL processor with integrated caching and compilation.
2
-
3
- This module implements the core compilation system for SQL statements with
4
- integrated parameter processing and caching.
1
+ """SQL compilation and caching.
5
2
 
6
3
  Components:
7
- - CompiledSQL: Immutable compilation result with complete information
8
- - SQLProcessor: Single-pass compiler with integrated caching
9
- - Integrated parameter processing via ParameterProcessor
10
-
11
- Features:
12
- - Single SQLGlot parse for efficient processing
13
- - AST-based operation type detection
14
- - Unified caching system with LRU eviction
15
- - Complete StatementConfig support
4
+ - CompiledSQL: Immutable compilation result
5
+ - SQLProcessor: SQL compiler with caching
6
+ - Parameter processing via ParameterProcessor
16
7
  """
17
8
 
18
9
  import hashlib
@@ -31,7 +22,7 @@ from sqlspec.utils.logging import get_logger
31
22
  if TYPE_CHECKING:
32
23
  from sqlspec.core.statement import StatementConfig
33
24
 
34
- # Define OperationType here to avoid circular import
25
+
35
26
  OperationType = Literal[
36
27
  "SELECT",
37
28
  "INSERT",
@@ -52,35 +43,24 @@ __all__ = ("CompiledSQL", "OperationType", "SQLProcessor")
52
43
 
53
44
  logger = get_logger("sqlspec.core.compiler")
54
45
 
55
- _OPERATION_TYPES = {
56
- "SELECT": "SELECT",
57
- "INSERT": "INSERT",
58
- "UPDATE": "UPDATE",
59
- "DELETE": "DELETE",
60
- "COPY": "COPY",
61
- "COPY_FROM": "COPY_FROM",
62
- "COPY_TO": "COPY_TO",
63
- "EXECUTE": "EXECUTE",
64
- "SCRIPT": "SCRIPT",
65
- "DDL": "DDL",
66
- "PRAGMA": "PRAGMA",
67
- "UNKNOWN": "UNKNOWN",
46
+ OPERATION_TYPE_MAP: "dict[type[exp.Expression], OperationType]" = {
47
+ exp.Select: "SELECT",
48
+ exp.Insert: "INSERT",
49
+ exp.Update: "UPDATE",
50
+ exp.Delete: "DELETE",
51
+ exp.Pragma: "PRAGMA",
52
+ exp.Command: "EXECUTE",
53
+ exp.Create: "DDL",
54
+ exp.Drop: "DDL",
55
+ exp.Alter: "DDL",
68
56
  }
69
57
 
70
58
 
71
- @mypyc_attr(allow_interpreted_subclasses=True)
59
+ @mypyc_attr(allow_interpreted_subclasses=False)
72
60
  class CompiledSQL:
73
- """Immutable compiled SQL result with complete information.
74
-
75
- This class represents the result of SQL compilation, containing all
76
- information needed for execution.
61
+ """Compiled SQL result.
77
62
 
78
- Features:
79
- - Immutable design for safe sharing
80
- - Cached hash for efficient dictionary operations
81
- - Complete operation type detection
82
- - Parameter style and execution information
83
- - Support for execute_many operations
63
+ Contains the result of SQL compilation with information needed for execution.
84
64
  """
85
65
 
86
66
  __slots__ = (
@@ -93,21 +73,23 @@ class CompiledSQL:
93
73
  "supports_many",
94
74
  )
95
75
 
76
+ operation_type: "OperationType"
77
+
96
78
  def __init__(
97
79
  self,
98
80
  compiled_sql: str,
99
81
  execution_parameters: Any,
100
- operation_type: str,
82
+ operation_type: "OperationType",
101
83
  expression: Optional["exp.Expression"] = None,
102
84
  parameter_style: Optional[str] = None,
103
85
  supports_many: bool = False,
104
86
  ) -> None:
105
- """Initialize immutable compiled result.
87
+ """Initialize compiled result.
106
88
 
107
89
  Args:
108
- compiled_sql: Final SQL string ready for execution
90
+ compiled_sql: SQL string ready for execution
109
91
  execution_parameters: Parameters in driver-specific format
110
- operation_type: Detected SQL operation type (SELECT, INSERT, etc.)
92
+ operation_type: SQL operation type (SELECT, INSERT, etc.)
111
93
  expression: SQLGlot AST expression
112
94
  parameter_style: Parameter style used in compilation
113
95
  supports_many: Whether this supports execute_many operations
@@ -121,15 +103,14 @@ class CompiledSQL:
121
103
  self._hash: Optional[int] = None
122
104
 
123
105
  def __hash__(self) -> int:
124
- """Cached hash value with optimization."""
106
+ """Cached hash value."""
125
107
  if self._hash is None:
126
- # Optimize by avoiding str() conversion if possible
127
108
  param_str = str(self.execution_parameters)
128
109
  self._hash = hash((self.compiled_sql, param_str, self.operation_type, self.parameter_style))
129
110
  return self._hash
130
111
 
131
112
  def __eq__(self, other: object) -> bool:
132
- """Equality comparison for compiled results."""
113
+ """Equality comparison."""
133
114
  if not isinstance(other, CompiledSQL):
134
115
  return False
135
116
  return (
@@ -140,7 +121,7 @@ class CompiledSQL:
140
121
  )
141
122
 
142
123
  def __repr__(self) -> str:
143
- """String representation for debugging."""
124
+ """String representation."""
144
125
  return (
145
126
  f"CompiledSQL(sql={self.compiled_sql!r}, "
146
127
  f"params={self.execution_parameters!r}, "
@@ -148,35 +129,21 @@ class CompiledSQL:
148
129
  )
149
130
 
150
131
 
151
- @mypyc_attr(allow_interpreted_subclasses=True)
132
+ @mypyc_attr(allow_interpreted_subclasses=False)
152
133
  class SQLProcessor:
153
- """SQL processor with integrated caching and compilation.
154
-
155
- This is the core compilation engine that processes SQL statements with
156
- integrated parameter processing and caching.
157
-
158
- Processing Flow:
159
- 1. Parameter detection and normalization (if needed)
160
- 2. Single SQLGlot parse
161
- 3. AST-based operation type detection
162
- 4. Parameter conversion (if needed)
163
- 5. Final SQL generation with execution parameters
164
-
165
- Features:
166
- - LRU cache with O(1) operations
167
- - Integrated parameter processing
168
- - Cached compilation results
169
- - Complete StatementConfig support
134
+ """SQL processor with compilation and caching.
135
+
136
+ Processes SQL statements with parameter processing and caching.
170
137
  """
171
138
 
172
139
  __slots__ = ("_cache", "_cache_hits", "_cache_misses", "_config", "_max_cache_size", "_parameter_processor")
173
140
 
174
141
  def __init__(self, config: "StatementConfig", max_cache_size: int = 1000) -> None:
175
- """Initialize processor with configuration and caching.
142
+ """Initialize processor.
176
143
 
177
144
  Args:
178
- config: Statement configuration with parameter processing settings
179
- max_cache_size: Maximum number of cached compilation results
145
+ config: Statement configuration
146
+ max_cache_size: Maximum number of compilation results to cache
180
147
  """
181
148
  self._config = config
182
149
  self._cache: OrderedDict[str, CompiledSQL] = OrderedDict()
@@ -186,15 +153,15 @@ class SQLProcessor:
186
153
  self._cache_misses = 0
187
154
 
188
155
  def compile(self, sql: str, parameters: Any = None, is_many: bool = False) -> CompiledSQL:
189
- """Compile SQL statement with integrated caching.
156
+ """Compile SQL statement.
190
157
 
191
158
  Args:
192
- sql: Raw SQL string for compilation
193
- parameters: Parameter values in any format
159
+ sql: SQL string for compilation
160
+ parameters: Parameter values
194
161
  is_many: Whether this is for execute_many operation
195
162
 
196
163
  Returns:
197
- CompiledSQL with all information for execution
164
+ CompiledSQL with execution information
198
165
  """
199
166
  if not self._config.enable_caching:
200
167
  return self._compile_uncached(sql, parameters, is_many)
@@ -202,7 +169,6 @@ class SQLProcessor:
202
169
  cache_key = self._make_cache_key(sql, parameters)
203
170
 
204
171
  if cache_key in self._cache:
205
- # Move to end for LRU behavior
206
172
  result = self._cache[cache_key]
207
173
  del self._cache[cache_key]
208
174
  self._cache[cache_key] = result
@@ -222,7 +188,7 @@ class SQLProcessor:
222
188
  """Compile SQL without caching.
223
189
 
224
190
  Args:
225
- sql: Raw SQL string
191
+ sql: SQL string
226
192
  parameters: Parameter values
227
193
  is_many: Whether this is for execute_many operation
228
194
 
@@ -230,10 +196,8 @@ class SQLProcessor:
230
196
  CompiledSQL result
231
197
  """
232
198
  try:
233
- # Cache dialect string to avoid repeated conversions
234
199
  dialect_str = str(self._config.dialect) if self._config.dialect else None
235
200
 
236
- # Process parameters in single call
237
201
  processed_sql: str
238
202
  processed_params: Any
239
203
  processed_sql, processed_params = self._parameter_processor.process(
@@ -244,7 +208,6 @@ class SQLProcessor:
244
208
  is_many=is_many,
245
209
  )
246
210
 
247
- # Optimize static compilation path
248
211
  if self._config.parameter_config.needs_static_script_compilation and processed_params is None:
249
212
  sqlglot_sql = processed_sql
250
213
  else:
@@ -255,15 +218,13 @@ class SQLProcessor:
255
218
  final_parameters = processed_params
256
219
  ast_was_transformed = False
257
220
  expression = None
258
- operation_type = "EXECUTE"
221
+ operation_type: OperationType = "EXECUTE"
259
222
 
260
223
  if self._config.enable_parsing:
261
224
  try:
262
- # Use copy=False for performance optimization
263
225
  expression = sqlglot.parse_one(sqlglot_sql, dialect=dialect_str)
264
226
  operation_type = self._detect_operation_type(expression)
265
227
 
266
- # Handle AST transformation if configured
267
228
  ast_transformer = self._config.parameter_config.ast_transformer
268
229
  if ast_transformer:
269
230
  expression, final_parameters = ast_transformer(expression, processed_params)
@@ -273,7 +234,6 @@ class SQLProcessor:
273
234
  expression = None
274
235
  operation_type = "EXECUTE"
275
236
 
276
- # Optimize final SQL generation path
277
237
  if self._config.parameter_config.needs_static_script_compilation and processed_params is None:
278
238
  final_sql, final_params = processed_sql, processed_params
279
239
  elif ast_was_transformed and expression is not None:
@@ -303,12 +263,10 @@ class SQLProcessor:
303
263
 
304
264
  except Exception as e:
305
265
  logger.warning("Compilation failed, using fallback: %s", e)
306
- return CompiledSQL(
307
- compiled_sql=sql, execution_parameters=parameters, operation_type=_OPERATION_TYPES["UNKNOWN"]
308
- )
266
+ return CompiledSQL(compiled_sql=sql, execution_parameters=parameters, operation_type="UNKNOWN")
309
267
 
310
268
  def _make_cache_key(self, sql: str, parameters: Any) -> str:
311
- """Generate cache key for compilation result.
269
+ """Generate cache key.
312
270
 
313
271
  Args:
314
272
  sql: SQL string
@@ -317,12 +275,11 @@ class SQLProcessor:
317
275
  Returns:
318
276
  Cache key string
319
277
  """
320
- # Optimize key generation by avoiding string conversion overhead
278
+
321
279
  param_repr = repr(parameters)
322
280
  dialect_str = str(self._config.dialect) if self._config.dialect else None
323
281
  param_style = self._config.parameter_config.default_parameter_style.value
324
282
 
325
- # Use direct tuple construction for better performance
326
283
  hash_data = (
327
284
  sql,
328
285
  param_repr,
@@ -332,34 +289,23 @@ class SQLProcessor:
332
289
  self._config.enable_transformations,
333
290
  )
334
291
 
335
- # Optimize hash computation
336
292
  hash_str = hashlib.sha256(str(hash_data).encode("utf-8")).hexdigest()[:16]
337
293
  return f"sql_{hash_str}"
338
294
 
339
- def _detect_operation_type(self, expression: "exp.Expression") -> str:
295
+ def _detect_operation_type(self, expression: "exp.Expression") -> "OperationType":
340
296
  """Detect operation type from AST.
341
297
 
342
- Uses SQLGlot AST structure to determine operation type.
343
-
344
298
  Args:
345
- expression: SQLGlot AST expression
299
+ expression: AST expression
346
300
 
347
301
  Returns:
348
- Operation type string
302
+ Operation type literal
349
303
  """
350
- # Use isinstance for compatibility with mocks and inheritance
351
- if isinstance(expression, exp.Select):
352
- return "SELECT"
353
- if isinstance(expression, exp.Insert):
354
- return "INSERT"
355
- if isinstance(expression, exp.Update):
356
- return "UPDATE"
357
- if isinstance(expression, exp.Delete):
358
- return "DELETE"
359
- if isinstance(expression, exp.Pragma):
360
- return "PRAGMA"
361
- if isinstance(expression, exp.Command):
362
- return "EXECUTE"
304
+
305
+ expr_type = type(expression)
306
+ if expr_type in OPERATION_TYPE_MAP:
307
+ return OPERATION_TYPE_MAP[expr_type] # pyright: ignore
308
+
363
309
  if isinstance(expression, exp.Copy):
364
310
  copy_kind = expression.args.get("kind")
365
311
  if copy_kind is True:
@@ -367,8 +313,7 @@ class SQLProcessor:
367
313
  if copy_kind is False:
368
314
  return "COPY_TO"
369
315
  return "COPY"
370
- if isinstance(expression, (exp.Create, exp.Drop, exp.Alter)):
371
- return "DDL"
316
+
372
317
  return "UNKNOWN"
373
318
 
374
319
  def _apply_final_transformations(
@@ -377,10 +322,10 @@ class SQLProcessor:
377
322
  """Apply final transformations.
378
323
 
379
324
  Args:
380
- expression: SQLGlot AST expression (if available)
381
- sql: Compiled SQL string (fallback)
325
+ expression: SQLGlot AST expression
326
+ sql: SQL string
382
327
  parameters: Execution parameters
383
- dialect_str: SQL dialect for AST-to-SQL conversion
328
+ dialect_str: SQL dialect
384
329
 
385
330
  Returns:
386
331
  Tuple of (final_sql, final_parameters)
@@ -395,7 +340,7 @@ class SQLProcessor:
395
340
  return sql, parameters
396
341
 
397
342
  def clear_cache(self) -> None:
398
- """Clear compilation cache."""
343
+ """Clear cache."""
399
344
  self._cache.clear()
400
345
  self._cache_hits = 0
401
346
  self._cache_misses = 0
@@ -405,7 +350,7 @@ class SQLProcessor:
405
350
  """Get cache statistics.
406
351
 
407
352
  Returns:
408
- Dictionary with cache hit/miss statistics
353
+ Dictionary with cache statistics
409
354
  """
410
355
  total_requests = self._cache_hits + self._cache_misses
411
356
  hit_rate_pct = int((self._cache_hits / total_requests) * 100) if total_requests > 0 else 0
sqlspec/core/filters.py CHANGED
@@ -25,6 +25,7 @@ from collections.abc import Sequence
25
25
  from datetime import datetime
26
26
  from typing import TYPE_CHECKING, Any, Generic, Literal, Optional, Union
27
27
 
28
+ import sqlglot
28
29
  from sqlglot import exp
29
30
  from typing_extensions import TypeAlias, TypeVar
30
31
 
@@ -160,7 +161,6 @@ class BeforeAfterFilter(StatementFilter):
160
161
  conditions: list[Condition] = []
161
162
  col_expr = exp.column(self.field_name)
162
163
 
163
- # Resolve parameter name conflicts
164
164
  proposed_names = []
165
165
  if self.before and self._param_name_before:
166
166
  proposed_names.append(self._param_name_before)
@@ -238,7 +238,6 @@ class OnBeforeAfterFilter(StatementFilter):
238
238
  def append_to_statement(self, statement: "SQL") -> "SQL":
239
239
  conditions: list[Condition] = []
240
240
 
241
- # Resolve parameter name conflicts
242
241
  proposed_names = []
243
242
  if self.on_or_before and self._param_name_on_or_before:
244
243
  proposed_names.append(self._param_name_on_or_before)
@@ -328,7 +327,6 @@ class InCollectionFilter(InAnyFilter[T]):
328
327
  if not self.values:
329
328
  return statement.where(exp.false())
330
329
 
331
- # Resolve parameter name conflicts
332
330
  resolved_names = self._resolve_parameter_conflicts(statement, self._param_names)
333
331
 
334
332
  placeholder_expressions: list[exp.Placeholder] = [
@@ -337,7 +335,6 @@ class InCollectionFilter(InAnyFilter[T]):
337
335
 
338
336
  result = statement.where(exp.In(this=exp.column(self.field_name), expressions=placeholder_expressions))
339
337
 
340
- # Add parameters with resolved names
341
338
  for resolved_name, value in zip(resolved_names, self.values):
342
339
  result = result.add_named_parameter(resolved_name, value)
343
340
  return result
@@ -383,7 +380,6 @@ class NotInCollectionFilter(InAnyFilter[T]):
383
380
  if self.values is None or not self.values:
384
381
  return statement
385
382
 
386
- # Resolve parameter name conflicts
387
383
  resolved_names = self._resolve_parameter_conflicts(statement, self._param_names)
388
384
 
389
385
  placeholder_expressions: list[exp.Placeholder] = [
@@ -394,7 +390,6 @@ class NotInCollectionFilter(InAnyFilter[T]):
394
390
  exp.Not(this=exp.In(this=exp.column(self.field_name), expressions=placeholder_expressions))
395
391
  )
396
392
 
397
- # Add parameters with resolved names
398
393
  for resolved_name, value in zip(resolved_names, self.values):
399
394
  result = result.add_named_parameter(resolved_name, value)
400
395
  return result
@@ -445,7 +440,6 @@ class AnyCollectionFilter(InAnyFilter[T]):
445
440
  if not self.values:
446
441
  return statement.where(exp.false())
447
442
 
448
- # Resolve parameter name conflicts
449
443
  resolved_names = self._resolve_parameter_conflicts(statement, self._param_names)
450
444
 
451
445
  placeholder_expressions: list[exp.Expression] = [
@@ -455,7 +449,6 @@ class AnyCollectionFilter(InAnyFilter[T]):
455
449
  array_expr = exp.Array(expressions=placeholder_expressions)
456
450
  result = statement.where(exp.EQ(this=exp.column(self.field_name), expression=exp.Any(this=array_expr)))
457
451
 
458
- # Add parameters with resolved names
459
452
  for resolved_name, value in zip(resolved_names, self.values):
460
453
  result = result.add_named_parameter(resolved_name, value)
461
454
  return result
@@ -500,7 +493,6 @@ class NotAnyCollectionFilter(InAnyFilter[T]):
500
493
  if self.values is None or not self.values:
501
494
  return statement
502
495
 
503
- # Resolve parameter name conflicts
504
496
  resolved_names = self._resolve_parameter_conflicts(statement, self._param_names)
505
497
 
506
498
  placeholder_expressions: list[exp.Expression] = [
@@ -511,7 +503,6 @@ class NotAnyCollectionFilter(InAnyFilter[T]):
511
503
  condition = exp.EQ(this=exp.column(self.field_name), expression=exp.Any(this=array_expr))
512
504
  result = statement.where(exp.Not(this=condition))
513
505
 
514
- # Add parameters with resolved names
515
506
  for resolved_name, value in zip(resolved_names, self.values):
516
507
  result = result.add_named_parameter(resolved_name, value)
517
508
  return result
@@ -558,27 +549,20 @@ class LimitOffsetFilter(PaginationFilter):
558
549
  return [], {self._limit_param_name: self.limit, self._offset_param_name: self.offset}
559
550
 
560
551
  def append_to_statement(self, statement: "SQL") -> "SQL":
561
- import sqlglot
562
- from sqlglot import exp
563
-
564
- # Resolve parameter name conflicts
565
552
  resolved_names = self._resolve_parameter_conflicts(statement, [self._limit_param_name, self._offset_param_name])
566
553
  limit_param_name, offset_param_name = resolved_names
567
554
 
568
555
  limit_placeholder = exp.Placeholder(this=limit_param_name)
569
556
  offset_placeholder = exp.Placeholder(this=offset_param_name)
570
557
 
571
- # Parse the current SQL to get the statement structure
572
558
  try:
573
559
  current_statement = sqlglot.parse_one(statement._raw_sql, dialect=getattr(statement, "_dialect", None))
574
560
  except Exception:
575
- # Fallback to wrapping in subquery if parsing fails
576
561
  current_statement = exp.Select().from_(f"({statement._raw_sql})")
577
562
 
578
563
  if isinstance(current_statement, exp.Select):
579
564
  new_statement = current_statement.limit(limit_placeholder).offset(offset_placeholder)
580
565
  else:
581
- # Wrap non-SELECT statements in a subquery
582
566
  new_statement = exp.Select().from_(current_statement).limit(limit_placeholder).offset(offset_placeholder)
583
567
 
584
568
  result = statement.copy(statement=new_statement)
@@ -678,7 +662,6 @@ class SearchFilter(StatementFilter):
678
662
  if not self.value or not self._param_name:
679
663
  return statement
680
664
 
681
- # Resolve parameter name conflicts
682
665
  resolved_names = self._resolve_parameter_conflicts(statement, [self._param_name])
683
666
  param_name = resolved_names[0]
684
667
 
@@ -701,7 +684,6 @@ class SearchFilter(StatementFilter):
701
684
  else:
702
685
  result = statement
703
686
 
704
- # Add parameter with resolved name
705
687
  search_value_with_wildcards = f"%{self.value}%"
706
688
  return result.add_named_parameter(param_name, search_value_with_wildcards)
707
689
 
@@ -745,7 +727,6 @@ class NotInSearchFilter(SearchFilter):
745
727
  if not self.value or not self._param_name:
746
728
  return statement
747
729
 
748
- # Resolve parameter name conflicts
749
730
  resolved_names = self._resolve_parameter_conflicts(statement, [self._param_name])
750
731
  param_name = resolved_names[0]
751
732
 
@@ -768,7 +749,6 @@ class NotInSearchFilter(SearchFilter):
768
749
  final_condition = exp.And(this=final_condition, expression=cond)
769
750
  result = statement.where(final_condition)
770
751
 
771
- # Add parameter with resolved name
772
752
  search_value_with_wildcards = f"%{self.value}%"
773
753
  return result.add_named_parameter(param_name, search_value_with_wildcards)
774
754