apexdevkit 1.33.1__tar.gz → 2.0.2__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.
Files changed (70) hide show
  1. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/PKG-INFO +3 -4
  2. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/annotation/deprecate.py +1 -1
  3. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/date.py +9 -19
  4. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/error.py +1 -1
  5. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/builder.py +3 -3
  6. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/docs.py +2 -2
  7. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/name.py +1 -1
  8. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/router.py +2 -120
  9. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/schema.py +17 -81
  10. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/service.py +3 -4
  11. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/formatter.py +20 -33
  12. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/query/generator.py +2 -2
  13. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/mixin.py +4 -4
  14. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/in_memory/repository.py +1 -1
  15. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/in_memory/store.py +4 -5
  16. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/connector.py +7 -7
  17. apexdevkit-2.0.2/apexdevkit/repository/sql/mssql/__init__.py +9 -0
  18. apexdevkit-2.0.2/apexdevkit/repository/sql/mssql/repository.py +79 -0
  19. apexdevkit-1.33.1/apexdevkit/repository/sql/mssql.py → apexdevkit-2.0.2/apexdevkit/repository/sql/mssql/table.py +39 -117
  20. apexdevkit-2.0.2/apexdevkit/repository/sql/sqlite/__init__.py +7 -0
  21. apexdevkit-2.0.2/apexdevkit/repository/sql/sqlite/repository.py +63 -0
  22. apexdevkit-1.33.1/apexdevkit/repository/sql/sqlite.py → apexdevkit-2.0.2/apexdevkit/repository/sql/sqlite/table.py +31 -91
  23. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/server.py +20 -13
  24. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/sync/source.py +6 -6
  25. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/sync/sync.py +6 -6
  26. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/sync/target.py +4 -4
  27. apexdevkit-2.0.2/apexdevkit/testing.py +157 -0
  28. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/pyproject.toml +5 -10
  29. apexdevkit-1.33.1/apexdevkit/environment.py +0 -10
  30. apexdevkit-1.33.1/apexdevkit/fluent.py +0 -44
  31. apexdevkit-1.33.1/apexdevkit/http/__init__.py +0 -19
  32. apexdevkit-1.33.1/apexdevkit/http/fake.py +0 -92
  33. apexdevkit-1.33.1/apexdevkit/http/fluent.py +0 -131
  34. apexdevkit-1.33.1/apexdevkit/http/httpx/__init__.py +0 -10
  35. apexdevkit-1.33.1/apexdevkit/http/httpx/client.py +0 -198
  36. apexdevkit-1.33.1/apexdevkit/http/httpx/hooks.py +0 -85
  37. apexdevkit-1.33.1/apexdevkit/http/json.py +0 -5
  38. apexdevkit-1.33.1/apexdevkit/http/url.py +0 -9
  39. apexdevkit-1.33.1/apexdevkit/repository/core/multi.py +0 -119
  40. apexdevkit-1.33.1/apexdevkit/security/__init__.py +0 -8
  41. apexdevkit-1.33.1/apexdevkit/security/core.py +0 -18
  42. apexdevkit-1.33.1/apexdevkit/security/hashing.py +0 -21
  43. apexdevkit-1.33.1/apexdevkit/testing/__init__.py +0 -9
  44. apexdevkit-1.33.1/apexdevkit/testing/database.py +0 -42
  45. apexdevkit-1.33.1/apexdevkit/testing/fake.py +0 -224
  46. apexdevkit-1.33.1/apexdevkit/testing/rest.py +0 -281
  47. apexdevkit-1.33.1/apexdevkit/value.py +0 -64
  48. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/LICENSE +0 -0
  49. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/README.md +0 -0
  50. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/__init__.py +0 -0
  51. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/annotation/__init__.py +0 -0
  52. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/__init__.py +0 -0
  53. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/dependable.py +0 -0
  54. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/resource.py +0 -0
  55. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/response.py +0 -0
  56. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/key_fn.py +0 -0
  57. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/py.typed +0 -0
  58. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/query/__init__.py +0 -0
  59. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/query/query.py +0 -0
  60. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/__init__.py +0 -0
  61. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/__init__.py +0 -0
  62. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/database.py +0 -0
  63. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/decorator.py +0 -0
  64. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/interface.py +0 -0
  65. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/in_memory/__init__.py +0 -0
  66. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/in_memory/mixin.py +0 -0
  67. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/__init__.py +0 -0
  68. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/field.py +0 -0
  69. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/sync/__init__.py +0 -0
  70. {apexdevkit-1.33.1 → apexdevkit-2.0.2}/apexdevkit/sync/observer.py +0 -0
@@ -1,20 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apexdevkit
3
- Version: 1.33.1
3
+ Version: 2.0.2
4
4
  Summary: Apex Development Tools for python.
5
5
  License-File: LICENSE
6
6
  Author: Apex Dev
7
7
  Author-email: dev@apex.ge
8
- Requires-Python: >=3.11,<4
8
+ Requires-Python: >=3.12,<4
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.11
11
10
  Classifier: Programming Language :: Python :: 3.12
12
11
  Classifier: Programming Language :: Python :: 3.13
13
12
  Classifier: Programming Language :: Python :: 3.14
14
13
  Requires-Dist: fastapi
15
- Requires-Dist: httpx
16
14
  Requires-Dist: pydantic
17
15
  Requires-Dist: pymssql (==2.*)
16
+ Requires-Dist: pypebbles (==0.3.*)
18
17
  Requires-Dist: python-dotenv
19
18
  Requires-Dist: sentry-sdk[fastapi]
20
19
  Requires-Dist: uvicorn
@@ -33,7 +33,7 @@ def deprecated(warning: str) -> Callable[[F], F]:
33
33
  return decorator
34
34
 
35
35
 
36
- def _wrap_function(func: F, warning: str) -> F:
36
+ def _wrap_function[F: Callable[..., Any]](func: F, warning: str) -> F:
37
37
  def wrapper(*args: Any, **kwargs: dict[str, Any]) -> Any:
38
38
  warn(warning, category=DeprecationWarning, stacklevel=2)
39
39
  return func(*args, **kwargs)
@@ -39,16 +39,11 @@ class DateTime:
39
39
  if time_zone is None:
40
40
  time_zone = ZoneInfo("UTC")
41
41
 
42
- try:
43
- dt = datetime.strptime(date, "%Y-%m-%d")
44
- dt = dt.replace(tzinfo=time_zone)
45
- timestamp_ms = int(dt.timestamp() * 1000)
46
- return cls(timestamp_ms=timestamp_ms)
42
+ dt = datetime.strptime(date, "%Y-%m-%d")
43
+ dt = dt.replace(tzinfo=time_zone)
44
+ timestamp_ms = int(dt.timestamp() * 1000)
47
45
 
48
- except ValueError as e:
49
- raise ValueError(
50
- f"Invalid date format: '{date}'. Expected 'yyyy-mm-dd'."
51
- ) from e
46
+ return cls(timestamp_ms=timestamp_ms)
52
47
 
53
48
  # Date in format of "yyyy-mm-ddTHH:MM:SS"
54
49
  @classmethod
@@ -58,16 +53,11 @@ class DateTime:
58
53
  if time_zone is None:
59
54
  time_zone = ZoneInfo("UTC")
60
55
 
61
- try:
62
- dt = datetime.strptime(date_time, "%Y-%m-%dT%H:%M:%S")
63
- dt = dt.replace(tzinfo=time_zone)
64
- timestamp_ms = int(dt.timestamp() * 1000)
65
- return cls(timestamp_ms=timestamp_ms)
66
- except ValueError as e:
67
- raise ValueError(
68
- f"Invalid datetime format: '{date_time}'."
69
- f" Expected 'yyyy-mm-ddTHH:MM:SS'."
70
- ) from e
56
+ dt = datetime.strptime(date_time, "%Y-%m-%dT%H:%M:%S")
57
+ dt = dt.replace(tzinfo=time_zone)
58
+ timestamp_ms = int(dt.timestamp() * 1000)
59
+
60
+ return cls(timestamp_ms=timestamp_ms)
71
61
 
72
62
  @classmethod
73
63
  def from_timestamp(cls, timestamp: float) -> DateTime:
@@ -31,7 +31,7 @@ class ExistsError(Exception):
31
31
  def __str__(self) -> str:
32
32
  return ",".join([f"{criteria(self.item)}" for criteria in self._duplicates])
33
33
 
34
- def fire(self) -> None:
34
+ def fire(self) -> None: # pragma: no cover
35
35
  if self._duplicates:
36
36
  raise self
37
37
 
@@ -65,7 +65,7 @@ class FastApiBuilder:
65
65
 
66
66
  return self
67
67
 
68
- def with_frontend(self, origin: str) -> Self:
68
+ def with_frontend(self, origin: str) -> Self: # pragma: no cover
69
69
  self.app.add_middleware(
70
70
  CORSMiddleware,
71
71
  allow_origins=[origin],
@@ -76,7 +76,7 @@ class FastApiBuilder:
76
76
 
77
77
  return self
78
78
 
79
- def with_swagger(self, **config: Any) -> Self:
79
+ def with_swagger(self, **config: Any) -> Self: # pragma: no cover
80
80
  self.app.swagger_ui_parameters = config
81
81
 
82
82
  return self
@@ -120,5 +120,5 @@ class _Endpoint:
120
120
  def normilized(self) -> str:
121
121
  return f"/{self.raw.replace('_', '-')}"
122
122
 
123
- def __str__(self) -> str:
123
+ def __str__(self) -> str: # pragma: no cover
124
124
  return self.normilized()
@@ -1,11 +1,11 @@
1
- from typing import Generic, TypeVar
1
+ from typing import TypeVar
2
2
 
3
3
  from pydantic import BaseModel
4
4
 
5
5
  PayloadT = TypeVar("PayloadT")
6
6
 
7
7
 
8
- class Response(BaseModel, Generic[PayloadT]):
8
+ class Response[PayloadT](BaseModel):
9
9
  status: str
10
10
  code: int
11
11
  data: PayloadT
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
4
 
5
- from apexdevkit.http import HttpUrl
5
+ from pypebbles.http import HttpUrl
6
6
 
7
7
 
8
8
  @dataclass
@@ -5,13 +5,13 @@ from typing import Annotated, Any, Protocol, Self, TypeVar
5
5
 
6
6
  from fastapi import APIRouter, Depends, Path, Query
7
7
  from fastapi.responses import JSONResponse
8
+ from pypebbles import FluentDict
8
9
 
9
10
  from apexdevkit.fastapi.name import RestfulName
10
11
  from apexdevkit.fastapi.resource import RestfulResource
11
12
  from apexdevkit.fastapi.response import RestfulResponse
12
13
  from apexdevkit.fastapi.schema import RestfulSchema, Schema, SchemaFields
13
- from apexdevkit.fastapi.service import RawCollection, RawItem, RestfulService
14
- from apexdevkit.fluent import FluentDict
14
+ from apexdevkit.fastapi.service import RawItem, RestfulService
15
15
 
16
16
 
17
17
  class RouterWithHiddenUnderscoreRoutes(APIRouter):
@@ -144,30 +144,6 @@ class RestfulRouter:
144
144
 
145
145
  return self
146
146
 
147
- def with_create_many(
148
- self,
149
- dependency: Dependency | None = None,
150
- is_documented: bool = True,
151
- ) -> Self:
152
- self.router.add_api_route(
153
- "/batch",
154
- self.resource.create_many(
155
- Service=self._resolve(dependency),
156
- Collection=Annotated[
157
- RawCollection,
158
- Depends(self._schema.for_create_many()),
159
- ],
160
- ),
161
- methods=["POST"],
162
- status_code=201,
163
- responses={409: {}},
164
- response_model=self._schema.for_collection(),
165
- include_in_schema=is_documented,
166
- summary="Create Many",
167
- )
168
-
169
- return self
170
-
171
147
  def with_read_one(
172
148
  self,
173
149
  dependency: Dependency | None = None,
@@ -217,50 +193,6 @@ class RestfulRouter:
217
193
 
218
194
  return self
219
195
 
220
- def with_filter(
221
- self,
222
- dependency: Dependency | None = None,
223
- is_documented: bool = True,
224
- ) -> Self:
225
- self.router.add_api_route(
226
- "/filter",
227
- self.resource.filter_with(
228
- Service=self._resolve(dependency),
229
- QueryOptions=Annotated[RawItem, Depends(self._schema.for_filters())],
230
- ),
231
- methods=["POST"],
232
- status_code=200,
233
- responses={},
234
- response_model=self._schema.for_collection(),
235
- include_in_schema=is_documented,
236
- summary="Read Filtered",
237
- )
238
-
239
- return self
240
-
241
- def with_aggregation(
242
- self,
243
- dependency: Dependency | None = None,
244
- is_documented: bool = True,
245
- ) -> Self:
246
- self.router.add_api_route(
247
- "/aggregation",
248
- self.resource.aggregation_with(
249
- Service=self._resolve(dependency),
250
- FilterOptions=Annotated[
251
- RawItem, Depends(self._schema.for_aggregation())
252
- ],
253
- ),
254
- methods=["POST"],
255
- status_code=200,
256
- responses={},
257
- response_model=self._schema.for_aggregation_result(),
258
- include_in_schema=is_documented,
259
- summary="Aggregation",
260
- )
261
-
262
- return self
263
-
264
196
  def with_read_all(
265
197
  self,
266
198
  dependency: Dependency | None = None,
@@ -307,30 +239,6 @@ class RestfulRouter:
307
239
 
308
240
  return self
309
241
 
310
- def with_update_many(
311
- self,
312
- dependency: Dependency | None = None,
313
- is_documented: bool = True,
314
- ) -> Self:
315
- self.router.add_api_route(
316
- "",
317
- self.resource.update_many(
318
- Service=self._resolve(dependency),
319
- Collection=Annotated[
320
- RawCollection,
321
- Depends(self._schema.for_update_many()),
322
- ],
323
- ),
324
- methods=["PATCH"],
325
- status_code=200,
326
- responses={},
327
- response_model=self._schema.for_no_data(),
328
- include_in_schema=is_documented,
329
- summary="Update Many",
330
- )
331
-
332
- return self
333
-
334
242
  def with_replace_one(
335
243
  self,
336
244
  dependency: Dependency | None = None,
@@ -355,30 +263,6 @@ class RestfulRouter:
355
263
 
356
264
  return self
357
265
 
358
- def with_replace_many(
359
- self,
360
- dependency: Dependency | None = None,
361
- is_documented: bool = True,
362
- ) -> Self:
363
- self.router.add_api_route(
364
- "/batch",
365
- self.resource.replace_many(
366
- Service=self._resolve(dependency),
367
- Collection=Annotated[
368
- RawCollection,
369
- Depends(self._schema.for_replace_many()),
370
- ],
371
- ),
372
- methods=["PUT"],
373
- status_code=200,
374
- responses={},
375
- response_model=self._schema.for_no_data(),
376
- include_in_schema=is_documented,
377
- summary="Replace Many",
378
- )
379
-
380
- return self
381
-
382
266
  def with_delete_one(
383
267
  self,
384
268
  dependency: Dependency | None = None,
@@ -412,11 +296,9 @@ class RestfulRouter:
412
296
  def default(self) -> Self:
413
297
  return (
414
298
  self.with_create_one()
415
- .with_create_many()
416
299
  .with_read_one()
417
300
  .with_read_all()
418
301
  .with_update_one()
419
- .with_update_many()
420
302
  .with_delete_one()
421
303
  )
422
304
 
@@ -1,20 +1,13 @@
1
1
  from abc import ABC, abstractmethod
2
- from collections.abc import Callable, Iterable, Iterator
2
+ from collections.abc import Callable, Iterator
3
3
  from dataclasses import dataclass
4
4
  from functools import cached_property
5
5
  from typing import Any
6
6
 
7
7
  from pydantic import BaseModel, create_model
8
+ from pypebbles import FluentDict
8
9
 
9
10
  from apexdevkit.fastapi.name import RestfulName
10
- from apexdevkit.fluent import FluentDict
11
- from apexdevkit.http import JsonDict
12
- from apexdevkit.value import Value
13
-
14
-
15
- class AggregationResult(BaseModel):
16
- field: str
17
- aggregation: Value
18
11
 
19
12
 
20
13
  class SchemaFields(ABC):
@@ -27,15 +20,6 @@ class SchemaFields(ABC):
27
20
  def editable(self) -> FluentDict[type]:
28
21
  return self.readable().drop("id")
29
22
 
30
- def filters(self) -> FluentDict[type]:
31
- return JsonDict()
32
-
33
- def aggregation_filters(self) -> FluentDict[type]:
34
- return JsonDict()
35
-
36
- def aggregation_result(self) -> FluentDict[type]:
37
- return JsonDict().with_a(count=int).and_a(sums=list[AggregationResult])
38
-
39
23
  @abstractmethod
40
24
  def readable(self) -> FluentDict[type]: # pragma: no cover
41
25
  pass
@@ -49,21 +33,22 @@ class RestfulSchema:
49
33
 
50
34
  def __post_init__(self) -> None:
51
35
  schema = self._schema_for("", self.fields.readable())
52
- create_schema = self._schema_for("Create", self.fields.writable())
53
- self._schema_for("Update", self.fields.editable())
54
- replace_schema = self._schema_for("Replace", self.fields.readable())
55
- update_many_item = self._schema_for(
56
- "UpdateManyItem", self.fields.editable().merge(self.fields.id())
36
+ self._schema_for(
37
+ "Item",
38
+ {
39
+ self.name.singular: schema,
40
+ },
57
41
  )
58
- self._schema_for("Filter", self.fields.filters())
59
- self._schema_for("Aggregation", self.fields.aggregation_filters())
60
- self._schema_for("AggregationResult", self.fields.aggregation_result())
61
-
62
- self._schema_for("Item", {self.name.singular: schema})
63
- self._schema_for("Collection", {self.name.plural: list[schema], "count": int})
64
- self._schema_for("CreateMany", {self.name.plural: list[create_schema]})
65
- self._schema_for("UpdateMany", {self.name.plural: list[update_many_item]})
66
- self._schema_for("ReplaceMany", {self.name.plural: list[replace_schema]})
42
+ self._schema_for(
43
+ "Collection",
44
+ {
45
+ self.name.plural: list[schema],
46
+ "count": int,
47
+ },
48
+ )
49
+ self._schema_for("Create", self.fields.writable())
50
+ self._schema_for("Update", self.fields.editable())
51
+ self._schema_for("Replace", self.fields.readable())
67
52
 
68
53
  def _schema_for(self, action: str, fields: dict[str, Any]) -> type[BaseModel]:
69
54
  if action not in self._models:
@@ -113,14 +98,6 @@ class RestfulSchema:
113
98
 
114
99
  return _
115
100
 
116
- def for_create_many(self) -> Callable[[BaseModel], Iterable[dict[str, Any]]]:
117
- schema = self._models["CreateMany"]
118
-
119
- def _(request: schema) -> Iterable[dict[str, Any]]:
120
- return [dict(item) for item in request.model_dump()[self.name.plural]]
121
-
122
- return _
123
-
124
101
  def for_update_one(self) -> Callable[[BaseModel], dict[str, Any]]:
125
102
  schema = self._models["Update"]
126
103
 
@@ -129,14 +106,6 @@ class RestfulSchema:
129
106
 
130
107
  return _
131
108
 
132
- def for_update_many(self) -> Callable[[BaseModel], Iterable[dict[str, Any]]]:
133
- schema = self._models["UpdateMany"]
134
-
135
- def _(request: schema) -> Iterable[dict[str, Any]]:
136
- return [dict(item) for item in request.model_dump()[self.name.plural]]
137
-
138
- return _
139
-
140
109
  def for_replace_one(self) -> Callable[[BaseModel], dict[str, Any]]:
141
110
  schema = self._models["Replace"]
142
111
 
@@ -145,39 +114,6 @@ class RestfulSchema:
145
114
 
146
115
  return _
147
116
 
148
- def for_replace_many(self) -> Callable[[BaseModel], Iterable[dict[str, Any]]]:
149
- schema = self._models["ReplaceMany"]
150
-
151
- def _(request: schema) -> Iterable[dict[str, Any]]:
152
- return [dict(item) for item in request.model_dump()[self.name.plural]]
153
-
154
- return _
155
-
156
- def for_filters(self) -> Callable[[BaseModel], dict[str, Any]]:
157
- schema = self._models["Filter"]
158
-
159
- def _(request: schema) -> dict[str, Any]:
160
- return request.model_dump()
161
-
162
- return _
163
-
164
- def for_aggregation(self) -> Callable[[BaseModel], dict[str, Any]]:
165
- schema = self._models["Aggregation"]
166
-
167
- def _(request: schema) -> dict[str, Any]:
168
- return request.model_dump()
169
-
170
- return _
171
-
172
- def for_aggregation_result(self) -> type[BaseModel]:
173
- return self._schema_for(
174
- "AggregationResultResponse",
175
- FluentDict[type]()
176
- .with_a(status=str)
177
- .and_a(code=int)
178
- .and_a(aggregations=self._models["AggregationResult"]),
179
- )
180
-
181
117
 
182
118
  @dataclass(frozen=True)
183
119
  class Schema:
@@ -3,11 +3,10 @@ from __future__ import annotations
3
3
  from collections.abc import Iterable, Mapping
4
4
  from dataclasses import dataclass
5
5
  from functools import cached_property
6
- from typing import Any, Generic
6
+ from typing import Any
7
7
 
8
8
  from apexdevkit.formatter import Formatter
9
- from apexdevkit.repository import BruteForceBatch, Repository
10
- from apexdevkit.repository.core import ItemT
9
+ from apexdevkit.repository import BruteForceBatch, Entity, Repository
11
10
  from apexdevkit.repository.core.interface import BatchRepository
12
11
 
13
12
  RawItem = Mapping[str, Any]
@@ -61,7 +60,7 @@ class RestfulService: # pragma: no cover
61
60
 
62
61
 
63
62
  @dataclass(frozen=True)
64
- class RestfulRepository(RestfulService, Generic[ItemT]):
63
+ class RestfulRepository[ItemT: Entity](RestfulService):
65
64
  repository: Repository[ItemT]
66
65
 
67
66
  formatter: Formatter[Mapping[str, Any], ItemT]
@@ -4,34 +4,29 @@ import pickle
4
4
  from collections.abc import Mapping
5
5
  from copy import deepcopy
6
6
  from dataclasses import asdict, dataclass, field, fields, is_dataclass
7
- from typing import Any, Generic, Protocol, Self, TypeVar, get_args, get_type_hints
7
+ from typing import Any, Protocol, Self, get_args, get_type_hints
8
8
 
9
- from apexdevkit.fluent import FluentDict
10
- from apexdevkit.value import Value
9
+ from pypebbles import FluentDict
11
10
 
12
- _SourceT = TypeVar("_SourceT")
13
- _TargetT = TypeVar("_TargetT")
14
- _ItemT = TypeVar("_ItemT")
15
11
 
16
-
17
- class Formatter(Protocol[_SourceT, _TargetT]): # pragma: no cover
18
- def load(self, source: _SourceT) -> _TargetT:
12
+ class Formatter[SourceT, TargetT](Protocol): # pragma: no cover
13
+ def load(self, source: SourceT) -> TargetT:
19
14
  pass
20
15
 
21
- def dump(self, target: _TargetT) -> _SourceT:
16
+ def dump(self, target: TargetT) -> SourceT:
22
17
  pass
23
18
 
24
19
 
25
20
  @dataclass(frozen=True)
26
- class AliasFormatter(Formatter[Mapping[str, Any], _TargetT]):
27
- inner: Formatter[Mapping[str, Any], _TargetT]
21
+ class AliasFormatter[TargetT](Formatter[Mapping[str, Any], TargetT]):
22
+ inner: Formatter[Mapping[str, Any], TargetT]
28
23
 
29
24
  alias: AliasMapping
30
25
 
31
- def load(self, source: Mapping[str, Any]) -> _TargetT:
26
+ def load(self, source: Mapping[str, Any]) -> TargetT:
32
27
  return self.inner.load(self.alias.reverse().translate(source))
33
28
 
34
- def dump(self, target: _TargetT) -> Mapping[str, Any]:
29
+ def dump(self, target: TargetT) -> Mapping[str, Any]:
35
30
  return self.alias.translate(self.inner.dump(target))
36
31
 
37
32
 
@@ -53,28 +48,28 @@ class AliasMapping:
53
48
  return self.alias.get(key, key)
54
49
 
55
50
 
56
- class PickleFormatter(Generic[_ItemT]):
57
- def dump(self, item: _ItemT) -> bytes:
51
+ class PickleFormatter[ItemT]:
52
+ def dump(self, item: ItemT) -> bytes:
58
53
  return pickle.dumps(item)
59
54
 
60
- def load(self, raw: bytes) -> _ItemT:
55
+ def load(self, raw: bytes) -> ItemT:
61
56
  return pickle.loads(raw) # type: ignore
62
57
 
63
58
 
64
59
  @dataclass
65
- class ListFormatter(Generic[_SourceT, _TargetT]):
66
- inner: Formatter[_SourceT, _TargetT]
60
+ class ListFormatter[SourceT, TargetT]:
61
+ inner: Formatter[SourceT, TargetT]
67
62
 
68
- def load(self, source: list[_SourceT]) -> list[_TargetT]:
63
+ def load(self, source: list[SourceT]) -> list[TargetT]:
69
64
  return [self.inner.load(item) for item in source]
70
65
 
71
- def dump(self, target: list[_TargetT]) -> list[_SourceT]:
66
+ def dump(self, target: list[TargetT]) -> list[SourceT]:
72
67
  return [self.inner.dump(item) for item in target]
73
68
 
74
69
 
75
70
  @dataclass
76
- class DataclassFormatter(Generic[_TargetT]):
77
- resource: type[_TargetT]
71
+ class DataclassFormatter[TargetT]:
72
+ resource: type[TargetT]
78
73
  sub_formatters: dict[str, Formatter[Any, Any]] = field(default_factory=dict)
79
74
 
80
75
  def and_nested(self, **formatters: Formatter[Any, Any]) -> Self:
@@ -85,7 +80,7 @@ class DataclassFormatter(Generic[_TargetT]):
85
80
 
86
81
  return self
87
82
 
88
- def load(self, source: Mapping[str, Any]) -> _TargetT:
83
+ def load(self, source: Mapping[str, Any]) -> TargetT:
89
84
  source = FluentDict[Any](deepcopy(source)).select(
90
85
  *self.resource.__annotations__.keys(),
91
86
  "id",
@@ -114,13 +109,5 @@ class DataclassFormatter(Generic[_TargetT]):
114
109
 
115
110
  return self.resource(**source)
116
111
 
117
- def dump(self, target: _TargetT) -> Mapping[str, Any]:
112
+ def dump(self, target: TargetT) -> Mapping[str, Any]:
118
113
  return asdict(target) # type: ignore
119
-
120
-
121
- class ValueFormatter:
122
- def load(self, raw: Mapping[str, Any]) -> Value:
123
- return DataclassFormatter(Value).load(raw)
124
-
125
- def dump(self, value: Value) -> Mapping[str, Any]:
126
- return DataclassFormatter(Value).dump(value)
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from collections import defaultdict
4
4
  from collections.abc import Iterable, Mapping
5
5
  from dataclasses import dataclass, field
6
- from typing import Any, ClassVar, Generic, Protocol, TypeVar
6
+ from typing import Any, ClassVar, Protocol, TypeVar
7
7
 
8
8
  from apexdevkit.annotation import deprecated
9
9
  from apexdevkit.error import ForbiddenError
@@ -33,7 +33,7 @@ class _Loader(Protocol[ItemT]):
33
33
 
34
34
 
35
35
  @dataclass
36
- class DefaultMsSqlFilter(Generic[ItemT]):
36
+ class DefaultMsSqlFilter[ItemT]:
37
37
  _database: Database = field(init=False)
38
38
  _query_builder: MsSqlQueryBuilder = field(init=False)
39
39
  _options: QueryOptions = field(init=False)
@@ -1,10 +1,10 @@
1
- from typing import Generic
1
+ from typing import Any
2
2
 
3
3
  from apexdevkit.error import DoesNotExistError
4
- from apexdevkit.repository.core import Entity, ItemT
4
+ from apexdevkit.repository.core import Entity
5
5
 
6
6
 
7
- class ContainsMixin(Generic[ItemT]):
7
+ class ContainsMixin:
8
8
  def __contains__(self, item: object) -> bool:
9
9
  match item:
10
10
  case Entity():
@@ -20,5 +20,5 @@ class ContainsMixin(Generic[ItemT]):
20
20
 
21
21
  return True
22
22
 
23
- def read(self, item_id: str) -> ItemT:
23
+ def read(self, item_id: str) -> Any:
24
24
  raise NotImplementedError
@@ -12,7 +12,7 @@ from .store import InMemoryByteStore, KeyValueStore
12
12
 
13
13
 
14
14
  @dataclass(frozen=True)
15
- class InMemoryRepository(ContainsMixin[ItemT], Repository[ItemT]):
15
+ class InMemoryRepository(ContainsMixin, Repository[ItemT]):
16
16
  store: KeyValueStore[ItemT] = field(default_factory=InMemoryByteStore)
17
17
  keys: list[KeyFn[ItemT]] = field(default_factory=lambda: [AttributeKey("id")])
18
18
 
@@ -2,13 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Iterable
4
4
  from dataclasses import dataclass, field
5
- from typing import Generic, Protocol
5
+ from typing import Protocol
6
6
 
7
7
  from apexdevkit.formatter import Formatter, PickleFormatter
8
- from apexdevkit.repository.core.interface import ItemT
9
8
 
10
9
 
11
- class KeyValueStore(Protocol[ItemT]): # pragma: no cover
10
+ class KeyValueStore[ItemT](Protocol): # pragma: no cover
12
11
  def count(self) -> int:
13
12
  pass
14
13
 
@@ -25,8 +24,8 @@ class KeyValueStore(Protocol[ItemT]): # pragma: no cover
25
24
  pass
26
25
 
27
26
 
28
- @dataclass
29
- class InMemoryByteStore(Generic[ItemT]):
27
+ @dataclass(frozen=True)
28
+ class InMemoryByteStore[ItemT]:
30
29
  formatter: Formatter[bytes, ItemT] = field(default_factory=PickleFormatter)
31
30
 
32
31
  items: dict[str, bytes] = field(default_factory=dict)