apexdevkit 1.23.11__tar.gz → 1.23.13__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.
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/PKG-INFO +1 -1
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/resource.py +2 -16
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/router.py +9 -25
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/schema.py +23 -4
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/service.py +1 -5
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/http/httpx/client.py +7 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/testing/rest.py +2 -11
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/pyproject.toml +1 -1
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/LICENSE +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/README.md +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/__init__.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/annotation/deprecate.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/date.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/environment.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/error.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/builder.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/dependable.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/name.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/request.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fastapi/response.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/fluent.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/formatter.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/http/__init__.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/http/fake.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/http/fluent.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/http/httpx/__init__.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/http/httpx/hooks.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/http/json.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/http/url.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/id.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/key_fn.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/py.typed +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/query/__init__.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/query/generator.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/query/query.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/__init__.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/base.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/connector.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/database.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/decorator.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/in_memory.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/interface.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/mssql.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/repository.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/sql.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/repository/sqlite.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/server.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/synchronization.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/testing/__init__.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/testing/database.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/testing/fake.py +0 -0
- {apexdevkit-1.23.11 → apexdevkit-1.23.13}/apexdevkit/value.py +0 -0
|
@@ -7,7 +7,6 @@ from pydantic import BaseModel
|
|
|
7
7
|
from starlette.responses import JSONResponse
|
|
8
8
|
|
|
9
9
|
from apexdevkit.error import DoesNotExistError, ExistsError, ForbiddenError
|
|
10
|
-
from apexdevkit.fastapi.name import RestfulName
|
|
11
10
|
from apexdevkit.fastapi.response import RestfulResponse
|
|
12
11
|
from apexdevkit.query.query import (
|
|
13
12
|
Aggregation,
|
|
@@ -88,13 +87,13 @@ class RestfulResource:
|
|
|
88
87
|
|
|
89
88
|
return endpoint
|
|
90
89
|
|
|
91
|
-
def
|
|
90
|
+
def aggregation_with(self, Service, FilterOptions) -> _Endpoint: # type: ignore
|
|
92
91
|
def endpoint(service: Service, options: FilterOptions) -> _Response:
|
|
93
92
|
try:
|
|
94
93
|
return {
|
|
95
94
|
"status": "success",
|
|
96
95
|
"code": 200,
|
|
97
|
-
"
|
|
96
|
+
"aggregations": service.aggregation_with(options),
|
|
98
97
|
}
|
|
99
98
|
except ForbiddenError as e:
|
|
100
99
|
return JSONResponse(self.response.forbidden(e), 403)
|
|
@@ -110,19 +109,6 @@ class RestfulResource:
|
|
|
110
109
|
|
|
111
110
|
return endpoint
|
|
112
111
|
|
|
113
|
-
def aggregate_with(self, Service) -> _Endpoint: # type: ignore
|
|
114
|
-
def endpoint(service: Service, options: _FooterOptions) -> _Response:
|
|
115
|
-
try:
|
|
116
|
-
return RestfulResponse(RestfulName("summary")).found_many(
|
|
117
|
-
list(service.aggregate_with(options.to_footer_options()))
|
|
118
|
-
)
|
|
119
|
-
except ForbiddenError as e:
|
|
120
|
-
return JSONResponse(
|
|
121
|
-
RestfulResponse(RestfulName("summary")).forbidden(e), 403
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
return endpoint
|
|
125
|
-
|
|
126
112
|
def update_one(self, Service, ItemId, Updates) -> _Endpoint: # type: ignore
|
|
127
113
|
def endpoint(service: Service, item_id: ItemId, updates: Updates) -> _Response:
|
|
128
114
|
try:
|
|
@@ -7,7 +7,7 @@ from fastapi import APIRouter, Depends, Path, Query
|
|
|
7
7
|
from fastapi.responses import JSONResponse
|
|
8
8
|
|
|
9
9
|
from apexdevkit.fastapi.name import RestfulName
|
|
10
|
-
from apexdevkit.fastapi.resource import RestfulResource
|
|
10
|
+
from apexdevkit.fastapi.resource import RestfulResource
|
|
11
11
|
from apexdevkit.fastapi.response import RestfulResponse
|
|
12
12
|
from apexdevkit.fastapi.schema import RestfulSchema, Schema, SchemaFields
|
|
13
13
|
from apexdevkit.fastapi.service import RawCollection, RawItem, RestfulService
|
|
@@ -185,23 +185,25 @@ class RestfulRouter:
|
|
|
185
185
|
|
|
186
186
|
return self
|
|
187
187
|
|
|
188
|
-
def
|
|
188
|
+
def with_aggregation_endpoint(
|
|
189
189
|
self,
|
|
190
190
|
dependency: Dependency | None = None,
|
|
191
191
|
is_documented: bool = True,
|
|
192
192
|
) -> Self:
|
|
193
193
|
self.router.add_api_route(
|
|
194
|
-
"/
|
|
195
|
-
self.resource.
|
|
194
|
+
"/aggregation",
|
|
195
|
+
self.resource.aggregation_with(
|
|
196
196
|
Service=self._resolve(dependency),
|
|
197
|
-
FilterOptions=Annotated[
|
|
197
|
+
FilterOptions=Annotated[
|
|
198
|
+
RawItem, Depends(self.schema.for_aggregation())
|
|
199
|
+
],
|
|
198
200
|
),
|
|
199
201
|
methods=["POST"],
|
|
200
202
|
status_code=200,
|
|
201
203
|
responses={},
|
|
202
|
-
response_model=
|
|
204
|
+
response_model=self.schema.for_aggregation_result(),
|
|
203
205
|
include_in_schema=is_documented,
|
|
204
|
-
summary="
|
|
206
|
+
summary="Aggregation",
|
|
205
207
|
)
|
|
206
208
|
|
|
207
209
|
return self
|
|
@@ -224,24 +226,6 @@ class RestfulRouter:
|
|
|
224
226
|
|
|
225
227
|
return self
|
|
226
228
|
|
|
227
|
-
def with_aggregate_endpoint(
|
|
228
|
-
self,
|
|
229
|
-
dependency: Dependency | None = None,
|
|
230
|
-
is_documented: bool = True,
|
|
231
|
-
) -> Self:
|
|
232
|
-
self.router.add_api_route(
|
|
233
|
-
"/aggregate",
|
|
234
|
-
self.resource.aggregate_with(Service=self._resolve(dependency)),
|
|
235
|
-
methods=["POST"],
|
|
236
|
-
status_code=200,
|
|
237
|
-
responses={},
|
|
238
|
-
response_model=SummaryResponse,
|
|
239
|
-
include_in_schema=is_documented,
|
|
240
|
-
summary="Read Aggregated",
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
return self
|
|
244
|
-
|
|
245
229
|
def with_update_one_endpoint(
|
|
246
230
|
self,
|
|
247
231
|
dependency: Dependency | None = None,
|
|
@@ -9,6 +9,12 @@ from pydantic import BaseModel, create_model
|
|
|
9
9
|
from apexdevkit.fastapi.name import RestfulName
|
|
10
10
|
from apexdevkit.fluent import FluentDict
|
|
11
11
|
from apexdevkit.http import JsonDict
|
|
12
|
+
from apexdevkit.value import Value
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AggregationResult(BaseModel):
|
|
16
|
+
field: str
|
|
17
|
+
aggregation: Value
|
|
12
18
|
|
|
13
19
|
|
|
14
20
|
class SchemaFields(ABC):
|
|
@@ -24,9 +30,12 @@ class SchemaFields(ABC):
|
|
|
24
30
|
def filters(self) -> FluentDict[type]:
|
|
25
31
|
return JsonDict()
|
|
26
32
|
|
|
27
|
-
def
|
|
33
|
+
def aggregation_filters(self) -> FluentDict[type]:
|
|
28
34
|
return JsonDict()
|
|
29
35
|
|
|
36
|
+
def aggregation_result(self) -> FluentDict[type]:
|
|
37
|
+
return JsonDict().with_a(count=int).and_a(sums=list[AggregationResult])
|
|
38
|
+
|
|
30
39
|
@abstractmethod
|
|
31
40
|
def readable(self) -> FluentDict[type]: # pragma: no cover
|
|
32
41
|
pass
|
|
@@ -46,7 +55,8 @@ class RestfulSchema:
|
|
|
46
55
|
"UpdateManyItem", self.fields.editable().merge(self.fields.id())
|
|
47
56
|
)
|
|
48
57
|
self._schema_for("Filter", self.fields.filters())
|
|
49
|
-
self._schema_for("
|
|
58
|
+
self._schema_for("Aggregation", self.fields.aggregation_filters())
|
|
59
|
+
self._schema_for("AggregationResult", self.fields.aggregation_result())
|
|
50
60
|
|
|
51
61
|
self._schema_for("Item", {self.name.singular: schema})
|
|
52
62
|
self._schema_for("Collection", {self.name.plural: list[schema], "count": int})
|
|
@@ -147,14 +157,23 @@ class RestfulSchema:
|
|
|
147
157
|
|
|
148
158
|
return _
|
|
149
159
|
|
|
150
|
-
def
|
|
151
|
-
schema = self.schemas["
|
|
160
|
+
def for_aggregation(self) -> Callable[[BaseModel], dict[str, Any]]:
|
|
161
|
+
schema = self.schemas["Aggregation"]
|
|
152
162
|
|
|
153
163
|
def _(request: schema) -> dict[str, Any]:
|
|
154
164
|
return request.model_dump()
|
|
155
165
|
|
|
156
166
|
return _
|
|
157
167
|
|
|
168
|
+
def for_aggregation_result(self) -> type[BaseModel]:
|
|
169
|
+
return self._schema_for(
|
|
170
|
+
"AggregationResultResponse",
|
|
171
|
+
FluentDict[type]()
|
|
172
|
+
.with_a(status=str)
|
|
173
|
+
.and_a(code=int)
|
|
174
|
+
.and_a(aggregations=self.schemas["AggregationResult"]),
|
|
175
|
+
)
|
|
176
|
+
|
|
158
177
|
|
|
159
178
|
@dataclass(frozen=True)
|
|
160
179
|
class Schema:
|
|
@@ -6,7 +6,6 @@ from functools import cached_property
|
|
|
6
6
|
from typing import Any, Generic, TypeVar
|
|
7
7
|
|
|
8
8
|
from apexdevkit.formatter import Formatter
|
|
9
|
-
from apexdevkit.query.query import FooterOptions, Summary
|
|
10
9
|
from apexdevkit.repository.decorator import BruteForceBatch
|
|
11
10
|
from apexdevkit.repository.interface import Repository
|
|
12
11
|
|
|
@@ -38,15 +37,12 @@ class RestfulService: # pragma: no cover
|
|
|
38
37
|
def filter_with(self, options: RawItem) -> RawCollection:
|
|
39
38
|
raise NotImplementedError(self.filter_with.__name__)
|
|
40
39
|
|
|
41
|
-
def
|
|
40
|
+
def aggregation_with(self, options: RawItem) -> RawItem:
|
|
42
41
|
raise NotImplementedError(self.filter_with.__name__)
|
|
43
42
|
|
|
44
43
|
def read_all(self) -> RawCollection:
|
|
45
44
|
raise NotImplementedError(self.read_all.__name__)
|
|
46
45
|
|
|
47
|
-
def aggregate_with(self, options: FooterOptions) -> Iterable[Summary]:
|
|
48
|
-
raise NotImplementedError(self.aggregate_with.__name__)
|
|
49
|
-
|
|
50
46
|
def update_one(self, item_id: str, **with_fields: Any) -> RawItem:
|
|
51
47
|
raise NotImplementedError(self.update_one.__name__)
|
|
52
48
|
|
|
@@ -54,6 +54,7 @@ class Httpx:
|
|
|
54
54
|
|
|
55
55
|
@dataclass
|
|
56
56
|
class Builder:
|
|
57
|
+
timeout_s: int = field(default_factory=lambda: 30)
|
|
57
58
|
config: HttpxConfig = field(default_factory=default_config)
|
|
58
59
|
|
|
59
60
|
request_handlers: list[_RequestHandler] = field(default_factory=list)
|
|
@@ -66,6 +67,11 @@ class Httpx:
|
|
|
66
67
|
|
|
67
68
|
return self
|
|
68
69
|
|
|
70
|
+
def with_timeout(self, timeout_s: int) -> Httpx.Builder:
|
|
71
|
+
self.timeout_s = timeout_s
|
|
72
|
+
|
|
73
|
+
return self
|
|
74
|
+
|
|
69
75
|
def and_config(self, value: HttpxConfig) -> Httpx.Builder:
|
|
70
76
|
self.config = value
|
|
71
77
|
|
|
@@ -87,6 +93,7 @@ class Httpx:
|
|
|
87
93
|
def _build_client(self) -> httpx.Client:
|
|
88
94
|
return httpx.Client(
|
|
89
95
|
base_url=self.url,
|
|
96
|
+
timeout=self.timeout_s,
|
|
90
97
|
event_hooks={
|
|
91
98
|
"request": self._build_before_request_hooks(),
|
|
92
99
|
"response": self._build_after_response_hooks(),
|
|
@@ -59,12 +59,12 @@ class _RestResource:
|
|
|
59
59
|
),
|
|
60
60
|
)
|
|
61
61
|
|
|
62
|
-
def
|
|
62
|
+
def aggregation_with(self) -> _TestRequest:
|
|
63
63
|
return _TestRequest(
|
|
64
64
|
self.name,
|
|
65
65
|
HttpRequest(
|
|
66
66
|
HttpMethod.post,
|
|
67
|
-
self.http.with_endpoint(self.name.plural).with_endpoint("
|
|
67
|
+
self.http.with_endpoint(self.name.plural).with_endpoint("aggregation"),
|
|
68
68
|
),
|
|
69
69
|
)
|
|
70
70
|
|
|
@@ -77,15 +77,6 @@ class _RestResource:
|
|
|
77
77
|
),
|
|
78
78
|
)
|
|
79
79
|
|
|
80
|
-
def aggregate_with(self) -> _TestRequest:
|
|
81
|
-
return _TestRequest(
|
|
82
|
-
RestfulName("summary"),
|
|
83
|
-
HttpRequest(
|
|
84
|
-
HttpMethod.post,
|
|
85
|
-
self.http.with_endpoint(self.name.plural).with_endpoint("aggregate"),
|
|
86
|
-
),
|
|
87
|
-
)
|
|
88
|
-
|
|
89
80
|
def update_one(self) -> _TestRequest:
|
|
90
81
|
return _TestRequest(
|
|
91
82
|
self.name,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|