jararaca 0.2.30__tar.gz → 0.2.32__tar.gz

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 jararaca might be problematic. Click here for more details.

Files changed (78) hide show
  1. {jararaca-0.2.30 → jararaca-0.2.32}/PKG-INFO +1 -1
  2. {jararaca-0.2.30 → jararaca-0.2.32}/pyproject.toml +1 -1
  3. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/persistence/sort_filter.py +66 -11
  4. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/persistence/utilities.py +20 -1
  5. {jararaca-0.2.30 → jararaca-0.2.32}/LICENSE +0 -0
  6. {jararaca-0.2.30 → jararaca-0.2.32}/README.md +0 -0
  7. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/Message Bus/Decorators.md +0 -0
  8. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/Message Bus/Interceptors.md +0 -0
  9. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/Observability/Decorators.md +0 -0
  10. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/Observability/Interceptors.md +0 -0
  11. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/Presentation/Decorators.md +0 -0
  12. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/RPC/RestClients/Decorators.md +0 -0
  13. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/RPC/RestClients/Middlewared.md +0 -0
  14. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/Schedule/Decorators.md +0 -0
  15. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/Websocket/Decorators.md +0 -0
  16. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Architecture/Websocket/Interceptors.md +0 -0
  17. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Concept/Adapters.md +0 -0
  18. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Concept/Hexagonal Architecture.md +0 -0
  19. {jararaca-0.2.30 → jararaca-0.2.32}/docs/Concept/Ports.md +0 -0
  20. {jararaca-0.2.30 → jararaca-0.2.32}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg +0 -0
  21. {jararaca-0.2.30 → jararaca-0.2.32}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp +0 -0
  22. {jararaca-0.2.30 → jararaca-0.2.32}/docs/assets/tracing_example.png +0 -0
  23. {jararaca-0.2.30 → jararaca-0.2.32}/docs/index.md +0 -0
  24. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/__init__.py +0 -0
  25. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/__main__.py +0 -0
  26. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/cli.py +0 -0
  27. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/common/__init__.py +0 -0
  28. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/core/__init__.py +0 -0
  29. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/core/providers.py +0 -0
  30. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/core/uow.py +0 -0
  31. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/di.py +0 -0
  32. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/files/entity.py.mako +0 -0
  33. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/lifecycle.py +0 -0
  34. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/messagebus/__init__.py +0 -0
  35. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/messagebus/decorators.py +0 -0
  36. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/messagebus/interceptors/__init__.py +0 -0
  37. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/messagebus/interceptors/publisher_interceptor.py +0 -0
  38. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/messagebus/publisher.py +0 -0
  39. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/messagebus/types.py +0 -0
  40. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/messagebus/worker.py +0 -0
  41. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/microservice.py +0 -0
  42. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/observability/decorators.py +0 -0
  43. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/observability/interceptor.py +0 -0
  44. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/observability/providers/__init__.py +0 -0
  45. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/observability/providers/otel.py +0 -0
  46. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/persistence/base.py +0 -0
  47. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/persistence/exports.py +0 -0
  48. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/persistence/interceptors/__init__.py +0 -0
  49. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +0 -0
  50. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/persistence/session.py +0 -0
  51. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/__init__.py +0 -0
  52. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/decorators.py +0 -0
  53. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/hooks.py +0 -0
  54. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/http_microservice.py +0 -0
  55. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/server.py +0 -0
  56. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/websocket/__init__.py +0 -0
  57. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/websocket/base_types.py +0 -0
  58. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/websocket/context.py +0 -0
  59. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/websocket/decorators.py +0 -0
  60. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/websocket/redis.py +0 -0
  61. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/websocket/types.py +0 -0
  62. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/presentation/websocket/websocket_interceptor.py +0 -0
  63. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/py.typed +0 -0
  64. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/rpc/__init__.py +0 -0
  65. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/rpc/http/__init__.py +0 -0
  66. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/rpc/http/backends/__init__.py +0 -0
  67. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/rpc/http/backends/httpx.py +0 -0
  68. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/rpc/http/backends/otel.py +0 -0
  69. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/rpc/http/decorators.py +0 -0
  70. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/rpc/http/httpx.py +0 -0
  71. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/scheduler/__init__.py +0 -0
  72. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/scheduler/decorators.py +0 -0
  73. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/scheduler/scheduler.py +0 -0
  74. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/tools/app_config/__init__.py +0 -0
  75. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/tools/app_config/decorators.py +0 -0
  76. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/tools/app_config/interceptor.py +0 -0
  77. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/tools/metadata.py +0 -0
  78. {jararaca-0.2.30 → jararaca-0.2.32}/src/jararaca/tools/typescript/interface_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jararaca
3
- Version: 0.2.30
3
+ Version: 0.2.32
4
4
  Summary: A simple and fast API framework for Python
5
5
  Home-page: https://github.com/LuscasLeo/jararaca
6
6
  Author: Lucas S
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.2.30"
3
+ version = "0.2.32"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"
@@ -1,3 +1,4 @@
1
+ import re
1
2
  from datetime import date, datetime
2
3
  from functools import reduce
3
4
  from typing import Literal, Tuple, TypeVar
@@ -10,7 +11,7 @@ from sqlalchemy.orm.attributes import InstrumentedAttribute
10
11
  from jararaca import BaseEntity
11
12
 
12
13
  FILTER_SORT_ENTITY_ATTR_MAP = dict[
13
- str, InstrumentedAttribute[str | int | datetime | date | UUID]
14
+ str, InstrumentedAttribute[str | int | datetime | date | UUID | None]
14
15
  ]
15
16
 
16
17
 
@@ -54,14 +55,12 @@ class FilterModel(BaseModel):
54
55
  INHERITS_BASE_ENTITY = TypeVar("INHERITS_BASE_ENTITY", bound=BaseEntity)
55
56
 
56
57
 
57
- class SortFilterRunner:
58
+ class FilterRuleApplier:
58
59
  def __init__(
59
60
  self,
60
61
  allowed_filters: FILTER_SORT_ENTITY_ATTR_MAP,
61
- allowed_sorts: FILTER_SORT_ENTITY_ATTR_MAP,
62
62
  ):
63
63
  self.allowed_filters = allowed_filters
64
- self.allowed_sorts = allowed_sorts
65
64
 
66
65
  def create_query_for_filter(
67
66
  self, query: Select[Tuple[INHERITS_BASE_ENTITY]], filter: FilterModel
@@ -139,25 +138,41 @@ class SortFilterRunner:
139
138
  case _:
140
139
  raise ValueError(f"Unsupported bool operator: {filter.operator}")
141
140
  elif field_type is int:
141
+ __value = (
142
+ filter.value[0] if isinstance(filter.value, list) else filter.value
143
+ )
144
+ if not re.match(r"^-?\d+$", __value):
145
+ raise ValueError(
146
+ f"Unsupported value type for int field: {type(__value)}"
147
+ )
148
+ number_value = int(__value)
142
149
  match filter.operator:
143
150
  case "=":
144
- return query.filter(field == filter.value)
151
+ return query.filter(field == number_value)
145
152
  case "!=":
146
- return query.filter(field != filter.value)
153
+ return query.filter(field != number_value)
147
154
  case ">":
148
- return query.filter(field > filter.value)
155
+ return query.filter(field > number_value)
149
156
  case "<":
150
- return query.filter(field < filter.value)
157
+ return query.filter(field < number_value)
151
158
  case ">=":
152
- return query.filter(field >= filter.value)
159
+ return query.filter(field >= number_value)
153
160
  case "<=":
154
- return query.filter(field <= filter.value)
161
+ return query.filter(field <= number_value)
155
162
  case "isEmpty":
156
163
  return query.filter(field == None) # noqa
157
164
  case "isNotEmpty":
158
165
  return query.filter(field != None) # noqa
159
166
  case "isAnyOf":
160
- return query.filter(field.in_(filter.value))
167
+ if not isinstance(filter.value, list):
168
+ raise ValueError(
169
+ f"Unsupported value type for isAnyOf operator: {type(filter.value)}"
170
+ )
171
+
172
+ number_values = [
173
+ int(v) for v in filter.value if re.match(r"^-?\d+$", v)
174
+ ]
175
+ return query.filter(field.in_(number_values))
161
176
  case _:
162
177
  raise ValueError(f"Unsupported int operator: {filter.operator}")
163
178
 
@@ -168,6 +183,14 @@ class SortFilterRunner:
168
183
  ) -> Select[Tuple[INHERITS_BASE_ENTITY]]:
169
184
  return reduce(lambda q, f: self.create_query_for_filter(q, f), filters, query)
170
185
 
186
+
187
+ class SortRuleApplier:
188
+ def __init__(
189
+ self,
190
+ allowed_sorts: FILTER_SORT_ENTITY_ATTR_MAP,
191
+ ):
192
+ self.allowed_sorts = allowed_sorts
193
+
171
194
  def create_query_for_sorting(
172
195
  self, query: Select[Tuple[INHERITS_BASE_ENTITY]], sort: SortModel
173
196
  ) -> Select[Tuple[INHERITS_BASE_ENTITY]]:
@@ -182,6 +205,38 @@ class SortFilterRunner:
182
205
  return reduce(lambda q, s: self.create_query_for_sorting(q, s), sorts, query)
183
206
 
184
207
 
208
+ class SortFilterRunner:
209
+ def __init__(
210
+ self,
211
+ allowed_filters: FILTER_SORT_ENTITY_ATTR_MAP,
212
+ allowed_sorts: FILTER_SORT_ENTITY_ATTR_MAP,
213
+ ):
214
+ self.allowed_filters = allowed_filters
215
+ self.allowed_sorts = allowed_sorts
216
+ self.filter_rule_applier = FilterRuleApplier(allowed_filters)
217
+ self.sort_rule_applier = SortRuleApplier(allowed_sorts)
218
+
219
+ def create_query_for_filter(
220
+ self, query: Select[Tuple[INHERITS_BASE_ENTITY]], filter: FilterModel
221
+ ) -> Select[Tuple[INHERITS_BASE_ENTITY]]:
222
+ return self.filter_rule_applier.create_query_for_filter(query, filter)
223
+
224
+ def create_query_for_filter_list(
225
+ self, query: Select[Tuple[INHERITS_BASE_ENTITY]], filters: list[FilterModel]
226
+ ) -> Select[Tuple[INHERITS_BASE_ENTITY]]:
227
+ return self.filter_rule_applier.create_query_for_filter_list(query, filters)
228
+
229
+ def create_query_for_sorting(
230
+ self, query: Select[Tuple[INHERITS_BASE_ENTITY]], sort: SortModel
231
+ ) -> Select[Tuple[INHERITS_BASE_ENTITY]]:
232
+ return self.sort_rule_applier.create_query_for_sorting(query, sort)
233
+
234
+ def create_query_for_sorting_list(
235
+ self, query: Select[Tuple[INHERITS_BASE_ENTITY]], sorts: list[SortModel]
236
+ ) -> Select[Tuple[INHERITS_BASE_ENTITY]]:
237
+ return self.sort_rule_applier.create_query_for_sorting_list(query, sorts)
238
+
239
+
185
240
  __all__ = [
186
241
  "SortFilterRunner",
187
242
  "FilterModel",
@@ -29,7 +29,12 @@ from jararaca.persistence.base import (
29
29
  BaseEntity,
30
30
  recursive_get_dict,
31
31
  )
32
- from jararaca.persistence.sort_filter import FilterModel, SortModel
32
+ from jararaca.persistence.sort_filter import (
33
+ FilterModel,
34
+ FilterRuleApplier,
35
+ SortModel,
36
+ SortRuleApplier,
37
+ )
33
38
 
34
39
  logger = logging.getLogger(__name__)
35
40
 
@@ -257,11 +262,15 @@ class QueryOperations(Generic[QUERY_FILTER_T, QUERY_ENTITY_T]):
257
262
  session_provider: Callable[[], AsyncSession],
258
263
  filters_functions: list[QueryInjector],
259
264
  unique: bool = False,
265
+ sort_rule_applier: SortRuleApplier | None = None,
266
+ filter_rule_applier: FilterRuleApplier | None = None,
260
267
  ) -> None:
261
268
  self.entity_type: type[QUERY_ENTITY_T] = entity_type
262
269
  self.session_provider = session_provider
263
270
  self.filters_functions = filters_functions
264
271
  self.unique = unique
272
+ self.sort_rule_applier = sort_rule_applier
273
+ self.filter_rule_applier = filter_rule_applier
265
274
 
266
275
  @property
267
276
  def session(self) -> AsyncSession:
@@ -281,6 +290,16 @@ class QueryOperations(Generic[QUERY_FILTER_T, QUERY_ENTITY_T]):
281
290
  select(self.entity_type),
282
291
  )
283
292
 
293
+ if self.sort_rule_applier:
294
+ query = self.sort_rule_applier.create_query_for_sorting_list(
295
+ query, filter.sort_models
296
+ )
297
+
298
+ if self.filter_rule_applier:
299
+ query = self.filter_rule_applier.create_query_for_filter_list(
300
+ query, filter.filter_models
301
+ )
302
+
284
303
  unpaginated_total = (
285
304
  await self.session.execute(
286
305
  select(func.count()).select_from(query.subquery())
File without changes
File without changes
File without changes
File without changes
File without changes