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,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