sqlspec 0.15.0__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/_sql.py +252 -29
- sqlspec/builder/_insert.py +12 -1
- sqlspec/builder/_parsing_utils.py +5 -1
- sqlspec/builder/mixins/_insert_operations.py +12 -2
- sqlspec/builder/mixins/_merge_operations.py +16 -4
- sqlspec/builder/mixins/_select_operations.py +4 -2
- sqlspec/builder/mixins/_update_operations.py +12 -2
- sqlspec/builder/mixins/_where_clause.py +163 -63
- sqlspec/core/filters.py +12 -10
- sqlspec/core/statement.py +17 -2
- sqlspec/driver/mixins/_result_tools.py +12 -16
- sqlspec/extensions/litestar/cli.py +1 -1
- sqlspec/extensions/litestar/plugin.py +2 -2
- sqlspec/utils/sync_tools.py +1 -1
- {sqlspec-0.15.0.dist-info → sqlspec-0.16.0.dist-info}/METADATA +1 -1
- {sqlspec-0.15.0.dist-info → sqlspec-0.16.0.dist-info}/RECORD +20 -20
- {sqlspec-0.15.0.dist-info → sqlspec-0.16.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.15.0.dist-info → sqlspec-0.16.0.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.15.0.dist-info → sqlspec-0.16.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.15.0.dist-info → sqlspec-0.16.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/_sql.py
CHANGED
|
@@ -4,17 +4,65 @@ Provides both statement builders (select, insert, update, etc.) and column expre
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
|
-
from typing import Any, Optional, Union
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
8
8
|
|
|
9
9
|
import sqlglot
|
|
10
10
|
from sqlglot import exp
|
|
11
11
|
from sqlglot.dialects.dialect import DialectType
|
|
12
12
|
from sqlglot.errors import ParseError as SQLGlotParseError
|
|
13
13
|
|
|
14
|
-
from sqlspec.builder import
|
|
14
|
+
from sqlspec.builder import (
|
|
15
|
+
AlterTable,
|
|
16
|
+
Column,
|
|
17
|
+
CommentOn,
|
|
18
|
+
CreateIndex,
|
|
19
|
+
CreateMaterializedView,
|
|
20
|
+
CreateSchema,
|
|
21
|
+
CreateTable,
|
|
22
|
+
CreateTableAsSelect,
|
|
23
|
+
CreateView,
|
|
24
|
+
Delete,
|
|
25
|
+
DropIndex,
|
|
26
|
+
DropSchema,
|
|
27
|
+
DropTable,
|
|
28
|
+
DropView,
|
|
29
|
+
Insert,
|
|
30
|
+
Merge,
|
|
31
|
+
RenameTable,
|
|
32
|
+
Select,
|
|
33
|
+
Truncate,
|
|
34
|
+
Update,
|
|
35
|
+
)
|
|
15
36
|
from sqlspec.exceptions import SQLBuilderError
|
|
16
37
|
|
|
17
|
-
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from sqlspec.core.statement import SQL
|
|
40
|
+
|
|
41
|
+
__all__ = (
|
|
42
|
+
"AlterTable",
|
|
43
|
+
"Case",
|
|
44
|
+
"Column",
|
|
45
|
+
"CommentOn",
|
|
46
|
+
"CreateIndex",
|
|
47
|
+
"CreateMaterializedView",
|
|
48
|
+
"CreateSchema",
|
|
49
|
+
"CreateTable",
|
|
50
|
+
"CreateTableAsSelect",
|
|
51
|
+
"CreateView",
|
|
52
|
+
"Delete",
|
|
53
|
+
"DropIndex",
|
|
54
|
+
"DropSchema",
|
|
55
|
+
"DropTable",
|
|
56
|
+
"DropView",
|
|
57
|
+
"Insert",
|
|
58
|
+
"Merge",
|
|
59
|
+
"RenameTable",
|
|
60
|
+
"SQLFactory",
|
|
61
|
+
"Select",
|
|
62
|
+
"Truncate",
|
|
63
|
+
"Update",
|
|
64
|
+
"sql",
|
|
65
|
+
)
|
|
18
66
|
|
|
19
67
|
logger = logging.getLogger("sqlspec")
|
|
20
68
|
|
|
@@ -212,6 +260,174 @@ class SQLFactory:
|
|
|
212
260
|
return builder.into(table_or_sql)
|
|
213
261
|
return builder
|
|
214
262
|
|
|
263
|
+
# ===================
|
|
264
|
+
# DDL Statement Builders
|
|
265
|
+
# ===================
|
|
266
|
+
|
|
267
|
+
def create_table(self, table_name: str, dialect: DialectType = None) -> "CreateTable":
|
|
268
|
+
"""Create a CREATE TABLE builder.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
table_name: Name of the table to create
|
|
272
|
+
dialect: Optional SQL dialect
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
CreateTable builder instance
|
|
276
|
+
"""
|
|
277
|
+
builder = CreateTable(table_name)
|
|
278
|
+
builder.dialect = dialect or self.dialect
|
|
279
|
+
return builder
|
|
280
|
+
|
|
281
|
+
def create_table_as_select(self, dialect: DialectType = None) -> "CreateTableAsSelect":
|
|
282
|
+
"""Create a CREATE TABLE AS SELECT builder.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
dialect: Optional SQL dialect
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
CreateTableAsSelect builder instance
|
|
289
|
+
"""
|
|
290
|
+
builder = CreateTableAsSelect()
|
|
291
|
+
builder.dialect = dialect or self.dialect
|
|
292
|
+
return builder
|
|
293
|
+
|
|
294
|
+
def create_view(self, dialect: DialectType = None) -> "CreateView":
|
|
295
|
+
"""Create a CREATE VIEW builder.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
dialect: Optional SQL dialect
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
CreateView builder instance
|
|
302
|
+
"""
|
|
303
|
+
builder = CreateView()
|
|
304
|
+
builder.dialect = dialect or self.dialect
|
|
305
|
+
return builder
|
|
306
|
+
|
|
307
|
+
def create_materialized_view(self, dialect: DialectType = None) -> "CreateMaterializedView":
|
|
308
|
+
"""Create a CREATE MATERIALIZED VIEW builder.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
dialect: Optional SQL dialect
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
CreateMaterializedView builder instance
|
|
315
|
+
"""
|
|
316
|
+
builder = CreateMaterializedView()
|
|
317
|
+
builder.dialect = dialect or self.dialect
|
|
318
|
+
return builder
|
|
319
|
+
|
|
320
|
+
def create_index(self, index_name: str, dialect: DialectType = None) -> "CreateIndex":
|
|
321
|
+
"""Create a CREATE INDEX builder.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
index_name: Name of the index to create
|
|
325
|
+
dialect: Optional SQL dialect
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
CreateIndex builder instance
|
|
329
|
+
"""
|
|
330
|
+
return CreateIndex(index_name, dialect=dialect or self.dialect)
|
|
331
|
+
|
|
332
|
+
def create_schema(self, dialect: DialectType = None) -> "CreateSchema":
|
|
333
|
+
"""Create a CREATE SCHEMA builder.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
dialect: Optional SQL dialect
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
CreateSchema builder instance
|
|
340
|
+
"""
|
|
341
|
+
builder = CreateSchema()
|
|
342
|
+
builder.dialect = dialect or self.dialect
|
|
343
|
+
return builder
|
|
344
|
+
|
|
345
|
+
def drop_table(self, table_name: str, dialect: DialectType = None) -> "DropTable":
|
|
346
|
+
"""Create a DROP TABLE builder.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
table_name: Name of the table to drop
|
|
350
|
+
dialect: Optional SQL dialect
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
DropTable builder instance
|
|
354
|
+
"""
|
|
355
|
+
return DropTable(table_name, dialect=dialect or self.dialect)
|
|
356
|
+
|
|
357
|
+
def drop_view(self, dialect: DialectType = None) -> "DropView":
|
|
358
|
+
"""Create a DROP VIEW builder.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
dialect: Optional SQL dialect
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
DropView builder instance
|
|
365
|
+
"""
|
|
366
|
+
return DropView(dialect=dialect or self.dialect)
|
|
367
|
+
|
|
368
|
+
def drop_index(self, index_name: str, dialect: DialectType = None) -> "DropIndex":
|
|
369
|
+
"""Create a DROP INDEX builder.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
index_name: Name of the index to drop
|
|
373
|
+
dialect: Optional SQL dialect
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
DropIndex builder instance
|
|
377
|
+
"""
|
|
378
|
+
return DropIndex(index_name, dialect=dialect or self.dialect)
|
|
379
|
+
|
|
380
|
+
def drop_schema(self, dialect: DialectType = None) -> "DropSchema":
|
|
381
|
+
"""Create a DROP SCHEMA builder.
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
dialect: Optional SQL dialect
|
|
385
|
+
|
|
386
|
+
Returns:
|
|
387
|
+
DropSchema builder instance
|
|
388
|
+
"""
|
|
389
|
+
return DropSchema(dialect=dialect or self.dialect)
|
|
390
|
+
|
|
391
|
+
def alter_table(self, table_name: str, dialect: DialectType = None) -> "AlterTable":
|
|
392
|
+
"""Create an ALTER TABLE builder.
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
table_name: Name of the table to alter
|
|
396
|
+
dialect: Optional SQL dialect
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
AlterTable builder instance
|
|
400
|
+
"""
|
|
401
|
+
builder = AlterTable(table_name)
|
|
402
|
+
builder.dialect = dialect or self.dialect
|
|
403
|
+
return builder
|
|
404
|
+
|
|
405
|
+
def rename_table(self, dialect: DialectType = None) -> "RenameTable":
|
|
406
|
+
"""Create a RENAME TABLE builder.
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
dialect: Optional SQL dialect
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
RenameTable builder instance
|
|
413
|
+
"""
|
|
414
|
+
builder = RenameTable()
|
|
415
|
+
builder.dialect = dialect or self.dialect
|
|
416
|
+
return builder
|
|
417
|
+
|
|
418
|
+
def comment_on(self, dialect: DialectType = None) -> "CommentOn":
|
|
419
|
+
"""Create a COMMENT ON builder.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
dialect: Optional SQL dialect
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
CommentOn builder instance
|
|
426
|
+
"""
|
|
427
|
+
builder = CommentOn()
|
|
428
|
+
builder.dialect = dialect or self.dialect
|
|
429
|
+
return builder
|
|
430
|
+
|
|
215
431
|
# ===================
|
|
216
432
|
# SQL Analysis Helpers
|
|
217
433
|
# ===================
|
|
@@ -363,8 +579,8 @@ class SQLFactory:
|
|
|
363
579
|
# ===================
|
|
364
580
|
|
|
365
581
|
@staticmethod
|
|
366
|
-
def raw(sql_fragment: str) -> exp.Expression:
|
|
367
|
-
"""Create a raw SQL expression from a string fragment.
|
|
582
|
+
def raw(sql_fragment: str, **parameters: Any) -> "Union[exp.Expression, SQL]":
|
|
583
|
+
"""Create a raw SQL expression from a string fragment with optional parameters.
|
|
368
584
|
|
|
369
585
|
This method makes it explicit that you are passing raw SQL that should
|
|
370
586
|
be parsed and included directly in the query. Useful for complex expressions,
|
|
@@ -372,30 +588,30 @@ class SQLFactory:
|
|
|
372
588
|
|
|
373
589
|
Args:
|
|
374
590
|
sql_fragment: Raw SQL string to parse into an expression.
|
|
591
|
+
**parameters: Named parameters for parameter binding.
|
|
375
592
|
|
|
376
593
|
Returns:
|
|
377
|
-
SQLGlot expression from the parsed SQL fragment.
|
|
594
|
+
SQLGlot expression from the parsed SQL fragment (if no parameters).
|
|
595
|
+
SQL statement object (if parameters provided).
|
|
378
596
|
|
|
379
597
|
Raises:
|
|
380
598
|
SQLBuilderError: If the SQL fragment cannot be parsed.
|
|
381
599
|
|
|
382
600
|
Example:
|
|
383
601
|
```python
|
|
384
|
-
# Raw
|
|
385
|
-
|
|
386
|
-
sql.raw("user.id AS u_id"), "name"
|
|
387
|
-
).from_("users")
|
|
602
|
+
# Raw expression without parameters (current behavior)
|
|
603
|
+
expr = sql.raw("COALESCE(name, 'Unknown')")
|
|
388
604
|
|
|
389
|
-
# Raw
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
)
|
|
605
|
+
# Raw SQL with named parameters (new functionality)
|
|
606
|
+
stmt = sql.raw(
|
|
607
|
+
"LOWER(name) LIKE LOWER(:pattern)", pattern=f"%{query}%"
|
|
608
|
+
)
|
|
393
609
|
|
|
394
|
-
# Raw complex expression
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
610
|
+
# Raw complex expression with parameters
|
|
611
|
+
expr = sql.raw(
|
|
612
|
+
"price BETWEEN :min_price AND :max_price",
|
|
613
|
+
min_price=100,
|
|
614
|
+
max_price=500,
|
|
399
615
|
)
|
|
400
616
|
|
|
401
617
|
# Raw window function
|
|
@@ -407,16 +623,23 @@ class SQLFactory:
|
|
|
407
623
|
).from_("employees")
|
|
408
624
|
```
|
|
409
625
|
"""
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
626
|
+
if not parameters:
|
|
627
|
+
# Original behavior - return pure expression
|
|
628
|
+
try:
|
|
629
|
+
parsed: Optional[exp.Expression] = exp.maybe_parse(sql_fragment)
|
|
630
|
+
if parsed is not None:
|
|
631
|
+
return parsed
|
|
632
|
+
if sql_fragment.strip().replace("_", "").replace(".", "").isalnum():
|
|
633
|
+
return exp.to_identifier(sql_fragment)
|
|
634
|
+
return exp.Literal.string(sql_fragment)
|
|
635
|
+
except Exception as e:
|
|
636
|
+
msg = f"Failed to parse raw SQL fragment '{sql_fragment}': {e}"
|
|
637
|
+
raise SQLBuilderError(msg) from e
|
|
638
|
+
|
|
639
|
+
# New behavior - return SQL statement with parameters
|
|
640
|
+
from sqlspec.core.statement import SQL
|
|
641
|
+
|
|
642
|
+
return SQL(sql_fragment, parameters)
|
|
420
643
|
|
|
421
644
|
# ===================
|
|
422
645
|
# Aggregate Functions
|
sqlspec/builder/_insert.py
CHANGED
|
@@ -119,7 +119,18 @@ class Insert(QueryBuilder, ReturningClauseMixin, InsertValuesMixin, InsertFromSe
|
|
|
119
119
|
msg = ERR_MSG_VALUES_COLUMNS_MISMATCH.format(values_len=len(values), columns_len=len(self._columns))
|
|
120
120
|
raise SQLBuilderError(msg)
|
|
121
121
|
|
|
122
|
-
param_names = [
|
|
122
|
+
param_names = []
|
|
123
|
+
for i, value in enumerate(values):
|
|
124
|
+
# Try to use column name if available, otherwise use position-based name
|
|
125
|
+
if self._columns and i < len(self._columns):
|
|
126
|
+
column_name = (
|
|
127
|
+
str(self._columns[i]).split(".")[-1] if "." in str(self._columns[i]) else str(self._columns[i])
|
|
128
|
+
)
|
|
129
|
+
param_name = self._generate_unique_parameter_name(column_name)
|
|
130
|
+
else:
|
|
131
|
+
param_name = self._generate_unique_parameter_name(f"value_{i + 1}")
|
|
132
|
+
_, param_name = self.add_parameter(value, name=param_name)
|
|
133
|
+
param_names.append(param_name)
|
|
123
134
|
value_placeholders = tuple(exp.var(name) for name in param_names)
|
|
124
135
|
|
|
125
136
|
current_values_expression = insert_expr.args.get("expression")
|
|
@@ -109,7 +109,11 @@ def parse_condition_expression(
|
|
|
109
109
|
if value is None:
|
|
110
110
|
return exp.Is(this=column_expr, expression=exp.null())
|
|
111
111
|
if builder and has_parameter_builder(builder):
|
|
112
|
-
|
|
112
|
+
from sqlspec.builder.mixins._where_clause import _extract_column_name
|
|
113
|
+
|
|
114
|
+
column_name = _extract_column_name(column)
|
|
115
|
+
param_name = builder._generate_unique_parameter_name(column_name)
|
|
116
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
113
117
|
return exp.EQ(this=column_expr, expression=exp.Placeholder(this=param_name))
|
|
114
118
|
if isinstance(value, str):
|
|
115
119
|
return exp.EQ(this=column_expr, expression=exp.convert(value))
|
|
@@ -78,11 +78,21 @@ class InsertValuesMixin:
|
|
|
78
78
|
except AttributeError:
|
|
79
79
|
pass
|
|
80
80
|
row_exprs = []
|
|
81
|
-
for v in values:
|
|
81
|
+
for i, v in enumerate(values):
|
|
82
82
|
if isinstance(v, exp.Expression):
|
|
83
83
|
row_exprs.append(v)
|
|
84
84
|
else:
|
|
85
|
-
|
|
85
|
+
# Try to use column name if available, otherwise use position-based name
|
|
86
|
+
try:
|
|
87
|
+
_columns = self._columns # type: ignore[attr-defined]
|
|
88
|
+
if _columns and i < len(_columns):
|
|
89
|
+
column_name = str(_columns[i]).split(".")[-1] if "." in str(_columns[i]) else str(_columns[i])
|
|
90
|
+
param_name = self._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
91
|
+
else:
|
|
92
|
+
param_name = self._generate_unique_parameter_name(f"value_{i + 1}") # type: ignore[attr-defined]
|
|
93
|
+
except AttributeError:
|
|
94
|
+
param_name = self._generate_unique_parameter_name(f"value_{i + 1}") # type: ignore[attr-defined]
|
|
95
|
+
_, param_name = self.add_parameter(v, name=param_name) # type: ignore[attr-defined]
|
|
86
96
|
row_exprs.append(exp.var(param_name))
|
|
87
97
|
values_expr = exp.Values(expressions=[row_exprs])
|
|
88
98
|
self._expression.set("expression", values_expr)
|
|
@@ -172,7 +172,11 @@ class MergeMatchedClauseMixin:
|
|
|
172
172
|
"""
|
|
173
173
|
update_expressions: list[exp.EQ] = []
|
|
174
174
|
for col, val in set_values.items():
|
|
175
|
-
|
|
175
|
+
column_name = col if isinstance(col, str) else str(col)
|
|
176
|
+
if "." in column_name:
|
|
177
|
+
column_name = column_name.split(".")[-1]
|
|
178
|
+
param_name = self._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
179
|
+
param_name = self.add_parameter(val, name=param_name)[1] # type: ignore[attr-defined]
|
|
176
180
|
update_expressions.append(exp.EQ(this=exp.column(col), expression=exp.var(param_name)))
|
|
177
181
|
|
|
178
182
|
when_args: dict[str, Any] = {"matched": True, "then": exp.Update(expressions=update_expressions)}
|
|
@@ -270,8 +274,12 @@ class MergeNotMatchedClauseMixin:
|
|
|
270
274
|
raise SQLBuilderError(msg)
|
|
271
275
|
|
|
272
276
|
parameterized_values: list[exp.Expression] = []
|
|
273
|
-
for val in values:
|
|
274
|
-
|
|
277
|
+
for i, val in enumerate(values):
|
|
278
|
+
column_name = columns[i] if isinstance(columns[i], str) else str(columns[i])
|
|
279
|
+
if "." in column_name:
|
|
280
|
+
column_name = column_name.split(".")[-1]
|
|
281
|
+
param_name = self._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
282
|
+
param_name = self.add_parameter(val, name=param_name)[1] # type: ignore[attr-defined]
|
|
275
283
|
parameterized_values.append(exp.var(param_name))
|
|
276
284
|
|
|
277
285
|
insert_args["this"] = exp.Tuple(expressions=[exp.column(c) for c in columns])
|
|
@@ -336,7 +344,11 @@ class MergeNotMatchedBySourceClauseMixin:
|
|
|
336
344
|
"""
|
|
337
345
|
update_expressions: list[exp.EQ] = []
|
|
338
346
|
for col, val in set_values.items():
|
|
339
|
-
|
|
347
|
+
column_name = col if isinstance(col, str) else str(col)
|
|
348
|
+
if "." in column_name:
|
|
349
|
+
column_name = column_name.split(".")[-1]
|
|
350
|
+
param_name = self._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
351
|
+
param_name = self.add_parameter(val, name=param_name)[1] # type: ignore[attr-defined]
|
|
340
352
|
update_expressions.append(exp.EQ(this=exp.column(col), expression=exp.var(param_name)))
|
|
341
353
|
|
|
342
354
|
when_args: dict[str, Any] = {
|
|
@@ -563,7 +563,8 @@ class CaseBuilder:
|
|
|
563
563
|
CaseBuilder: The current builder instance for method chaining.
|
|
564
564
|
"""
|
|
565
565
|
cond_expr = exp.condition(condition) if isinstance(condition, str) else condition
|
|
566
|
-
param_name = self._parent.
|
|
566
|
+
param_name = self._parent._generate_unique_parameter_name("case_when_value")
|
|
567
|
+
param_name = self._parent.add_parameter(value, name=param_name)[1]
|
|
567
568
|
value_expr = exp.Placeholder(this=param_name)
|
|
568
569
|
|
|
569
570
|
when_clause = exp.When(this=cond_expr, then=value_expr)
|
|
@@ -582,7 +583,8 @@ class CaseBuilder:
|
|
|
582
583
|
Returns:
|
|
583
584
|
CaseBuilder: The current builder instance for method chaining.
|
|
584
585
|
"""
|
|
585
|
-
param_name = self._parent.
|
|
586
|
+
param_name = self._parent._generate_unique_parameter_name("case_else_value")
|
|
587
|
+
param_name = self._parent.add_parameter(value, name=param_name)[1]
|
|
586
588
|
value_expr = exp.Placeholder(this=param_name)
|
|
587
589
|
self._case_expr.set("default", value_expr)
|
|
588
590
|
return self
|
|
@@ -81,7 +81,12 @@ class UpdateSetClauseMixin:
|
|
|
81
81
|
for p_name, p_value in val.parameters.items():
|
|
82
82
|
self.add_parameter(p_value, name=p_name) # type: ignore[attr-defined]
|
|
83
83
|
else:
|
|
84
|
-
|
|
84
|
+
column_name = col if isinstance(col, str) else str(col)
|
|
85
|
+
# Extract just the column part if table.column format
|
|
86
|
+
if "." in column_name:
|
|
87
|
+
column_name = column_name.split(".")[-1]
|
|
88
|
+
param_name = self._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
89
|
+
param_name = self.add_parameter(val, name=param_name)[1] # type: ignore[attr-defined]
|
|
85
90
|
value_expr = exp.Placeholder(this=param_name)
|
|
86
91
|
assignments.append(exp.EQ(this=col_expr, expression=value_expr))
|
|
87
92
|
elif (len(args) == 1 and isinstance(args[0], Mapping)) or kwargs:
|
|
@@ -97,7 +102,12 @@ class UpdateSetClauseMixin:
|
|
|
97
102
|
for p_name, p_value in val.parameters.items():
|
|
98
103
|
self.add_parameter(p_value, name=p_name) # type: ignore[attr-defined]
|
|
99
104
|
else:
|
|
100
|
-
|
|
105
|
+
# Extract column name for parameter naming
|
|
106
|
+
column_name = col if isinstance(col, str) else str(col)
|
|
107
|
+
if "." in column_name:
|
|
108
|
+
column_name = column_name.split(".")[-1]
|
|
109
|
+
param_name = self._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
110
|
+
param_name = self.add_parameter(val, name=param_name)[1] # type: ignore[attr-defined]
|
|
101
111
|
value_expr = exp.Placeholder(this=param_name)
|
|
102
112
|
assignments.append(exp.EQ(this=exp.column(col), expression=value_expr))
|
|
103
113
|
else:
|
|
@@ -10,6 +10,29 @@ from sqlspec.builder._parsing_utils import parse_column_expression, parse_condit
|
|
|
10
10
|
from sqlspec.exceptions import SQLBuilderError
|
|
11
11
|
from sqlspec.utils.type_guards import has_query_builder_parameters, has_sqlglot_expression, is_iterable_parameters
|
|
12
12
|
|
|
13
|
+
|
|
14
|
+
def _extract_column_name(column: Union[str, exp.Column]) -> str:
|
|
15
|
+
"""Extract column name from column expression for parameter naming.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
column: Column expression (string or SQLGlot Column)
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Column name as string for use as parameter name
|
|
22
|
+
"""
|
|
23
|
+
if isinstance(column, str):
|
|
24
|
+
# Handle simple column names and table.column references
|
|
25
|
+
if "." in column:
|
|
26
|
+
return column.split(".")[-1] # Return just the column part
|
|
27
|
+
return column
|
|
28
|
+
if isinstance(column, exp.Column):
|
|
29
|
+
# Extract the column name from SQLGlot Column expression
|
|
30
|
+
if column.this and hasattr(column.this, "this"):
|
|
31
|
+
return str(column.this.this)
|
|
32
|
+
return str(column.this) if column.this else "column"
|
|
33
|
+
return "column"
|
|
34
|
+
|
|
35
|
+
|
|
13
36
|
if TYPE_CHECKING:
|
|
14
37
|
from sqlspec.builder._column import ColumnExpression
|
|
15
38
|
from sqlspec.protocols import SQLBuilderProtocol
|
|
@@ -20,28 +43,42 @@ __all__ = ("HavingClauseMixin", "WhereClauseMixin")
|
|
|
20
43
|
class WhereClauseMixin:
|
|
21
44
|
"""Mixin providing WHERE clause methods for SELECT, UPDATE, and DELETE builders."""
|
|
22
45
|
|
|
23
|
-
def _handle_in_operator(
|
|
46
|
+
def _handle_in_operator(
|
|
47
|
+
self, column_exp: exp.Expression, value: Any, column_name: str = "column"
|
|
48
|
+
) -> exp.Expression:
|
|
24
49
|
"""Handle IN operator."""
|
|
25
50
|
builder = cast("SQLBuilderProtocol", self)
|
|
26
51
|
if is_iterable_parameters(value):
|
|
27
52
|
placeholders = []
|
|
28
|
-
for v in value:
|
|
29
|
-
|
|
53
|
+
for i, v in enumerate(value):
|
|
54
|
+
if len(value) == 1:
|
|
55
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
56
|
+
else:
|
|
57
|
+
param_name = builder._generate_unique_parameter_name(f"{column_name}_{i + 1}") # type: ignore[attr-defined]
|
|
58
|
+
_, param_name = builder.add_parameter(v, name=param_name)
|
|
30
59
|
placeholders.append(exp.Placeholder(this=param_name))
|
|
31
60
|
return exp.In(this=column_exp, expressions=placeholders)
|
|
32
|
-
|
|
61
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
62
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
33
63
|
return exp.In(this=column_exp, expressions=[exp.Placeholder(this=param_name)])
|
|
34
64
|
|
|
35
|
-
def _handle_not_in_operator(
|
|
65
|
+
def _handle_not_in_operator(
|
|
66
|
+
self, column_exp: exp.Expression, value: Any, column_name: str = "column"
|
|
67
|
+
) -> exp.Expression:
|
|
36
68
|
"""Handle NOT IN operator."""
|
|
37
69
|
builder = cast("SQLBuilderProtocol", self)
|
|
38
70
|
if is_iterable_parameters(value):
|
|
39
71
|
placeholders = []
|
|
40
|
-
for v in value:
|
|
41
|
-
|
|
72
|
+
for i, v in enumerate(value):
|
|
73
|
+
if len(value) == 1:
|
|
74
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
75
|
+
else:
|
|
76
|
+
param_name = builder._generate_unique_parameter_name(f"{column_name}_{i + 1}") # type: ignore[attr-defined]
|
|
77
|
+
_, param_name = builder.add_parameter(v, name=param_name)
|
|
42
78
|
placeholders.append(exp.Placeholder(this=param_name))
|
|
43
79
|
return exp.Not(this=exp.In(this=column_exp, expressions=placeholders))
|
|
44
|
-
|
|
80
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
81
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
45
82
|
return exp.Not(this=exp.In(this=column_exp, expressions=[exp.Placeholder(this=param_name)]))
|
|
46
83
|
|
|
47
84
|
def _handle_is_operator(self, column_exp: exp.Expression, value: Any) -> exp.Expression:
|
|
@@ -54,26 +91,34 @@ class WhereClauseMixin:
|
|
|
54
91
|
value_expr = exp.Null() if value is None else exp.convert(value)
|
|
55
92
|
return exp.Not(this=exp.Is(this=column_exp, expression=value_expr))
|
|
56
93
|
|
|
57
|
-
def _handle_between_operator(
|
|
94
|
+
def _handle_between_operator(
|
|
95
|
+
self, column_exp: exp.Expression, value: Any, column_name: str = "column"
|
|
96
|
+
) -> exp.Expression:
|
|
58
97
|
"""Handle BETWEEN operator."""
|
|
59
98
|
if is_iterable_parameters(value) and len(value) == 2:
|
|
60
99
|
builder = cast("SQLBuilderProtocol", self)
|
|
61
100
|
low, high = value
|
|
62
|
-
|
|
63
|
-
|
|
101
|
+
low_param = builder._generate_unique_parameter_name(f"{column_name}_low") # type: ignore[attr-defined]
|
|
102
|
+
high_param = builder._generate_unique_parameter_name(f"{column_name}_high") # type: ignore[attr-defined]
|
|
103
|
+
_, low_param = builder.add_parameter(low, name=low_param)
|
|
104
|
+
_, high_param = builder.add_parameter(high, name=high_param)
|
|
64
105
|
return exp.Between(
|
|
65
106
|
this=column_exp, low=exp.Placeholder(this=low_param), high=exp.Placeholder(this=high_param)
|
|
66
107
|
)
|
|
67
108
|
msg = f"BETWEEN operator requires a tuple of two values, got {type(value).__name__}"
|
|
68
109
|
raise SQLBuilderError(msg)
|
|
69
110
|
|
|
70
|
-
def _handle_not_between_operator(
|
|
111
|
+
def _handle_not_between_operator(
|
|
112
|
+
self, column_exp: exp.Expression, value: Any, column_name: str = "column"
|
|
113
|
+
) -> exp.Expression:
|
|
71
114
|
"""Handle NOT BETWEEN operator."""
|
|
72
115
|
if is_iterable_parameters(value) and len(value) == 2:
|
|
73
116
|
builder = cast("SQLBuilderProtocol", self)
|
|
74
117
|
low, high = value
|
|
75
|
-
|
|
76
|
-
|
|
118
|
+
low_param = builder._generate_unique_parameter_name(f"{column_name}_low") # type: ignore[attr-defined]
|
|
119
|
+
high_param = builder._generate_unique_parameter_name(f"{column_name}_high") # type: ignore[attr-defined]
|
|
120
|
+
_, low_param = builder.add_parameter(low, name=low_param)
|
|
121
|
+
_, high_param = builder.add_parameter(high, name=high_param)
|
|
77
122
|
return exp.Not(
|
|
78
123
|
this=exp.Between(
|
|
79
124
|
this=column_exp, low=exp.Placeholder(this=low_param), high=exp.Placeholder(this=high_param)
|
|
@@ -85,13 +130,15 @@ class WhereClauseMixin:
|
|
|
85
130
|
def _process_tuple_condition(self, condition: tuple) -> exp.Expression:
|
|
86
131
|
"""Process tuple-based WHERE conditions."""
|
|
87
132
|
builder = cast("SQLBuilderProtocol", self)
|
|
88
|
-
|
|
89
|
-
column_exp = parse_column_expression(
|
|
133
|
+
column_name_raw = str(condition[0])
|
|
134
|
+
column_exp = parse_column_expression(column_name_raw)
|
|
135
|
+
column_name = _extract_column_name(column_name_raw)
|
|
90
136
|
|
|
91
137
|
if len(condition) == 2:
|
|
92
138
|
# (column, value) tuple for equality
|
|
93
139
|
value = condition[1]
|
|
94
|
-
|
|
140
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
141
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
95
142
|
return exp.EQ(this=column_exp, expression=exp.Placeholder(this=param_name))
|
|
96
143
|
|
|
97
144
|
if len(condition) == 3:
|
|
@@ -100,42 +147,50 @@ class WhereClauseMixin:
|
|
|
100
147
|
value = condition[2]
|
|
101
148
|
|
|
102
149
|
if operator == "=":
|
|
103
|
-
|
|
150
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
151
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
104
152
|
return exp.EQ(this=column_exp, expression=exp.Placeholder(this=param_name))
|
|
105
153
|
if operator in {"!=", "<>"}:
|
|
106
|
-
|
|
154
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
155
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
107
156
|
return exp.NEQ(this=column_exp, expression=exp.Placeholder(this=param_name))
|
|
108
157
|
if operator == ">":
|
|
109
|
-
|
|
158
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
159
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
110
160
|
return exp.GT(this=column_exp, expression=exp.Placeholder(this=param_name))
|
|
111
161
|
if operator == ">=":
|
|
112
|
-
|
|
162
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
163
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
113
164
|
return exp.GTE(this=column_exp, expression=exp.Placeholder(this=param_name))
|
|
114
165
|
if operator == "<":
|
|
115
|
-
|
|
166
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
167
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
116
168
|
return exp.LT(this=column_exp, expression=exp.Placeholder(this=param_name))
|
|
117
169
|
if operator == "<=":
|
|
118
|
-
|
|
170
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
171
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
119
172
|
return exp.LTE(this=column_exp, expression=exp.Placeholder(this=param_name))
|
|
120
173
|
if operator == "LIKE":
|
|
121
|
-
|
|
174
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
175
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
122
176
|
return exp.Like(this=column_exp, expression=exp.Placeholder(this=param_name))
|
|
123
177
|
if operator == "NOT LIKE":
|
|
124
|
-
|
|
178
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
179
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
125
180
|
return exp.Not(this=exp.Like(this=column_exp, expression=exp.Placeholder(this=param_name)))
|
|
126
181
|
|
|
127
182
|
if operator == "IN":
|
|
128
|
-
return self._handle_in_operator(column_exp, value)
|
|
183
|
+
return self._handle_in_operator(column_exp, value, column_name)
|
|
129
184
|
if operator == "NOT IN":
|
|
130
|
-
return self._handle_not_in_operator(column_exp, value)
|
|
185
|
+
return self._handle_not_in_operator(column_exp, value, column_name)
|
|
131
186
|
if operator == "IS":
|
|
132
187
|
return self._handle_is_operator(column_exp, value)
|
|
133
188
|
if operator == "IS NOT":
|
|
134
189
|
return self._handle_is_not_operator(column_exp, value)
|
|
135
190
|
if operator == "BETWEEN":
|
|
136
|
-
return self._handle_between_operator(column_exp, value)
|
|
191
|
+
return self._handle_between_operator(column_exp, value, column_name)
|
|
137
192
|
if operator == "NOT BETWEEN":
|
|
138
|
-
return self._handle_not_between_operator(column_exp, value)
|
|
193
|
+
return self._handle_not_between_operator(column_exp, value, column_name)
|
|
139
194
|
|
|
140
195
|
msg = f"Unsupported operator: {operator}"
|
|
141
196
|
raise SQLBuilderError(msg)
|
|
@@ -218,86 +273,107 @@ class WhereClauseMixin:
|
|
|
218
273
|
def where_eq(self, column: Union[str, exp.Column], value: Any) -> Self:
|
|
219
274
|
"""Add WHERE column = value clause."""
|
|
220
275
|
builder = cast("SQLBuilderProtocol", self)
|
|
221
|
-
|
|
276
|
+
column_name = _extract_column_name(column)
|
|
277
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
278
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
222
279
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
223
|
-
condition: exp.Expression = col_expr.eq(exp.
|
|
280
|
+
condition: exp.Expression = col_expr.eq(exp.Placeholder(this=param_name))
|
|
224
281
|
return self.where(condition)
|
|
225
282
|
|
|
226
283
|
def where_neq(self, column: Union[str, exp.Column], value: Any) -> Self:
|
|
227
284
|
"""Add WHERE column != value clause."""
|
|
228
285
|
builder = cast("SQLBuilderProtocol", self)
|
|
229
|
-
|
|
286
|
+
column_name = _extract_column_name(column)
|
|
287
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
288
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
230
289
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
231
|
-
condition: exp.Expression = col_expr.neq(exp.
|
|
290
|
+
condition: exp.Expression = col_expr.neq(exp.Placeholder(this=param_name))
|
|
232
291
|
return self.where(condition)
|
|
233
292
|
|
|
234
293
|
def where_lt(self, column: Union[str, exp.Column], value: Any) -> Self:
|
|
235
294
|
"""Add WHERE column < value clause."""
|
|
236
295
|
builder = cast("SQLBuilderProtocol", self)
|
|
237
|
-
|
|
296
|
+
column_name = _extract_column_name(column)
|
|
297
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
298
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
238
299
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
239
|
-
condition: exp.Expression = exp.LT(this=col_expr, expression=exp.
|
|
300
|
+
condition: exp.Expression = exp.LT(this=col_expr, expression=exp.Placeholder(this=param_name))
|
|
240
301
|
return self.where(condition)
|
|
241
302
|
|
|
242
303
|
def where_lte(self, column: Union[str, exp.Column], value: Any) -> Self:
|
|
243
304
|
"""Add WHERE column <= value clause."""
|
|
244
305
|
builder = cast("SQLBuilderProtocol", self)
|
|
245
|
-
|
|
306
|
+
column_name = _extract_column_name(column)
|
|
307
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
308
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
246
309
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
247
|
-
condition: exp.Expression = exp.LTE(this=col_expr, expression=exp.
|
|
310
|
+
condition: exp.Expression = exp.LTE(this=col_expr, expression=exp.Placeholder(this=param_name))
|
|
248
311
|
return self.where(condition)
|
|
249
312
|
|
|
250
313
|
def where_gt(self, column: Union[str, exp.Column], value: Any) -> Self:
|
|
251
314
|
"""Add WHERE column > value clause."""
|
|
252
315
|
builder = cast("SQLBuilderProtocol", self)
|
|
253
|
-
|
|
316
|
+
column_name = _extract_column_name(column)
|
|
317
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
318
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
254
319
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
255
|
-
condition: exp.Expression = exp.GT(this=col_expr, expression=exp.
|
|
320
|
+
condition: exp.Expression = exp.GT(this=col_expr, expression=exp.Placeholder(this=param_name))
|
|
256
321
|
return self.where(condition)
|
|
257
322
|
|
|
258
323
|
def where_gte(self, column: Union[str, exp.Column], value: Any) -> Self:
|
|
259
324
|
"""Add WHERE column >= value clause."""
|
|
260
325
|
builder = cast("SQLBuilderProtocol", self)
|
|
261
|
-
|
|
326
|
+
column_name = _extract_column_name(column)
|
|
327
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
328
|
+
_, param_name = builder.add_parameter(value, name=param_name)
|
|
262
329
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
263
|
-
condition: exp.Expression = exp.GTE(this=col_expr, expression=exp.
|
|
330
|
+
condition: exp.Expression = exp.GTE(this=col_expr, expression=exp.Placeholder(this=param_name))
|
|
264
331
|
return self.where(condition)
|
|
265
332
|
|
|
266
333
|
def where_between(self, column: Union[str, exp.Column], low: Any, high: Any) -> Self:
|
|
267
334
|
"""Add WHERE column BETWEEN low AND high clause."""
|
|
268
335
|
builder = cast("SQLBuilderProtocol", self)
|
|
269
|
-
|
|
270
|
-
|
|
336
|
+
column_name = _extract_column_name(column)
|
|
337
|
+
low_param = builder._generate_unique_parameter_name(f"{column_name}_low") # type: ignore[attr-defined]
|
|
338
|
+
high_param = builder._generate_unique_parameter_name(f"{column_name}_high") # type: ignore[attr-defined]
|
|
339
|
+
_, low_param = builder.add_parameter(low, name=low_param)
|
|
340
|
+
_, high_param = builder.add_parameter(high, name=high_param)
|
|
271
341
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
272
|
-
condition: exp.Expression = col_expr.between(exp.
|
|
342
|
+
condition: exp.Expression = col_expr.between(exp.Placeholder(this=low_param), exp.Placeholder(this=high_param))
|
|
273
343
|
return self.where(condition)
|
|
274
344
|
|
|
275
345
|
def where_like(self, column: Union[str, exp.Column], pattern: str, escape: Optional[str] = None) -> Self:
|
|
276
346
|
"""Add WHERE column LIKE pattern clause."""
|
|
277
347
|
builder = cast("SQLBuilderProtocol", self)
|
|
278
|
-
|
|
348
|
+
column_name = _extract_column_name(column)
|
|
349
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
350
|
+
_, param_name = builder.add_parameter(pattern, name=param_name)
|
|
279
351
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
280
352
|
if escape is not None:
|
|
281
|
-
cond = exp.Like(this=col_expr, expression=exp.
|
|
353
|
+
cond = exp.Like(this=col_expr, expression=exp.Placeholder(this=param_name), escape=exp.convert(str(escape)))
|
|
282
354
|
else:
|
|
283
|
-
cond = col_expr.like(exp.
|
|
355
|
+
cond = col_expr.like(exp.Placeholder(this=param_name))
|
|
284
356
|
condition: exp.Expression = cond
|
|
285
357
|
return self.where(condition)
|
|
286
358
|
|
|
287
359
|
def where_not_like(self, column: Union[str, exp.Column], pattern: str) -> Self:
|
|
288
360
|
"""Add WHERE column NOT LIKE pattern clause."""
|
|
289
361
|
builder = cast("SQLBuilderProtocol", self)
|
|
290
|
-
|
|
362
|
+
column_name = _extract_column_name(column)
|
|
363
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
364
|
+
_, param_name = builder.add_parameter(pattern, name=param_name)
|
|
291
365
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
292
|
-
condition: exp.Expression = col_expr.like(exp.
|
|
366
|
+
condition: exp.Expression = col_expr.like(exp.Placeholder(this=param_name)).not_()
|
|
293
367
|
return self.where(condition)
|
|
294
368
|
|
|
295
369
|
def where_ilike(self, column: Union[str, exp.Column], pattern: str) -> Self:
|
|
296
370
|
"""Add WHERE column ILIKE pattern clause."""
|
|
297
371
|
builder = cast("SQLBuilderProtocol", self)
|
|
298
|
-
|
|
372
|
+
column_name = _extract_column_name(column)
|
|
373
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
374
|
+
_, param_name = builder.add_parameter(pattern, name=param_name)
|
|
299
375
|
col_expr = parse_column_expression(column) if not isinstance(column, exp.Column) else column
|
|
300
|
-
condition: exp.Expression = col_expr.ilike(exp.
|
|
376
|
+
condition: exp.Expression = col_expr.ilike(exp.Placeholder(this=param_name))
|
|
301
377
|
return self.where(condition)
|
|
302
378
|
|
|
303
379
|
def where_is_null(self, column: Union[str, exp.Column]) -> Self:
|
|
@@ -322,6 +398,10 @@ class WhereClauseMixin:
|
|
|
322
398
|
subquery = values.build() # pyright: ignore
|
|
323
399
|
sql_str = subquery.sql
|
|
324
400
|
subquery_exp = exp.paren(exp.maybe_parse(sql_str, dialect=builder.dialect_name)) # pyright: ignore
|
|
401
|
+
# Merge subquery parameters into parent builder
|
|
402
|
+
if hasattr(subquery, "parameters"):
|
|
403
|
+
for param_name, param_value in subquery.parameters.items(): # pyright: ignore[reportAttributeAccessIssue]
|
|
404
|
+
builder.add_parameter(param_value, name=param_name)
|
|
325
405
|
else:
|
|
326
406
|
subquery_exp = values # type: ignore[assignment]
|
|
327
407
|
condition = col_expr.isin(subquery_exp)
|
|
@@ -329,10 +409,15 @@ class WhereClauseMixin:
|
|
|
329
409
|
if not is_iterable_parameters(values) or isinstance(values, (str, bytes)):
|
|
330
410
|
msg = "Unsupported type for 'values' in WHERE IN"
|
|
331
411
|
raise SQLBuilderError(msg)
|
|
412
|
+
column_name = _extract_column_name(column)
|
|
332
413
|
parameters = []
|
|
333
|
-
for v in values:
|
|
334
|
-
|
|
335
|
-
|
|
414
|
+
for i, v in enumerate(values):
|
|
415
|
+
if len(values) == 1:
|
|
416
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
417
|
+
else:
|
|
418
|
+
param_name = builder._generate_unique_parameter_name(f"{column_name}_{i + 1}") # type: ignore[attr-defined]
|
|
419
|
+
_, param_name = builder.add_parameter(v, name=param_name)
|
|
420
|
+
parameters.append(exp.Placeholder(this=param_name))
|
|
336
421
|
condition = col_expr.isin(*parameters)
|
|
337
422
|
return self.where(condition)
|
|
338
423
|
|
|
@@ -353,10 +438,15 @@ class WhereClauseMixin:
|
|
|
353
438
|
if not is_iterable_parameters(values) or isinstance(values, (str, bytes)):
|
|
354
439
|
msg = "Values for where_not_in must be a non-string iterable or subquery."
|
|
355
440
|
raise SQLBuilderError(msg)
|
|
441
|
+
column_name = _extract_column_name(column)
|
|
356
442
|
parameters = []
|
|
357
|
-
for v in values:
|
|
358
|
-
|
|
359
|
-
|
|
443
|
+
for i, v in enumerate(values):
|
|
444
|
+
if len(values) == 1:
|
|
445
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
446
|
+
else:
|
|
447
|
+
param_name = builder._generate_unique_parameter_name(f"{column_name}_{i + 1}") # type: ignore[attr-defined]
|
|
448
|
+
_, param_name = builder.add_parameter(v, name=param_name)
|
|
449
|
+
parameters.append(exp.Placeholder(this=param_name))
|
|
360
450
|
condition = exp.Not(this=col_expr.isin(*parameters))
|
|
361
451
|
return self.where(condition)
|
|
362
452
|
|
|
@@ -438,10 +528,15 @@ class WhereClauseMixin:
|
|
|
438
528
|
if not is_iterable_parameters(values) or isinstance(values, bytes):
|
|
439
529
|
msg = "Unsupported type for 'values' in WHERE ANY"
|
|
440
530
|
raise SQLBuilderError(msg)
|
|
531
|
+
column_name = _extract_column_name(column)
|
|
441
532
|
parameters = []
|
|
442
|
-
for v in values:
|
|
443
|
-
|
|
444
|
-
|
|
533
|
+
for i, v in enumerate(values):
|
|
534
|
+
if len(values) == 1:
|
|
535
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
536
|
+
else:
|
|
537
|
+
param_name = builder._generate_unique_parameter_name(f"{column_name}_any_{i + 1}") # type: ignore[attr-defined]
|
|
538
|
+
_, param_name = builder.add_parameter(v, name=param_name)
|
|
539
|
+
parameters.append(exp.Placeholder(this=param_name))
|
|
445
540
|
tuple_expr = exp.Tuple(expressions=parameters)
|
|
446
541
|
condition = exp.EQ(this=col_expr, expression=exp.Any(this=tuple_expr))
|
|
447
542
|
return self.where(condition)
|
|
@@ -473,10 +568,15 @@ class WhereClauseMixin:
|
|
|
473
568
|
if not is_iterable_parameters(values) or isinstance(values, bytes):
|
|
474
569
|
msg = "Unsupported type for 'values' in WHERE NOT ANY"
|
|
475
570
|
raise SQLBuilderError(msg)
|
|
571
|
+
column_name = _extract_column_name(column)
|
|
476
572
|
parameters = []
|
|
477
|
-
for v in values:
|
|
478
|
-
|
|
479
|
-
|
|
573
|
+
for i, v in enumerate(values):
|
|
574
|
+
if len(values) == 1:
|
|
575
|
+
param_name = builder._generate_unique_parameter_name(column_name) # type: ignore[attr-defined]
|
|
576
|
+
else:
|
|
577
|
+
param_name = builder._generate_unique_parameter_name(f"{column_name}_not_any_{i + 1}") # type: ignore[attr-defined]
|
|
578
|
+
_, param_name = builder.add_parameter(v, name=param_name)
|
|
579
|
+
parameters.append(exp.Placeholder(this=param_name))
|
|
480
580
|
tuple_expr = exp.Tuple(expressions=parameters)
|
|
481
581
|
condition = exp.NEQ(this=col_expr, expression=exp.Any(this=tuple_expr))
|
|
482
582
|
return self.where(condition)
|
sqlspec/core/filters.py
CHANGED
|
@@ -558,6 +558,7 @@ class LimitOffsetFilter(PaginationFilter):
|
|
|
558
558
|
return [], {self._limit_param_name: self.limit, self._offset_param_name: self.offset}
|
|
559
559
|
|
|
560
560
|
def append_to_statement(self, statement: "SQL") -> "SQL":
|
|
561
|
+
import sqlglot
|
|
561
562
|
from sqlglot import exp
|
|
562
563
|
|
|
563
564
|
# Resolve parameter name conflicts
|
|
@@ -567,17 +568,18 @@ class LimitOffsetFilter(PaginationFilter):
|
|
|
567
568
|
limit_placeholder = exp.Placeholder(this=limit_param_name)
|
|
568
569
|
offset_placeholder = exp.Placeholder(this=offset_param_name)
|
|
569
570
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
else exp.Select().from_(statement._statement).limit(limit_placeholder)
|
|
577
|
-
)
|
|
571
|
+
# Parse the current SQL to get the statement structure
|
|
572
|
+
try:
|
|
573
|
+
current_statement = sqlglot.parse_one(statement._raw_sql, dialect=getattr(statement, "_dialect", None))
|
|
574
|
+
except Exception:
|
|
575
|
+
# Fallback to wrapping in subquery if parsing fails
|
|
576
|
+
current_statement = exp.Select().from_(f"({statement._raw_sql})")
|
|
578
577
|
|
|
579
|
-
if isinstance(
|
|
580
|
-
new_statement =
|
|
578
|
+
if isinstance(current_statement, exp.Select):
|
|
579
|
+
new_statement = current_statement.limit(limit_placeholder).offset(offset_placeholder)
|
|
580
|
+
else:
|
|
581
|
+
# Wrap non-SELECT statements in a subquery
|
|
582
|
+
new_statement = exp.Select().from_(current_statement).limit(limit_placeholder).offset(offset_placeholder)
|
|
581
583
|
|
|
582
584
|
result = statement.copy(statement=new_statement)
|
|
583
585
|
|
sqlspec/core/statement.py
CHANGED
|
@@ -368,6 +368,10 @@ class SQL:
|
|
|
368
368
|
new_sql = SQL(
|
|
369
369
|
self._raw_sql, *self._original_parameters, statement_config=self._statement_config, is_many=self._is_many
|
|
370
370
|
)
|
|
371
|
+
# Preserve accumulated parameters when marking as script
|
|
372
|
+
new_sql._named_parameters.update(self._named_parameters)
|
|
373
|
+
new_sql._positional_parameters = self._positional_parameters.copy()
|
|
374
|
+
new_sql._filters = self._filters.copy()
|
|
371
375
|
new_sql._is_script = True
|
|
372
376
|
return new_sql
|
|
373
377
|
|
|
@@ -375,13 +379,19 @@ class SQL:
|
|
|
375
379
|
self, statement: "Optional[Union[str, exp.Expression]]" = None, parameters: Optional[Any] = None, **kwargs: Any
|
|
376
380
|
) -> "SQL":
|
|
377
381
|
"""Create copy with modifications."""
|
|
378
|
-
|
|
382
|
+
new_sql = SQL(
|
|
379
383
|
statement or self._raw_sql,
|
|
380
384
|
*(parameters if parameters is not None else self._original_parameters),
|
|
381
385
|
statement_config=self._statement_config,
|
|
382
386
|
is_many=self._is_many,
|
|
383
387
|
**kwargs,
|
|
384
388
|
)
|
|
389
|
+
# Only preserve accumulated parameters when no explicit parameters are provided
|
|
390
|
+
if parameters is None:
|
|
391
|
+
new_sql._named_parameters.update(self._named_parameters)
|
|
392
|
+
new_sql._positional_parameters = self._positional_parameters.copy()
|
|
393
|
+
new_sql._filters = self._filters.copy()
|
|
394
|
+
return new_sql
|
|
385
395
|
|
|
386
396
|
def add_named_parameter(self, name: str, value: Any) -> "SQL":
|
|
387
397
|
"""Add a named parameter and return a new SQL instance.
|
|
@@ -437,9 +447,14 @@ class SQL:
|
|
|
437
447
|
|
|
438
448
|
new_sql_text = new_expr.sql(dialect=self._dialect)
|
|
439
449
|
|
|
440
|
-
|
|
450
|
+
new_sql = SQL(
|
|
441
451
|
new_sql_text, *self._original_parameters, statement_config=self._statement_config, is_many=self._is_many
|
|
442
452
|
)
|
|
453
|
+
# Preserve accumulated named parameters when creating WHERE clause
|
|
454
|
+
new_sql._named_parameters.update(self._named_parameters)
|
|
455
|
+
new_sql._positional_parameters = self._positional_parameters.copy()
|
|
456
|
+
new_sql._filters = self._filters.copy()
|
|
457
|
+
return new_sql
|
|
443
458
|
|
|
444
459
|
def __hash__(self) -> int:
|
|
445
460
|
"""Hash value."""
|
|
@@ -5,7 +5,7 @@ from collections.abc import Sequence
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from functools import partial
|
|
7
7
|
from pathlib import Path, PurePath
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import Any, Callable, Optional, overload
|
|
9
9
|
from uuid import UUID
|
|
10
10
|
|
|
11
11
|
from mypy_extensions import trait
|
|
@@ -13,8 +13,6 @@ from mypy_extensions import trait
|
|
|
13
13
|
from sqlspec.exceptions import SQLSpecError, wrap_exceptions
|
|
14
14
|
from sqlspec.typing import (
|
|
15
15
|
CATTRS_INSTALLED,
|
|
16
|
-
DataclassProtocol,
|
|
17
|
-
DictLike,
|
|
18
16
|
ModelDTOT,
|
|
19
17
|
ModelT,
|
|
20
18
|
attrs_asdict,
|
|
@@ -25,9 +23,6 @@ from sqlspec.typing import (
|
|
|
25
23
|
)
|
|
26
24
|
from sqlspec.utils.type_guards import is_attrs_schema, is_dataclass, is_msgspec_struct, is_pydantic_model
|
|
27
25
|
|
|
28
|
-
if TYPE_CHECKING:
|
|
29
|
-
from sqlspec._typing import AttrsInstanceStub, BaseModelStub, StructStub
|
|
30
|
-
|
|
31
26
|
__all__ = ("_DEFAULT_TYPE_DECODERS", "_default_msgspec_deserializer")
|
|
32
27
|
|
|
33
28
|
|
|
@@ -74,36 +69,37 @@ class ToSchemaMixin:
|
|
|
74
69
|
# Schema conversion overloads - handle common cases first
|
|
75
70
|
@overload
|
|
76
71
|
@staticmethod
|
|
72
|
+
def to_schema(data: "list[dict[str, Any]]") -> "list[dict[str, Any]]": ...
|
|
73
|
+
@overload
|
|
74
|
+
@staticmethod
|
|
77
75
|
def to_schema(data: "list[dict[str, Any]]", *, schema_type: "type[ModelDTOT]") -> "list[ModelDTOT]": ...
|
|
78
76
|
@overload
|
|
79
77
|
@staticmethod
|
|
80
78
|
def to_schema(data: "list[dict[str, Any]]", *, schema_type: None = None) -> "list[dict[str, Any]]": ...
|
|
81
79
|
@overload
|
|
82
80
|
@staticmethod
|
|
81
|
+
def to_schema(data: "dict[str, Any]") -> "dict[str, Any]": ...
|
|
82
|
+
@overload
|
|
83
|
+
@staticmethod
|
|
83
84
|
def to_schema(data: "dict[str, Any]", *, schema_type: "type[ModelDTOT]") -> "ModelDTOT": ...
|
|
84
85
|
@overload
|
|
85
86
|
@staticmethod
|
|
86
87
|
def to_schema(data: "dict[str, Any]", *, schema_type: None = None) -> "dict[str, Any]": ...
|
|
87
88
|
@overload
|
|
88
89
|
@staticmethod
|
|
90
|
+
def to_schema(data: "list[ModelT]") -> "list[ModelT]": ...
|
|
91
|
+
@overload
|
|
92
|
+
@staticmethod
|
|
89
93
|
def to_schema(data: "list[ModelT]", *, schema_type: "type[ModelDTOT]") -> "list[ModelDTOT]": ...
|
|
90
94
|
@overload
|
|
91
95
|
@staticmethod
|
|
92
96
|
def to_schema(data: "list[ModelT]", *, schema_type: None = None) -> "list[ModelT]": ...
|
|
93
97
|
@overload
|
|
94
98
|
@staticmethod
|
|
95
|
-
def to_schema(
|
|
96
|
-
data: "Union[DictLike, StructStub, BaseModelStub, DataclassProtocol, AttrsInstanceStub]",
|
|
97
|
-
*,
|
|
98
|
-
schema_type: "type[ModelDTOT]",
|
|
99
|
-
) -> "ModelDTOT": ...
|
|
99
|
+
def to_schema(data: "ModelT") -> "ModelT": ...
|
|
100
100
|
@overload
|
|
101
101
|
@staticmethod
|
|
102
|
-
def to_schema(
|
|
103
|
-
data: "Union[DictLike, StructStub, BaseModelStub, DataclassProtocol, AttrsInstanceStub]",
|
|
104
|
-
*,
|
|
105
|
-
schema_type: None = None,
|
|
106
|
-
) -> "Union[DictLike, StructStub, BaseModelStub, DataclassProtocol, AttrsInstanceStub]": ...
|
|
102
|
+
def to_schema(data: Any, *, schema_type: None = None) -> Any: ...
|
|
107
103
|
|
|
108
104
|
@staticmethod
|
|
109
105
|
def to_schema(data: Any, *, schema_type: "Optional[type[ModelDTOT]]" = None) -> Any:
|
|
@@ -39,7 +39,7 @@ def get_database_migration_plugin(app: "Litestar") -> "SQLSpec":
|
|
|
39
39
|
raise ImproperConfigurationError(msg)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
@click.group(cls=LitestarGroup, name="
|
|
42
|
+
@click.group(cls=LitestarGroup, name="db")
|
|
43
43
|
def database_group(ctx: "click.Context") -> None:
|
|
44
44
|
"""Manage SQLSpec database components."""
|
|
45
45
|
ctx.obj = {"app": ctx.obj, "configs": get_database_migration_plugin(ctx.obj.app).config}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, Any, Union
|
|
2
2
|
|
|
3
3
|
from litestar.di import Provide
|
|
4
|
-
from litestar.plugins import InitPluginProtocol
|
|
4
|
+
from litestar.plugins import CLIPlugin, InitPluginProtocol
|
|
5
5
|
|
|
6
6
|
from sqlspec.base import SQLSpec as SQLSpecBase
|
|
7
7
|
from sqlspec.config import AsyncConfigT, DatabaseConfigProtocol, DriverT, SyncConfigT
|
|
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
|
|
17
17
|
logger = get_logger("extensions.litestar")
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
class SQLSpec(InitPluginProtocol, SQLSpecBase):
|
|
20
|
+
class SQLSpec(InitPluginProtocol, CLIPlugin, SQLSpecBase):
|
|
21
21
|
"""Litestar plugin for SQLSpec database integration."""
|
|
22
22
|
|
|
23
23
|
__slots__ = ("_config", "_plugin_configs")
|
sqlspec/utils/sync_tools.py
CHANGED
|
@@ -2,7 +2,7 @@ sqlspec/__init__.py,sha256=8_TR9bXd7bkA4qBGCzTHNawH7KXaJ4YlnCJzJwvgud8,2066
|
|
|
2
2
|
sqlspec/__main__.py,sha256=lXBKZMOXA1uY735Rnsb-GS7aXy0nt22tYmd2X9FcxrY,253
|
|
3
3
|
sqlspec/__metadata__.py,sha256=IUw6MCTy1oeUJ1jAVYbuJLkOWbiAWorZ5W-E-SAD9N4,395
|
|
4
4
|
sqlspec/_serialization.py,sha256=6U5-smk2h2yl0i6am2prtOLJTdu4NJQdcLlSfSUMaUQ,2590
|
|
5
|
-
sqlspec/_sql.py,sha256=
|
|
5
|
+
sqlspec/_sql.py,sha256=HbJYrs9NCEUQhFermrcS5fDhm3aRxbabLLESHf2aMQg,45544
|
|
6
6
|
sqlspec/_typing.py,sha256=jv-7QHGLrJLfnP86bR-Xcmj3PDoddNZEKDz_vYRBiAU,22684
|
|
7
7
|
sqlspec/base.py,sha256=lVLzFD-nzEU6QnwnU0kRWh3XWjbvXWX0XnnUViYBoQk,21767
|
|
8
8
|
sqlspec/cli.py,sha256=3ZxPwl4neNWyrAkM9J9ccC_gaFigDJbhuZfx15JVE7E,9903
|
|
@@ -59,47 +59,47 @@ sqlspec/builder/_column.py,sha256=sGDoRhgeqNv69M2jIcNDWxTsMV3TKRNtktpDwl_ssSI,13
|
|
|
59
59
|
sqlspec/builder/_ddl.py,sha256=6TvCMiJAuPBtwXbAupGKnrJ9Wb9-VK5P6cfEFbE9CT8,50284
|
|
60
60
|
sqlspec/builder/_ddl_utils.py,sha256=qlKT9TqlaymwZLiZjHXIVvFofiWekCLNu-AvPFzUiac,4115
|
|
61
61
|
sqlspec/builder/_delete.py,sha256=YCAV7GUutY-j1Z6tQ9Q0CE4K4Z5LbZXldMOpS2uxAi4,2301
|
|
62
|
-
sqlspec/builder/_insert.py,sha256=
|
|
62
|
+
sqlspec/builder/_insert.py,sha256=ozqnpsQUcqzjvGvcgaUKzvrH9GKisY2DGYR7EwXdi_E,9089
|
|
63
63
|
sqlspec/builder/_merge.py,sha256=pabh0G7DsMZoOG8cGep0qLLdgnyoxQFRUUglhE5yScE,1570
|
|
64
|
-
sqlspec/builder/_parsing_utils.py,sha256=
|
|
64
|
+
sqlspec/builder/_parsing_utils.py,sha256=3XRrL2T2eG_aHfF1kQID9dZpxIgVAkB4u8Mzl1Nm-Cs,5617
|
|
65
65
|
sqlspec/builder/_select.py,sha256=oxi-5ezjsAt7n6OQm1FNCSO_wFo8djWBPL9f-kiUo9g,5992
|
|
66
66
|
sqlspec/builder/_update.py,sha256=l9tHwC96VSmk8zGMhzB_S4YuD2_6q4cBXMboqoqvLJ0,5969
|
|
67
67
|
sqlspec/builder/mixins/__init__.py,sha256=YXhAzKmQbQtne5j26SKWY8PUxwosl0RhlhLoahAdkj0,1885
|
|
68
68
|
sqlspec/builder/mixins/_cte_and_set_ops.py,sha256=BPPkDTFo2Feja7Vers0BrC_JIYcpfOYSTZ9GIV_UOZ4,8317
|
|
69
69
|
sqlspec/builder/mixins/_delete_operations.py,sha256=0f8ZZMFx5b53EUx1oF264owLb6aWP45naeB6g-BZQys,1068
|
|
70
|
-
sqlspec/builder/mixins/_insert_operations.py,sha256=
|
|
70
|
+
sqlspec/builder/mixins/_insert_operations.py,sha256=O2Au5gnoPXTsLtPrlqtHwonIKgY4MV6nkIdzXr3gySk,6340
|
|
71
71
|
sqlspec/builder/mixins/_join_operations.py,sha256=5qloj7JmRWBi7pFBpAY1acwg_O_1CpcHeYMbzkBKfBE,5507
|
|
72
|
-
sqlspec/builder/mixins/_merge_operations.py,sha256=
|
|
72
|
+
sqlspec/builder/mixins/_merge_operations.py,sha256=AnbZ53hXNsfCXdfOvZvSSLW-359R3XwaQD8y_-EBpZc,17642
|
|
73
73
|
sqlspec/builder/mixins/_order_limit_operations.py,sha256=NuNUb_DJKTdnbjasjOh27zLtbr1JZ4ygS0NH76G4foI,4514
|
|
74
74
|
sqlspec/builder/mixins/_pivot_operations.py,sha256=nkV9kG15rSoX0IWRAmaZjxyY8J7_5sScgxrRtYjddqE,5886
|
|
75
|
-
sqlspec/builder/mixins/_select_operations.py,sha256
|
|
76
|
-
sqlspec/builder/mixins/_update_operations.py,sha256=
|
|
77
|
-
sqlspec/builder/mixins/_where_clause.py,sha256=
|
|
75
|
+
sqlspec/builder/mixins/_select_operations.py,sha256=VvmMUmz2Fyhsv-J5O-3iLxMi59tupmgekPLCYxACJSg,24896
|
|
76
|
+
sqlspec/builder/mixins/_update_operations.py,sha256=j4jN1gJnFu-9PG14xgoqXOW1-9GMb__1yLs_GXExWMA,7649
|
|
77
|
+
sqlspec/builder/mixins/_where_clause.py,sha256=tQ3n48tOwlI67oqtY2BV0Tuv-TDNP8N9ceyxKL_92yQ,33289
|
|
78
78
|
sqlspec/core/__init__.py,sha256=rU_xGsXhqIOnBbyB2InhJknYePm5NQ2DSWdBigror4g,1775
|
|
79
79
|
sqlspec/core/cache.py,sha256=CQ_xTBQVJaBxB5-ipiw4Oj6JObrcMFtXYRLMSvbXGnE,27130
|
|
80
80
|
sqlspec/core/compiler.py,sha256=we_ifDr7JOAu3EycmWDxynOYq8ufjwcZl9MDXFTf5cQ,13959
|
|
81
|
-
sqlspec/core/filters.py,sha256=
|
|
81
|
+
sqlspec/core/filters.py,sha256=X0wRd0vNOFgeOK98ReeTyKt408GCnnmE9p45Bvur3kw,31351
|
|
82
82
|
sqlspec/core/hashing.py,sha256=4KyAFWtFDMYreoBGGPQppEuMWO6_NrRYlw9Lm-qeJqo,10429
|
|
83
83
|
sqlspec/core/parameters.py,sha256=X5e9SKGS1gkn7Sv6qAkzZtllIQDmhuUxAnLFlxBkAns,52833
|
|
84
84
|
sqlspec/core/result.py,sha256=vdPXLApkS0F2Jz-Bq7-A-bKf7g4JIs5_57nAI4O4tC0,21100
|
|
85
85
|
sqlspec/core/splitter.py,sha256=cb2P1B0q5vvALHi3SEJ7VdbRHH2GWsftrmJi9PYMbeE,28089
|
|
86
|
-
sqlspec/core/statement.py,sha256=
|
|
86
|
+
sqlspec/core/statement.py,sha256=XdS8YUMEVR1qVjE48a0dIh8554Tm8lTLsa4z7sgM2vE,25117
|
|
87
87
|
sqlspec/driver/__init__.py,sha256=QVpDRQGd1GreIP199en6qDbq-cZJcEF5go68DINagUk,569
|
|
88
88
|
sqlspec/driver/_async.py,sha256=0P3VlBYXfythkh9c1wCE3oZMwQa0NtbW_6SljPxpcAw,18858
|
|
89
89
|
sqlspec/driver/_common.py,sha256=go-SZRYlx_qEh8A9BGFl_BVByEdnLvtSXi6bqA6wOmU,25553
|
|
90
90
|
sqlspec/driver/_sync.py,sha256=UZKCTrKh48lzRONk-eX5q6qKBLZOawODaPN_28ObACE,18586
|
|
91
91
|
sqlspec/driver/mixins/__init__.py,sha256=gN4pQyJXxNy0xi91dcMJGA7DQ7TbjGjQI24SSpZc6Go,248
|
|
92
|
-
sqlspec/driver/mixins/_result_tools.py,sha256=
|
|
92
|
+
sqlspec/driver/mixins/_result_tools.py,sha256=s1NWsE_Tiq7R_f6rSqjbPm6SFVYpRBdSdCb0ejlX66c,6733
|
|
93
93
|
sqlspec/driver/mixins/_sql_translator.py,sha256=zpaJsS0_-zVvm3u2yCQ8VkILrZ7j28925SyZe1ChvlM,1491
|
|
94
94
|
sqlspec/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
95
95
|
sqlspec/extensions/aiosql/__init__.py,sha256=-9cefc9pYPf9vCgALoB-y1DtmcgRjKe2azfl6RIarAA,414
|
|
96
96
|
sqlspec/extensions/aiosql/adapter.py,sha256=CXkNZaZq86ZhfYFGx4IFbkHmbIFQKMd9CS6Q2jkMCok,16009
|
|
97
97
|
sqlspec/extensions/litestar/__init__.py,sha256=tOmQ7RHSWOot7p30gk0efxxuP0OCq1opyyZqNmQY7FE,320
|
|
98
98
|
sqlspec/extensions/litestar/_utils.py,sha256=o-FuUj1_WkDrLxQxiP6hXDak66XfyRP3QLyEVKrIRjI,1954
|
|
99
|
-
sqlspec/extensions/litestar/cli.py,sha256=
|
|
99
|
+
sqlspec/extensions/litestar/cli.py,sha256=X4DlAx3Ry-ccOjAQSxe8SMtyJKCFJVLTbENPU_efKuU,1356
|
|
100
100
|
sqlspec/extensions/litestar/config.py,sha256=3UI_vhtbupCLsf1nhUgUpRlCoUS5c0GsAjWvegT0c3c,4462
|
|
101
101
|
sqlspec/extensions/litestar/handlers.py,sha256=3LreU8rZvuHaJnKlN09ttu4wSorWJedsuKgeLT-cOEc,9993
|
|
102
|
-
sqlspec/extensions/litestar/plugin.py,sha256=
|
|
102
|
+
sqlspec/extensions/litestar/plugin.py,sha256=I0aRnL4oZPUYk7pYhZSL3yikl7ViM0kr33kVmH4W-MU,5637
|
|
103
103
|
sqlspec/extensions/litestar/providers.py,sha256=5LRb5JvRV_XZdNOKkdaIy3j5x-dFCcAi1ea1pgwuapI,18882
|
|
104
104
|
sqlspec/migrations/__init__.py,sha256=n9y2yLQb02zMz36bPXnrInsSIMLunwHvO7e8UvCYBJc,1061
|
|
105
105
|
sqlspec/migrations/base.py,sha256=D5-k0m4SnmVU0QRRPcMCvMAyEoAaceYYmD8JprSozDA,13251
|
|
@@ -123,12 +123,12 @@ sqlspec/utils/logging.py,sha256=ZEaj7J8oALrs_-p535vSUFo2tfrHkOEcL5pK2JGGFgM,3708
|
|
|
123
123
|
sqlspec/utils/module_loader.py,sha256=m5PSN9NwOLd0ZJBuqMVYVi-vaIQMBCVd25vnM3-rv3k,2823
|
|
124
124
|
sqlspec/utils/serializers.py,sha256=TKsRryRcYMnb8Z8MGkYGClIxcYvC8CW7MsrPQTJqEcY,154
|
|
125
125
|
sqlspec/utils/singleton.py,sha256=SKnszJi1NPeERgX7IjVIGYAYx4XqR1E_rph3bU6olAU,1047
|
|
126
|
-
sqlspec/utils/sync_tools.py,sha256=
|
|
126
|
+
sqlspec/utils/sync_tools.py,sha256=WRuk1ZEhb_0CRrumAdnmi-i-dV6qVd3cgJyZw8RY9QQ,7390
|
|
127
127
|
sqlspec/utils/text.py,sha256=n5K0gvXvyCc8jNteNKsBOymwf_JnQ65f3lu0YaYq4Ys,2898
|
|
128
128
|
sqlspec/utils/type_guards.py,sha256=AJKSQ323mNfhRbytI2e4N2cy2P6MMG7fp75foVnz328,30339
|
|
129
|
-
sqlspec-0.
|
|
130
|
-
sqlspec-0.
|
|
131
|
-
sqlspec-0.
|
|
132
|
-
sqlspec-0.
|
|
133
|
-
sqlspec-0.
|
|
134
|
-
sqlspec-0.
|
|
129
|
+
sqlspec-0.16.0.dist-info/METADATA,sha256=YmaZ4D_0DDG-phbhQMQFcP0lEYVPCpTtd7rJdzEL0BU,16822
|
|
130
|
+
sqlspec-0.16.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
131
|
+
sqlspec-0.16.0.dist-info/entry_points.txt,sha256=G-ZqY1Nuuw3Iys7nXw23f6ILenk_Lt47VdK2mhJCWHg,53
|
|
132
|
+
sqlspec-0.16.0.dist-info/licenses/LICENSE,sha256=MdujfZ6l5HuLz4mElxlu049itenOR3gnhN1_Nd3nVcM,1078
|
|
133
|
+
sqlspec-0.16.0.dist-info/licenses/NOTICE,sha256=Lyir8ozXWov7CyYS4huVaOCNrtgL17P-bNV-5daLntQ,1634
|
|
134
|
+
sqlspec-0.16.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|