sqlspec 0.16.1__cp39-cp39-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.
- 51ff5a9eadfdefd49f98__mypyc.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/__init__.py +92 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_serialization.py +77 -0
- sqlspec/_sql.py +1780 -0
- sqlspec/_typing.py +680 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +5 -0
- sqlspec/adapters/adbc/_types.py +12 -0
- sqlspec/adapters/adbc/config.py +361 -0
- sqlspec/adapters/adbc/driver.py +512 -0
- sqlspec/adapters/aiosqlite/__init__.py +19 -0
- sqlspec/adapters/aiosqlite/_types.py +13 -0
- sqlspec/adapters/aiosqlite/config.py +253 -0
- sqlspec/adapters/aiosqlite/driver.py +248 -0
- sqlspec/adapters/asyncmy/__init__.py +19 -0
- sqlspec/adapters/asyncmy/_types.py +12 -0
- sqlspec/adapters/asyncmy/config.py +180 -0
- sqlspec/adapters/asyncmy/driver.py +274 -0
- sqlspec/adapters/asyncpg/__init__.py +21 -0
- sqlspec/adapters/asyncpg/_types.py +17 -0
- sqlspec/adapters/asyncpg/config.py +229 -0
- sqlspec/adapters/asyncpg/driver.py +344 -0
- sqlspec/adapters/bigquery/__init__.py +18 -0
- sqlspec/adapters/bigquery/_types.py +12 -0
- sqlspec/adapters/bigquery/config.py +298 -0
- sqlspec/adapters/bigquery/driver.py +558 -0
- sqlspec/adapters/duckdb/__init__.py +22 -0
- sqlspec/adapters/duckdb/_types.py +12 -0
- sqlspec/adapters/duckdb/config.py +504 -0
- sqlspec/adapters/duckdb/driver.py +368 -0
- sqlspec/adapters/oracledb/__init__.py +32 -0
- sqlspec/adapters/oracledb/_types.py +14 -0
- sqlspec/adapters/oracledb/config.py +317 -0
- sqlspec/adapters/oracledb/driver.py +538 -0
- sqlspec/adapters/psqlpy/__init__.py +16 -0
- sqlspec/adapters/psqlpy/_types.py +11 -0
- sqlspec/adapters/psqlpy/config.py +214 -0
- sqlspec/adapters/psqlpy/driver.py +530 -0
- sqlspec/adapters/psycopg/__init__.py +32 -0
- sqlspec/adapters/psycopg/_types.py +17 -0
- sqlspec/adapters/psycopg/config.py +426 -0
- sqlspec/adapters/psycopg/driver.py +796 -0
- sqlspec/adapters/sqlite/__init__.py +15 -0
- sqlspec/adapters/sqlite/_types.py +11 -0
- sqlspec/adapters/sqlite/config.py +240 -0
- sqlspec/adapters/sqlite/driver.py +294 -0
- sqlspec/base.py +571 -0
- sqlspec/builder/__init__.py +62 -0
- sqlspec/builder/_base.py +473 -0
- sqlspec/builder/_column.py +320 -0
- sqlspec/builder/_ddl.py +1346 -0
- sqlspec/builder/_ddl_utils.py +103 -0
- sqlspec/builder/_delete.py +76 -0
- sqlspec/builder/_insert.py +256 -0
- sqlspec/builder/_merge.py +71 -0
- sqlspec/builder/_parsing_utils.py +140 -0
- sqlspec/builder/_select.py +170 -0
- sqlspec/builder/_update.py +188 -0
- sqlspec/builder/mixins/__init__.py +55 -0
- sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
- sqlspec/builder/mixins/_delete_operations.py +41 -0
- sqlspec/builder/mixins/_insert_operations.py +244 -0
- sqlspec/builder/mixins/_join_operations.py +122 -0
- sqlspec/builder/mixins/_merge_operations.py +476 -0
- sqlspec/builder/mixins/_order_limit_operations.py +135 -0
- sqlspec/builder/mixins/_pivot_operations.py +153 -0
- sqlspec/builder/mixins/_select_operations.py +603 -0
- sqlspec/builder/mixins/_update_operations.py +187 -0
- sqlspec/builder/mixins/_where_clause.py +621 -0
- sqlspec/cli.py +247 -0
- sqlspec/config.py +395 -0
- sqlspec/core/__init__.py +63 -0
- sqlspec/core/cache.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/cache.py +871 -0
- sqlspec/core/compiler.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/compiler.py +417 -0
- sqlspec/core/filters.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/filters.py +830 -0
- sqlspec/core/hashing.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/hashing.py +310 -0
- sqlspec/core/parameters.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters.py +1237 -0
- sqlspec/core/result.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result.py +677 -0
- sqlspec/core/splitter.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/splitter.py +819 -0
- sqlspec/core/statement.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/statement.py +676 -0
- sqlspec/driver/__init__.py +19 -0
- sqlspec/driver/_async.py +502 -0
- sqlspec/driver/_common.py +631 -0
- sqlspec/driver/_sync.py +503 -0
- sqlspec/driver/mixins/__init__.py +6 -0
- sqlspec/driver/mixins/_result_tools.py +193 -0
- sqlspec/driver/mixins/_sql_translator.py +86 -0
- sqlspec/exceptions.py +193 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/aiosql/__init__.py +10 -0
- sqlspec/extensions/aiosql/adapter.py +461 -0
- sqlspec/extensions/litestar/__init__.py +6 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/cli.py +48 -0
- sqlspec/extensions/litestar/config.py +92 -0
- sqlspec/extensions/litestar/handlers.py +260 -0
- sqlspec/extensions/litestar/plugin.py +145 -0
- sqlspec/extensions/litestar/providers.py +454 -0
- sqlspec/loader.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/loader.py +760 -0
- sqlspec/migrations/__init__.py +35 -0
- sqlspec/migrations/base.py +414 -0
- sqlspec/migrations/commands.py +443 -0
- sqlspec/migrations/loaders.py +402 -0
- sqlspec/migrations/runner.py +213 -0
- sqlspec/migrations/tracker.py +140 -0
- sqlspec/migrations/utils.py +129 -0
- sqlspec/protocols.py +407 -0
- sqlspec/py.typed +0 -0
- sqlspec/storage/__init__.py +23 -0
- sqlspec/storage/backends/__init__.py +0 -0
- sqlspec/storage/backends/base.py +163 -0
- sqlspec/storage/backends/fsspec.py +386 -0
- sqlspec/storage/backends/obstore.py +459 -0
- sqlspec/storage/capabilities.py +102 -0
- sqlspec/storage/registry.py +239 -0
- sqlspec/typing.py +299 -0
- sqlspec/utils/__init__.py +3 -0
- sqlspec/utils/correlation.py +150 -0
- sqlspec/utils/deprecation.py +106 -0
- sqlspec/utils/fixtures.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/fixtures.py +58 -0
- sqlspec/utils/logging.py +127 -0
- sqlspec/utils/module_loader.py +89 -0
- sqlspec/utils/serializers.py +4 -0
- sqlspec/utils/singleton.py +32 -0
- sqlspec/utils/sync_tools.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/sync_tools.py +237 -0
- sqlspec/utils/text.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/text.py +96 -0
- sqlspec/utils/type_guards.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_guards.py +1139 -0
- sqlspec-0.16.1.dist-info/METADATA +365 -0
- sqlspec-0.16.1.dist-info/RECORD +148 -0
- sqlspec-0.16.1.dist-info/WHEEL +7 -0
- sqlspec-0.16.1.dist-info/entry_points.txt +2 -0
- sqlspec-0.16.1.dist-info/licenses/LICENSE +21 -0
- sqlspec-0.16.1.dist-info/licenses/NOTICE +29 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# ruff: noqa: B008
|
|
2
|
+
"""Application dependency providers generators.
|
|
3
|
+
|
|
4
|
+
This module contains functions to create dependency providers for services and filters.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import datetime
|
|
8
|
+
import inspect
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from typing import Any, Literal, NamedTuple, Optional, TypedDict, Union, cast
|
|
11
|
+
from uuid import UUID
|
|
12
|
+
|
|
13
|
+
from litestar.di import Provide
|
|
14
|
+
from litestar.params import Dependency, Parameter
|
|
15
|
+
from typing_extensions import NotRequired
|
|
16
|
+
|
|
17
|
+
from sqlspec.core.filters import (
|
|
18
|
+
BeforeAfterFilter,
|
|
19
|
+
FilterTypes,
|
|
20
|
+
InCollectionFilter,
|
|
21
|
+
LimitOffsetFilter,
|
|
22
|
+
NotInCollectionFilter,
|
|
23
|
+
OrderByFilter,
|
|
24
|
+
SearchFilter,
|
|
25
|
+
)
|
|
26
|
+
from sqlspec.utils.singleton import SingletonMeta
|
|
27
|
+
from sqlspec.utils.text import camelize
|
|
28
|
+
|
|
29
|
+
__all__ = (
|
|
30
|
+
"DEPENDENCY_DEFAULTS",
|
|
31
|
+
"BooleanOrNone",
|
|
32
|
+
"DTorNone",
|
|
33
|
+
"DependencyDefaults",
|
|
34
|
+
"FieldNameType",
|
|
35
|
+
"FilterConfig",
|
|
36
|
+
"HashableType",
|
|
37
|
+
"HashableValue",
|
|
38
|
+
"IntOrNone",
|
|
39
|
+
"SortOrder",
|
|
40
|
+
"SortOrderOrNone",
|
|
41
|
+
"StringOrNone",
|
|
42
|
+
"UuidOrNone",
|
|
43
|
+
"create_filter_dependencies",
|
|
44
|
+
"dep_cache",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
DTorNone = Optional[datetime.datetime]
|
|
48
|
+
StringOrNone = Optional[str]
|
|
49
|
+
UuidOrNone = Optional[UUID]
|
|
50
|
+
IntOrNone = Optional[int]
|
|
51
|
+
BooleanOrNone = Optional[bool]
|
|
52
|
+
SortOrder = Literal["asc", "desc"]
|
|
53
|
+
SortOrderOrNone = Optional[SortOrder]
|
|
54
|
+
HashableValue = Union[str, int, float, bool, None]
|
|
55
|
+
HashableType = Union[HashableValue, tuple[Any, ...], tuple[tuple[str, Any], ...], tuple[HashableValue, ...]]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class DependencyDefaults:
|
|
59
|
+
FILTERS_DEPENDENCY_KEY: str = "filters"
|
|
60
|
+
CREATED_FILTER_DEPENDENCY_KEY: str = "created_filter"
|
|
61
|
+
ID_FILTER_DEPENDENCY_KEY: str = "id_filter"
|
|
62
|
+
LIMIT_OFFSET_FILTER_DEPENDENCY_KEY: str = "limit_offset_filter"
|
|
63
|
+
UPDATED_FILTER_DEPENDENCY_KEY: str = "updated_filter"
|
|
64
|
+
ORDER_BY_FILTER_DEPENDENCY_KEY: str = "order_by_filter"
|
|
65
|
+
SEARCH_FILTER_DEPENDENCY_KEY: str = "search_filter"
|
|
66
|
+
DEFAULT_PAGINATION_SIZE: int = 20
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
DEPENDENCY_DEFAULTS = DependencyDefaults()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class FieldNameType(NamedTuple):
|
|
73
|
+
"""Type for field name and associated type information for filter configuration."""
|
|
74
|
+
|
|
75
|
+
name: str
|
|
76
|
+
type_hint: type[Any] = str
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class FilterConfig(TypedDict):
|
|
80
|
+
"""Configuration for generating dynamic filters."""
|
|
81
|
+
|
|
82
|
+
id_filter: NotRequired[type[Union[UUID, int, str]]]
|
|
83
|
+
id_field: NotRequired[str]
|
|
84
|
+
sort_field: NotRequired[str]
|
|
85
|
+
sort_order: NotRequired[SortOrder]
|
|
86
|
+
pagination_type: NotRequired[Literal["limit_offset"]]
|
|
87
|
+
pagination_size: NotRequired[int]
|
|
88
|
+
search: NotRequired[Union[str, set[str], list[str]]]
|
|
89
|
+
search_ignore_case: NotRequired[bool]
|
|
90
|
+
created_at: NotRequired[bool]
|
|
91
|
+
updated_at: NotRequired[bool]
|
|
92
|
+
not_in_fields: NotRequired[Union[FieldNameType, set[FieldNameType], list[Union[str, FieldNameType]]]]
|
|
93
|
+
in_fields: NotRequired[Union[FieldNameType, set[FieldNameType], list[Union[str, FieldNameType]]]]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class DependencyCache(metaclass=SingletonMeta):
|
|
97
|
+
"""Dependency cache for memoizing dynamically generated dependencies."""
|
|
98
|
+
|
|
99
|
+
def __init__(self) -> None:
|
|
100
|
+
self.dependencies: dict[Union[int, str], dict[str, Provide]] = {}
|
|
101
|
+
|
|
102
|
+
def add_dependencies(self, key: Union[int, str], dependencies: dict[str, Provide]) -> None:
|
|
103
|
+
self.dependencies[key] = dependencies
|
|
104
|
+
|
|
105
|
+
def get_dependencies(self, key: Union[int, str]) -> Optional[dict[str, Provide]]:
|
|
106
|
+
return self.dependencies.get(key)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
dep_cache = DependencyCache()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def create_filter_dependencies(
|
|
113
|
+
config: FilterConfig, dep_defaults: DependencyDefaults = DEPENDENCY_DEFAULTS
|
|
114
|
+
) -> dict[str, Provide]:
|
|
115
|
+
"""Create a dependency provider for the combined filter function.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
config: FilterConfig instance with desired settings.
|
|
119
|
+
dep_defaults: Dependency defaults to use for the filter dependencies
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
A dependency provider function for the combined filter function.
|
|
123
|
+
"""
|
|
124
|
+
if (deps := dep_cache.get_dependencies(cache_key := hash(_make_hashable(config)))) is not None:
|
|
125
|
+
return deps
|
|
126
|
+
deps = _create_statement_filters(config, dep_defaults)
|
|
127
|
+
dep_cache.add_dependencies(cache_key, deps)
|
|
128
|
+
return deps
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _make_hashable(value: Any) -> HashableType:
|
|
132
|
+
"""Convert a value into a hashable type for caching purposes.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
value: Any value that needs to be made hashable.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
A hashable version of the value.
|
|
139
|
+
"""
|
|
140
|
+
if isinstance(value, dict):
|
|
141
|
+
items = []
|
|
142
|
+
for k in sorted(value.keys()): # pyright: ignore
|
|
143
|
+
v = value[k]
|
|
144
|
+
items.append((str(k), _make_hashable(v)))
|
|
145
|
+
return tuple(items)
|
|
146
|
+
if isinstance(value, (list, set)):
|
|
147
|
+
hashable_items = [_make_hashable(item) for item in value]
|
|
148
|
+
filtered_items = [item for item in hashable_items if item is not None]
|
|
149
|
+
return tuple(sorted(filtered_items, key=str))
|
|
150
|
+
if isinstance(value, (str, int, float, bool, type(None))):
|
|
151
|
+
return value
|
|
152
|
+
return str(value)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _create_statement_filters(
|
|
156
|
+
config: FilterConfig, dep_defaults: DependencyDefaults = DEPENDENCY_DEFAULTS
|
|
157
|
+
) -> dict[str, Provide]:
|
|
158
|
+
"""Create filter dependencies based on configuration.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
config: Configuration dictionary specifying which filters to enable
|
|
162
|
+
dep_defaults: Dependency defaults to use for the filter dependencies
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Dictionary of filter provider functions
|
|
166
|
+
"""
|
|
167
|
+
filters: dict[str, Provide] = {}
|
|
168
|
+
|
|
169
|
+
if config.get("id_filter", False):
|
|
170
|
+
|
|
171
|
+
def provide_id_filter( # pyright: ignore[reportUnknownParameterType]
|
|
172
|
+
ids: Optional[list[str]] = Parameter(query="ids", default=None, required=False),
|
|
173
|
+
) -> InCollectionFilter: # pyright: ignore[reportMissingTypeArgument]
|
|
174
|
+
return InCollectionFilter(field_name=config.get("id_field", "id"), values=ids)
|
|
175
|
+
|
|
176
|
+
filters[dep_defaults.ID_FILTER_DEPENDENCY_KEY] = Provide(provide_id_filter, sync_to_thread=False) # pyright: ignore[reportUnknownArgumentType]
|
|
177
|
+
|
|
178
|
+
if config.get("created_at", False):
|
|
179
|
+
|
|
180
|
+
def provide_created_filter(
|
|
181
|
+
before: DTorNone = Parameter(query="createdBefore", default=None, required=False),
|
|
182
|
+
after: DTorNone = Parameter(query="createdAfter", default=None, required=False),
|
|
183
|
+
) -> BeforeAfterFilter:
|
|
184
|
+
return BeforeAfterFilter("created_at", before, after)
|
|
185
|
+
|
|
186
|
+
filters[dep_defaults.CREATED_FILTER_DEPENDENCY_KEY] = Provide(provide_created_filter, sync_to_thread=False)
|
|
187
|
+
|
|
188
|
+
if config.get("updated_at", False):
|
|
189
|
+
|
|
190
|
+
def provide_updated_filter(
|
|
191
|
+
before: DTorNone = Parameter(query="updatedBefore", default=None, required=False),
|
|
192
|
+
after: DTorNone = Parameter(query="updatedAfter", default=None, required=False),
|
|
193
|
+
) -> BeforeAfterFilter:
|
|
194
|
+
return BeforeAfterFilter("updated_at", before, after)
|
|
195
|
+
|
|
196
|
+
filters[dep_defaults.UPDATED_FILTER_DEPENDENCY_KEY] = Provide(provide_updated_filter, sync_to_thread=False)
|
|
197
|
+
|
|
198
|
+
if config.get("pagination_type") == "limit_offset":
|
|
199
|
+
|
|
200
|
+
def provide_limit_offset_pagination(
|
|
201
|
+
current_page: int = Parameter(ge=1, query="currentPage", default=1, required=False),
|
|
202
|
+
page_size: int = Parameter(
|
|
203
|
+
query="pageSize",
|
|
204
|
+
ge=1,
|
|
205
|
+
default=config.get("pagination_size", dep_defaults.DEFAULT_PAGINATION_SIZE),
|
|
206
|
+
required=False,
|
|
207
|
+
),
|
|
208
|
+
) -> LimitOffsetFilter:
|
|
209
|
+
return LimitOffsetFilter(page_size, page_size * (current_page - 1))
|
|
210
|
+
|
|
211
|
+
filters[dep_defaults.LIMIT_OFFSET_FILTER_DEPENDENCY_KEY] = Provide(
|
|
212
|
+
provide_limit_offset_pagination, sync_to_thread=False
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
if search_fields := config.get("search"):
|
|
216
|
+
|
|
217
|
+
def provide_search_filter(
|
|
218
|
+
search_string: StringOrNone = Parameter(
|
|
219
|
+
title="Field to search", query="searchString", default=None, required=False
|
|
220
|
+
),
|
|
221
|
+
ignore_case: BooleanOrNone = Parameter(
|
|
222
|
+
title="Search should be case sensitive",
|
|
223
|
+
query="searchIgnoreCase",
|
|
224
|
+
default=config.get("search_ignore_case", False),
|
|
225
|
+
required=False,
|
|
226
|
+
),
|
|
227
|
+
) -> SearchFilter:
|
|
228
|
+
field_names = set(search_fields.split(",")) if isinstance(search_fields, str) else set(search_fields)
|
|
229
|
+
|
|
230
|
+
return SearchFilter(
|
|
231
|
+
field_name=field_names,
|
|
232
|
+
value=search_string, # type: ignore[arg-type]
|
|
233
|
+
ignore_case=ignore_case or False,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
filters[dep_defaults.SEARCH_FILTER_DEPENDENCY_KEY] = Provide(provide_search_filter, sync_to_thread=False)
|
|
237
|
+
|
|
238
|
+
if sort_field := config.get("sort_field"):
|
|
239
|
+
|
|
240
|
+
def provide_order_by(
|
|
241
|
+
field_name: StringOrNone = Parameter(
|
|
242
|
+
title="Order by field", query="orderBy", default=sort_field, required=False
|
|
243
|
+
),
|
|
244
|
+
sort_order: SortOrderOrNone = Parameter(
|
|
245
|
+
title="Field to search", query="sortOrder", default=config.get("sort_order", "desc"), required=False
|
|
246
|
+
),
|
|
247
|
+
) -> OrderByFilter:
|
|
248
|
+
return OrderByFilter(field_name=field_name, sort_order=sort_order) # type: ignore[arg-type]
|
|
249
|
+
|
|
250
|
+
filters[dep_defaults.ORDER_BY_FILTER_DEPENDENCY_KEY] = Provide(provide_order_by, sync_to_thread=False)
|
|
251
|
+
|
|
252
|
+
if not_in_fields := config.get("not_in_fields"):
|
|
253
|
+
not_in_fields = {not_in_fields} if isinstance(not_in_fields, (str, FieldNameType)) else not_in_fields
|
|
254
|
+
|
|
255
|
+
for field_def in not_in_fields:
|
|
256
|
+
field_def = FieldNameType(name=field_def, type_hint=str) if isinstance(field_def, str) else field_def
|
|
257
|
+
|
|
258
|
+
def create_not_in_filter_provider( # pyright: ignore
|
|
259
|
+
field_name: FieldNameType,
|
|
260
|
+
) -> Callable[..., Optional[NotInCollectionFilter[field_def.type_hint]]]: # type: ignore
|
|
261
|
+
def provide_not_in_filter( # pyright: ignore
|
|
262
|
+
values: Optional[list[field_name.type_hint]] = Parameter( # type: ignore
|
|
263
|
+
query=camelize(f"{field_name.name}_not_in"), default=None, required=False
|
|
264
|
+
),
|
|
265
|
+
) -> Optional[NotInCollectionFilter[field_name.type_hint]]: # type: ignore
|
|
266
|
+
return (
|
|
267
|
+
NotInCollectionFilter[field_name.type_hint](field_name=field_name.name, values=values) # type: ignore
|
|
268
|
+
if values
|
|
269
|
+
else None
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
return provide_not_in_filter # pyright: ignore
|
|
273
|
+
|
|
274
|
+
provider = create_not_in_filter_provider(field_def) # pyright: ignore
|
|
275
|
+
filters[f"{field_def.name}_not_in_filter"] = Provide(provider, sync_to_thread=False) # pyright: ignore
|
|
276
|
+
|
|
277
|
+
if in_fields := config.get("in_fields"):
|
|
278
|
+
in_fields = {in_fields} if isinstance(in_fields, (str, FieldNameType)) else in_fields
|
|
279
|
+
|
|
280
|
+
for field_def in in_fields:
|
|
281
|
+
field_def = FieldNameType(name=field_def, type_hint=str) if isinstance(field_def, str) else field_def
|
|
282
|
+
|
|
283
|
+
def create_in_filter_provider( # pyright: ignore
|
|
284
|
+
field_name: FieldNameType,
|
|
285
|
+
) -> Callable[..., Optional[InCollectionFilter[field_def.type_hint]]]: # type: ignore # pyright: ignore
|
|
286
|
+
def provide_in_filter( # pyright: ignore
|
|
287
|
+
values: Optional[list[field_name.type_hint]] = Parameter( # type: ignore # pyright: ignore
|
|
288
|
+
query=camelize(f"{field_name.name}_in"), default=None, required=False
|
|
289
|
+
),
|
|
290
|
+
) -> Optional[InCollectionFilter[field_name.type_hint]]: # type: ignore # pyright: ignore
|
|
291
|
+
return (
|
|
292
|
+
InCollectionFilter[field_name.type_hint](field_name=field_name.name, values=values) # type: ignore # pyright: ignore
|
|
293
|
+
if values
|
|
294
|
+
else None
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
return provide_in_filter # pyright: ignore
|
|
298
|
+
|
|
299
|
+
provider = create_in_filter_provider(field_def) # type: ignore
|
|
300
|
+
filters[f"{field_def.name}_in_filter"] = Provide(provider, sync_to_thread=False) # pyright: ignore
|
|
301
|
+
|
|
302
|
+
if filters:
|
|
303
|
+
filters[dep_defaults.FILTERS_DEPENDENCY_KEY] = Provide(
|
|
304
|
+
_create_filter_aggregate_function(config), sync_to_thread=False
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
return filters
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _create_filter_aggregate_function(config: FilterConfig) -> Callable[..., list[FilterTypes]]:
|
|
311
|
+
"""Create filter aggregation function based on configuration.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
config: The filter configuration.
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
Function that returns list of configured filters.
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
parameters: dict[str, inspect.Parameter] = {}
|
|
321
|
+
annotations: dict[str, Any] = {}
|
|
322
|
+
|
|
323
|
+
if cls := config.get("id_filter"):
|
|
324
|
+
parameters["id_filter"] = inspect.Parameter(
|
|
325
|
+
name="id_filter",
|
|
326
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
327
|
+
default=Dependency(skip_validation=True),
|
|
328
|
+
annotation=InCollectionFilter[cls], # type: ignore[valid-type]
|
|
329
|
+
)
|
|
330
|
+
annotations["id_filter"] = InCollectionFilter[cls] # type: ignore[valid-type]
|
|
331
|
+
|
|
332
|
+
if config.get("created_at"):
|
|
333
|
+
parameters["created_filter"] = inspect.Parameter(
|
|
334
|
+
name="created_filter",
|
|
335
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
336
|
+
default=Dependency(skip_validation=True),
|
|
337
|
+
annotation=BeforeAfterFilter,
|
|
338
|
+
)
|
|
339
|
+
annotations["created_filter"] = BeforeAfterFilter
|
|
340
|
+
|
|
341
|
+
if config.get("updated_at"):
|
|
342
|
+
parameters["updated_filter"] = inspect.Parameter(
|
|
343
|
+
name="updated_filter",
|
|
344
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
345
|
+
default=Dependency(skip_validation=True),
|
|
346
|
+
annotation=BeforeAfterFilter,
|
|
347
|
+
)
|
|
348
|
+
annotations["updated_filter"] = BeforeAfterFilter
|
|
349
|
+
|
|
350
|
+
if config.get("search"):
|
|
351
|
+
parameters["search_filter"] = inspect.Parameter(
|
|
352
|
+
name="search_filter",
|
|
353
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
354
|
+
default=Dependency(skip_validation=True),
|
|
355
|
+
annotation=SearchFilter,
|
|
356
|
+
)
|
|
357
|
+
annotations["search_filter"] = SearchFilter
|
|
358
|
+
|
|
359
|
+
if config.get("pagination_type") == "limit_offset":
|
|
360
|
+
parameters["limit_offset_filter"] = inspect.Parameter(
|
|
361
|
+
name="limit_offset_filter",
|
|
362
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
363
|
+
default=Dependency(skip_validation=True),
|
|
364
|
+
annotation=LimitOffsetFilter,
|
|
365
|
+
)
|
|
366
|
+
annotations["limit_offset_filter"] = LimitOffsetFilter
|
|
367
|
+
|
|
368
|
+
if config.get("sort_field"):
|
|
369
|
+
parameters["order_by_filter"] = inspect.Parameter(
|
|
370
|
+
name="order_by_filter",
|
|
371
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
372
|
+
default=Dependency(skip_validation=True),
|
|
373
|
+
annotation=OrderByFilter,
|
|
374
|
+
)
|
|
375
|
+
annotations["order_by_filter"] = OrderByFilter
|
|
376
|
+
|
|
377
|
+
if not_in_fields := config.get("not_in_fields"):
|
|
378
|
+
for field_def in not_in_fields:
|
|
379
|
+
field_def = FieldNameType(name=field_def, type_hint=str) if isinstance(field_def, str) else field_def
|
|
380
|
+
parameters[f"{field_def.name}_not_in_filter"] = inspect.Parameter(
|
|
381
|
+
name=f"{field_def.name}_not_in_filter",
|
|
382
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
383
|
+
default=Dependency(skip_validation=True),
|
|
384
|
+
annotation=NotInCollectionFilter[field_def.type_hint], # type: ignore
|
|
385
|
+
)
|
|
386
|
+
annotations[f"{field_def.name}_not_in_filter"] = NotInCollectionFilter[field_def.type_hint] # type: ignore
|
|
387
|
+
|
|
388
|
+
if in_fields := config.get("in_fields"):
|
|
389
|
+
for field_def in in_fields:
|
|
390
|
+
field_def = FieldNameType(name=field_def, type_hint=str) if isinstance(field_def, str) else field_def
|
|
391
|
+
parameters[f"{field_def.name}_in_filter"] = inspect.Parameter(
|
|
392
|
+
name=f"{field_def.name}_in_filter",
|
|
393
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
394
|
+
default=Dependency(skip_validation=True),
|
|
395
|
+
annotation=InCollectionFilter[field_def.type_hint], # type: ignore
|
|
396
|
+
)
|
|
397
|
+
annotations[f"{field_def.name}_in_filter"] = InCollectionFilter[field_def.type_hint] # type: ignore
|
|
398
|
+
|
|
399
|
+
def provide_filters(**kwargs: FilterTypes) -> list[FilterTypes]:
|
|
400
|
+
"""Aggregate filter dependencies based on configuration.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
**kwargs: Filter parameters dynamically provided based on configuration.
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
List of configured filters.
|
|
407
|
+
"""
|
|
408
|
+
filters: list[FilterTypes] = []
|
|
409
|
+
if id_filter := kwargs.get("id_filter"):
|
|
410
|
+
filters.append(id_filter)
|
|
411
|
+
if created_filter := kwargs.get("created_filter"):
|
|
412
|
+
filters.append(created_filter)
|
|
413
|
+
if limit_offset := kwargs.get("limit_offset_filter"):
|
|
414
|
+
filters.append(limit_offset)
|
|
415
|
+
if updated_filter := kwargs.get("updated_filter"):
|
|
416
|
+
filters.append(updated_filter)
|
|
417
|
+
if (
|
|
418
|
+
(search_filter := cast("Optional[SearchFilter]", kwargs.get("search_filter")))
|
|
419
|
+
and search_filter is not None # pyright: ignore[reportUnnecessaryComparison]
|
|
420
|
+
and search_filter.field_name is not None # pyright: ignore[reportUnnecessaryComparison]
|
|
421
|
+
and search_filter.value is not None # pyright: ignore[reportUnnecessaryComparison]
|
|
422
|
+
):
|
|
423
|
+
filters.append(search_filter)
|
|
424
|
+
if (
|
|
425
|
+
(order_by := cast("Optional[OrderByFilter]", kwargs.get("order_by_filter")))
|
|
426
|
+
and order_by is not None # pyright: ignore[reportUnnecessaryComparison]
|
|
427
|
+
and order_by.field_name is not None # pyright: ignore[reportUnnecessaryComparison]
|
|
428
|
+
):
|
|
429
|
+
filters.append(order_by)
|
|
430
|
+
|
|
431
|
+
if not_in_fields := config.get("not_in_fields"):
|
|
432
|
+
not_in_fields = {not_in_fields} if isinstance(not_in_fields, (str, FieldNameType)) else not_in_fields
|
|
433
|
+
for field_def in not_in_fields:
|
|
434
|
+
field_def = FieldNameType(name=field_def, type_hint=str) if isinstance(field_def, str) else field_def
|
|
435
|
+
filter_ = kwargs.get(f"{field_def.name}_not_in_filter")
|
|
436
|
+
if filter_ is not None:
|
|
437
|
+
filters.append(filter_)
|
|
438
|
+
|
|
439
|
+
if in_fields := config.get("in_fields"):
|
|
440
|
+
in_fields = {in_fields} if isinstance(in_fields, (str, FieldNameType)) else in_fields
|
|
441
|
+
for field_def in in_fields:
|
|
442
|
+
field_def = FieldNameType(name=field_def, type_hint=str) if isinstance(field_def, str) else field_def
|
|
443
|
+
filter_ = kwargs.get(f"{field_def.name}_in_filter")
|
|
444
|
+
if filter_ is not None:
|
|
445
|
+
filters.append(filter_)
|
|
446
|
+
return filters
|
|
447
|
+
|
|
448
|
+
provide_filters.__signature__ = inspect.Signature( # type: ignore
|
|
449
|
+
parameters=list(parameters.values()), return_annotation=list[FilterTypes]
|
|
450
|
+
)
|
|
451
|
+
provide_filters.__annotations__ = annotations
|
|
452
|
+
provide_filters.__annotations__["return"] = list[FilterTypes]
|
|
453
|
+
|
|
454
|
+
return provide_filters
|
|
Binary file
|