apexdevkit 1.28.2__tar.gz → 1.29.1__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.28.2 → apexdevkit-1.29.1}/PKG-INFO +1 -1
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/service.py +1 -2
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/repository/__init__.py +15 -7
- apexdevkit-1.29.1/apexdevkit/repository/core/__init__.py +26 -0
- {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/core}/database.py +12 -0
- {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/core}/decorator.py +2 -5
- apexdevkit-1.29.1/apexdevkit/repository/core/interface.py +55 -0
- apexdevkit-1.28.2/apexdevkit/repository/repository.py → apexdevkit-1.29.1/apexdevkit/repository/core/multi.py +2 -3
- apexdevkit-1.29.1/apexdevkit/repository/in_memory/__init__.py +8 -0
- apexdevkit-1.29.1/apexdevkit/repository/in_memory/builder.py +62 -0
- apexdevkit-1.29.1/apexdevkit/repository/in_memory/multi_key.py +53 -0
- apexdevkit-1.29.1/apexdevkit/repository/in_memory/single_key.py +51 -0
- apexdevkit-1.29.1/apexdevkit/repository/in_memory/store.py +62 -0
- apexdevkit-1.29.1/apexdevkit/repository/sql/__init__.py +11 -0
- {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/sql}/connector.py +1 -12
- {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/sql}/mssql.py +1 -1
- {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/sql}/sqlite.py +2 -8
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/pyproject.toml +2 -2
- apexdevkit-1.28.2/apexdevkit/repository/base.py +0 -27
- apexdevkit-1.28.2/apexdevkit/repository/in_memory.py +0 -209
- apexdevkit-1.28.2/apexdevkit/repository/interface.py +0 -37
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/LICENSE +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/README.md +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/__init__.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/annotation/deprecate.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/date.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/environment.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/error.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/builder.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/dependable.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/name.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/resource.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/response.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/router.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fastapi/schema.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/fluent.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/formatter.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/http/__init__.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/http/fake.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/http/fluent.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/http/httpx/__init__.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/http/httpx/client.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/http/httpx/hooks.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/http/json.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/http/url.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/id.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/key_fn.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/py.typed +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/query/__init__.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/query/generator.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/query/query.py +0 -0
- /apexdevkit-1.28.2/apexdevkit/repository/sql.py → /apexdevkit-1.29.1/apexdevkit/repository/sql/field.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/server.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/synchronization.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/testing/__init__.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/testing/database.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/testing/fake.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/testing/rest.py +0 -0
- {apexdevkit-1.28.2 → apexdevkit-1.29.1}/apexdevkit/value.py +0 -0
|
@@ -6,8 +6,7 @@ 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.repository
|
|
10
|
-
from apexdevkit.repository.interface import Repository
|
|
9
|
+
from apexdevkit.repository import BruteForceBatch, Repository
|
|
11
10
|
|
|
12
11
|
RawItem = Mapping[str, Any]
|
|
13
12
|
RawCollection = Iterable[RawItem]
|
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
from apexdevkit.repository.
|
|
2
|
-
|
|
1
|
+
from apexdevkit.repository.core import (
|
|
2
|
+
BruteForceBatch,
|
|
3
3
|
Connection,
|
|
4
4
|
Connector,
|
|
5
5
|
Cursor,
|
|
6
6
|
Database,
|
|
7
7
|
DatabaseCommand,
|
|
8
|
+
Repository,
|
|
9
|
+
RepositoryBase,
|
|
10
|
+
RepositoryDecorator,
|
|
8
11
|
)
|
|
9
12
|
from apexdevkit.repository.in_memory import (
|
|
10
13
|
InMemoryByteStore,
|
|
11
14
|
InMemoryRepository,
|
|
12
15
|
KeyValueStore,
|
|
13
16
|
)
|
|
14
|
-
from apexdevkit.repository.
|
|
15
|
-
from apexdevkit.repository.mssql import MsSqlRepository
|
|
17
|
+
from apexdevkit.repository.sql import MsSqlRepository, SqliteRepository
|
|
16
18
|
|
|
17
19
|
__all__ = [
|
|
20
|
+
# Core
|
|
21
|
+
"BruteForceBatch",
|
|
18
22
|
"Connection",
|
|
19
23
|
"Connector",
|
|
20
24
|
"Cursor",
|
|
21
25
|
"Database",
|
|
22
26
|
"DatabaseCommand",
|
|
23
|
-
"InMemoryRepository",
|
|
24
|
-
"InMemoryByteStore",
|
|
25
|
-
"KeyValueStore",
|
|
26
27
|
"Repository",
|
|
27
28
|
"RepositoryBase",
|
|
29
|
+
"RepositoryDecorator",
|
|
30
|
+
# In-memory
|
|
31
|
+
"InMemoryByteStore",
|
|
32
|
+
"InMemoryRepository",
|
|
33
|
+
"KeyValueStore",
|
|
34
|
+
# SQL
|
|
28
35
|
"MsSqlRepository",
|
|
36
|
+
"SqliteRepository",
|
|
29
37
|
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from .database import (
|
|
2
|
+
Connection,
|
|
3
|
+
ConnectionContextManager,
|
|
4
|
+
Connector,
|
|
5
|
+
Cursor,
|
|
6
|
+
Database,
|
|
7
|
+
DatabaseCommand,
|
|
8
|
+
)
|
|
9
|
+
from .decorator import BruteForceBatch, RepositoryDecorator
|
|
10
|
+
from .interface import Repository, RepositoryBase
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
# Database
|
|
14
|
+
"Connection",
|
|
15
|
+
"ConnectionContextManager",
|
|
16
|
+
"Connector",
|
|
17
|
+
"Cursor",
|
|
18
|
+
"Database",
|
|
19
|
+
"DatabaseCommand",
|
|
20
|
+
# Decorator
|
|
21
|
+
"RepositoryDecorator",
|
|
22
|
+
"BruteForceBatch",
|
|
23
|
+
# Interface
|
|
24
|
+
"Repository",
|
|
25
|
+
"RepositoryBase",
|
|
26
|
+
]
|
{apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/core}/database.py
RENAMED
|
@@ -97,3 +97,15 @@ class DatabaseCommand:
|
|
|
97
97
|
|
|
98
98
|
def __str__(self) -> str: # pragma: no cover
|
|
99
99
|
return self.value % self.payload
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class ConnectionContextManager(AbstractContextManager[Connection]):
|
|
103
|
+
def __init__(self, connection: Connection) -> None:
|
|
104
|
+
self.connection = connection
|
|
105
|
+
|
|
106
|
+
def __enter__(self) -> Connection:
|
|
107
|
+
return self.connection
|
|
108
|
+
|
|
109
|
+
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
|
|
110
|
+
self.connection.cursor().close()
|
|
111
|
+
self.connection.close()
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from collections.abc import Iterable, Iterator
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Generic
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from .interface import ItemT, Repository
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
@dataclass
|
|
@@ -21,9 +21,6 @@ class RepositoryDecorator(Generic[ItemT]): # pragma: no cover
|
|
|
21
21
|
def delete(self, item_id: str) -> None:
|
|
22
22
|
self.inner.delete(item_id)
|
|
23
23
|
|
|
24
|
-
def bind(self, **kwargs: Any) -> Repository[ItemT]:
|
|
25
|
-
return self.inner.bind(**kwargs)
|
|
26
|
-
|
|
27
24
|
def __iter__(self) -> Iterator[ItemT]:
|
|
28
25
|
return self.inner.__iter__()
|
|
29
26
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
4
|
+
from typing import Generic, Protocol, TypeVar
|
|
5
|
+
|
|
6
|
+
ItemT = TypeVar("ItemT")
|
|
7
|
+
KeyFn = Callable[[ItemT], str]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Repository(Protocol[ItemT]): # pragma: no cover
|
|
11
|
+
def create(self, item: ItemT) -> ItemT:
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
def read(self, item_id: str) -> ItemT:
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def update(self, item: ItemT) -> None:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
def delete(self, item_id: str) -> None:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def __iter__(self) -> Iterator[ItemT]:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
def __len__(self) -> int:
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BatchRepository(Repository[ItemT], Protocol[ItemT]): # pragma: no cover
|
|
31
|
+
def create_many(self, items: Iterable[ItemT]) -> Iterable[ItemT]:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
def update_many(self, items: Iterable[ItemT]) -> None:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class RepositoryBase(Generic[ItemT]): # pragma: no cover
|
|
39
|
+
def create(self, item: ItemT) -> ItemT:
|
|
40
|
+
raise NotImplementedError
|
|
41
|
+
|
|
42
|
+
def read(self, item_id: str) -> ItemT:
|
|
43
|
+
raise NotImplementedError
|
|
44
|
+
|
|
45
|
+
def update(self, item: ItemT) -> None:
|
|
46
|
+
raise NotImplementedError
|
|
47
|
+
|
|
48
|
+
def delete(self, item_id: str) -> None:
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
|
|
51
|
+
def __iter__(self) -> Iterator[ItemT]:
|
|
52
|
+
raise NotImplementedError
|
|
53
|
+
|
|
54
|
+
def __len__(self) -> int:
|
|
55
|
+
raise NotImplementedError
|
|
@@ -2,13 +2,12 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable, Iterator
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Generic
|
|
5
|
+
from typing import Generic
|
|
6
6
|
|
|
7
7
|
from apexdevkit.error import DoesNotExistError
|
|
8
8
|
from apexdevkit.formatter import Formatter
|
|
9
|
-
from apexdevkit.repository import Repository, RepositoryBase
|
|
10
9
|
|
|
11
|
-
ItemT
|
|
10
|
+
from .interface import ItemT, Repository, RepositoryBase
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
@dataclass(frozen=True)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Generic
|
|
6
|
+
|
|
7
|
+
from apexdevkit.error import ExistsError
|
|
8
|
+
from apexdevkit.key_fn import AttributeKey
|
|
9
|
+
from apexdevkit.repository.core.interface import ItemT, KeyFn, Repository
|
|
10
|
+
|
|
11
|
+
from .multi_key import MultiKeyRepository
|
|
12
|
+
from .single_key import SingleKeyRepository
|
|
13
|
+
from .store import InMemoryByteStore, KeyValueStore
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class InMemoryRepository(Generic[ItemT]):
|
|
18
|
+
store: KeyValueStore[ItemT] = field(default_factory=lambda: InMemoryByteStore())
|
|
19
|
+
keys: list[KeyFn[ItemT]] = field(default_factory=list)
|
|
20
|
+
seeds: frozenset[ItemT] = field(default_factory=frozenset)
|
|
21
|
+
|
|
22
|
+
def with_store(self, value: KeyValueStore[ItemT]) -> InMemoryRepository[ItemT]:
|
|
23
|
+
return InMemoryRepository(store=value, keys=self.keys, seeds=self.seeds)
|
|
24
|
+
|
|
25
|
+
def and_key(self, function: KeyFn[ItemT]) -> InMemoryRepository[ItemT]:
|
|
26
|
+
return self.with_key(function)
|
|
27
|
+
|
|
28
|
+
def with_key(self, function: KeyFn[ItemT]) -> InMemoryRepository[ItemT]:
|
|
29
|
+
return InMemoryRepository(
|
|
30
|
+
store=self.store,
|
|
31
|
+
keys=[*self.keys, function],
|
|
32
|
+
seeds=self.seeds,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def and_seeded(self, *items: ItemT) -> InMemoryRepository[ItemT]:
|
|
36
|
+
return self.with_seeded(*items)
|
|
37
|
+
|
|
38
|
+
def with_seeded(self, *items: ItemT) -> InMemoryRepository[ItemT]:
|
|
39
|
+
return InMemoryRepository(
|
|
40
|
+
store=self.store,
|
|
41
|
+
keys=self.keys,
|
|
42
|
+
seeds=self.seeds.union(set(items)),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def build(self) -> Repository[ItemT]:
|
|
46
|
+
return self._seed(self._create())
|
|
47
|
+
|
|
48
|
+
def _seed(self, repository: Repository[ItemT]) -> Repository[ItemT]:
|
|
49
|
+
for seed in self.seeds:
|
|
50
|
+
with suppress(ExistsError):
|
|
51
|
+
repository.create(seed)
|
|
52
|
+
|
|
53
|
+
return repository
|
|
54
|
+
|
|
55
|
+
def _create(self) -> Repository[ItemT]:
|
|
56
|
+
match len(self.keys):
|
|
57
|
+
case 0:
|
|
58
|
+
return SingleKeyRepository(self.store, pk=AttributeKey("id"))
|
|
59
|
+
case 1:
|
|
60
|
+
return SingleKeyRepository(self.store, pk=self.keys[0])
|
|
61
|
+
case _:
|
|
62
|
+
return MultiKeyRepository(self.store, keys=self.keys)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterator
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
|
|
6
|
+
from apexdevkit.error import DoesNotExistError, ExistsError
|
|
7
|
+
from apexdevkit.repository.core.interface import ItemT, KeyFn, RepositoryBase
|
|
8
|
+
|
|
9
|
+
from .store import KeyValueStore
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class MultiKeyRepository(RepositoryBase[ItemT]):
|
|
14
|
+
store: KeyValueStore[ItemT]
|
|
15
|
+
|
|
16
|
+
keys: list[KeyFn[ItemT]] = field(default_factory=list)
|
|
17
|
+
|
|
18
|
+
def create(self, item: ItemT) -> ItemT:
|
|
19
|
+
self._ensure_does_not_exist(item)
|
|
20
|
+
self.store.set(self._pk(item), item)
|
|
21
|
+
|
|
22
|
+
return item
|
|
23
|
+
|
|
24
|
+
def _ensure_does_not_exist(self, new: ItemT) -> None:
|
|
25
|
+
for existing in self:
|
|
26
|
+
for key in self.keys:
|
|
27
|
+
if key(new) == key(existing):
|
|
28
|
+
ExistsError(existing).with_duplicate(key).fire()
|
|
29
|
+
|
|
30
|
+
def _pk(self, item: ItemT) -> str:
|
|
31
|
+
return self.keys[0](item)
|
|
32
|
+
|
|
33
|
+
def update(self, item: ItemT) -> None:
|
|
34
|
+
self.delete(self._pk(item))
|
|
35
|
+
self.create(item)
|
|
36
|
+
|
|
37
|
+
def delete(self, item_id: str) -> None:
|
|
38
|
+
item = self.read(item_id)
|
|
39
|
+
self.store.drop(self._pk(item))
|
|
40
|
+
|
|
41
|
+
def read(self, item_id: str) -> ItemT:
|
|
42
|
+
for key in self.keys:
|
|
43
|
+
for item in self:
|
|
44
|
+
if key(item) == str(item_id):
|
|
45
|
+
return item
|
|
46
|
+
|
|
47
|
+
raise DoesNotExistError(item_id)
|
|
48
|
+
|
|
49
|
+
def __iter__(self) -> Iterator[ItemT]:
|
|
50
|
+
return iter(self.store.values())
|
|
51
|
+
|
|
52
|
+
def __len__(self) -> int:
|
|
53
|
+
return self.store.count()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterator
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
from apexdevkit.error import DoesNotExistError, ExistsError
|
|
7
|
+
from apexdevkit.repository.core.interface import ItemT, KeyFn, RepositoryBase
|
|
8
|
+
|
|
9
|
+
from .store import KeyValueStore
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class SingleKeyRepository(RepositoryBase[ItemT]):
|
|
14
|
+
store: KeyValueStore[ItemT]
|
|
15
|
+
pk: KeyFn[ItemT]
|
|
16
|
+
|
|
17
|
+
def create(self, item: ItemT) -> ItemT:
|
|
18
|
+
self._ensure_does_not_exist(item)
|
|
19
|
+
self.store.set(self.pk(item), item)
|
|
20
|
+
|
|
21
|
+
return item
|
|
22
|
+
|
|
23
|
+
def _ensure_does_not_exist(self, new: ItemT) -> None:
|
|
24
|
+
try:
|
|
25
|
+
existing = self.store.get(self.pk(new))
|
|
26
|
+
except KeyError:
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
ExistsError(existing).with_duplicate(self.pk).fire()
|
|
30
|
+
|
|
31
|
+
def update(self, item: ItemT) -> None:
|
|
32
|
+
self.delete(self.pk(item))
|
|
33
|
+
self.create(item)
|
|
34
|
+
|
|
35
|
+
def delete(self, item_id: str) -> None:
|
|
36
|
+
try:
|
|
37
|
+
self.store.drop(item_id)
|
|
38
|
+
except KeyError as e:
|
|
39
|
+
raise DoesNotExistError(item_id) from e
|
|
40
|
+
|
|
41
|
+
def read(self, item_id: str) -> ItemT:
|
|
42
|
+
try:
|
|
43
|
+
return self.store.get(item_id)
|
|
44
|
+
except KeyError as e:
|
|
45
|
+
raise DoesNotExistError(item_id) from e
|
|
46
|
+
|
|
47
|
+
def __iter__(self) -> Iterator[ItemT]:
|
|
48
|
+
return iter(self.store.values())
|
|
49
|
+
|
|
50
|
+
def __len__(self) -> int:
|
|
51
|
+
return self.store.count()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from collections.abc import Iterable, MutableMapping
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Any, Generic, Protocol
|
|
7
|
+
|
|
8
|
+
from apexdevkit.formatter import Formatter, PickleFormatter
|
|
9
|
+
from apexdevkit.repository.core.interface import ItemT
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class KeyValueStore(Protocol[ItemT]): # pragma: no cover
|
|
13
|
+
def count(self) -> int:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
def set(self, key: str, value: ItemT) -> None:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
def get(self, key: str) -> ItemT:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
def drop(self, key: str) -> None:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def values(self) -> Iterable[ItemT]:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class InMemoryByteStore(Generic[ItemT]):
|
|
31
|
+
formatter: Formatter[bytes, ItemT] = field(default_factory=PickleFormatter)
|
|
32
|
+
|
|
33
|
+
items: dict[str, bytes] = field(default_factory=dict)
|
|
34
|
+
|
|
35
|
+
def count(self) -> int:
|
|
36
|
+
return len(self.items)
|
|
37
|
+
|
|
38
|
+
def set(self, key: str, value: ItemT) -> None:
|
|
39
|
+
self.items[key] = self.formatter.dump(value)
|
|
40
|
+
|
|
41
|
+
def get(self, key: str) -> ItemT:
|
|
42
|
+
return self.formatter.load(self.items[key])
|
|
43
|
+
|
|
44
|
+
def drop(self, key: str) -> None:
|
|
45
|
+
del self.items[key]
|
|
46
|
+
|
|
47
|
+
def values(self) -> Iterable[ItemT]:
|
|
48
|
+
for raw in self.items.values():
|
|
49
|
+
yield self.formatter.load(raw)
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class Cache:
|
|
53
|
+
items: MutableMapping[str, InMemoryByteStore[Any]] = field(init=False)
|
|
54
|
+
|
|
55
|
+
def __post_init__(self) -> None:
|
|
56
|
+
self.items = defaultdict(InMemoryByteStore)
|
|
57
|
+
|
|
58
|
+
def store_for(self, name: str) -> InMemoryByteStore[Any]:
|
|
59
|
+
return self.items[name]
|
|
60
|
+
|
|
61
|
+
def clear(self) -> None:
|
|
62
|
+
self.items.clear()
|
{apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/sql}/connector.py
RENAMED
|
@@ -9,6 +9,7 @@ from typing import Any
|
|
|
9
9
|
import pymssql
|
|
10
10
|
|
|
11
11
|
from apexdevkit.repository import Connection
|
|
12
|
+
from apexdevkit.repository.core.database import ConnectionContextManager
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
@dataclass(frozen=True)
|
|
@@ -63,18 +64,6 @@ class MsSqlConnector:
|
|
|
63
64
|
)
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
class ConnectionContextManager(AbstractContextManager[Connection]):
|
|
67
|
-
def __init__(self, connection: Connection) -> None:
|
|
68
|
-
self.connection = connection
|
|
69
|
-
|
|
70
|
-
def __enter__(self) -> Connection:
|
|
71
|
-
return self.connection
|
|
72
|
-
|
|
73
|
-
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
|
|
74
|
-
self.connection.cursor().close()
|
|
75
|
-
self.connection.close()
|
|
76
|
-
|
|
77
|
-
|
|
78
67
|
@dataclass
|
|
79
68
|
class MsSqlConnectionAdapter:
|
|
80
69
|
connection: pymssql.Connection[pymssql.DictRow]
|
{apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/sql}/mssql.py
RENAMED
|
@@ -9,7 +9,7 @@ from pymssql.exceptions import DatabaseError, OperationalError
|
|
|
9
9
|
from apexdevkit.error import DoesNotExistError, ExistsError
|
|
10
10
|
from apexdevkit.formatter import Formatter
|
|
11
11
|
from apexdevkit.repository import Database, DatabaseCommand, RepositoryBase
|
|
12
|
-
from apexdevkit.repository.sql import NotNone, SqlFieldManager, _SqlField
|
|
12
|
+
from apexdevkit.repository.sql.field import NotNone, SqlFieldManager, _SqlField
|
|
13
13
|
|
|
14
14
|
ItemT = TypeVar("ItemT")
|
|
15
15
|
|
{apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.1/apexdevkit/repository/sql}/sqlite.py
RENAMED
|
@@ -8,8 +8,8 @@ from typing import Any, Generic
|
|
|
8
8
|
from apexdevkit.error import DoesNotExistError, ExistsError
|
|
9
9
|
from apexdevkit.formatter import Formatter
|
|
10
10
|
from apexdevkit.repository import Database, DatabaseCommand, RepositoryBase
|
|
11
|
-
from apexdevkit.repository.interface import ItemT
|
|
12
|
-
from apexdevkit.repository.sql import NotNone, SqlFieldManager, _SqlField
|
|
11
|
+
from apexdevkit.repository.core.interface import ItemT
|
|
12
|
+
from apexdevkit.repository.sql.field import NotNone, SqlFieldManager, _SqlField
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
@dataclass(frozen=True)
|
|
@@ -17,9 +17,6 @@ class SqliteRepository(RepositoryBase[ItemT]):
|
|
|
17
17
|
db: Database
|
|
18
18
|
table: SqlTable[ItemT]
|
|
19
19
|
|
|
20
|
-
def bind(self, **kwargs: Any) -> SqliteRepository[ItemT]:
|
|
21
|
-
return SqliteRepository(self.db, self.table.bind(**kwargs))
|
|
22
|
-
|
|
23
20
|
def __iter__(self) -> Iterator[ItemT]:
|
|
24
21
|
for raw in self.db.execute(self.table.select_all()).fetch_all():
|
|
25
22
|
yield self.table.load(raw)
|
|
@@ -61,9 +58,6 @@ class SqliteRepository(RepositoryBase[ItemT]):
|
|
|
61
58
|
|
|
62
59
|
|
|
63
60
|
class SqlTable(Generic[ItemT]): # pragma: no cover
|
|
64
|
-
def bind(self, **_: Any) -> SqlTable[ItemT]:
|
|
65
|
-
return self
|
|
66
|
-
|
|
67
61
|
def count_all(self) -> DatabaseCommand:
|
|
68
62
|
raise NotImplementedError
|
|
69
63
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "apexdevkit"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.29.1"
|
|
4
4
|
description = "Apex Development Tools for python."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -30,7 +30,7 @@ faker = "*"
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
[tool.poetry.group.lint.dependencies]
|
|
33
|
-
apexcodexpy = "
|
|
33
|
+
apexcodexpy = "0.3.1"
|
|
34
34
|
|
|
35
35
|
[tool.mypy]
|
|
36
36
|
ignore_missing_imports = true
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from collections.abc import Iterator
|
|
2
|
-
from typing import Any, Generic
|
|
3
|
-
|
|
4
|
-
from apexdevkit.repository.interface import ItemT, Repository
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class RepositoryBase(Generic[ItemT]): # pragma: no cover
|
|
8
|
-
def create(self, item: ItemT) -> ItemT:
|
|
9
|
-
raise NotImplementedError
|
|
10
|
-
|
|
11
|
-
def read(self, item_id: str) -> ItemT:
|
|
12
|
-
raise NotImplementedError
|
|
13
|
-
|
|
14
|
-
def update(self, item: ItemT) -> None:
|
|
15
|
-
raise NotImplementedError
|
|
16
|
-
|
|
17
|
-
def delete(self, item_id: str) -> None:
|
|
18
|
-
raise NotImplementedError
|
|
19
|
-
|
|
20
|
-
def bind(self, **kwargs: Any) -> Repository[ItemT]:
|
|
21
|
-
raise NotImplementedError
|
|
22
|
-
|
|
23
|
-
def __iter__(self) -> Iterator[ItemT]:
|
|
24
|
-
raise NotImplementedError
|
|
25
|
-
|
|
26
|
-
def __len__(self) -> int:
|
|
27
|
-
raise NotImplementedError
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from collections import defaultdict
|
|
4
|
-
from collections.abc import Callable, Iterable, Iterator, MutableMapping
|
|
5
|
-
from contextlib import suppress
|
|
6
|
-
from dataclasses import dataclass, field
|
|
7
|
-
from typing import Any, Generic, Protocol, Self
|
|
8
|
-
|
|
9
|
-
from apexdevkit.error import DoesNotExistError, ExistsError
|
|
10
|
-
from apexdevkit.formatter import Formatter, PickleFormatter
|
|
11
|
-
from apexdevkit.key_fn import AttributeKey
|
|
12
|
-
from apexdevkit.repository import RepositoryBase
|
|
13
|
-
from apexdevkit.repository.interface import ItemT, Repository
|
|
14
|
-
|
|
15
|
-
_KeyFunction = Callable[[ItemT], str]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@dataclass(frozen=True)
|
|
19
|
-
class InMemoryRepository(Generic[ItemT]):
|
|
20
|
-
store: KeyValueStore[ItemT] = field(default_factory=lambda: InMemoryByteStore())
|
|
21
|
-
keys: list[_KeyFunction[ItemT]] = field(default_factory=list)
|
|
22
|
-
seeds: frozenset[ItemT] = field(default_factory=frozenset)
|
|
23
|
-
|
|
24
|
-
def with_store(self, value: KeyValueStore[ItemT]) -> InMemoryRepository[ItemT]:
|
|
25
|
-
return InMemoryRepository(store=value, keys=self.keys, seeds=self.seeds)
|
|
26
|
-
|
|
27
|
-
def and_key(self, function: _KeyFunction[ItemT]) -> InMemoryRepository[ItemT]:
|
|
28
|
-
return self.with_key(function)
|
|
29
|
-
|
|
30
|
-
def with_key(self, function: _KeyFunction[ItemT]) -> InMemoryRepository[ItemT]:
|
|
31
|
-
return InMemoryRepository(
|
|
32
|
-
store=self.store,
|
|
33
|
-
keys=[*self.keys, function],
|
|
34
|
-
seeds=self.seeds,
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
def and_seeded(self, *items: ItemT) -> InMemoryRepository[ItemT]:
|
|
38
|
-
return self.with_seeded(*items)
|
|
39
|
-
|
|
40
|
-
def with_seeded(self, *items: ItemT) -> InMemoryRepository[ItemT]:
|
|
41
|
-
return InMemoryRepository(
|
|
42
|
-
store=self.store,
|
|
43
|
-
keys=self.keys,
|
|
44
|
-
seeds=self.seeds.union(set(items)),
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
def build(self) -> Repository[ItemT]:
|
|
48
|
-
return self._seed(self._create())
|
|
49
|
-
|
|
50
|
-
def _seed(self, repository: Repository[ItemT]) -> Repository[ItemT]:
|
|
51
|
-
for seed in self.seeds:
|
|
52
|
-
with suppress(ExistsError):
|
|
53
|
-
repository.create(seed)
|
|
54
|
-
|
|
55
|
-
return repository
|
|
56
|
-
|
|
57
|
-
def _create(self) -> Repository[ItemT]:
|
|
58
|
-
match len(self.keys):
|
|
59
|
-
case 0:
|
|
60
|
-
return _SingleKeyRepository(self.store, pk=AttributeKey("id"))
|
|
61
|
-
case 1:
|
|
62
|
-
return _SingleKeyRepository(self.store, pk=self.keys[0])
|
|
63
|
-
case _:
|
|
64
|
-
return _ManyKeyRepository(self.store, keys=self.keys)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class KeyValueStore(Protocol[ItemT]): # pragma: no cover
|
|
68
|
-
def count(self) -> int:
|
|
69
|
-
pass
|
|
70
|
-
|
|
71
|
-
def set(self, key: str, value: ItemT) -> None:
|
|
72
|
-
pass
|
|
73
|
-
|
|
74
|
-
def get(self, key: str) -> ItemT:
|
|
75
|
-
pass
|
|
76
|
-
|
|
77
|
-
def drop(self, key: str) -> None:
|
|
78
|
-
pass
|
|
79
|
-
|
|
80
|
-
def values(self) -> Iterable[ItemT]:
|
|
81
|
-
pass
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@dataclass
|
|
85
|
-
class InMemoryByteStore(Generic[ItemT]):
|
|
86
|
-
formatter: Formatter[bytes, ItemT] = field(default_factory=PickleFormatter)
|
|
87
|
-
|
|
88
|
-
items: dict[str, bytes] = field(default_factory=dict)
|
|
89
|
-
|
|
90
|
-
def count(self) -> int:
|
|
91
|
-
return len(self.items)
|
|
92
|
-
|
|
93
|
-
def set(self, key: str, value: ItemT) -> None:
|
|
94
|
-
self.items[key] = self.formatter.dump(value)
|
|
95
|
-
|
|
96
|
-
def get(self, key: str) -> ItemT:
|
|
97
|
-
return self.formatter.load(self.items[key])
|
|
98
|
-
|
|
99
|
-
def drop(self, key: str) -> None:
|
|
100
|
-
del self.items[key]
|
|
101
|
-
|
|
102
|
-
def values(self) -> Iterable[ItemT]:
|
|
103
|
-
for raw in self.items.values():
|
|
104
|
-
yield self.formatter.load(raw)
|
|
105
|
-
|
|
106
|
-
@dataclass
|
|
107
|
-
class Cache:
|
|
108
|
-
items: MutableMapping[str, InMemoryByteStore[Any]] = field(init=False)
|
|
109
|
-
|
|
110
|
-
def __post_init__(self) -> None:
|
|
111
|
-
self.items = defaultdict(InMemoryByteStore)
|
|
112
|
-
|
|
113
|
-
def store_for(self, name: str) -> InMemoryByteStore[Any]:
|
|
114
|
-
return self.items[name]
|
|
115
|
-
|
|
116
|
-
def clear(self) -> None:
|
|
117
|
-
self.items.clear()
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@dataclass
|
|
121
|
-
class _SingleKeyRepository(RepositoryBase[ItemT]):
|
|
122
|
-
store: KeyValueStore[ItemT]
|
|
123
|
-
pk: _KeyFunction[ItemT]
|
|
124
|
-
|
|
125
|
-
def bind(self, **_: Any) -> Self: # pragma: no cover
|
|
126
|
-
return self
|
|
127
|
-
|
|
128
|
-
def create(self, item: ItemT) -> ItemT:
|
|
129
|
-
self._ensure_does_not_exist(item)
|
|
130
|
-
self.store.set(self.pk(item), item)
|
|
131
|
-
|
|
132
|
-
return item
|
|
133
|
-
|
|
134
|
-
def _ensure_does_not_exist(self, new: ItemT) -> None:
|
|
135
|
-
try:
|
|
136
|
-
existing = self.store.get(self.pk(new))
|
|
137
|
-
except KeyError:
|
|
138
|
-
return
|
|
139
|
-
|
|
140
|
-
ExistsError(existing).with_duplicate(self.pk).fire()
|
|
141
|
-
|
|
142
|
-
def update(self, item: ItemT) -> None:
|
|
143
|
-
self.delete(self.pk(item))
|
|
144
|
-
self.create(item)
|
|
145
|
-
|
|
146
|
-
def delete(self, item_id: str) -> None:
|
|
147
|
-
try:
|
|
148
|
-
self.store.drop(item_id)
|
|
149
|
-
except KeyError as e:
|
|
150
|
-
raise DoesNotExistError(item_id) from e
|
|
151
|
-
|
|
152
|
-
def read(self, item_id: str) -> ItemT:
|
|
153
|
-
try:
|
|
154
|
-
return self.store.get(item_id)
|
|
155
|
-
except KeyError as e:
|
|
156
|
-
raise DoesNotExistError(item_id) from e
|
|
157
|
-
|
|
158
|
-
def __iter__(self) -> Iterator[ItemT]:
|
|
159
|
-
return iter(self.store.values())
|
|
160
|
-
|
|
161
|
-
def __len__(self) -> int:
|
|
162
|
-
return self.store.count()
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
@dataclass
|
|
166
|
-
class _ManyKeyRepository(RepositoryBase[ItemT]):
|
|
167
|
-
store: KeyValueStore[ItemT]
|
|
168
|
-
|
|
169
|
-
keys: list[_KeyFunction[ItemT]] = field(default_factory=list)
|
|
170
|
-
|
|
171
|
-
def bind(self, **_: Any) -> Self: # pragma: no cover
|
|
172
|
-
return self
|
|
173
|
-
|
|
174
|
-
def create(self, item: ItemT) -> ItemT:
|
|
175
|
-
self._ensure_does_not_exist(item)
|
|
176
|
-
self.store.set(self._pk(item), item)
|
|
177
|
-
|
|
178
|
-
return item
|
|
179
|
-
|
|
180
|
-
def _ensure_does_not_exist(self, new: ItemT) -> None:
|
|
181
|
-
for existing in self:
|
|
182
|
-
for key in self.keys:
|
|
183
|
-
if key(new) == key(existing):
|
|
184
|
-
ExistsError(existing).with_duplicate(key).fire()
|
|
185
|
-
|
|
186
|
-
def _pk(self, item: ItemT) -> str:
|
|
187
|
-
return self.keys[0](item)
|
|
188
|
-
|
|
189
|
-
def update(self, item: ItemT) -> None:
|
|
190
|
-
self.delete(self._pk(item))
|
|
191
|
-
self.create(item)
|
|
192
|
-
|
|
193
|
-
def delete(self, item_id: str) -> None:
|
|
194
|
-
item = self.read(item_id)
|
|
195
|
-
self.store.drop(self._pk(item))
|
|
196
|
-
|
|
197
|
-
def read(self, item_id: str) -> ItemT:
|
|
198
|
-
for key in self.keys:
|
|
199
|
-
for item in self:
|
|
200
|
-
if key(item) == str(item_id):
|
|
201
|
-
return item
|
|
202
|
-
|
|
203
|
-
raise DoesNotExistError(item_id)
|
|
204
|
-
|
|
205
|
-
def __iter__(self) -> Iterator[ItemT]:
|
|
206
|
-
return iter(self.store.values())
|
|
207
|
-
|
|
208
|
-
def __len__(self) -> int:
|
|
209
|
-
return self.store.count()
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from collections.abc import Iterable, Iterator
|
|
4
|
-
from typing import Any, Protocol, TypeVar
|
|
5
|
-
|
|
6
|
-
ItemT = TypeVar("ItemT")
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Repository(Protocol[ItemT]): # pragma: no cover
|
|
10
|
-
def create(self, item: ItemT) -> ItemT:
|
|
11
|
-
pass
|
|
12
|
-
|
|
13
|
-
def read(self, item_id: str) -> ItemT:
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
|
-
def update(self, item: ItemT) -> None:
|
|
17
|
-
pass
|
|
18
|
-
|
|
19
|
-
def delete(self, item_id: str) -> None:
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
def bind(self, **kwargs: Any) -> Repository[ItemT]:
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
def __iter__(self) -> Iterator[ItemT]:
|
|
26
|
-
pass
|
|
27
|
-
|
|
28
|
-
def __len__(self) -> int:
|
|
29
|
-
pass
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class BatchRepository(Repository[ItemT], Protocol[ItemT]): # pragma: no cover
|
|
33
|
-
def create_many(self, items: Iterable[ItemT]) -> Iterable[ItemT]:
|
|
34
|
-
pass
|
|
35
|
-
|
|
36
|
-
def update_many(self, items: Iterable[ItemT]) -> None:
|
|
37
|
-
pass
|
|
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
|