apexdevkit 1.8.3__tar.gz → 1.8.5__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.8.3 → apexdevkit-1.8.5}/PKG-INFO +1 -1
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/http/httpx.py +22 -10
- apexdevkit-1.8.5/apexdevkit/repository/sqlite.py +101 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/pyproject.toml +1 -1
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/LICENSE +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/README.md +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/__init__.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/annotation/deprecate.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/error.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/builder.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/dependable.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/resource.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/response.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/router.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/schema.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/fastapi/service.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/formatter.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/http/__init__.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/http/fake.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/http/fluent.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/http/json.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/http/url.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/py.typed +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/repository/__init__.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/repository/base.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/repository/connector.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/repository/database.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/repository/in_memory.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/repository/interface.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/testing/__init__.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/testing/database.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/testing/fake.py +0 -0
- {apexdevkit-1.8.3 → apexdevkit-1.8.5}/apexdevkit/testing/rest.py +0 -0
|
@@ -8,6 +8,7 @@ from httpx import Client
|
|
|
8
8
|
|
|
9
9
|
from apexdevkit.http.fluent import HttpMethod, HttpResponse
|
|
10
10
|
from apexdevkit.http.json import JsonDict
|
|
11
|
+
from apexdevkit.http.url import HttpUrl
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def default_config() -> HttpxConfig:
|
|
@@ -22,12 +23,10 @@ class Httpx:
|
|
|
22
23
|
|
|
23
24
|
@classmethod
|
|
24
25
|
def create_for(cls, url: str) -> Self:
|
|
25
|
-
return cls(Client(base_url=url)
|
|
26
|
+
return cls(Client(base_url=url))
|
|
26
27
|
|
|
27
28
|
def with_endpoint(self, value: str) -> Httpx:
|
|
28
|
-
self.client
|
|
29
|
-
|
|
30
|
-
return self
|
|
29
|
+
return Httpx(self.client, self.config.with_endpoint(value))
|
|
31
30
|
|
|
32
31
|
def with_header(self, key: str, value: str) -> Httpx:
|
|
33
32
|
return Httpx(self.client, self.config.with_header(key, value))
|
|
@@ -39,7 +38,12 @@ class Httpx:
|
|
|
39
38
|
return Httpx(self.client, self.config.with_json(value))
|
|
40
39
|
|
|
41
40
|
def request(self, method: HttpMethod, endpoint: str = "") -> HttpResponse:
|
|
42
|
-
return _HttpxResponse(
|
|
41
|
+
return _HttpxResponse(
|
|
42
|
+
self.client.request(
|
|
43
|
+
method.name,
|
|
44
|
+
**self.config.with_endpoint(endpoint),
|
|
45
|
+
)
|
|
46
|
+
)
|
|
43
47
|
|
|
44
48
|
|
|
45
49
|
@dataclass
|
|
@@ -58,14 +62,22 @@ class _HttpxResponse:
|
|
|
58
62
|
|
|
59
63
|
@dataclass(frozen=True)
|
|
60
64
|
class HttpxConfig(Mapping[str, Any]):
|
|
61
|
-
|
|
65
|
+
endpoint: str = ""
|
|
62
66
|
headers: JsonDict = field(default_factory=JsonDict)
|
|
63
67
|
params: JsonDict = field(default_factory=JsonDict)
|
|
64
68
|
json: JsonDict = field(default_factory=JsonDict)
|
|
65
69
|
|
|
70
|
+
def with_endpoint(self, endpoint: str) -> HttpxConfig:
|
|
71
|
+
return HttpxConfig(
|
|
72
|
+
endpoint=HttpUrl(self.endpoint) + endpoint,
|
|
73
|
+
headers=self.headers,
|
|
74
|
+
params=self.params,
|
|
75
|
+
json=self.json,
|
|
76
|
+
)
|
|
77
|
+
|
|
66
78
|
def with_header(self, key: str, value: str) -> HttpxConfig:
|
|
67
79
|
return HttpxConfig(
|
|
68
|
-
|
|
80
|
+
endpoint=self.endpoint,
|
|
69
81
|
headers=self.headers.merge(JsonDict({key: value})),
|
|
70
82
|
params=self.params,
|
|
71
83
|
json=self.json,
|
|
@@ -73,7 +85,7 @@ class HttpxConfig(Mapping[str, Any]):
|
|
|
73
85
|
|
|
74
86
|
def with_param(self, key: str, value: str) -> HttpxConfig:
|
|
75
87
|
return HttpxConfig(
|
|
76
|
-
|
|
88
|
+
endpoint=self.endpoint,
|
|
77
89
|
headers=self.headers,
|
|
78
90
|
params=self.params.merge(JsonDict({key: value})),
|
|
79
91
|
json=self.json,
|
|
@@ -81,7 +93,7 @@ class HttpxConfig(Mapping[str, Any]):
|
|
|
81
93
|
|
|
82
94
|
def with_json(self, value: JsonDict) -> HttpxConfig:
|
|
83
95
|
return HttpxConfig(
|
|
84
|
-
|
|
96
|
+
endpoint=self.endpoint,
|
|
85
97
|
headers=self.headers,
|
|
86
98
|
params=self.params,
|
|
87
99
|
json=value,
|
|
@@ -89,7 +101,7 @@ class HttpxConfig(Mapping[str, Any]):
|
|
|
89
101
|
|
|
90
102
|
def as_dict(self) -> dict[str, Any]:
|
|
91
103
|
return {
|
|
92
|
-
"
|
|
104
|
+
"url": self.endpoint,
|
|
93
105
|
"headers": dict(self.headers),
|
|
94
106
|
"params": dict(self.params),
|
|
95
107
|
"json": dict(self.json),
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from sqlite3 import IntegrityError
|
|
5
|
+
from typing import Any, Callable, Generic, Iterator, Protocol, TypeVar
|
|
6
|
+
|
|
7
|
+
from apexdevkit.error import DoesNotExistError, ExistsError
|
|
8
|
+
from apexdevkit.repository import Database, DatabaseCommand
|
|
9
|
+
|
|
10
|
+
ItemT = TypeVar("ItemT")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class SqliteRepository(Generic[ItemT]):
|
|
15
|
+
db: Database
|
|
16
|
+
table: SqlTable[ItemT]
|
|
17
|
+
duplicate_criteria: Callable[[ItemT], str] = lambda i: "Unknown"
|
|
18
|
+
|
|
19
|
+
def __iter__(self) -> Iterator[ItemT]:
|
|
20
|
+
for raw in self.db.execute(self.table.select_all()).fetch_all():
|
|
21
|
+
yield self.table.load(raw)
|
|
22
|
+
|
|
23
|
+
def __len__(self) -> int:
|
|
24
|
+
raw = self.db.execute(self.table.count_all()).fetch_one()
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
return int(raw["n_items"])
|
|
28
|
+
except KeyError:
|
|
29
|
+
raise UnknownError(raw)
|
|
30
|
+
|
|
31
|
+
def create(self, item: ItemT) -> ItemT:
|
|
32
|
+
try:
|
|
33
|
+
return self.table.load(self.db.execute(self.table.insert(item)).fetch_one())
|
|
34
|
+
except IntegrityError: # pragma: no cover
|
|
35
|
+
ExistsError(item).with_duplicate(self.duplicate_criteria).fire()
|
|
36
|
+
return item
|
|
37
|
+
|
|
38
|
+
def create_many(self, items: list[ItemT]) -> list[ItemT]:
|
|
39
|
+
result = []
|
|
40
|
+
for item in items:
|
|
41
|
+
try:
|
|
42
|
+
result.append(
|
|
43
|
+
self.table.load(
|
|
44
|
+
self.db.execute(self.table.insert(item)).fetch_one()
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
except IntegrityError: # pragma: no cover
|
|
48
|
+
ExistsError(item).with_duplicate(self.duplicate_criteria).fire()
|
|
49
|
+
return result
|
|
50
|
+
|
|
51
|
+
def read(self, item_id: str) -> ItemT:
|
|
52
|
+
raw = self.db.execute(self.table.select(item_id)).fetch_one()
|
|
53
|
+
|
|
54
|
+
if not raw:
|
|
55
|
+
raise DoesNotExistError(item_id)
|
|
56
|
+
|
|
57
|
+
return self.table.load(raw)
|
|
58
|
+
|
|
59
|
+
def update(self, item: ItemT) -> None:
|
|
60
|
+
self.db.execute(self.table.update(item)).fetch_none()
|
|
61
|
+
|
|
62
|
+
def update_many(self, items: list[ItemT]) -> None:
|
|
63
|
+
for item in items:
|
|
64
|
+
self.update(item)
|
|
65
|
+
|
|
66
|
+
def delete(self, item_id: str) -> None:
|
|
67
|
+
self.db.execute(self.table.delete(item_id)).fetch_none()
|
|
68
|
+
|
|
69
|
+
def delete_all(self) -> None:
|
|
70
|
+
self.db.execute(self.table.delete_all()).fetch_none()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class SqlTable(Protocol[ItemT]): # pragma: no cover
|
|
74
|
+
def count_all(self) -> DatabaseCommand:
|
|
75
|
+
raise NotImplementedError("Not implemented")
|
|
76
|
+
|
|
77
|
+
def insert(self, item: ItemT) -> DatabaseCommand:
|
|
78
|
+
raise NotImplementedError("Not implemented")
|
|
79
|
+
|
|
80
|
+
def select(self, item_id: str) -> DatabaseCommand:
|
|
81
|
+
raise NotImplementedError("Not implemented")
|
|
82
|
+
|
|
83
|
+
def select_all(self) -> DatabaseCommand:
|
|
84
|
+
raise NotImplementedError("Not implemented")
|
|
85
|
+
|
|
86
|
+
def update(self, item: ItemT) -> DatabaseCommand:
|
|
87
|
+
raise NotImplementedError("Not implemented")
|
|
88
|
+
|
|
89
|
+
def delete(self, item_id: str) -> DatabaseCommand:
|
|
90
|
+
raise NotImplementedError("Not implemented")
|
|
91
|
+
|
|
92
|
+
def delete_all(self) -> DatabaseCommand:
|
|
93
|
+
raise NotImplementedError("Not implemented")
|
|
94
|
+
|
|
95
|
+
def load(self, data: dict[str, Any]) -> ItemT:
|
|
96
|
+
raise NotImplementedError("Not implemented")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class UnknownError(Exception):
|
|
101
|
+
raw: dict[str, Any]
|
|
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
|