sqlspec 0.16.1__cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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 (148) hide show
  1. 51ff5a9eadfdefd49f98__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
  2. sqlspec/__init__.py +92 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_serialization.py +77 -0
  6. sqlspec/_sql.py +1780 -0
  7. sqlspec/_typing.py +680 -0
  8. sqlspec/adapters/__init__.py +0 -0
  9. sqlspec/adapters/adbc/__init__.py +5 -0
  10. sqlspec/adapters/adbc/_types.py +12 -0
  11. sqlspec/adapters/adbc/config.py +361 -0
  12. sqlspec/adapters/adbc/driver.py +512 -0
  13. sqlspec/adapters/aiosqlite/__init__.py +19 -0
  14. sqlspec/adapters/aiosqlite/_types.py +13 -0
  15. sqlspec/adapters/aiosqlite/config.py +253 -0
  16. sqlspec/adapters/aiosqlite/driver.py +248 -0
  17. sqlspec/adapters/asyncmy/__init__.py +19 -0
  18. sqlspec/adapters/asyncmy/_types.py +12 -0
  19. sqlspec/adapters/asyncmy/config.py +180 -0
  20. sqlspec/adapters/asyncmy/driver.py +274 -0
  21. sqlspec/adapters/asyncpg/__init__.py +21 -0
  22. sqlspec/adapters/asyncpg/_types.py +17 -0
  23. sqlspec/adapters/asyncpg/config.py +229 -0
  24. sqlspec/adapters/asyncpg/driver.py +344 -0
  25. sqlspec/adapters/bigquery/__init__.py +18 -0
  26. sqlspec/adapters/bigquery/_types.py +12 -0
  27. sqlspec/adapters/bigquery/config.py +298 -0
  28. sqlspec/adapters/bigquery/driver.py +558 -0
  29. sqlspec/adapters/duckdb/__init__.py +22 -0
  30. sqlspec/adapters/duckdb/_types.py +12 -0
  31. sqlspec/adapters/duckdb/config.py +504 -0
  32. sqlspec/adapters/duckdb/driver.py +368 -0
  33. sqlspec/adapters/oracledb/__init__.py +32 -0
  34. sqlspec/adapters/oracledb/_types.py +14 -0
  35. sqlspec/adapters/oracledb/config.py +317 -0
  36. sqlspec/adapters/oracledb/driver.py +538 -0
  37. sqlspec/adapters/psqlpy/__init__.py +16 -0
  38. sqlspec/adapters/psqlpy/_types.py +11 -0
  39. sqlspec/adapters/psqlpy/config.py +214 -0
  40. sqlspec/adapters/psqlpy/driver.py +530 -0
  41. sqlspec/adapters/psycopg/__init__.py +32 -0
  42. sqlspec/adapters/psycopg/_types.py +17 -0
  43. sqlspec/adapters/psycopg/config.py +426 -0
  44. sqlspec/adapters/psycopg/driver.py +796 -0
  45. sqlspec/adapters/sqlite/__init__.py +15 -0
  46. sqlspec/adapters/sqlite/_types.py +11 -0
  47. sqlspec/adapters/sqlite/config.py +240 -0
  48. sqlspec/adapters/sqlite/driver.py +294 -0
  49. sqlspec/base.py +571 -0
  50. sqlspec/builder/__init__.py +62 -0
  51. sqlspec/builder/_base.py +473 -0
  52. sqlspec/builder/_column.py +320 -0
  53. sqlspec/builder/_ddl.py +1346 -0
  54. sqlspec/builder/_ddl_utils.py +103 -0
  55. sqlspec/builder/_delete.py +76 -0
  56. sqlspec/builder/_insert.py +256 -0
  57. sqlspec/builder/_merge.py +71 -0
  58. sqlspec/builder/_parsing_utils.py +140 -0
  59. sqlspec/builder/_select.py +170 -0
  60. sqlspec/builder/_update.py +188 -0
  61. sqlspec/builder/mixins/__init__.py +55 -0
  62. sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
  63. sqlspec/builder/mixins/_delete_operations.py +41 -0
  64. sqlspec/builder/mixins/_insert_operations.py +244 -0
  65. sqlspec/builder/mixins/_join_operations.py +122 -0
  66. sqlspec/builder/mixins/_merge_operations.py +476 -0
  67. sqlspec/builder/mixins/_order_limit_operations.py +135 -0
  68. sqlspec/builder/mixins/_pivot_operations.py +153 -0
  69. sqlspec/builder/mixins/_select_operations.py +603 -0
  70. sqlspec/builder/mixins/_update_operations.py +187 -0
  71. sqlspec/builder/mixins/_where_clause.py +621 -0
  72. sqlspec/cli.py +247 -0
  73. sqlspec/config.py +395 -0
  74. sqlspec/core/__init__.py +63 -0
  75. sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
  76. sqlspec/core/cache.py +871 -0
  77. sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
  78. sqlspec/core/compiler.py +417 -0
  79. sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
  80. sqlspec/core/filters.py +830 -0
  81. sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
  82. sqlspec/core/hashing.py +310 -0
  83. sqlspec/core/parameters.cpython-310-aarch64-linux-gnu.so +0 -0
  84. sqlspec/core/parameters.py +1237 -0
  85. sqlspec/core/result.cpython-310-aarch64-linux-gnu.so +0 -0
  86. sqlspec/core/result.py +677 -0
  87. sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
  88. sqlspec/core/splitter.py +819 -0
  89. sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
  90. sqlspec/core/statement.py +676 -0
  91. sqlspec/driver/__init__.py +19 -0
  92. sqlspec/driver/_async.py +502 -0
  93. sqlspec/driver/_common.py +631 -0
  94. sqlspec/driver/_sync.py +503 -0
  95. sqlspec/driver/mixins/__init__.py +6 -0
  96. sqlspec/driver/mixins/_result_tools.py +193 -0
  97. sqlspec/driver/mixins/_sql_translator.py +86 -0
  98. sqlspec/exceptions.py +193 -0
  99. sqlspec/extensions/__init__.py +0 -0
  100. sqlspec/extensions/aiosql/__init__.py +10 -0
  101. sqlspec/extensions/aiosql/adapter.py +461 -0
  102. sqlspec/extensions/litestar/__init__.py +6 -0
  103. sqlspec/extensions/litestar/_utils.py +52 -0
  104. sqlspec/extensions/litestar/cli.py +48 -0
  105. sqlspec/extensions/litestar/config.py +92 -0
  106. sqlspec/extensions/litestar/handlers.py +260 -0
  107. sqlspec/extensions/litestar/plugin.py +145 -0
  108. sqlspec/extensions/litestar/providers.py +454 -0
  109. sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
  110. sqlspec/loader.py +760 -0
  111. sqlspec/migrations/__init__.py +35 -0
  112. sqlspec/migrations/base.py +414 -0
  113. sqlspec/migrations/commands.py +443 -0
  114. sqlspec/migrations/loaders.py +402 -0
  115. sqlspec/migrations/runner.py +213 -0
  116. sqlspec/migrations/tracker.py +140 -0
  117. sqlspec/migrations/utils.py +129 -0
  118. sqlspec/protocols.py +407 -0
  119. sqlspec/py.typed +0 -0
  120. sqlspec/storage/__init__.py +23 -0
  121. sqlspec/storage/backends/__init__.py +0 -0
  122. sqlspec/storage/backends/base.py +163 -0
  123. sqlspec/storage/backends/fsspec.py +386 -0
  124. sqlspec/storage/backends/obstore.py +459 -0
  125. sqlspec/storage/capabilities.py +102 -0
  126. sqlspec/storage/registry.py +239 -0
  127. sqlspec/typing.py +299 -0
  128. sqlspec/utils/__init__.py +3 -0
  129. sqlspec/utils/correlation.py +150 -0
  130. sqlspec/utils/deprecation.py +106 -0
  131. sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
  132. sqlspec/utils/fixtures.py +58 -0
  133. sqlspec/utils/logging.py +127 -0
  134. sqlspec/utils/module_loader.py +89 -0
  135. sqlspec/utils/serializers.py +4 -0
  136. sqlspec/utils/singleton.py +32 -0
  137. sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
  138. sqlspec/utils/sync_tools.py +237 -0
  139. sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
  140. sqlspec/utils/text.py +96 -0
  141. sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
  142. sqlspec/utils/type_guards.py +1139 -0
  143. sqlspec-0.16.1.dist-info/METADATA +365 -0
  144. sqlspec-0.16.1.dist-info/RECORD +148 -0
  145. sqlspec-0.16.1.dist-info/WHEEL +7 -0
  146. sqlspec-0.16.1.dist-info/entry_points.txt +2 -0
  147. sqlspec-0.16.1.dist-info/licenses/LICENSE +21 -0
  148. sqlspec-0.16.1.dist-info/licenses/NOTICE +29 -0
@@ -0,0 +1,193 @@
1
+ # pyright: reportCallIssue=false, reportAttributeAccessIssue=false, reportArgumentType=false
2
+ import datetime
3
+ import logging
4
+ from collections.abc import Sequence
5
+ from enum import Enum
6
+ from functools import partial
7
+ from pathlib import Path, PurePath
8
+ from typing import Any, Callable, Final, Optional, overload
9
+ from uuid import UUID
10
+
11
+ from mypy_extensions import trait
12
+
13
+ from sqlspec.exceptions import SQLSpecError
14
+ from sqlspec.typing import (
15
+ CATTRS_INSTALLED,
16
+ ModelDTOT,
17
+ ModelT,
18
+ attrs_asdict,
19
+ cattrs_structure,
20
+ cattrs_unstructure,
21
+ convert,
22
+ get_type_adapter,
23
+ )
24
+ from sqlspec.utils.type_guards import is_attrs_schema, is_dataclass, is_msgspec_struct, is_pydantic_model
25
+
26
+ __all__ = ("_DEFAULT_TYPE_DECODERS", "_default_msgspec_deserializer")
27
+
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+ # Constants for performance optimization
32
+ _DATETIME_TYPES: Final[set[type]] = {datetime.datetime, datetime.date, datetime.time}
33
+ _PATH_TYPES: Final[tuple[type, ...]] = (Path, PurePath, UUID)
34
+
35
+ _DEFAULT_TYPE_DECODERS: Final[list[tuple[Callable[[Any], bool], Callable[[Any, Any], Any]]]] = [
36
+ (lambda x: x is UUID, lambda t, v: t(v.hex)),
37
+ (lambda x: x is datetime.datetime, lambda t, v: t(v.isoformat())),
38
+ (lambda x: x is datetime.date, lambda t, v: t(v.isoformat())),
39
+ (lambda x: x is datetime.time, lambda t, v: t(v.isoformat())),
40
+ (lambda x: x is Enum, lambda t, v: t(v.value)),
41
+ ]
42
+
43
+
44
+ def _default_msgspec_deserializer(
45
+ target_type: Any, value: Any, type_decoders: "Optional[Sequence[tuple[Any, Any]]]" = None
46
+ ) -> Any:
47
+ """Default msgspec deserializer with type conversion support.
48
+
49
+ Converts values to appropriate types for msgspec deserialization, including
50
+ UUID, datetime, date, time, Enum, Path, and PurePath types.
51
+ """
52
+ if type_decoders:
53
+ for predicate, decoder in type_decoders:
54
+ if predicate(target_type):
55
+ return decoder(target_type, value)
56
+
57
+ # Fast path checks using type identity and isinstance
58
+ if target_type is UUID and isinstance(value, UUID):
59
+ return value.hex
60
+
61
+ # Use pre-computed set for faster lookup
62
+ if target_type in _DATETIME_TYPES:
63
+ try:
64
+ return value.isoformat()
65
+ except AttributeError:
66
+ pass
67
+
68
+ if isinstance(target_type, type) and issubclass(target_type, Enum) and isinstance(value, Enum):
69
+ return value.value
70
+
71
+ if isinstance(value, target_type):
72
+ return value
73
+
74
+ # Check for path types using pre-computed tuple
75
+ if isinstance(target_type, type):
76
+ try:
77
+ if issubclass(target_type, (Path, PurePath)) or issubclass(target_type, UUID):
78
+ return target_type(str(value))
79
+ except (TypeError, ValueError):
80
+ pass
81
+
82
+ return value
83
+
84
+
85
+ @trait
86
+ class ToSchemaMixin:
87
+ __slots__ = ()
88
+
89
+ # Schema conversion overloads - handle common cases first
90
+ @overload
91
+ @staticmethod
92
+ def to_schema(data: "list[dict[str, Any]]") -> "list[dict[str, Any]]": ...
93
+ @overload
94
+ @staticmethod
95
+ def to_schema(data: "list[dict[str, Any]]", *, schema_type: "type[ModelDTOT]") -> "list[ModelDTOT]": ...
96
+ @overload
97
+ @staticmethod
98
+ def to_schema(data: "list[dict[str, Any]]", *, schema_type: None = None) -> "list[dict[str, Any]]": ...
99
+ @overload
100
+ @staticmethod
101
+ def to_schema(data: "dict[str, Any]") -> "dict[str, Any]": ...
102
+ @overload
103
+ @staticmethod
104
+ def to_schema(data: "dict[str, Any]", *, schema_type: "type[ModelDTOT]") -> "ModelDTOT": ...
105
+ @overload
106
+ @staticmethod
107
+ def to_schema(data: "dict[str, Any]", *, schema_type: None = None) -> "dict[str, Any]": ...
108
+ @overload
109
+ @staticmethod
110
+ def to_schema(data: "list[ModelT]") -> "list[ModelT]": ...
111
+ @overload
112
+ @staticmethod
113
+ def to_schema(data: "list[ModelT]", *, schema_type: "type[ModelDTOT]") -> "list[ModelDTOT]": ...
114
+ @overload
115
+ @staticmethod
116
+ def to_schema(data: "list[ModelT]", *, schema_type: None = None) -> "list[ModelT]": ...
117
+ @overload
118
+ @staticmethod
119
+ def to_schema(data: "ModelT") -> "ModelT": ...
120
+ @overload
121
+ @staticmethod
122
+ def to_schema(data: Any, *, schema_type: None = None) -> Any: ...
123
+
124
+ @staticmethod
125
+ def to_schema(data: Any, *, schema_type: "Optional[type[ModelDTOT]]" = None) -> Any:
126
+ """Convert data to a specified schema type.
127
+
128
+ Supports conversion to dataclasses, msgspec structs, Pydantic models, and attrs classes.
129
+ Handles both single objects and sequences.
130
+
131
+ Raises:
132
+ SQLSpecError if `schema_type` is not a valid type.
133
+
134
+ Returns:
135
+ Converted data in the specified schema type.
136
+
137
+ """
138
+ if schema_type is None:
139
+ return data
140
+ if is_dataclass(schema_type):
141
+ if isinstance(data, list):
142
+ result: list[Any] = []
143
+ for item in data:
144
+ if hasattr(item, "keys"):
145
+ result.append(schema_type(**dict(item))) # type: ignore[operator]
146
+ else:
147
+ result.append(item)
148
+ return result
149
+ if hasattr(data, "keys"):
150
+ return schema_type(**dict(data)) # type: ignore[operator]
151
+ if isinstance(data, dict):
152
+ return schema_type(**data) # type: ignore[operator]
153
+ return data
154
+ if is_msgspec_struct(schema_type):
155
+ # Cache the deserializer to avoid repeated partial() calls
156
+ deserializer = partial(_default_msgspec_deserializer, type_decoders=_DEFAULT_TYPE_DECODERS)
157
+ if not isinstance(data, Sequence):
158
+ return convert(obj=data, type=schema_type, from_attributes=True, dec_hook=deserializer)
159
+ return convert(
160
+ obj=data,
161
+ type=list[schema_type], # type: ignore[valid-type] # pyright: ignore
162
+ from_attributes=True,
163
+ dec_hook=deserializer,
164
+ )
165
+ if is_pydantic_model(schema_type):
166
+ if not isinstance(data, Sequence):
167
+ adapter = get_type_adapter(schema_type)
168
+ return adapter.validate_python(data, from_attributes=True) # pyright: ignore
169
+ list_adapter = get_type_adapter(list[schema_type]) # type: ignore[valid-type] # pyright: ignore
170
+ return list_adapter.validate_python(data, from_attributes=True)
171
+ if is_attrs_schema(schema_type):
172
+ if CATTRS_INSTALLED:
173
+ if isinstance(data, Sequence):
174
+ return cattrs_structure(data, list[schema_type]) # type: ignore[valid-type] # pyright: ignore
175
+ if hasattr(data, "__attrs_attrs__"):
176
+ unstructured_data = cattrs_unstructure(data)
177
+ return cattrs_structure(unstructured_data, schema_type) # pyright: ignore
178
+ return cattrs_structure(data, schema_type) # pyright: ignore
179
+ if isinstance(data, list):
180
+ attrs_result: list[Any] = []
181
+ for item in data:
182
+ if hasattr(item, "keys"):
183
+ attrs_result.append(schema_type(**dict(item)))
184
+ else:
185
+ attrs_result.append(schema_type(**attrs_asdict(item)))
186
+ return attrs_result
187
+ if hasattr(data, "keys"):
188
+ return schema_type(**dict(data))
189
+ if isinstance(data, dict):
190
+ return schema_type(**data)
191
+ return data
192
+ msg = "`schema_type` should be a valid Dataclass, Pydantic model, Msgspec struct, or Attrs class"
193
+ raise SQLSpecError(msg)
@@ -0,0 +1,86 @@
1
+ from typing import Final, NoReturn, Optional
2
+
3
+ from mypy_extensions import trait
4
+ from sqlglot import exp, parse_one
5
+ from sqlglot.dialects.dialect import DialectType
6
+
7
+ from sqlspec.core.statement import SQL, Statement
8
+ from sqlspec.exceptions import SQLConversionError
9
+
10
+ __all__ = ("SQLTranslatorMixin",)
11
+
12
+ # Constants for better performance
13
+ _DEFAULT_PRETTY: Final[bool] = True
14
+
15
+
16
+ @trait
17
+ class SQLTranslatorMixin:
18
+ """Mixin for drivers supporting SQL translation."""
19
+
20
+ __slots__ = ()
21
+
22
+ def convert_to_dialect(
23
+ self, statement: "Statement", to_dialect: "Optional[DialectType]" = None, pretty: bool = _DEFAULT_PRETTY
24
+ ) -> str:
25
+ """Convert a statement to a target SQL dialect.
26
+
27
+ Args:
28
+ statement: SQL statement to convert
29
+ to_dialect: Target dialect (defaults to current dialect)
30
+ pretty: Whether to format the output SQL
31
+
32
+ Returns:
33
+ SQL string in target dialect
34
+
35
+ Raises:
36
+ SQLConversionError: If parsing or conversion fails
37
+ """
38
+ # Fast path: get the parsed expression with minimal allocations
39
+ parsed_expression: Optional[exp.Expression] = None
40
+
41
+ if statement is not None and isinstance(statement, SQL):
42
+ if statement.expression is None:
43
+ self._raise_statement_parse_error()
44
+ parsed_expression = statement.expression
45
+ elif isinstance(statement, exp.Expression):
46
+ parsed_expression = statement
47
+ else:
48
+ parsed_expression = self._parse_statement_safely(statement)
49
+
50
+ # Get target dialect with fallback
51
+ target_dialect = to_dialect or self.dialect # type: ignore[attr-defined]
52
+
53
+ # Generate SQL with error handling
54
+ return self._generate_sql_safely(parsed_expression, target_dialect, pretty)
55
+
56
+ def _parse_statement_safely(self, statement: "Statement") -> "exp.Expression":
57
+ """Parse statement with copy=False optimization and proper error handling."""
58
+ try:
59
+ # Convert statement to string if needed
60
+ sql_string = str(statement)
61
+ # Use copy=False for better performance
62
+ return parse_one(sql_string, dialect=self.dialect, copy=False) # type: ignore[attr-defined]
63
+ except Exception as e:
64
+ self._raise_parse_error(e)
65
+
66
+ def _generate_sql_safely(self, expression: "exp.Expression", dialect: DialectType, pretty: bool) -> str:
67
+ """Generate SQL with proper error handling."""
68
+ try:
69
+ return expression.sql(dialect=dialect, pretty=pretty)
70
+ except Exception as e:
71
+ self._raise_conversion_error(dialect, e)
72
+
73
+ def _raise_statement_parse_error(self) -> NoReturn:
74
+ """Raise error for unparsable statements."""
75
+ msg = "Statement could not be parsed"
76
+ raise SQLConversionError(msg)
77
+
78
+ def _raise_parse_error(self, e: Exception) -> NoReturn:
79
+ """Raise error for parsing failures."""
80
+ error_msg = f"Failed to parse SQL statement: {e!s}"
81
+ raise SQLConversionError(error_msg) from e
82
+
83
+ def _raise_conversion_error(self, dialect: DialectType, e: Exception) -> NoReturn:
84
+ """Raise error for conversion failures."""
85
+ error_msg = f"Failed to convert SQL expression to {dialect}: {e!s}"
86
+ raise SQLConversionError(error_msg) from e
sqlspec/exceptions.py ADDED
@@ -0,0 +1,193 @@
1
+ from collections.abc import Generator
2
+ from contextlib import contextmanager
3
+ from typing import Any, Optional, Union
4
+
5
+ __all__ = (
6
+ "FileNotFoundInStorageError",
7
+ "ImproperConfigurationError",
8
+ "IntegrityError",
9
+ "MissingDependencyError",
10
+ "MultipleResultsFoundError",
11
+ "NotFoundError",
12
+ "RepositoryError",
13
+ "SQLBuilderError",
14
+ "SQLConversionError",
15
+ "SQLFileNotFoundError",
16
+ "SQLFileParseError",
17
+ "SQLParsingError",
18
+ "SQLSpecError",
19
+ "SerializationError",
20
+ "StorageOperationFailedError",
21
+ )
22
+
23
+
24
+ class SQLSpecError(Exception):
25
+ """Base exception class for SQLSpec exceptions."""
26
+
27
+ detail: str
28
+
29
+ def __init__(self, *args: Any, detail: str = "") -> None:
30
+ """Initialize SQLSpecError.
31
+
32
+ Args:
33
+ *args: args are converted to :class:`str` before passing to :class:`Exception`
34
+ detail: detail of the exception.
35
+ """
36
+ str_args = [str(arg) for arg in args if arg]
37
+ if not detail:
38
+ if str_args:
39
+ detail, *str_args = str_args
40
+ elif hasattr(self, "detail"):
41
+ detail = self.detail
42
+ self.detail = detail
43
+ super().__init__(*str_args)
44
+
45
+ def __repr__(self) -> str:
46
+ if self.detail:
47
+ return f"{self.__class__.__name__} - {self.detail}"
48
+ return self.__class__.__name__
49
+
50
+ def __str__(self) -> str:
51
+ return " ".join((*self.args, self.detail)).strip()
52
+
53
+
54
+ class MissingDependencyError(SQLSpecError, ImportError):
55
+ """Raised when a required dependency is not installed."""
56
+
57
+ def __init__(self, package: str, install_package: Optional[str] = None) -> None:
58
+ super().__init__(
59
+ f"Package {package!r} is not installed but required. You can install it by running "
60
+ f"'pip install sqlspec[{install_package or package}]' to install sqlspec with the required extra "
61
+ f"or 'pip install {install_package or package}' to install the package separately"
62
+ )
63
+
64
+
65
+ class BackendNotRegisteredError(SQLSpecError):
66
+ """Raised when a requested storage backend key is not registered."""
67
+
68
+ def __init__(self, backend_key: str) -> None:
69
+ super().__init__(f"Storage backend '{backend_key}' is not registered. Please register it before use.")
70
+
71
+
72
+ class SQLParsingError(SQLSpecError):
73
+ """Issues parsing SQL statements."""
74
+
75
+ def __init__(self, message: Optional[str] = None) -> None:
76
+ if message is None:
77
+ message = "Issues parsing SQL statement."
78
+ super().__init__(message)
79
+
80
+
81
+ class SQLBuilderError(SQLSpecError):
82
+ """Issues Building or Generating SQL statements."""
83
+
84
+ def __init__(self, message: Optional[str] = None) -> None:
85
+ if message is None:
86
+ message = "Issues building SQL statement."
87
+ super().__init__(message)
88
+
89
+
90
+ class SQLConversionError(SQLSpecError):
91
+ """Issues converting SQL statements."""
92
+
93
+ def __init__(self, message: Optional[str] = None) -> None:
94
+ if message is None:
95
+ message = "Issues converting SQL statement."
96
+ super().__init__(message)
97
+
98
+
99
+ class ImproperConfigurationError(SQLSpecError):
100
+ """Raised when configuration is invalid or incomplete."""
101
+
102
+
103
+ class SerializationError(SQLSpecError):
104
+ """Encoding or decoding of an object failed."""
105
+
106
+
107
+ class RepositoryError(SQLSpecError):
108
+ """Base repository exception type."""
109
+
110
+
111
+ class IntegrityError(RepositoryError):
112
+ """Data integrity error."""
113
+
114
+
115
+ class NotFoundError(RepositoryError):
116
+ """An identity does not exist."""
117
+
118
+
119
+ class MultipleResultsFoundError(RepositoryError):
120
+ """A single database result was required but more than one were found."""
121
+
122
+
123
+ class StorageOperationFailedError(SQLSpecError):
124
+ """Raised when a storage backend operation fails (e.g., network, permission, API error)."""
125
+
126
+
127
+ class FileNotFoundInStorageError(StorageOperationFailedError):
128
+ """Raised when a file or object is not found in the storage backend."""
129
+
130
+
131
+ class SQLFileNotFoundError(SQLSpecError):
132
+ """Raised when a SQL file cannot be found."""
133
+
134
+ def __init__(self, name: str, path: "Optional[str]" = None) -> None:
135
+ """Initialize the error.
136
+
137
+ Args:
138
+ name: Name of the SQL file.
139
+ path: Optional path where the file was expected.
140
+ """
141
+ message = f"SQL file '{name}' not found at path: {path}" if path else f"SQL file '{name}' not found"
142
+ super().__init__(message)
143
+ self.name = name
144
+ self.path = path
145
+
146
+
147
+ class SQLFileParseError(SQLSpecError):
148
+ """Raised when a SQL file cannot be parsed."""
149
+
150
+ def __init__(self, name: str, path: str, original_error: "Exception") -> None:
151
+ """Initialize the error.
152
+
153
+ Args:
154
+ name: Name of the SQL file.
155
+ path: Path to the SQL file.
156
+ original_error: The underlying parsing error.
157
+ """
158
+ message = f"Failed to parse SQL file '{name}' at {path}: {original_error}"
159
+ super().__init__(message)
160
+ self.name = name
161
+ self.path = path
162
+ self.original_error = original_error
163
+
164
+
165
+ @contextmanager
166
+ def wrap_exceptions(
167
+ wrap_exceptions: bool = True, suppress: "Optional[Union[type[Exception], tuple[type[Exception], ...]]]" = None
168
+ ) -> Generator[None, None, None]:
169
+ """Context manager for exception handling with optional suppression.
170
+
171
+ Args:
172
+ wrap_exceptions: If True, wrap exceptions in RepositoryError. If False, let them pass through.
173
+ suppress: Exception type(s) to suppress completely (like contextlib.suppress).
174
+ If provided, these exceptions are caught and ignored.
175
+ """
176
+ try:
177
+ yield
178
+
179
+ except Exception as exc:
180
+ if suppress is not None and (
181
+ (isinstance(suppress, type) and isinstance(exc, suppress))
182
+ or (isinstance(suppress, tuple) and isinstance(exc, suppress))
183
+ ):
184
+ return # Suppress this exception
185
+
186
+ # If it's already a SQLSpec exception, don't wrap it
187
+ if isinstance(exc, SQLSpecError):
188
+ raise
189
+
190
+ if wrap_exceptions is False:
191
+ raise
192
+ msg = "An error occurred during the operation."
193
+ raise RepositoryError(detail=msg) from exc
File without changes
@@ -0,0 +1,10 @@
1
+ """SQLSpec aiosql integration for loading SQL files.
2
+
3
+ This module provides a simple way to load aiosql-style SQL files and use them
4
+ with SQLSpec drivers. It focuses on just the file parsing functionality,
5
+ returning SQL objects that work with existing SQLSpec execution.
6
+ """
7
+
8
+ from sqlspec.extensions.aiosql.adapter import AiosqlAsyncAdapter, AiosqlSyncAdapter
9
+
10
+ __all__ = ("AiosqlAsyncAdapter", "AiosqlSyncAdapter")