apexdevkit 2.2.1__tar.gz → 2.3.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 (52) hide show
  1. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/PKG-INFO +1 -1
  2. apexdevkit-2.3.2/apexdevkit/fastapi/__init__.py +15 -0
  3. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/fastapi/builder.py +4 -39
  4. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/fastapi/dependable.py +6 -14
  5. apexdevkit-2.2.1/apexdevkit/fastapi/resource.py → apexdevkit-2.3.2/apexdevkit/fastapi/endpoints.py +1 -1
  6. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/fastapi/router.py +28 -26
  7. apexdevkit-2.3.2/apexdevkit/fastapi/service.py +137 -0
  8. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/formatter.py +9 -3
  9. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/testing.py +3 -2
  10. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/pyproject.toml +3 -3
  11. apexdevkit-2.2.1/apexdevkit/fastapi/__init__.py +0 -13
  12. apexdevkit-2.2.1/apexdevkit/fastapi/service.py +0 -68
  13. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/LICENSE +0 -0
  14. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/README.md +0 -0
  15. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/__init__.py +0 -0
  16. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/annotation/__init__.py +0 -0
  17. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/annotation/deprecate.py +0 -0
  18. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/date.py +0 -0
  19. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/error.py +0 -0
  20. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/fastapi/name.py +0 -0
  21. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/fastapi/response.py +0 -0
  22. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/fastapi/schema.py +0 -0
  23. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/key_fn.py +0 -0
  24. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/py.typed +0 -0
  25. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/query/__init__.py +0 -0
  26. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/query/generator.py +0 -0
  27. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/query/query.py +0 -0
  28. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/__init__.py +0 -0
  29. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/core/__init__.py +0 -0
  30. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/core/database.py +0 -0
  31. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/core/decorator.py +0 -0
  32. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/core/interface.py +0 -0
  33. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/core/mixin.py +0 -0
  34. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/in_memory/__init__.py +0 -0
  35. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/in_memory/mixin.py +0 -0
  36. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/in_memory/repository.py +0 -0
  37. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/in_memory/store.py +0 -0
  38. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/__init__.py +0 -0
  39. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/connector.py +0 -0
  40. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/field.py +0 -0
  41. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/mssql/__init__.py +0 -0
  42. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/mssql/repository.py +0 -0
  43. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/mssql/table.py +0 -0
  44. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/sqlite/__init__.py +0 -0
  45. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/sqlite/repository.py +0 -0
  46. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/repository/sql/sqlite/table.py +0 -0
  47. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/server.py +0 -0
  48. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/sync/__init__.py +0 -0
  49. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/sync/observer.py +0 -0
  50. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/sync/source.py +0 -0
  51. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/sync/sync.py +0 -0
  52. {apexdevkit-2.2.1 → apexdevkit-2.3.2}/apexdevkit/sync/target.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apexdevkit
3
- Version: 2.2.1
3
+ Version: 2.3.2
4
4
  Summary: Apex Development Tools for python.
5
5
  License-File: LICENSE
6
6
  Author: Apex Dev
@@ -0,0 +1,15 @@
1
+ from apexdevkit.fastapi.builder import FastApiBuilder
2
+ from apexdevkit.fastapi.router import RestfulRouter
3
+ from apexdevkit.fastapi.service import (
4
+ RestfulRepository,
5
+ RestfulResource,
6
+ RestfulService,
7
+ )
8
+
9
+ __all__ = [
10
+ "FastApiBuilder",
11
+ "RestfulRepository",
12
+ "RestfulResource",
13
+ "RestfulRouter",
14
+ "RestfulService",
15
+ ]
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from abc import ABC, abstractmethod
4
3
  from dataclasses import dataclass, field
5
4
  from typing import TYPE_CHECKING, Any, Protocol, Self
6
5
 
@@ -10,13 +9,10 @@ from fastapi.responses import JSONResponse
10
9
 
11
10
  from apexdevkit.annotation import deprecated
12
11
  from apexdevkit.error import ApiError
13
- from apexdevkit.fastapi.dependable import DependableBuilder
14
12
 
15
13
  if TYPE_CHECKING:
16
14
  from collections.abc import Mapping, MutableSet
17
15
 
18
- from apexdevkit.fastapi.service import RestfulService
19
-
20
16
 
21
17
  @dataclass
22
18
  class FastApiBuilder:
@@ -57,7 +53,7 @@ class FastApiBuilder:
57
53
  for key, value in values.items():
58
54
  self.app.include_router(
59
55
  value,
60
- prefix=_Endpoint(key).normilized(),
56
+ prefix=_Endpoint(key).normalized(),
61
57
  tags=value.tags or [key.title()],
62
58
  )
63
59
 
@@ -65,7 +61,7 @@ class FastApiBuilder:
65
61
 
66
62
  def with_mounted(self, **apps: FastAPI) -> Self:
67
63
  for path, app in apps.items():
68
- self.app.mount(_Endpoint(path).normilized(), app)
64
+ self.app.mount(_Endpoint(path).normalized(), app)
69
65
 
70
66
  return self
71
67
 
@@ -125,43 +121,12 @@ class CORSApplicator:
125
121
  )
126
122
 
127
123
 
128
- @dataclass
129
- class RestfulServiceBuilder(ABC):
130
- parent_id: str = field(init=False)
131
- user: Any = field(init=False)
132
-
133
- def as_dependable(self) -> DependableBuilder:
134
- return DependableBuilder.from_builder(self)
135
-
136
- def with_user(self, user: Any) -> RestfulServiceBuilder:
137
- self.user = user
138
-
139
- return self
140
-
141
- def with_parent(self, identity: str) -> RestfulServiceBuilder:
142
- self.parent_id = identity
143
-
144
- return self
145
-
146
- @abstractmethod
147
- def build(self) -> RestfulService: # pragma: no cover
148
- pass
149
-
150
-
151
- @dataclass
152
- class PreBuilt(RestfulServiceBuilder): # pragma: no cover
153
- service: RestfulService
154
-
155
- def build(self) -> RestfulService:
156
- return self.service
157
-
158
-
159
124
  @dataclass(frozen=True)
160
125
  class _Endpoint:
161
126
  raw: str
162
127
 
163
- def normilized(self) -> str:
128
+ def normalized(self) -> str:
164
129
  return f"/{self.raw.replace('_', '-')}"
165
130
 
166
131
  def __str__(self) -> str: # pragma: no cover
167
- return self.normilized()
132
+ return self.normalized()
@@ -3,19 +3,11 @@ from dataclasses import dataclass
3
3
  from typing import Annotated, Any, Protocol
4
4
 
5
5
  from fastapi import Depends, Path
6
- from fastapi.requests import Request
7
6
 
8
7
  from apexdevkit.error import ApiError, DoesNotExistError, ForbiddenError
9
8
  from apexdevkit.fastapi.name import RestfulName
10
9
  from apexdevkit.fastapi.response import RestfulResponse
11
- from apexdevkit.fastapi.service import RestfulService
12
-
13
-
14
- def inject(dependency: str) -> Any: # pragma: no cover
15
- def get(request: Request) -> Any:
16
- return getattr(request.app.state, dependency)
17
-
18
- return Depends(get)
10
+ from apexdevkit.fastapi.service import RestfulResource
19
11
 
20
12
 
21
13
  class _ServiceBuilder(Protocol):
@@ -25,7 +17,7 @@ class _ServiceBuilder(Protocol):
25
17
  def with_parent(self, identity: str) -> "_ServiceBuilder":
26
18
  pass
27
19
 
28
- def build(self) -> RestfulService: # pragma: no cover
20
+ def build(self) -> RestfulResource: # pragma: no cover
29
21
  pass
30
22
 
31
23
 
@@ -38,10 +30,10 @@ class _Dependency(Protocol):
38
30
  class ServiceDependency:
39
31
  dependency: _Dependency
40
32
 
41
- def as_dependable(self) -> type[RestfulService]:
33
+ def as_dependable(self) -> type[RestfulResource]:
42
34
  Builder = self.dependency.as_dependable()
43
35
 
44
- def _(builder: Builder) -> RestfulService:
36
+ def _(builder: Builder) -> RestfulResource:
45
37
  try:
46
38
  return builder.build()
47
39
  except ForbiddenError as e:
@@ -49,7 +41,7 @@ class ServiceDependency:
49
41
  403, RestfulResponse(RestfulName("unknown")).forbidden(e)
50
42
  ) from e
51
43
 
52
- return Annotated[RestfulService, Depends(_)]
44
+ return Annotated[RestfulResource, Depends(_)]
53
45
 
54
46
 
55
47
  @dataclass(frozen=True)
@@ -119,5 +111,5 @@ class DependableBuilder:
119
111
  def with_user(self, extract_user: Callable[..., Any]) -> "DependableBuilder":
120
112
  return DependableBuilder(UserDependency(extract_user, self.dependency))
121
113
 
122
- def as_dependable(self) -> type[RestfulService]:
114
+ def as_dependable(self) -> type[RestfulResource]:
123
115
  return ServiceDependency(self.dependency).as_dependable()
@@ -12,7 +12,7 @@ _Endpoint = Callable[..., _Response]
12
12
 
13
13
 
14
14
  @dataclass(frozen=True)
15
- class RestfulResource:
15
+ class RestfulEndpoints:
16
16
  response: RestfulResponse
17
17
 
18
18
  def create_one_endpoint(self, Service, Item) -> _Endpoint:
@@ -1,4 +1,4 @@
1
- from collections.abc import Callable
1
+ from collections.abc import Callable, Mapping
2
2
  from dataclasses import dataclass, field
3
3
  from enum import Enum
4
4
  from typing import Annotated, Any, Protocol, Self
@@ -7,11 +7,13 @@ from fastapi import APIRouter, Depends, Path, Query
7
7
  from fastapi.responses import JSONResponse
8
8
  from pypebbles import FluentDict
9
9
 
10
+ from apexdevkit.fastapi.endpoints import RestfulEndpoints
10
11
  from apexdevkit.fastapi.name import RestfulName
11
- from apexdevkit.fastapi.resource import RestfulResource
12
12
  from apexdevkit.fastapi.response import RestfulResponse
13
13
  from apexdevkit.fastapi.schema import RestfulSchema, Schema, SchemaFields
14
- from apexdevkit.fastapi.service import RawItem, RestfulService
14
+ from apexdevkit.fastapi.service import RestfulResource
15
+
16
+ RawItem = Mapping[str, Any]
15
17
 
16
18
 
17
19
  class RouterWithHiddenUnderscoreRoutes(APIRouter):
@@ -48,23 +50,23 @@ class RouterWithHiddenUnderscoreRoutes(APIRouter):
48
50
  _Response = JSONResponse | dict[str, Any]
49
51
 
50
52
 
51
- class Dependency(Protocol): # pragma: no cover
52
- def as_dependable(self) -> type[RestfulService]:
53
+ class Dependency[T](Protocol): # pragma: no cover
54
+ def as_dependable(self) -> type[RestfulResource[T]]:
53
55
  pass
54
56
 
55
57
 
56
58
  @dataclass
57
- class RestfulRouter:
59
+ class RestfulRouter[T]:
58
60
  name: RestfulName
59
61
 
60
62
  parent: RestfulName | None = None
61
63
  router: APIRouter = field(default_factory=RouterWithHiddenUnderscoreRoutes)
62
64
 
63
65
  _schema: RestfulSchema = field(init=False)
64
- _dependency: Dependency | None = field(init=False, default=None)
66
+ _dependency: Dependency[T] | None = field(init=False, default=None)
65
67
 
66
68
  @classmethod
67
- def named(cls, singular: str, *, plural: str | None = None) -> "RestfulRouter":
69
+ def named(cls, singular: str, *, plural: str | None = None) -> "RestfulRouter[T]":
68
70
  if plural:
69
71
  return cls(RestfulName(singular, plural))
70
72
 
@@ -79,8 +81,8 @@ class RestfulRouter:
79
81
  return self
80
82
 
81
83
  @property
82
- def resource(self) -> RestfulResource:
83
- return RestfulResource(RestfulResponse(self.name))
84
+ def endpoints(self) -> RestfulEndpoints:
85
+ return RestfulEndpoints(RestfulResponse(self.name))
84
86
 
85
87
  @property
86
88
  def id_alias(self) -> str:
@@ -113,20 +115,20 @@ class RestfulRouter:
113
115
 
114
116
  return self
115
117
 
116
- def with_default_dependency(self, value: Dependency) -> Self:
118
+ def with_default_dependency(self, value: Dependency[T]) -> Self:
117
119
  self._dependency = value
118
120
 
119
121
  return self
120
122
 
121
123
  def with_create_one(
122
124
  self,
123
- dependency: Dependency | None = None,
125
+ dependency: Dependency[T] | None = None,
124
126
  *,
125
127
  is_documented: bool = True,
126
128
  ) -> Self:
127
129
  self.router.add_api_route(
128
130
  "",
129
- self.resource.create_one_endpoint(
131
+ self.endpoints.create_one_endpoint(
130
132
  Service=self._resolve(dependency),
131
133
  Item=Annotated[
132
134
  RawItem,
@@ -145,13 +147,13 @@ class RestfulRouter:
145
147
 
146
148
  def with_read_one(
147
149
  self,
148
- dependency: Dependency | None = None,
150
+ dependency: Dependency[T] | None = None,
149
151
  *,
150
152
  is_documented: bool = True,
151
153
  ) -> Self:
152
154
  self.router.add_api_route(
153
155
  self.item_path,
154
- self.resource.read_one_endpoint(
156
+ self.endpoints.read_one_endpoint(
155
157
  Service=self._resolve(dependency),
156
158
  ItemId=Annotated[
157
159
  str,
@@ -171,13 +173,13 @@ class RestfulRouter:
171
173
  def with_read_many(
172
174
  self,
173
175
  query: FluentDict[Any],
174
- dependency: Dependency | None = None,
176
+ dependency: Dependency[T] | None = None,
175
177
  *,
176
178
  is_documented: bool = True,
177
179
  ) -> Self:
178
180
  self.router.add_api_route(
179
181
  "",
180
- self.resource.read_many_endpoint(
182
+ self.endpoints.read_many_endpoint(
181
183
  Service=self._resolve(dependency),
182
184
  QueryParams=Annotated[
183
185
  Schema(self.name.singular).optional_schema_for(
@@ -199,13 +201,13 @@ class RestfulRouter:
199
201
 
200
202
  def with_read_all(
201
203
  self,
202
- dependency: Dependency | None = None,
204
+ dependency: Dependency[T] | None = None,
203
205
  *,
204
206
  is_documented: bool = True,
205
207
  ) -> Self:
206
208
  self.router.add_api_route(
207
209
  "",
208
- self.resource.read_all_endpoint(
210
+ self.endpoints.read_all_endpoint(
209
211
  Service=self._resolve(dependency),
210
212
  ),
211
213
  methods=["GET"],
@@ -220,13 +222,13 @@ class RestfulRouter:
220
222
 
221
223
  def with_update_one(
222
224
  self,
223
- dependency: Dependency | None = None,
225
+ dependency: Dependency[T] | None = None,
224
226
  *,
225
227
  is_documented: bool = True,
226
228
  ) -> Self:
227
229
  self.router.add_api_route(
228
230
  self.item_path,
229
- self.resource.update_one_endpoint(
231
+ self.endpoints.update_one_endpoint(
230
232
  Service=self._resolve(dependency),
231
233
  ItemId=Annotated[
232
234
  str,
@@ -249,13 +251,13 @@ class RestfulRouter:
249
251
 
250
252
  def with_replace_one(
251
253
  self,
252
- dependency: Dependency | None = None,
254
+ dependency: Dependency[T] | None = None,
253
255
  *,
254
256
  is_documented: bool = True,
255
257
  ) -> Self:
256
258
  self.router.add_api_route(
257
259
  "",
258
- self.resource.replace_one_endpoint(
260
+ self.endpoints.replace_one_endpoint(
259
261
  Service=self._resolve(dependency),
260
262
  Item=Annotated[
261
263
  RawItem,
@@ -274,13 +276,13 @@ class RestfulRouter:
274
276
 
275
277
  def with_delete_one(
276
278
  self,
277
- dependency: Dependency | None = None,
279
+ dependency: Dependency[T] | None = None,
278
280
  *,
279
281
  is_documented: bool = True,
280
282
  ) -> Self:
281
283
  self.router.add_api_route(
282
284
  self.item_path,
283
- self.resource.delete_one_endpoint(
285
+ self.endpoints.delete_one_endpoint(
284
286
  Service=self._resolve(dependency),
285
287
  ItemId=Annotated[
286
288
  str,
@@ -315,7 +317,7 @@ class RestfulRouter:
315
317
  def build(self) -> APIRouter:
316
318
  return self.router
317
319
 
318
- def _resolve(self, dependency: Dependency | None) -> type[RestfulService]:
320
+ def _resolve(self, dependency: Dependency[T] | None) -> type[RestfulResource[T]]:
319
321
  resolved = dependency or self._dependency
320
322
  assert resolved, "One of default or endpoint dependency must be specified"
321
323
 
@@ -0,0 +1,137 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from dataclasses import dataclass, field
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from pypebbles import JsonDict
8
+
9
+ if TYPE_CHECKING:
10
+ from collections.abc import Iterable, Mapping
11
+
12
+ from apexdevkit.formatter import Formatter
13
+ from apexdevkit.repository import Entity, Repository
14
+
15
+
16
+ @dataclass(frozen=True, kw_only=True)
17
+ class RestfulResource[T]:
18
+ service: RestfulService[T]
19
+ formatter: Formatter[Mapping[str, Any], T]
20
+
21
+ def create_one(self, item: Mapping[str, Any]) -> Mapping[str, Any]:
22
+ result = self.service.create_one(self.formatter.load(item))
23
+
24
+ return self.formatter.dump(result)
25
+
26
+ def read_one(self, item_id: str) -> Mapping[str, Any]:
27
+ result = self.service.read_one(with_id=item_id)
28
+
29
+ return self.formatter.dump(result)
30
+
31
+ def read_all(self) -> Iterable[Mapping[str, Any]]:
32
+ result = self.service.read_all()
33
+
34
+ return [self.formatter.dump(item) for item in result]
35
+
36
+ def read_many(self, **params: Any) -> Iterable[Mapping[str, Any]]:
37
+ result = self.service.read_many(JsonDict(params))
38
+
39
+ return [self.formatter.dump(item) for item in result]
40
+
41
+ def update_one(self, item_id: str, **with_fields: Any) -> Mapping[str, Any]:
42
+ current = self.service.read_one(with_id=item_id)
43
+ updated = {**self.formatter.dump(current), **with_fields}
44
+ result = self.service.update_one(self.formatter.load(updated))
45
+
46
+ return self.formatter.dump(result)
47
+
48
+ def replace_one(self, item: Mapping[str, Any]) -> Mapping[str, Any]:
49
+ result = self.service.update_one(self.formatter.load(item))
50
+
51
+ return self.formatter.dump(result)
52
+
53
+ def delete_one(self, item_id: str) -> None:
54
+ self.service.delete_one(with_id=item_id)
55
+
56
+ @dataclass(kw_only=True)
57
+ class Builder[BT](ABC):
58
+ formatter: Formatter[Mapping[str, Any], BT]
59
+
60
+ parent_id: str = field(init=False)
61
+ user: Any = field(init=False)
62
+
63
+ def with_user(self, user: Any) -> RestfulResource.Builder[BT]:
64
+ self.user = user
65
+
66
+ return self
67
+
68
+ def with_parent(self, identity: str) -> RestfulResource.Builder[BT]:
69
+ self.parent_id = identity
70
+
71
+ return self
72
+
73
+ def build(self) -> RestfulResource[BT]:
74
+ return RestfulResource(
75
+ service=self.service(),
76
+ formatter=self.formatter,
77
+ )
78
+
79
+ @abstractmethod
80
+ def service(self) -> RestfulService[BT]:
81
+ pass
82
+
83
+ @dataclass(kw_only=True)
84
+ class PreBuilt[PBT](Builder[PBT]): # pragma: no cover
85
+ instance: RestfulService[PBT]
86
+
87
+ def service(self) -> RestfulService[PBT]:
88
+ return self.instance
89
+
90
+
91
+ class RestfulService[T]:
92
+ def create_one(self, item: T) -> T:
93
+ raise NotImplementedError
94
+
95
+ def read_one(self, *, with_id: str) -> T:
96
+ raise NotImplementedError
97
+
98
+ def read_all(self) -> Iterable[T]:
99
+ raise NotImplementedError
100
+
101
+ def read_many(self, query: JsonDict) -> Iterable[T]:
102
+ raise NotImplementedError
103
+
104
+ def update_one(self, item: T) -> T:
105
+ raise NotImplementedError
106
+
107
+ def delete_one(self, with_id: str) -> T:
108
+ raise NotImplementedError
109
+
110
+
111
+ @dataclass(frozen=True)
112
+ class RestfulRepository[T: Entity](RestfulService[T]):
113
+ repository: Repository[T]
114
+
115
+ def create_one(self, item: T) -> T:
116
+ return self.repository.create(item)
117
+
118
+ def read_one(self, *, with_id: str) -> T:
119
+ return self.repository.read(with_id)
120
+
121
+ def read_all(self) -> Iterable[T]:
122
+ yield from self.repository
123
+
124
+ def read_many(self, query: JsonDict) -> Iterable[T]:
125
+ raise NotImplementedError
126
+
127
+ def update_one(self, item: T) -> T:
128
+ self.repository.update(item)
129
+
130
+ return item
131
+
132
+ def delete_one(self, with_id: str) -> T:
133
+ result = self.repository.read(with_id)
134
+
135
+ self.repository.delete(with_id)
136
+
137
+ return result
@@ -17,6 +17,14 @@ class Formatter[SourceT, TargetT](Protocol): # pragma: no cover
17
17
  pass
18
18
 
19
19
 
20
+ class NoFormatter[S, T]:
21
+ def load(self, source: S) -> T:
22
+ raise NotImplementedError
23
+
24
+ def dump(self, target: T) -> S:
25
+ raise NotImplementedError
26
+
27
+
20
28
  @dataclass(frozen=True)
21
29
  class AliasFormatter[TargetT](Formatter[Mapping[str, Any], TargetT]):
22
30
  inner: Formatter[Mapping[str, Any], TargetT]
@@ -82,9 +90,7 @@ class DataclassFormatter[TargetT]:
82
90
 
83
91
  def load(self, source: Mapping[str, Any]) -> TargetT:
84
92
  source = FluentDict[Any](deepcopy(source)).select(
85
- *self.resource.__annotations__.keys(),
86
- "id",
87
- "idempotency_id",
93
+ *self.resource.__dataclass_fields__, # type: ignore[attr-defined]
88
94
  )
89
95
 
90
96
  for key in fields(self.resource): # type: ignore
@@ -127,9 +127,10 @@ class ResponseProbe:
127
127
  return self.with_item(value)
128
128
 
129
129
  def with_item(self, value: Any) -> Self:
130
- assert self.response.item() == value, self.response.raw
130
+ if self.response.item() == value:
131
+ return self
131
132
 
132
- return self
133
+ raise AssertionError("expected=", self.response.item(), "actual=", value)
133
134
 
134
135
  def and_collection(self, values: Collection[Any]) -> Self:
135
136
  return self.with_collection(values)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "apexdevkit"
3
- version = "2.2.1"
3
+ version = "2.3.2"
4
4
  description = "Apex Development Tools for python."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -31,7 +31,7 @@ pytest-env = "*"
31
31
  pytest-recording = "*"
32
32
 
33
33
  [tool.ruff.lint.per-file-ignores]
34
- "apexdevkit/fastapi/resource.py" = [ "N803" ]
34
+ "apexdevkit/fastapi/endpoints.py" = [ "N803" ]
35
35
  "apexdevkit/fastapi/dependable.py" = [ "N806" ]
36
36
 
37
37
  [tool.ruff.lint.mccabe]
@@ -80,7 +80,7 @@ ignore = [
80
80
  [tool.mypy]
81
81
  exclude = [
82
82
  "apexdevkit/fastapi/dependable.py",
83
- "apexdevkit/fastapi/resource.py",
83
+ "apexdevkit/fastapi/endpoints.py",
84
84
  "apexdevkit/fastapi/schema.py",
85
85
  ]
86
86
  ignore_missing_imports = true
@@ -1,13 +0,0 @@
1
- from apexdevkit.fastapi.builder import FastApiBuilder, RestfulServiceBuilder
2
- from apexdevkit.fastapi.dependable import inject
3
- from apexdevkit.fastapi.router import RestfulRouter, RouterWithHiddenUnderscoreRoutes
4
- from apexdevkit.fastapi.service import RestfulRepository
5
-
6
- __all__ = [
7
- "FastApiBuilder",
8
- "RestfulRepository",
9
- "RestfulRouter",
10
- "RestfulServiceBuilder",
11
- "RouterWithHiddenUnderscoreRoutes",
12
- "inject",
13
- ]
@@ -1,68 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import Iterable, Mapping
4
- from dataclasses import dataclass
5
- from typing import TYPE_CHECKING, Any
6
-
7
- from apexdevkit.repository import Entity, Repository
8
-
9
- if TYPE_CHECKING:
10
- from apexdevkit.formatter import Formatter
11
-
12
- RawItem = Mapping[str, Any]
13
- RawCollection = Iterable[RawItem]
14
-
15
-
16
- class RestfulService: # pragma: no cover
17
- def create_one(self, item: RawItem) -> RawItem:
18
- raise NotImplementedError(self.create_one.__name__)
19
-
20
- def read_one(self, item_id: str) -> RawItem:
21
- raise NotImplementedError(self.read_one.__name__)
22
-
23
- def read_many(self, **params: Any) -> RawCollection:
24
- raise NotImplementedError(self.read_many.__name__)
25
-
26
- def read_all(self) -> RawCollection:
27
- raise NotImplementedError(self.read_all.__name__)
28
-
29
- def update_one(self, item_id: str, **with_fields: Any) -> RawItem:
30
- raise NotImplementedError(self.update_one.__name__)
31
-
32
- def replace_one(self, item: RawItem) -> RawItem:
33
- raise NotImplementedError(self.replace_one.__name__)
34
-
35
- def delete_one(self, item_id: str) -> None:
36
- raise NotImplementedError(self.delete_one.__name__)
37
-
38
-
39
- @dataclass(frozen=True)
40
- class RestfulRepository[ItemT: Entity](RestfulService):
41
- repository: Repository[ItemT]
42
-
43
- formatter: Formatter[Mapping[str, Any], ItemT]
44
-
45
- def create_one(self, item: RawItem) -> RawItem:
46
- return self.formatter.dump(self.repository.create(self.formatter.load(item)))
47
-
48
- def read_one(self, item_id: str) -> RawItem:
49
- return self.formatter.dump(self.repository.read(item_id))
50
-
51
- def read_all(self) -> RawCollection:
52
- return [self.formatter.dump(item) for item in self.repository]
53
-
54
- def update_one(self, item_id: str, **with_fields: Any) -> RawItem:
55
- data = dict(self.formatter.dump(self.repository.read(item_id)))
56
- data.update(**with_fields)
57
-
58
- self.repository.update(self.formatter.load(data))
59
-
60
- return data
61
-
62
- def replace_one(self, item: RawItem) -> RawItem:
63
- self.repository.update(self.formatter.load(item))
64
-
65
- return item
66
-
67
- def delete_one(self, item_id: str) -> None:
68
- self.repository.delete(item_id)
File without changes
File without changes