sqlspec 0.26.0__py3-none-any.whl → 0.28.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/__init__.py +7 -15
- sqlspec/_serialization.py +55 -25
- sqlspec/_typing.py +155 -52
- sqlspec/adapters/adbc/_types.py +1 -1
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +880 -0
- sqlspec/adapters/adbc/config.py +62 -12
- sqlspec/adapters/adbc/data_dictionary.py +74 -2
- sqlspec/adapters/adbc/driver.py +226 -58
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +504 -0
- sqlspec/adapters/adbc/type_converter.py +44 -50
- sqlspec/adapters/aiosqlite/_types.py +1 -1
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +536 -0
- sqlspec/adapters/aiosqlite/config.py +86 -16
- sqlspec/adapters/aiosqlite/data_dictionary.py +34 -2
- sqlspec/adapters/aiosqlite/driver.py +127 -38
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +281 -0
- sqlspec/adapters/aiosqlite/pool.py +7 -7
- sqlspec/adapters/asyncmy/__init__.py +7 -1
- sqlspec/adapters/asyncmy/_types.py +1 -1
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +503 -0
- sqlspec/adapters/asyncmy/config.py +59 -17
- sqlspec/adapters/asyncmy/data_dictionary.py +41 -2
- sqlspec/adapters/asyncmy/driver.py +293 -62
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +2 -1
- sqlspec/adapters/asyncpg/_type_handlers.py +71 -0
- sqlspec/adapters/asyncpg/_types.py +11 -7
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +460 -0
- sqlspec/adapters/asyncpg/config.py +57 -36
- sqlspec/adapters/asyncpg/data_dictionary.py +48 -2
- sqlspec/adapters/asyncpg/driver.py +153 -23
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +253 -0
- sqlspec/adapters/bigquery/_types.py +1 -1
- sqlspec/adapters/bigquery/adk/__init__.py +5 -0
- sqlspec/adapters/bigquery/adk/store.py +585 -0
- sqlspec/adapters/bigquery/config.py +36 -11
- sqlspec/adapters/bigquery/data_dictionary.py +42 -2
- sqlspec/adapters/bigquery/driver.py +489 -144
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +327 -0
- sqlspec/adapters/bigquery/type_converter.py +55 -23
- sqlspec/adapters/duckdb/_types.py +2 -2
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +563 -0
- sqlspec/adapters/duckdb/config.py +79 -21
- sqlspec/adapters/duckdb/data_dictionary.py +41 -2
- sqlspec/adapters/duckdb/driver.py +225 -44
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +332 -0
- sqlspec/adapters/duckdb/pool.py +5 -5
- sqlspec/adapters/duckdb/type_converter.py +51 -21
- sqlspec/adapters/oracledb/_numpy_handlers.py +133 -0
- sqlspec/adapters/oracledb/_types.py +20 -2
- sqlspec/adapters/oracledb/adk/__init__.py +5 -0
- sqlspec/adapters/oracledb/adk/store.py +1628 -0
- sqlspec/adapters/oracledb/config.py +120 -36
- sqlspec/adapters/oracledb/data_dictionary.py +87 -20
- sqlspec/adapters/oracledb/driver.py +475 -86
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +765 -0
- sqlspec/adapters/oracledb/migrations.py +316 -25
- sqlspec/adapters/oracledb/type_converter.py +91 -16
- sqlspec/adapters/psqlpy/_type_handlers.py +44 -0
- sqlspec/adapters/psqlpy/_types.py +2 -1
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +483 -0
- sqlspec/adapters/psqlpy/config.py +45 -19
- sqlspec/adapters/psqlpy/data_dictionary.py +48 -2
- sqlspec/adapters/psqlpy/driver.py +108 -41
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +272 -0
- sqlspec/adapters/psqlpy/type_converter.py +40 -11
- sqlspec/adapters/psycopg/_type_handlers.py +80 -0
- sqlspec/adapters/psycopg/_types.py +2 -1
- sqlspec/adapters/psycopg/adk/__init__.py +5 -0
- sqlspec/adapters/psycopg/adk/store.py +962 -0
- sqlspec/adapters/psycopg/config.py +65 -37
- sqlspec/adapters/psycopg/data_dictionary.py +91 -3
- sqlspec/adapters/psycopg/driver.py +200 -78
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +554 -0
- sqlspec/adapters/sqlite/__init__.py +2 -1
- sqlspec/adapters/sqlite/_type_handlers.py +86 -0
- sqlspec/adapters/sqlite/_types.py +1 -1
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +582 -0
- sqlspec/adapters/sqlite/config.py +85 -16
- sqlspec/adapters/sqlite/data_dictionary.py +34 -2
- sqlspec/adapters/sqlite/driver.py +120 -52
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +318 -0
- sqlspec/adapters/sqlite/pool.py +5 -5
- sqlspec/base.py +45 -26
- sqlspec/builder/__init__.py +73 -4
- sqlspec/builder/_base.py +91 -58
- sqlspec/builder/_column.py +5 -5
- sqlspec/builder/_ddl.py +98 -89
- sqlspec/builder/_delete.py +5 -4
- sqlspec/builder/_dml.py +388 -0
- sqlspec/{_sql.py → builder/_factory.py} +41 -44
- sqlspec/builder/_insert.py +5 -82
- sqlspec/builder/{mixins/_join_operations.py → _join.py} +145 -143
- sqlspec/builder/_merge.py +446 -11
- sqlspec/builder/_parsing_utils.py +9 -11
- sqlspec/builder/_select.py +1313 -25
- sqlspec/builder/_update.py +11 -42
- sqlspec/cli.py +76 -69
- sqlspec/config.py +331 -62
- sqlspec/core/__init__.py +5 -4
- sqlspec/core/cache.py +18 -18
- sqlspec/core/compiler.py +6 -8
- sqlspec/core/filters.py +55 -47
- sqlspec/core/hashing.py +9 -9
- sqlspec/core/parameters.py +76 -45
- sqlspec/core/result.py +234 -47
- sqlspec/core/splitter.py +16 -17
- sqlspec/core/statement.py +32 -31
- sqlspec/core/type_conversion.py +3 -2
- sqlspec/driver/__init__.py +1 -3
- sqlspec/driver/_async.py +183 -160
- sqlspec/driver/_common.py +197 -109
- sqlspec/driver/_sync.py +189 -161
- sqlspec/driver/mixins/_result_tools.py +20 -236
- sqlspec/driver/mixins/_sql_translator.py +4 -4
- sqlspec/exceptions.py +70 -7
- sqlspec/extensions/adk/__init__.py +53 -0
- sqlspec/extensions/adk/_types.py +51 -0
- sqlspec/extensions/adk/converters.py +172 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +144 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +181 -0
- sqlspec/extensions/adk/store.py +536 -0
- sqlspec/extensions/aiosql/adapter.py +69 -61
- sqlspec/extensions/fastapi/__init__.py +21 -0
- sqlspec/extensions/fastapi/extension.py +331 -0
- sqlspec/extensions/fastapi/providers.py +543 -0
- sqlspec/extensions/flask/__init__.py +36 -0
- sqlspec/extensions/flask/_state.py +71 -0
- sqlspec/extensions/flask/_utils.py +40 -0
- sqlspec/extensions/flask/extension.py +389 -0
- sqlspec/extensions/litestar/__init__.py +21 -4
- sqlspec/extensions/litestar/cli.py +54 -10
- sqlspec/extensions/litestar/config.py +56 -266
- sqlspec/extensions/litestar/handlers.py +46 -17
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +349 -224
- sqlspec/extensions/litestar/providers.py +25 -25
- sqlspec/extensions/litestar/store.py +265 -0
- sqlspec/extensions/starlette/__init__.py +10 -0
- sqlspec/extensions/starlette/_state.py +25 -0
- sqlspec/extensions/starlette/_utils.py +52 -0
- sqlspec/extensions/starlette/extension.py +254 -0
- sqlspec/extensions/starlette/middleware.py +154 -0
- sqlspec/loader.py +30 -49
- sqlspec/migrations/base.py +200 -76
- sqlspec/migrations/commands.py +591 -62
- sqlspec/migrations/context.py +6 -9
- sqlspec/migrations/fix.py +199 -0
- sqlspec/migrations/loaders.py +47 -19
- sqlspec/migrations/runner.py +241 -75
- sqlspec/migrations/tracker.py +237 -21
- sqlspec/migrations/utils.py +51 -3
- sqlspec/migrations/validation.py +177 -0
- sqlspec/protocols.py +106 -36
- sqlspec/storage/_utils.py +85 -0
- sqlspec/storage/backends/fsspec.py +133 -107
- sqlspec/storage/backends/local.py +78 -51
- sqlspec/storage/backends/obstore.py +276 -168
- sqlspec/storage/registry.py +75 -39
- sqlspec/typing.py +30 -84
- sqlspec/utils/__init__.py +25 -4
- sqlspec/utils/arrow_helpers.py +81 -0
- sqlspec/utils/config_resolver.py +6 -6
- sqlspec/utils/correlation.py +4 -5
- sqlspec/utils/data_transformation.py +3 -2
- sqlspec/utils/deprecation.py +9 -8
- sqlspec/utils/fixtures.py +4 -4
- sqlspec/utils/logging.py +46 -6
- sqlspec/utils/module_loader.py +205 -5
- sqlspec/utils/portal.py +311 -0
- sqlspec/utils/schema.py +288 -0
- sqlspec/utils/serializers.py +113 -4
- sqlspec/utils/sync_tools.py +36 -22
- sqlspec/utils/text.py +1 -2
- sqlspec/utils/type_guards.py +136 -20
- sqlspec/utils/version.py +433 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/METADATA +41 -22
- sqlspec-0.28.0.dist-info/RECORD +221 -0
- sqlspec/builder/mixins/__init__.py +0 -55
- sqlspec/builder/mixins/_cte_and_set_ops.py +0 -253
- sqlspec/builder/mixins/_delete_operations.py +0 -50
- sqlspec/builder/mixins/_insert_operations.py +0 -282
- sqlspec/builder/mixins/_merge_operations.py +0 -698
- sqlspec/builder/mixins/_order_limit_operations.py +0 -145
- sqlspec/builder/mixins/_pivot_operations.py +0 -157
- sqlspec/builder/mixins/_select_operations.py +0 -930
- sqlspec/builder/mixins/_update_operations.py +0 -199
- sqlspec/builder/mixins/_where_clause.py +0 -1298
- sqlspec-0.26.0.dist-info/RECORD +0 -157
- sqlspec-0.26.0.dist-info/licenses/NOTICE +0 -29
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/licenses/LICENSE +0 -0
sqlspec/utils/type_guards.py
CHANGED
|
@@ -7,7 +7,9 @@ understand type narrowing, replacing defensive hasattr() and duck typing pattern
|
|
|
7
7
|
from collections.abc import Sequence
|
|
8
8
|
from collections.abc import Set as AbstractSet
|
|
9
9
|
from functools import lru_cache
|
|
10
|
-
from typing import TYPE_CHECKING, Any,
|
|
10
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
11
|
+
|
|
12
|
+
from typing_extensions import is_typeddict
|
|
11
13
|
|
|
12
14
|
from sqlspec.typing import (
|
|
13
15
|
ATTRS_INSTALLED,
|
|
@@ -24,9 +26,9 @@ from sqlspec.typing import (
|
|
|
24
26
|
|
|
25
27
|
if TYPE_CHECKING:
|
|
26
28
|
from dataclasses import Field
|
|
29
|
+
from typing import TypeGuard
|
|
27
30
|
|
|
28
31
|
from sqlglot import exp
|
|
29
|
-
from typing_extensions import TypeGuard
|
|
30
32
|
|
|
31
33
|
from sqlspec._typing import AttrsInstanceStub, BaseModelStub, DTODataStub, StructStub
|
|
32
34
|
from sqlspec.builder import Select
|
|
@@ -46,6 +48,7 @@ if TYPE_CHECKING:
|
|
|
46
48
|
ObjectStoreItemProtocol,
|
|
47
49
|
ParameterValueProtocol,
|
|
48
50
|
SQLBuilderProtocol,
|
|
51
|
+
SupportsArrowResults,
|
|
49
52
|
WithMethodProtocol,
|
|
50
53
|
)
|
|
51
54
|
from sqlspec.typing import SupportedSchemaModel
|
|
@@ -100,6 +103,7 @@ __all__ = (
|
|
|
100
103
|
"is_indexable_row",
|
|
101
104
|
"is_iterable_parameters",
|
|
102
105
|
"is_limit_offset_filter",
|
|
106
|
+
"is_local_path",
|
|
103
107
|
"is_msgspec_struct",
|
|
104
108
|
"is_msgspec_struct_with_field",
|
|
105
109
|
"is_msgspec_struct_without_field",
|
|
@@ -117,8 +121,11 @@ __all__ = (
|
|
|
117
121
|
"is_select_builder",
|
|
118
122
|
"is_statement_filter",
|
|
119
123
|
"is_string_literal",
|
|
124
|
+
"is_typed_dict",
|
|
120
125
|
"is_typed_parameter",
|
|
121
126
|
"schema_dump",
|
|
127
|
+
"supports_arrow_native",
|
|
128
|
+
"supports_arrow_results",
|
|
122
129
|
"supports_limit",
|
|
123
130
|
"supports_offset",
|
|
124
131
|
"supports_order_by",
|
|
@@ -126,6 +133,18 @@ __all__ = (
|
|
|
126
133
|
)
|
|
127
134
|
|
|
128
135
|
|
|
136
|
+
def is_typed_dict(obj: Any) -> "TypeGuard[type]":
|
|
137
|
+
"""Check if an object is a TypedDict class.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
obj: The object to check
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
True if the object is a TypedDict class, False otherwise
|
|
144
|
+
"""
|
|
145
|
+
return is_typeddict(obj)
|
|
146
|
+
|
|
147
|
+
|
|
129
148
|
def is_statement_filter(obj: Any) -> "TypeGuard[StatementFilter]":
|
|
130
149
|
"""Check if an object implements the StatementFilter protocol.
|
|
131
150
|
|
|
@@ -434,7 +453,7 @@ def is_msgspec_struct_without_field(obj: Any, field_name: str) -> "TypeGuard[Str
|
|
|
434
453
|
|
|
435
454
|
|
|
436
455
|
@lru_cache(maxsize=500)
|
|
437
|
-
def _detect_rename_pattern(field_name: str, encode_name: str) -> "
|
|
456
|
+
def _detect_rename_pattern(field_name: str, encode_name: str) -> "str | None":
|
|
438
457
|
"""Detect the rename pattern by comparing field name transformations.
|
|
439
458
|
|
|
440
459
|
Args:
|
|
@@ -458,7 +477,7 @@ def _detect_rename_pattern(field_name: str, encode_name: str) -> "Optional[str]"
|
|
|
458
477
|
return None
|
|
459
478
|
|
|
460
479
|
|
|
461
|
-
def get_msgspec_rename_config(schema_type: type) -> "
|
|
480
|
+
def get_msgspec_rename_config(schema_type: type) -> "str | None":
|
|
462
481
|
"""Extract msgspec rename configuration from a struct type.
|
|
463
482
|
|
|
464
483
|
Analyzes field name transformations to detect the rename pattern used by msgspec.
|
|
@@ -611,7 +630,7 @@ def is_schema(obj: Any) -> "TypeGuard[SupportedSchemaModel]":
|
|
|
611
630
|
)
|
|
612
631
|
|
|
613
632
|
|
|
614
|
-
def is_schema_or_dict(obj: Any) -> "TypeGuard[
|
|
633
|
+
def is_schema_or_dict(obj: Any) -> "TypeGuard[SupportedSchemaModel | dict[str, Any]]":
|
|
615
634
|
"""Check if a value is a msgspec Struct, Pydantic model, or dict.
|
|
616
635
|
|
|
617
636
|
Args:
|
|
@@ -649,7 +668,7 @@ def is_schema_without_field(obj: Any, field_name: str) -> "TypeGuard[SupportedSc
|
|
|
649
668
|
return not is_schema_with_field(obj, field_name)
|
|
650
669
|
|
|
651
670
|
|
|
652
|
-
def is_schema_or_dict_with_field(obj: Any, field_name: str) -> "TypeGuard[
|
|
671
|
+
def is_schema_or_dict_with_field(obj: Any, field_name: str) -> "TypeGuard[SupportedSchemaModel | dict[str, Any]]":
|
|
653
672
|
"""Check if a value is a msgspec Struct, Pydantic model, or dict with a specific field.
|
|
654
673
|
|
|
655
674
|
Args:
|
|
@@ -662,9 +681,7 @@ def is_schema_or_dict_with_field(obj: Any, field_name: str) -> "TypeGuard[Union[
|
|
|
662
681
|
return is_schema_with_field(obj, field_name) or is_dict_with_field(obj, field_name)
|
|
663
682
|
|
|
664
683
|
|
|
665
|
-
def is_schema_or_dict_without_field(
|
|
666
|
-
obj: Any, field_name: str
|
|
667
|
-
) -> "TypeGuard[Union[SupportedSchemaModel, dict[str, Any]]]":
|
|
684
|
+
def is_schema_or_dict_without_field(obj: Any, field_name: str) -> "TypeGuard[SupportedSchemaModel | dict[str, Any]]":
|
|
668
685
|
"""Check if a value is a msgspec Struct, Pydantic model, or dict without a specific field.
|
|
669
686
|
|
|
670
687
|
Args:
|
|
@@ -721,8 +738,8 @@ def extract_dataclass_fields(
|
|
|
721
738
|
obj: "DataclassProtocol",
|
|
722
739
|
exclude_none: bool = False,
|
|
723
740
|
exclude_empty: bool = False,
|
|
724
|
-
include: "
|
|
725
|
-
exclude: "
|
|
741
|
+
include: "AbstractSet[str] | None" = None,
|
|
742
|
+
exclude: "AbstractSet[str] | None" = None,
|
|
726
743
|
) -> "tuple[Field[Any], ...]":
|
|
727
744
|
"""Extract dataclass fields.
|
|
728
745
|
|
|
@@ -767,8 +784,8 @@ def extract_dataclass_items(
|
|
|
767
784
|
obj: "DataclassProtocol",
|
|
768
785
|
exclude_none: bool = False,
|
|
769
786
|
exclude_empty: bool = False,
|
|
770
|
-
include: "
|
|
771
|
-
exclude: "
|
|
787
|
+
include: "AbstractSet[str] | None" = None,
|
|
788
|
+
exclude: "AbstractSet[str] | None" = None,
|
|
772
789
|
) -> "tuple[tuple[str, Any], ...]":
|
|
773
790
|
"""Extract name-value pairs from a dataclass instance.
|
|
774
791
|
|
|
@@ -791,7 +808,7 @@ def dataclass_to_dict(
|
|
|
791
808
|
exclude_none: bool = False,
|
|
792
809
|
exclude_empty: bool = False,
|
|
793
810
|
convert_nested: bool = True,
|
|
794
|
-
exclude: "
|
|
811
|
+
exclude: "AbstractSet[str] | None" = None,
|
|
795
812
|
) -> "dict[str, Any]":
|
|
796
813
|
"""Convert a dataclass instance to a dictionary.
|
|
797
814
|
|
|
@@ -978,7 +995,7 @@ def has_attr(obj: Any, attr: str) -> bool:
|
|
|
978
995
|
return True
|
|
979
996
|
|
|
980
997
|
|
|
981
|
-
def get_node_this(node: "exp.Expression", default:
|
|
998
|
+
def get_node_this(node: "exp.Expression", default: Any | None = None) -> Any:
|
|
982
999
|
"""Safely get the 'this' attribute from a SQLGlot node.
|
|
983
1000
|
|
|
984
1001
|
Args:
|
|
@@ -1010,7 +1027,7 @@ def has_this_attribute(node: "exp.Expression") -> bool:
|
|
|
1010
1027
|
return True
|
|
1011
1028
|
|
|
1012
1029
|
|
|
1013
|
-
def get_node_expressions(node: "exp.Expression", default:
|
|
1030
|
+
def get_node_expressions(node: "exp.Expression", default: Any | None = None) -> Any:
|
|
1014
1031
|
"""Safely get the 'expressions' attribute from a SQLGlot node.
|
|
1015
1032
|
|
|
1016
1033
|
Args:
|
|
@@ -1042,7 +1059,7 @@ def has_expressions_attribute(node: "exp.Expression") -> bool:
|
|
|
1042
1059
|
return True
|
|
1043
1060
|
|
|
1044
1061
|
|
|
1045
|
-
def get_literal_parent(literal: "exp.Expression", default:
|
|
1062
|
+
def get_literal_parent(literal: "exp.Expression", default: Any | None = None) -> Any:
|
|
1046
1063
|
"""Safely get the 'parent' attribute from a SQLGlot literal.
|
|
1047
1064
|
|
|
1048
1065
|
Args:
|
|
@@ -1113,7 +1130,7 @@ def is_number_literal(literal: "exp.Literal") -> bool:
|
|
|
1113
1130
|
return False
|
|
1114
1131
|
|
|
1115
1132
|
|
|
1116
|
-
def get_initial_expression(context: Any) -> "
|
|
1133
|
+
def get_initial_expression(context: Any) -> "exp.Expression | None":
|
|
1117
1134
|
"""Safely get initial_expression from context.
|
|
1118
1135
|
|
|
1119
1136
|
Args:
|
|
@@ -1128,7 +1145,7 @@ def get_initial_expression(context: Any) -> "Optional[exp.Expression]":
|
|
|
1128
1145
|
return None
|
|
1129
1146
|
|
|
1130
1147
|
|
|
1131
|
-
def expression_has_limit(expr: "
|
|
1148
|
+
def expression_has_limit(expr: "exp.Expression | None") -> bool:
|
|
1132
1149
|
"""Check if an expression has a limit clause.
|
|
1133
1150
|
|
|
1134
1151
|
Args:
|
|
@@ -1160,7 +1177,7 @@ def get_value_attribute(obj: Any) -> Any:
|
|
|
1160
1177
|
return obj
|
|
1161
1178
|
|
|
1162
1179
|
|
|
1163
|
-
def get_param_style_and_name(param: Any) -> "tuple[
|
|
1180
|
+
def get_param_style_and_name(param: Any) -> "tuple[str | None, str | None]":
|
|
1164
1181
|
"""Safely get style and name attributes from a parameter.
|
|
1165
1182
|
|
|
1166
1183
|
Args:
|
|
@@ -1242,3 +1259,102 @@ def has_expression_and_parameters(obj: Any) -> bool:
|
|
|
1242
1259
|
True if the object has both attributes, False otherwise
|
|
1243
1260
|
"""
|
|
1244
1261
|
return hasattr(obj, "expression") and hasattr(obj, "parameters")
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
WINDOWS_DRIVE_PATTERN_LENGTH = 3
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
def is_local_path(uri: str) -> bool:
|
|
1268
|
+
r"""Check if URI represents a local filesystem path.
|
|
1269
|
+
|
|
1270
|
+
Detects local paths including:
|
|
1271
|
+
- file:// URIs
|
|
1272
|
+
- Absolute paths (Unix: /, Windows: C:\\)
|
|
1273
|
+
- Relative paths (., .., ~)
|
|
1274
|
+
|
|
1275
|
+
Args:
|
|
1276
|
+
uri: URI or path string to check.
|
|
1277
|
+
|
|
1278
|
+
Returns:
|
|
1279
|
+
True if uri is a local path, False for remote URIs.
|
|
1280
|
+
|
|
1281
|
+
Examples:
|
|
1282
|
+
>>> is_local_path("file:///data/file.txt")
|
|
1283
|
+
True
|
|
1284
|
+
>>> is_local_path("/absolute/path")
|
|
1285
|
+
True
|
|
1286
|
+
>>> is_local_path("s3://bucket/key")
|
|
1287
|
+
False
|
|
1288
|
+
"""
|
|
1289
|
+
if not uri:
|
|
1290
|
+
return False
|
|
1291
|
+
|
|
1292
|
+
if "://" in uri and not uri.startswith("file://"):
|
|
1293
|
+
return False
|
|
1294
|
+
|
|
1295
|
+
if uri.startswith("file://"):
|
|
1296
|
+
return True
|
|
1297
|
+
|
|
1298
|
+
if uri.startswith("/"):
|
|
1299
|
+
return True
|
|
1300
|
+
|
|
1301
|
+
if uri.startswith((".", "~")):
|
|
1302
|
+
return True
|
|
1303
|
+
|
|
1304
|
+
if len(uri) >= WINDOWS_DRIVE_PATTERN_LENGTH and uri[1:3] == ":\\":
|
|
1305
|
+
return True
|
|
1306
|
+
|
|
1307
|
+
return "/" in uri or "\\" in uri
|
|
1308
|
+
|
|
1309
|
+
|
|
1310
|
+
def supports_arrow_native(backend: Any) -> bool:
|
|
1311
|
+
"""Check if storage backend supports native Arrow operations.
|
|
1312
|
+
|
|
1313
|
+
Some storage backends (like certain obstore stores) have native
|
|
1314
|
+
Arrow read/write support, which is faster than going through bytes.
|
|
1315
|
+
|
|
1316
|
+
Args:
|
|
1317
|
+
backend: Storage backend instance to check.
|
|
1318
|
+
|
|
1319
|
+
Returns:
|
|
1320
|
+
True if backend has native read_arrow/write_arrow methods.
|
|
1321
|
+
|
|
1322
|
+
Examples:
|
|
1323
|
+
>>> from sqlspec.storage.backends.obstore import ObStoreBackend
|
|
1324
|
+
>>> backend = ObStoreBackend("file:///tmp")
|
|
1325
|
+
>>> supports_arrow_native(backend)
|
|
1326
|
+
False
|
|
1327
|
+
"""
|
|
1328
|
+
from sqlspec.protocols import ObjectStoreProtocol
|
|
1329
|
+
|
|
1330
|
+
if not isinstance(backend, ObjectStoreProtocol):
|
|
1331
|
+
return False
|
|
1332
|
+
|
|
1333
|
+
try:
|
|
1334
|
+
store = backend.store # type: ignore[attr-defined]
|
|
1335
|
+
return callable(getattr(store, "read_arrow", None))
|
|
1336
|
+
except AttributeError:
|
|
1337
|
+
return False
|
|
1338
|
+
|
|
1339
|
+
|
|
1340
|
+
def supports_arrow_results(obj: Any) -> "TypeGuard[SupportsArrowResults]":
|
|
1341
|
+
"""Check if object supports Arrow result format.
|
|
1342
|
+
|
|
1343
|
+
Use this type guard to check if a driver or adapter supports returning
|
|
1344
|
+
query results in Apache Arrow format via select_to_arrow() method.
|
|
1345
|
+
|
|
1346
|
+
Args:
|
|
1347
|
+
obj: Object to check for Arrow results support.
|
|
1348
|
+
|
|
1349
|
+
Returns:
|
|
1350
|
+
True if object implements SupportsArrowResults protocol.
|
|
1351
|
+
|
|
1352
|
+
Examples:
|
|
1353
|
+
>>> from sqlspec.adapters.duckdb import DuckDBDriver
|
|
1354
|
+
>>> driver = DuckDBDriver(...)
|
|
1355
|
+
>>> supports_arrow_results(driver)
|
|
1356
|
+
True
|
|
1357
|
+
"""
|
|
1358
|
+
from sqlspec.protocols import SupportsArrowResults
|
|
1359
|
+
|
|
1360
|
+
return isinstance(obj, SupportsArrowResults)
|