sqlspec 0.13.1__py3-none-any.whl → 0.16.2__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 (185) hide show
  1. sqlspec/__init__.py +71 -8
  2. sqlspec/__main__.py +12 -0
  3. sqlspec/__metadata__.py +1 -3
  4. sqlspec/_serialization.py +1 -2
  5. sqlspec/_sql.py +930 -136
  6. sqlspec/_typing.py +278 -142
  7. sqlspec/adapters/adbc/__init__.py +4 -3
  8. sqlspec/adapters/adbc/_types.py +12 -0
  9. sqlspec/adapters/adbc/config.py +116 -285
  10. sqlspec/adapters/adbc/driver.py +462 -340
  11. sqlspec/adapters/aiosqlite/__init__.py +18 -3
  12. sqlspec/adapters/aiosqlite/_types.py +13 -0
  13. sqlspec/adapters/aiosqlite/config.py +202 -150
  14. sqlspec/adapters/aiosqlite/driver.py +226 -247
  15. sqlspec/adapters/asyncmy/__init__.py +18 -3
  16. sqlspec/adapters/asyncmy/_types.py +12 -0
  17. sqlspec/adapters/asyncmy/config.py +80 -199
  18. sqlspec/adapters/asyncmy/driver.py +257 -215
  19. sqlspec/adapters/asyncpg/__init__.py +19 -4
  20. sqlspec/adapters/asyncpg/_types.py +17 -0
  21. sqlspec/adapters/asyncpg/config.py +81 -214
  22. sqlspec/adapters/asyncpg/driver.py +284 -359
  23. sqlspec/adapters/bigquery/__init__.py +17 -3
  24. sqlspec/adapters/bigquery/_types.py +12 -0
  25. sqlspec/adapters/bigquery/config.py +191 -299
  26. sqlspec/adapters/bigquery/driver.py +474 -634
  27. sqlspec/adapters/duckdb/__init__.py +14 -3
  28. sqlspec/adapters/duckdb/_types.py +12 -0
  29. sqlspec/adapters/duckdb/config.py +414 -397
  30. sqlspec/adapters/duckdb/driver.py +342 -393
  31. sqlspec/adapters/oracledb/__init__.py +19 -5
  32. sqlspec/adapters/oracledb/_types.py +14 -0
  33. sqlspec/adapters/oracledb/config.py +123 -458
  34. sqlspec/adapters/oracledb/driver.py +505 -531
  35. sqlspec/adapters/psqlpy/__init__.py +13 -3
  36. sqlspec/adapters/psqlpy/_types.py +11 -0
  37. sqlspec/adapters/psqlpy/config.py +93 -307
  38. sqlspec/adapters/psqlpy/driver.py +504 -213
  39. sqlspec/adapters/psycopg/__init__.py +19 -5
  40. sqlspec/adapters/psycopg/_types.py +17 -0
  41. sqlspec/adapters/psycopg/config.py +143 -472
  42. sqlspec/adapters/psycopg/driver.py +704 -825
  43. sqlspec/adapters/sqlite/__init__.py +14 -3
  44. sqlspec/adapters/sqlite/_types.py +11 -0
  45. sqlspec/adapters/sqlite/config.py +208 -142
  46. sqlspec/adapters/sqlite/driver.py +263 -278
  47. sqlspec/base.py +105 -9
  48. sqlspec/{statement/builder → builder}/__init__.py +12 -14
  49. sqlspec/{statement/builder/base.py → builder/_base.py} +184 -86
  50. sqlspec/{statement/builder/column.py → builder/_column.py} +97 -60
  51. sqlspec/{statement/builder/ddl.py → builder/_ddl.py} +61 -131
  52. sqlspec/{statement/builder → builder}/_ddl_utils.py +4 -10
  53. sqlspec/{statement/builder/delete.py → builder/_delete.py} +10 -30
  54. sqlspec/builder/_insert.py +421 -0
  55. sqlspec/builder/_merge.py +71 -0
  56. sqlspec/{statement/builder → builder}/_parsing_utils.py +49 -26
  57. sqlspec/builder/_select.py +170 -0
  58. sqlspec/{statement/builder/update.py → builder/_update.py} +16 -20
  59. sqlspec/builder/mixins/__init__.py +55 -0
  60. sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
  61. sqlspec/{statement/builder/mixins/_delete_from.py → builder/mixins/_delete_operations.py} +8 -1
  62. sqlspec/builder/mixins/_insert_operations.py +244 -0
  63. sqlspec/{statement/builder/mixins/_join.py → builder/mixins/_join_operations.py} +45 -13
  64. sqlspec/{statement/builder/mixins/_merge_clauses.py → builder/mixins/_merge_operations.py} +188 -30
  65. sqlspec/builder/mixins/_order_limit_operations.py +135 -0
  66. sqlspec/builder/mixins/_pivot_operations.py +153 -0
  67. sqlspec/builder/mixins/_select_operations.py +604 -0
  68. sqlspec/builder/mixins/_update_operations.py +202 -0
  69. sqlspec/builder/mixins/_where_clause.py +644 -0
  70. sqlspec/cli.py +247 -0
  71. sqlspec/config.py +183 -138
  72. sqlspec/core/__init__.py +63 -0
  73. sqlspec/core/cache.py +871 -0
  74. sqlspec/core/compiler.py +417 -0
  75. sqlspec/core/filters.py +830 -0
  76. sqlspec/core/hashing.py +310 -0
  77. sqlspec/core/parameters.py +1237 -0
  78. sqlspec/core/result.py +677 -0
  79. sqlspec/{statement → core}/splitter.py +321 -191
  80. sqlspec/core/statement.py +676 -0
  81. sqlspec/driver/__init__.py +7 -10
  82. sqlspec/driver/_async.py +422 -163
  83. sqlspec/driver/_common.py +545 -287
  84. sqlspec/driver/_sync.py +426 -160
  85. sqlspec/driver/mixins/__init__.py +2 -13
  86. sqlspec/driver/mixins/_result_tools.py +193 -0
  87. sqlspec/driver/mixins/_sql_translator.py +65 -14
  88. sqlspec/exceptions.py +5 -252
  89. sqlspec/extensions/aiosql/adapter.py +93 -96
  90. sqlspec/extensions/litestar/__init__.py +2 -1
  91. sqlspec/extensions/litestar/cli.py +48 -0
  92. sqlspec/extensions/litestar/config.py +0 -1
  93. sqlspec/extensions/litestar/handlers.py +15 -26
  94. sqlspec/extensions/litestar/plugin.py +21 -16
  95. sqlspec/extensions/litestar/providers.py +17 -52
  96. sqlspec/loader.py +423 -104
  97. sqlspec/migrations/__init__.py +35 -0
  98. sqlspec/migrations/base.py +414 -0
  99. sqlspec/migrations/commands.py +443 -0
  100. sqlspec/migrations/loaders.py +402 -0
  101. sqlspec/migrations/runner.py +213 -0
  102. sqlspec/migrations/tracker.py +140 -0
  103. sqlspec/migrations/utils.py +129 -0
  104. sqlspec/protocols.py +51 -186
  105. sqlspec/storage/__init__.py +1 -1
  106. sqlspec/storage/backends/base.py +37 -40
  107. sqlspec/storage/backends/fsspec.py +136 -112
  108. sqlspec/storage/backends/obstore.py +138 -160
  109. sqlspec/storage/capabilities.py +5 -4
  110. sqlspec/storage/registry.py +57 -106
  111. sqlspec/typing.py +136 -115
  112. sqlspec/utils/__init__.py +2 -2
  113. sqlspec/utils/correlation.py +0 -3
  114. sqlspec/utils/deprecation.py +6 -6
  115. sqlspec/utils/fixtures.py +6 -6
  116. sqlspec/utils/logging.py +0 -2
  117. sqlspec/utils/module_loader.py +7 -12
  118. sqlspec/utils/singleton.py +0 -1
  119. sqlspec/utils/sync_tools.py +17 -38
  120. sqlspec/utils/text.py +12 -51
  121. sqlspec/utils/type_guards.py +482 -235
  122. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/METADATA +7 -2
  123. sqlspec-0.16.2.dist-info/RECORD +134 -0
  124. sqlspec-0.16.2.dist-info/entry_points.txt +2 -0
  125. sqlspec/driver/connection.py +0 -207
  126. sqlspec/driver/mixins/_csv_writer.py +0 -91
  127. sqlspec/driver/mixins/_pipeline.py +0 -512
  128. sqlspec/driver/mixins/_result_utils.py +0 -140
  129. sqlspec/driver/mixins/_storage.py +0 -926
  130. sqlspec/driver/mixins/_type_coercion.py +0 -130
  131. sqlspec/driver/parameters.py +0 -138
  132. sqlspec/service/__init__.py +0 -4
  133. sqlspec/service/_util.py +0 -147
  134. sqlspec/service/base.py +0 -1131
  135. sqlspec/service/pagination.py +0 -26
  136. sqlspec/statement/__init__.py +0 -21
  137. sqlspec/statement/builder/insert.py +0 -288
  138. sqlspec/statement/builder/merge.py +0 -95
  139. sqlspec/statement/builder/mixins/__init__.py +0 -65
  140. sqlspec/statement/builder/mixins/_aggregate_functions.py +0 -250
  141. sqlspec/statement/builder/mixins/_case_builder.py +0 -91
  142. sqlspec/statement/builder/mixins/_common_table_expr.py +0 -90
  143. sqlspec/statement/builder/mixins/_from.py +0 -63
  144. sqlspec/statement/builder/mixins/_group_by.py +0 -118
  145. sqlspec/statement/builder/mixins/_having.py +0 -35
  146. sqlspec/statement/builder/mixins/_insert_from_select.py +0 -47
  147. sqlspec/statement/builder/mixins/_insert_into.py +0 -36
  148. sqlspec/statement/builder/mixins/_insert_values.py +0 -67
  149. sqlspec/statement/builder/mixins/_limit_offset.py +0 -53
  150. sqlspec/statement/builder/mixins/_order_by.py +0 -46
  151. sqlspec/statement/builder/mixins/_pivot.py +0 -79
  152. sqlspec/statement/builder/mixins/_returning.py +0 -37
  153. sqlspec/statement/builder/mixins/_select_columns.py +0 -61
  154. sqlspec/statement/builder/mixins/_set_ops.py +0 -122
  155. sqlspec/statement/builder/mixins/_unpivot.py +0 -77
  156. sqlspec/statement/builder/mixins/_update_from.py +0 -55
  157. sqlspec/statement/builder/mixins/_update_set.py +0 -94
  158. sqlspec/statement/builder/mixins/_update_table.py +0 -29
  159. sqlspec/statement/builder/mixins/_where.py +0 -401
  160. sqlspec/statement/builder/mixins/_window_functions.py +0 -86
  161. sqlspec/statement/builder/select.py +0 -221
  162. sqlspec/statement/filters.py +0 -596
  163. sqlspec/statement/parameter_manager.py +0 -220
  164. sqlspec/statement/parameters.py +0 -867
  165. sqlspec/statement/pipelines/__init__.py +0 -210
  166. sqlspec/statement/pipelines/analyzers/__init__.py +0 -9
  167. sqlspec/statement/pipelines/analyzers/_analyzer.py +0 -646
  168. sqlspec/statement/pipelines/context.py +0 -115
  169. sqlspec/statement/pipelines/transformers/__init__.py +0 -7
  170. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +0 -88
  171. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +0 -1247
  172. sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +0 -76
  173. sqlspec/statement/pipelines/validators/__init__.py +0 -23
  174. sqlspec/statement/pipelines/validators/_dml_safety.py +0 -290
  175. sqlspec/statement/pipelines/validators/_parameter_style.py +0 -370
  176. sqlspec/statement/pipelines/validators/_performance.py +0 -718
  177. sqlspec/statement/pipelines/validators/_security.py +0 -967
  178. sqlspec/statement/result.py +0 -435
  179. sqlspec/statement/sql.py +0 -1704
  180. sqlspec/statement/sql_compiler.py +0 -140
  181. sqlspec/utils/cached_property.py +0 -25
  182. sqlspec-0.13.1.dist-info/RECORD +0 -150
  183. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/WHEEL +0 -0
  184. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/LICENSE +0 -0
  185. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,202 @@
1
+ """Update operation mixins for SQL builders."""
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, Optional, Union, cast
5
+
6
+ from mypy_extensions import trait
7
+ from sqlglot import exp
8
+ from typing_extensions import Self
9
+
10
+ from sqlspec.exceptions import SQLBuilderError
11
+ from sqlspec.utils.type_guards import has_query_builder_parameters
12
+
13
+ __all__ = ("UpdateFromClauseMixin", "UpdateSetClauseMixin", "UpdateTableClauseMixin")
14
+
15
+ MIN_SET_ARGS = 2
16
+
17
+
18
+ @trait
19
+ class UpdateTableClauseMixin:
20
+ """Mixin providing TABLE clause for UPDATE builders."""
21
+
22
+ __slots__ = ()
23
+
24
+ # Type annotation for PyRight - this will be provided by the base class
25
+ _expression: Optional[exp.Expression]
26
+
27
+ def table(self, table_name: str, alias: Optional[str] = None) -> Self:
28
+ """Set the table to update.
29
+
30
+ Args:
31
+ table_name: The name of the table.
32
+ alias: Optional alias for the table.
33
+
34
+ Returns:
35
+ The current builder instance for method chaining.
36
+ """
37
+ if self._expression is None or not isinstance(self._expression, exp.Update):
38
+ self._expression = exp.Update(this=None, expressions=[], joins=[])
39
+ table_expr: exp.Expression = exp.to_table(table_name, alias=alias)
40
+ self._expression.set("this", table_expr)
41
+ setattr(self, "_table", table_name)
42
+ return self
43
+
44
+
45
+ @trait
46
+ class UpdateSetClauseMixin:
47
+ """Mixin providing SET clause for UPDATE builders."""
48
+
49
+ __slots__ = ()
50
+
51
+ # Type annotation for PyRight - this will be provided by the base class
52
+ _expression: Optional[exp.Expression]
53
+
54
+ def add_parameter(self, value: Any, name: Optional[str] = None) -> tuple[Any, str]:
55
+ """Add parameter - provided by QueryBuilder."""
56
+ msg = "Method must be provided by QueryBuilder subclass"
57
+ raise NotImplementedError(msg)
58
+
59
+ def _generate_unique_parameter_name(self, base_name: str) -> str:
60
+ """Generate unique parameter name - provided by QueryBuilder."""
61
+ msg = "Method must be provided by QueryBuilder subclass"
62
+ raise NotImplementedError(msg)
63
+
64
+ def _process_update_value(self, val: Any, col: Any) -> exp.Expression:
65
+ """Process a value for UPDATE assignment, handling SQL objects and parameters.
66
+
67
+ Args:
68
+ val: The value to process
69
+ col: The column name for parameter naming
70
+
71
+ Returns:
72
+ The processed expression for the value
73
+ """
74
+ if isinstance(val, exp.Expression):
75
+ return val
76
+ if has_query_builder_parameters(val):
77
+ subquery = val.build()
78
+ sql_str = subquery.sql if hasattr(subquery, "sql") and not callable(subquery.sql) else str(subquery)
79
+ value_expr = exp.paren(exp.maybe_parse(sql_str, dialect=getattr(self, "dialect", None)))
80
+ if has_query_builder_parameters(val):
81
+ for p_name, p_value in val.parameters.items():
82
+ self.add_parameter(p_value, name=p_name)
83
+ return value_expr
84
+ if hasattr(val, "expression") and hasattr(val, "sql"):
85
+ # Handle SQL objects (from sql.raw with parameters)
86
+ expression = getattr(val, "expression", None)
87
+ if expression is not None and isinstance(expression, exp.Expression):
88
+ # Merge parameters from SQL object into builder
89
+ if hasattr(val, "parameters"):
90
+ sql_parameters = getattr(val, "parameters", {})
91
+ for param_name, param_value in sql_parameters.items():
92
+ self.add_parameter(param_value, name=param_name)
93
+ return cast("exp.Expression", expression)
94
+ # If expression is None, fall back to parsing the raw SQL
95
+ sql_text = getattr(val, "sql", "")
96
+ # Merge parameters even when parsing raw SQL
97
+ if hasattr(val, "parameters"):
98
+ sql_parameters = getattr(val, "parameters", {})
99
+ for param_name, param_value in sql_parameters.items():
100
+ self.add_parameter(param_value, name=param_name)
101
+ parsed_expr = exp.maybe_parse(sql_text)
102
+ return parsed_expr if parsed_expr is not None else exp.convert(str(sql_text))
103
+ column_name = col if isinstance(col, str) else str(col)
104
+ if "." in column_name:
105
+ column_name = column_name.split(".")[-1]
106
+ param_name = self._generate_unique_parameter_name(column_name)
107
+ param_name = self.add_parameter(val, name=param_name)[1]
108
+ return exp.Placeholder(this=param_name)
109
+
110
+ def set(self, *args: Any, **kwargs: Any) -> Self:
111
+ """Set columns and values for the UPDATE statement.
112
+
113
+ Supports:
114
+ - set(column, value)
115
+ - set(mapping)
116
+ - set(**kwargs)
117
+ - set(mapping, **kwargs)
118
+
119
+ Args:
120
+ *args: Either (column, value) or a mapping.
121
+ **kwargs: Column-value pairs to set.
122
+
123
+ Raises:
124
+ SQLBuilderError: If the current expression is not an UPDATE statement or usage is invalid.
125
+
126
+ Returns:
127
+ The current builder instance for method chaining.
128
+ """
129
+ if self._expression is None:
130
+ self._expression = exp.Update()
131
+ if not isinstance(self._expression, exp.Update):
132
+ msg = "Cannot add SET clause to non-UPDATE expression."
133
+ raise SQLBuilderError(msg)
134
+ assignments = []
135
+ if len(args) == MIN_SET_ARGS and not kwargs:
136
+ col, val = args
137
+ col_expr = col if isinstance(col, exp.Column) else exp.column(col)
138
+ value_expr = self._process_update_value(val, col)
139
+ assignments.append(exp.EQ(this=col_expr, expression=value_expr))
140
+ elif (len(args) == 1 and isinstance(args[0], Mapping)) or kwargs:
141
+ all_values = dict(args[0] if args else {}, **kwargs)
142
+ for col, val in all_values.items():
143
+ value_expr = self._process_update_value(val, col)
144
+ assignments.append(exp.EQ(this=exp.column(col), expression=value_expr))
145
+ else:
146
+ msg = "Invalid arguments for set(): use (column, value), mapping, or kwargs."
147
+ raise SQLBuilderError(msg)
148
+ existing = self._expression.args.get("expressions", [])
149
+ self._expression.set("expressions", existing + assignments)
150
+ return self
151
+
152
+
153
+ @trait
154
+ class UpdateFromClauseMixin:
155
+ """Mixin providing FROM clause for UPDATE builders (e.g., PostgreSQL style)."""
156
+
157
+ __slots__ = ()
158
+
159
+ # Type annotation for PyRight - this will be provided by the base class
160
+ _expression: Optional[exp.Expression]
161
+
162
+ def from_(self, table: Union[str, exp.Expression, Any], alias: Optional[str] = None) -> Self:
163
+ """Add a FROM clause to the UPDATE statement.
164
+
165
+ Args:
166
+ table: The table name, expression, or subquery to add to the FROM clause.
167
+ alias: Optional alias for the table in the FROM clause.
168
+
169
+ Returns:
170
+ The current builder instance for method chaining.
171
+
172
+ Raises:
173
+ SQLBuilderError: If the current expression is not an UPDATE statement.
174
+ """
175
+ if self._expression is None or not isinstance(self._expression, exp.Update):
176
+ msg = "Cannot add FROM clause to non-UPDATE expression. Set the main table first."
177
+ raise SQLBuilderError(msg)
178
+ table_expr: exp.Expression
179
+ if isinstance(table, str):
180
+ table_expr = exp.to_table(table, alias=alias)
181
+ elif has_query_builder_parameters(table):
182
+ subquery_builder_parameters = getattr(table, "_parameters", None)
183
+ if subquery_builder_parameters:
184
+ for p_name, p_value in subquery_builder_parameters.items():
185
+ self.add_parameter(p_value, name=p_name) # type: ignore[attr-defined]
186
+ subquery_exp = exp.paren(getattr(table, "_expression", exp.select()))
187
+ table_expr = exp.alias_(subquery_exp, alias) if alias else subquery_exp
188
+ elif isinstance(table, exp.Expression):
189
+ table_expr = exp.alias_(table, alias) if alias else table
190
+ else:
191
+ msg = f"Unsupported table type for FROM clause: {type(table)}"
192
+ raise SQLBuilderError(msg)
193
+ if self._expression.args.get("from") is None:
194
+ self._expression.set("from", exp.From(expressions=[]))
195
+ from_clause = self._expression.args["from"]
196
+ if hasattr(from_clause, "append"):
197
+ from_clause.append("expressions", table_expr)
198
+ else:
199
+ if not from_clause.expressions:
200
+ from_clause.expressions = []
201
+ from_clause.expressions.append(table_expr)
202
+ return self