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,435 +0,0 @@
1
- """SQL statement result classes for handling different types of SQL operations."""
2
-
3
- from abc import ABC, abstractmethod
4
- from collections.abc import Mapping, Sequence
5
- from dataclasses import dataclass, field
6
- from typing import TYPE_CHECKING, Any, Generic, Literal, Optional, Union
7
-
8
- from typing_extensions import TypeVar
9
-
10
- from sqlspec.typing import ArrowTable, RowT
11
-
12
- if TYPE_CHECKING:
13
- from sqlspec.statement.sql import SQL
14
-
15
- __all__ = ("ArrowResult", "SQLResult", "StatementResult")
16
-
17
-
18
- T = TypeVar("T")
19
-
20
- OperationType = Literal["SELECT", "INSERT", "UPDATE", "DELETE", "EXECUTE", "SCRIPT"]
21
-
22
-
23
- @dataclass
24
- class StatementResult(ABC, Generic[RowT]):
25
- """Base class for SQL statement execution results.
26
-
27
- This class provides a common interface for handling different types of
28
- SQL operation results. Subclasses implement specific behavior for
29
- SELECT, INSERT/UPDATE/DELETE, and script operations.
30
-
31
- Args:
32
- statement: The original SQL statement that was executed.
33
- data: The result data from the operation.
34
- rows_affected: Number of rows affected by the operation (if applicable).
35
- last_inserted_id: Last inserted ID (if applicable).
36
- execution_time: Time taken to execute the statement in seconds.
37
- metadata: Additional metadata about the operation.
38
- """
39
-
40
- statement: "SQL"
41
- """The original SQL statement that was executed."""
42
- data: "Any"
43
- """The result data from the operation."""
44
- rows_affected: int = 0
45
- """Number of rows affected by the operation."""
46
- last_inserted_id: Optional[Union[int, str]] = None
47
- """Last inserted ID from the operation."""
48
- execution_time: Optional[float] = None
49
- """Time taken to execute the statement in seconds."""
50
- metadata: "dict[str, Any]" = field(default_factory=dict)
51
- """Additional metadata about the operation."""
52
-
53
- @abstractmethod
54
- def is_success(self) -> bool:
55
- """Check if the operation was successful.
56
-
57
- Returns:
58
- True if the operation completed successfully, False otherwise.
59
- """
60
-
61
- @abstractmethod
62
- def get_data(self) -> "Any":
63
- """Get the processed data from the result.
64
-
65
- Returns:
66
- The processed result data in an appropriate format.
67
- """
68
-
69
- def get_metadata(self, key: str, default: Any = None) -> Any:
70
- """Get metadata value by key.
71
-
72
- Args:
73
- key: The metadata key to retrieve.
74
- default: Default value if key is not found.
75
-
76
- Returns:
77
- The metadata value or default.
78
- """
79
- return self.metadata.get(key, default)
80
-
81
- def set_metadata(self, key: str, value: Any) -> None:
82
- """Set metadata value by key.
83
-
84
- Args:
85
- key: The metadata key to set.
86
- value: The value to set.
87
- """
88
- self.metadata[key] = value
89
-
90
-
91
- @dataclass
92
- class SQLResult(StatementResult[RowT], Generic[RowT]):
93
- """Unified result class for SQL operations that return a list of rows
94
- or affect rows (e.g., SELECT, INSERT, UPDATE, DELETE).
95
-
96
- For DML operations with RETURNING clauses, the returned data will be in `self.data`.
97
- The `operation_type` attribute helps distinguish the nature of the operation.
98
-
99
- For script execution, this class also tracks multiple statement results and errors.
100
- """
101
-
102
- data: "list[RowT]" = field(default_factory=list)
103
- error: Optional[Exception] = None
104
- operation_type: OperationType = "SELECT"
105
- operation_index: Optional[int] = None
106
- pipeline_sql: Optional["SQL"] = None
107
- parameters: Optional[Any] = None
108
- column_names: "list[str]" = field(default_factory=list)
109
- total_count: Optional[int] = None
110
- has_more: bool = False
111
- inserted_ids: "list[Union[int, str]]" = field(default_factory=list)
112
- statement_results: "list[SQLResult[Any]]" = field(default_factory=list)
113
- """Individual statement results when executing scripts."""
114
- errors: "list[str]" = field(default_factory=list)
115
- """Errors encountered during script execution."""
116
- total_statements: int = 0
117
- """Total number of statements in the script."""
118
- successful_statements: int = 0
119
- """Number of statements that executed successfully."""
120
-
121
- def __post_init__(self) -> None:
122
- """Post-initialization to infer column names and total count if not provided."""
123
- if not self.column_names and self.data and isinstance(self.data[0], Mapping):
124
- self.column_names = list(self.data[0].keys())
125
- if self.total_count is None:
126
- self.total_count = len(self.data) if self.data is not None else 0
127
-
128
- def is_success(self) -> bool:
129
- """Check if the operation was successful.
130
-
131
- - For SELECT: True if data is not None and rows_affected is not negative.
132
- - For DML (INSERT, UPDATE, DELETE, EXECUTE): True if rows_affected is >= 0.
133
- - For SCRIPT: True if no errors and all statements succeeded.
134
- """
135
- op_type = self.operation_type.upper()
136
-
137
- if op_type == "SCRIPT" or self.statement_results:
138
- return not self.errors and self.total_statements == self.successful_statements
139
-
140
- if op_type == "SELECT":
141
- return self.data is not None and (self.rows_affected is None or self.rows_affected >= 0)
142
-
143
- if op_type in {"INSERT", "UPDATE", "DELETE", "EXECUTE"}:
144
- return self.rows_affected is not None and self.rows_affected >= 0
145
-
146
- return False
147
-
148
- def get_data(self) -> "Union[list[RowT], dict[str, Any]]":
149
- """Get the data from the result.
150
-
151
- For regular operations, returns the list of rows.
152
- For script operations, returns a summary dictionary.
153
- """
154
- if self.operation_type.upper() == "SCRIPT" or self.statement_results:
155
- return {
156
- "total_statements": self.total_statements,
157
- "successful_statements": self.successful_statements,
158
- "failed_statements": self.total_statements - self.successful_statements,
159
- "errors": self.errors,
160
- "statement_results": self.statement_results,
161
- "total_rows_affected": self.get_total_rows_affected(),
162
- }
163
- return self.data
164
-
165
- def add_statement_result(self, result: "SQLResult[Any]") -> None:
166
- """Add a statement result to the script execution results."""
167
- self.statement_results.append(result)
168
- self.total_statements += 1
169
- if result.is_success():
170
- self.successful_statements += 1
171
-
172
- def add_error(self, error: str) -> None:
173
- """Add an error message to the script execution errors."""
174
- self.errors.append(error)
175
-
176
- def get_statement_result(self, index: int) -> "Optional[SQLResult[Any]]":
177
- """Get a statement result by index."""
178
- if 0 <= index < len(self.statement_results):
179
- return self.statement_results[index]
180
- return None
181
-
182
- def get_total_rows_affected(self) -> int:
183
- """Get the total number of rows affected across all statements."""
184
- if self.statement_results:
185
- return sum(
186
- stmt.rows_affected for stmt in self.statement_results if stmt.rows_affected and stmt.rows_affected > 0
187
- )
188
- return self.rows_affected if self.rows_affected and self.rows_affected > 0 else 0
189
-
190
- @property
191
- def num_rows(self) -> int:
192
- return self.get_total_rows_affected()
193
-
194
- @property
195
- def num_columns(self) -> int:
196
- """Get the number of columns in the result data."""
197
- return len(self.column_names) if self.column_names else 0
198
-
199
- def get_errors(self) -> "list[str]":
200
- """Get all errors from script execution."""
201
- return self.errors.copy()
202
-
203
- def has_errors(self) -> bool:
204
- """Check if there are any errors from script execution."""
205
- return len(self.errors) > 0
206
-
207
- def get_first(self) -> "Optional[RowT]":
208
- """Get the first row from the result, if any."""
209
- return self.data[0] if self.data else None
210
-
211
- def get_count(self) -> int:
212
- """Get the number of rows in the current result set (e.g., a page of data)."""
213
- return len(self.data) if self.data is not None else 0
214
-
215
- def is_empty(self) -> bool:
216
- """Check if the result set (self.data) is empty."""
217
- return not self.data
218
-
219
- def get_affected_count(self) -> int:
220
- """Get the number of rows affected by a DML operation."""
221
- return self.rows_affected or 0
222
-
223
- def was_inserted(self) -> bool:
224
- """Check if this was an INSERT operation."""
225
- return self.operation_type.upper() == "INSERT"
226
-
227
- def was_updated(self) -> bool:
228
- """Check if this was an UPDATE operation."""
229
- return self.operation_type.upper() == "UPDATE"
230
-
231
- def was_deleted(self) -> bool:
232
- """Check if this was a DELETE operation."""
233
- return self.operation_type.upper() == "DELETE"
234
-
235
- def __len__(self) -> int:
236
- """Get the number of rows in the result set.
237
-
238
- Returns:
239
- Number of rows in the data.
240
- """
241
- return len(self.data) if self.data is not None else 0
242
-
243
- def __getitem__(self, index: int) -> "RowT":
244
- """Get a row by index.
245
-
246
- Args:
247
- index: Row index
248
-
249
- Returns:
250
- The row at the specified index
251
-
252
- Raises:
253
- TypeError: If data is None
254
- """
255
- if self.data is None:
256
- msg = "No data available"
257
- raise TypeError(msg)
258
- return self.data[index]
259
-
260
- def all(self) -> "list[RowT]":
261
- """Return all rows as a list.
262
-
263
- Returns:
264
- List of all rows in the result
265
- """
266
- if self.data is None:
267
- return []
268
- return self.data
269
-
270
- def one(self) -> "RowT":
271
- """Return exactly one row.
272
-
273
- Returns:
274
- The single row
275
-
276
- Raises:
277
- ValueError: If no results or more than one result
278
- """
279
- if self.data is None or len(self.data) == 0:
280
- msg = "No result found, exactly one row expected"
281
- raise ValueError(msg)
282
- if len(self.data) > 1:
283
- msg = f"Multiple results found ({len(self.data)}), exactly one row expected"
284
- raise ValueError(msg)
285
- return self.data[0]
286
-
287
- def one_or_none(self) -> "Optional[RowT]":
288
- """Return at most one row.
289
-
290
- Returns:
291
- The single row or None if no results
292
-
293
- Raises:
294
- ValueError: If more than one result
295
- """
296
- if self.data is None or len(self.data) == 0:
297
- return None
298
- if len(self.data) > 1:
299
- msg = f"Multiple results found ({len(self.data)}), at most one row expected"
300
- raise ValueError(msg)
301
- return self.data[0]
302
-
303
- def scalar(self) -> Any:
304
- """Return the first column of the first row.
305
-
306
- Returns:
307
- The scalar value from first column of first row
308
-
309
- Raises:
310
- ValueError: If no results
311
- """
312
- row = self.one()
313
- if isinstance(row, Mapping):
314
- if not row:
315
- msg = "Row has no columns"
316
- raise ValueError(msg)
317
- first_key = next(iter(row.keys()))
318
- return row[first_key]
319
- if isinstance(row, Sequence) and not isinstance(row, (str, bytes)):
320
- if len(row) == 0:
321
- msg = "Row has no columns"
322
- raise ValueError(msg)
323
- return row[0]
324
- return row
325
-
326
- def scalar_or_none(self) -> Any:
327
- """Return the first column of the first row, or None if no results.
328
-
329
- Returns:
330
- The scalar value from first column of first row, or None
331
- """
332
- row = self.one_or_none()
333
- if row is None:
334
- return None
335
-
336
- if isinstance(row, Mapping):
337
- if not row:
338
- return None
339
- first_key = next(iter(row.keys()))
340
- return row[first_key]
341
- if isinstance(row, Sequence) and not isinstance(row, (str, bytes)):
342
- if len(row) == 0:
343
- return None
344
- return row[0]
345
- return row
346
-
347
-
348
- @dataclass
349
- class ArrowResult(StatementResult[ArrowTable]):
350
- """Result class for SQL operations that return Apache Arrow data.
351
-
352
- This class is used when database drivers support returning results as
353
- Apache Arrow format for high-performance data interchange, especially
354
- useful for analytics workloads and data science applications.
355
-
356
- Args:
357
- statement: The original SQL statement that was executed.
358
- data: The Apache Arrow Table containing the result data.
359
- schema: Optional Arrow schema information.
360
- """
361
-
362
- schema: Optional["dict[str, Any]"] = None
363
- """Optional Arrow schema information."""
364
- data: "ArrowTable"
365
- """The result data from the operation."""
366
-
367
- def is_success(self) -> bool:
368
- """Check if the operation was successful.
369
-
370
- Returns:
371
- True if Arrow table data is available, False otherwise.
372
- """
373
- return self.data is not None
374
-
375
- def get_data(self) -> "ArrowTable":
376
- """Get the Apache Arrow Table from the result.
377
-
378
- Returns:
379
- The Arrow table containing the result data.
380
-
381
- Raises:
382
- ValueError: If no Arrow table is available.
383
- """
384
- if self.data is None:
385
- msg = "No Arrow table available for this result"
386
- raise ValueError(msg)
387
- return self.data
388
-
389
- @property
390
- def column_names(self) -> "list[str]":
391
- """Get the column names from the Arrow table.
392
-
393
- Returns:
394
- List of column names.
395
-
396
- Raises:
397
- ValueError: If no Arrow table is available.
398
- """
399
- if self.data is None:
400
- msg = "No Arrow table available"
401
- raise ValueError(msg)
402
-
403
- return self.data.column_names
404
-
405
- @property
406
- def num_rows(self) -> int:
407
- """Get the number of rows in the Arrow table.
408
-
409
- Returns:
410
- Number of rows.
411
-
412
- Raises:
413
- ValueError: If no Arrow table is available.
414
- """
415
- if self.data is None:
416
- msg = "No Arrow table available"
417
- raise ValueError(msg)
418
-
419
- return self.data.num_rows
420
-
421
- @property
422
- def num_columns(self) -> int:
423
- """Get the number of columns in the Arrow table.
424
-
425
- Returns:
426
- Number of columns.
427
-
428
- Raises:
429
- ValueError: If no Arrow table is available.
430
- """
431
- if self.data is None:
432
- msg = "No Arrow table available"
433
- raise ValueError(msg)
434
-
435
- return self.data.num_columns