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
@@ -1,220 +0,0 @@
1
- """Parameter management for SQL objects."""
2
-
3
- from typing import Any, Optional
4
-
5
- from sqlspec.statement.filters import StatementFilter
6
- from sqlspec.statement.parameters import ParameterConverter, ParameterStyle
7
-
8
- __all__ = ("ParameterManager",)
9
-
10
-
11
- class ParameterManager:
12
- """Manages parameter processing and conversion for SQL objects."""
13
-
14
- def __init__(
15
- self,
16
- parameters: "Optional[tuple[Any, ...]]" = None,
17
- kwargs: "Optional[dict[str, Any]]" = None,
18
- converter: "Optional[ParameterConverter]" = None,
19
- ) -> None:
20
- self.converter = converter or ParameterConverter()
21
- self.named_params: dict[str, Any] = {}
22
- self.filters: list[StatementFilter] = []
23
- self._positional_parameters = parameters or ()
24
- self._named_parameters = kwargs or {}
25
- if parameters:
26
- for i, param in enumerate(parameters):
27
- self.named_params[f"pos_param_{i}"] = param
28
- if kwargs:
29
- self.process_parameters(**kwargs)
30
-
31
- def process_parameters(self, *parameters: Any, **kwargs: Any) -> None:
32
- """Process positional parameters and kwargs into named parameters."""
33
- for i, param in enumerate(parameters):
34
- if isinstance(param, StatementFilter):
35
- self.filters.append(param)
36
- pos_params, named_params = param.extract_parameters()
37
- for j, p_param in enumerate(pos_params):
38
- self.named_params[f"pos_param_{i}_{j}"] = p_param
39
- self.named_params.update(named_params)
40
- elif isinstance(param, (list, tuple)):
41
- for j, p_param in enumerate(param):
42
- self.named_params[f"pos_param_{i}_{j}"] = p_param
43
- elif isinstance(param, dict):
44
- self.named_params.update(param)
45
- else:
46
- self.named_params[f"pos_param_{i}"] = param
47
- if "parameters" in kwargs:
48
- param_value = kwargs.pop("parameters")
49
- if isinstance(param_value, (list, tuple)):
50
- for i, p_param in enumerate(param_value):
51
- self.named_params[f"kw_pos_param_{i}"] = p_param
52
- elif isinstance(param_value, dict):
53
- self.named_params.update(param_value)
54
- else:
55
- self.named_params["kw_single_param"] = param_value
56
-
57
- for key, value in kwargs.items():
58
- if not key.startswith("_"):
59
- self.named_params[key] = value
60
-
61
- def get_compiled_parameters(self, param_info: list[Any], target_style: ParameterStyle) -> Any:
62
- """Compile internal named parameters into the target style."""
63
- if target_style == ParameterStyle.POSITIONAL_COLON:
64
- return self._convert_to_positional_colon_format(self.named_params, param_info)
65
- if target_style in {ParameterStyle.QMARK, ParameterStyle.NUMERIC, ParameterStyle.POSITIONAL_PYFORMAT}:
66
- return self._convert_to_positional_format(self.named_params, param_info)
67
- if target_style == ParameterStyle.NAMED_COLON:
68
- return self._convert_to_named_colon_format(self.named_params, param_info)
69
- if target_style == ParameterStyle.NAMED_PYFORMAT:
70
- return self._convert_to_named_pyformat_format(self.named_params, param_info)
71
- return self.named_params
72
-
73
- def copy_from(self, other: "ParameterManager") -> None:
74
- """Copy parameters and filters from another parameter manager."""
75
- self.named_params.update(other.named_params)
76
- self.filters.extend(other.filters)
77
-
78
- def add_named_parameter(self, name: str, value: Any) -> None:
79
- """Add a named parameter."""
80
- self.named_params[name] = value
81
- self._named_parameters[name] = value
82
-
83
- def get_unique_parameter_name(
84
- self, base_name: str, namespace: Optional[str] = None, preserve_original: bool = False
85
- ) -> str:
86
- """Generate a unique parameter name."""
87
- all_param_names = set(self.named_params.keys())
88
- candidate = f"{namespace}_{base_name}" if namespace else base_name
89
-
90
- if preserve_original and candidate not in all_param_names:
91
- return candidate
92
-
93
- if candidate not in all_param_names:
94
- return candidate
95
-
96
- counter = 1
97
- while True:
98
- new_candidate = f"{candidate}_{counter}"
99
- if new_candidate not in all_param_names:
100
- return new_candidate
101
- counter += 1
102
-
103
- def _convert_to_positional_format(self, params: dict[str, Any], param_info: list[Any]) -> list[Any]:
104
- """Convert to positional format (list).
105
-
106
- This is used for parameter styles like QMARK (?), NUMERIC ($1), and POSITIONAL_PYFORMAT (%s).
107
- """
108
- if not param_info:
109
- return list(params.values())
110
-
111
- result = []
112
- for i, info in enumerate(param_info):
113
- if info.name and info.name in params:
114
- result.append(params[info.name])
115
- elif f"pos_param_{i}" in params:
116
- result.append(params[f"pos_param_{i}"])
117
- elif f"kw_pos_param_{i}" in params:
118
- result.append(params[f"kw_pos_param_{i}"])
119
- elif f"arg_{i}" in params:
120
- result.append(params[f"arg_{i}"])
121
- else:
122
- result.append(None)
123
- return result
124
-
125
- def _convert_to_positional_colon_format(self, params: dict[str, Any], param_info: list[Any]) -> dict[str, Any]:
126
- """Convert to positional colon format (Oracle :1, :2 style).
127
-
128
- Oracle's positional parameters are 1-indexed and are accessed by string keys.
129
- Returns a dict with string keys "1", "2", etc.
130
- """
131
- digit_keys = {k: v for k, v in params.items() if k.isdigit()}
132
- if (
133
- digit_keys
134
- and param_info
135
- and all(hasattr(info, "style") and info.style == ParameterStyle.POSITIONAL_COLON for info in param_info)
136
- ):
137
- required_nums = {info.name for info in param_info if hasattr(info, "name")}
138
- if required_nums.issubset(digit_keys.keys()):
139
- return digit_keys
140
-
141
- # This handles cases like :0, :1, :3 (with gaps) where we should preserve the actual numbers
142
- if param_info and all(
143
- hasattr(info, "style")
144
- and info.style == ParameterStyle.POSITIONAL_COLON
145
- and hasattr(info, "name")
146
- and info.name.isdigit()
147
- for info in param_info
148
- ):
149
- result = {}
150
- positional_values = self._convert_to_positional_format(params, param_info)
151
- for i, value in enumerate(positional_values):
152
- if value is not None:
153
- numeric_key = str(i)
154
- if any(info.name == numeric_key for info in param_info):
155
- result[numeric_key] = value
156
- else:
157
- result[str(i + 1)] = value
158
-
159
- return result
160
-
161
- positional_list = self._convert_to_positional_format(params, param_info)
162
- return {str(i + 1): value for i, value in enumerate(positional_list)}
163
-
164
- def _convert_to_named_colon_format(self, params: dict[str, Any], param_info: list[Any]) -> dict[str, Any]:
165
- """Convert to named colon format (:name style).
166
-
167
- This format expects a dictionary with parameter names as keys.
168
- We need to ensure all placeholders have corresponding values.
169
- """
170
- result = {}
171
- for info in param_info:
172
- if info.name:
173
- if info.name in params:
174
- result[info.name] = params[info.name]
175
- else:
176
- for key, value in params.items():
177
- if key.endswith(f"_{info.ordinal}") or key == f"arg_{info.ordinal}":
178
- result[info.name] = value
179
- break
180
- else:
181
- gen_name = f"arg_{info.ordinal}"
182
- if f"pos_param_{info.ordinal}" in params:
183
- result[gen_name] = params[f"pos_param_{info.ordinal}"]
184
- elif f"kw_pos_param_{info.ordinal}" in params:
185
- result[gen_name] = params[f"kw_pos_param_{info.ordinal}"]
186
- elif gen_name in params:
187
- result[gen_name] = params[gen_name]
188
- for key, value in params.items():
189
- if not key.startswith(("pos_param_", "kw_pos_param_", "arg_")) and key not in result:
190
- result[key] = value
191
-
192
- return result
193
-
194
- def _convert_to_named_pyformat_format(self, params: dict[str, Any], param_info: list[Any]) -> dict[str, Any]:
195
- """Convert to named pyformat format (%(name)s style).
196
-
197
- This is similar to named colon format but uses Python string formatting syntax.
198
- """
199
- return self._convert_to_named_colon_format(params, param_info)
200
-
201
- @property
202
- def positional_parameters(self) -> tuple[Any, ...]:
203
- """Get the original positional parameters."""
204
- return self._positional_parameters
205
-
206
- @property
207
- def named_parameters(self) -> dict[str, Any]:
208
- """Get the combined named parameters."""
209
- return self.named_params
210
-
211
- def get_parameter_info(self) -> tuple[tuple[Any, ...], dict[str, Any]]:
212
- """Get parameter information in the legacy format.
213
-
214
- This method provides backward compatibility for code expecting
215
- the old parameter_info format.
216
-
217
- Returns:
218
- Tuple of (positional_parameters, named_parameters)
219
- """
220
- return (self._positional_parameters, self._named_parameters)