apexdevkit 1.28.2__tar.gz → 1.29.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 (62) hide show
  1. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/PKG-INFO +1 -1
  2. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/service.py +3 -6
  3. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/formatter.py +13 -13
  4. apexdevkit-1.29.2/apexdevkit/repository/__init__.py +41 -0
  5. apexdevkit-1.29.2/apexdevkit/repository/core/__init__.py +27 -0
  6. {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.2/apexdevkit/repository/core}/database.py +12 -0
  7. {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.2/apexdevkit/repository/core}/decorator.py +2 -5
  8. apexdevkit-1.29.2/apexdevkit/repository/core/interface.py +68 -0
  9. apexdevkit-1.28.2/apexdevkit/repository/repository.py → apexdevkit-1.29.2/apexdevkit/repository/core/multi.py +2 -3
  10. apexdevkit-1.29.2/apexdevkit/repository/in_memory/__init__.py +10 -0
  11. apexdevkit-1.29.2/apexdevkit/repository/in_memory/mixin.py +20 -0
  12. apexdevkit-1.29.2/apexdevkit/repository/in_memory/repository.py +70 -0
  13. apexdevkit-1.29.2/apexdevkit/repository/in_memory/store.py +48 -0
  14. apexdevkit-1.29.2/apexdevkit/repository/sql/__init__.py +11 -0
  15. {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.2/apexdevkit/repository/sql}/connector.py +1 -12
  16. {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.2/apexdevkit/repository/sql}/mssql.py +3 -5
  17. {apexdevkit-1.28.2/apexdevkit/repository → apexdevkit-1.29.2/apexdevkit/repository/sql}/sqlite.py +2 -8
  18. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/pyproject.toml +2 -2
  19. apexdevkit-1.28.2/apexdevkit/repository/__init__.py +0 -29
  20. apexdevkit-1.28.2/apexdevkit/repository/base.py +0 -27
  21. apexdevkit-1.28.2/apexdevkit/repository/in_memory.py +0 -209
  22. apexdevkit-1.28.2/apexdevkit/repository/interface.py +0 -37
  23. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/LICENSE +0 -0
  24. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/README.md +0 -0
  25. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/__init__.py +0 -0
  26. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/annotation/__init__.py +0 -0
  27. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/annotation/deprecate.py +0 -0
  28. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/date.py +0 -0
  29. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/environment.py +0 -0
  30. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/error.py +0 -0
  31. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/__init__.py +0 -0
  32. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/builder.py +0 -0
  33. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/dependable.py +0 -0
  34. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/docs.py +0 -0
  35. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/name.py +0 -0
  36. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/resource.py +0 -0
  37. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/response.py +0 -0
  38. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/router.py +0 -0
  39. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fastapi/schema.py +0 -0
  40. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/fluent.py +0 -0
  41. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/http/__init__.py +0 -0
  42. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/http/fake.py +0 -0
  43. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/http/fluent.py +0 -0
  44. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/http/httpx/__init__.py +0 -0
  45. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/http/httpx/client.py +0 -0
  46. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/http/httpx/hooks.py +0 -0
  47. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/http/json.py +0 -0
  48. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/http/url.py +0 -0
  49. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/id.py +0 -0
  50. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/key_fn.py +0 -0
  51. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/py.typed +0 -0
  52. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/query/__init__.py +0 -0
  53. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/query/generator.py +0 -0
  54. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/query/query.py +0 -0
  55. /apexdevkit-1.28.2/apexdevkit/repository/sql.py → /apexdevkit-1.29.2/apexdevkit/repository/sql/field.py +0 -0
  56. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/server.py +0 -0
  57. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/synchronization.py +0 -0
  58. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/testing/__init__.py +0 -0
  59. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/testing/database.py +0 -0
  60. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/testing/fake.py +0 -0
  61. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/testing/rest.py +0 -0
  62. {apexdevkit-1.28.2 → apexdevkit-1.29.2}/apexdevkit/value.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apexdevkit
3
- Version: 1.28.2
3
+ Version: 1.29.2
4
4
  Summary: Apex Development Tools for python.
5
5
  License-File: LICENSE
6
6
  Author: Apex Dev
@@ -3,11 +3,11 @@ 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, TypeVar
6
+ from typing import Any, Generic
7
7
 
8
8
  from apexdevkit.formatter import Formatter
9
- from apexdevkit.repository.decorator import BruteForceBatch
10
- from apexdevkit.repository.interface import Repository
9
+ from apexdevkit.repository import BruteForceBatch, Repository
10
+ from apexdevkit.repository.core import ItemT
11
11
 
12
12
  RawItem = Mapping[str, Any]
13
13
  RawCollection = Iterable[RawItem]
@@ -59,9 +59,6 @@ class RestfulService: # pragma: no cover
59
59
  raise NotImplementedError(self.delete_one.__name__)
60
60
 
61
61
 
62
- ItemT = TypeVar("ItemT")
63
-
64
-
65
62
  @dataclass(frozen=True)
66
63
  class RestfulRepository(RestfulService, Generic[ItemT]):
67
64
  repository: Repository[ItemT]
@@ -85,8 +85,8 @@ class DataclassFormatter(Generic[_TargetT]):
85
85
 
86
86
  return self
87
87
 
88
- def load(self, raw: Mapping[str, Any]) -> _TargetT:
89
- raw = FluentDict[Any](deepcopy(raw)).select(
88
+ def load(self, source: Mapping[str, Any]) -> _TargetT:
89
+ source = FluentDict[Any](deepcopy(source)).select(
90
90
  *self.resource.__annotations__.keys(),
91
91
  "id",
92
92
  "idempotency_id",
@@ -95,27 +95,27 @@ class DataclassFormatter(Generic[_TargetT]):
95
95
  for key in fields(self.resource): # type: ignore
96
96
  types = get_type_hints(self.resource)
97
97
  key_type = types[key.name]
98
- if key.name not in raw:
98
+ if key.name not in source:
99
99
  continue
100
100
  if key.name in self.sub_formatters:
101
- raw[key.name] = (
102
- self.sub_formatters[key.name].load(raw.pop(key.name))
103
- if raw[key.name]
104
- else raw[key.name]
101
+ source[key.name] = (
102
+ self.sub_formatters[key.name].load(source.pop(key.name))
103
+ if source[key.name]
104
+ else source[key.name]
105
105
  )
106
106
  elif is_dataclass(key_type):
107
- raw[key.name] = DataclassFormatter(key_type).load(raw[key.name]) # type: ignore
107
+ source[key.name] = DataclassFormatter(key_type).load(source[key.name]) # type: ignore
108
108
  else:
109
109
  args = get_args(key_type)
110
110
  if len(args) == 1 and is_dataclass(args[0]):
111
- raw[key.name] = ListFormatter(DataclassFormatter(args[0])).load( # type: ignore
112
- raw[key.name]
111
+ source[key.name] = ListFormatter(DataclassFormatter(args[0])).load( # type: ignore
112
+ source[key.name]
113
113
  )
114
114
 
115
- return self.resource(**raw)
115
+ return self.resource(**source)
116
116
 
117
- def dump(self, item: _TargetT) -> Mapping[str, Any]:
118
- return asdict(item) # type: ignore
117
+ def dump(self, target: _TargetT) -> Mapping[str, Any]:
118
+ return asdict(target) # type: ignore
119
119
 
120
120
 
121
121
  class ValueFormatter:
@@ -0,0 +1,41 @@
1
+ from .core import (
2
+ BruteForceBatch,
3
+ Connection,
4
+ Connector,
5
+ Cursor,
6
+ Database,
7
+ DatabaseCommand,
8
+ Repository,
9
+ RepositoryBase,
10
+ RepositoryDecorator,
11
+ )
12
+ from .core.interface import Entity
13
+ from .in_memory import (
14
+ CacheMixin,
15
+ InMemoryByteStore,
16
+ InMemoryRepository,
17
+ KeyValueStore,
18
+ )
19
+ from .sql import MsSqlRepository, SqliteRepository
20
+
21
+ __all__ = [
22
+ "Entity",
23
+ # Core
24
+ "BruteForceBatch",
25
+ "Connection",
26
+ "Connector",
27
+ "Cursor",
28
+ "Database",
29
+ "DatabaseCommand",
30
+ "Repository",
31
+ "RepositoryBase",
32
+ "RepositoryDecorator",
33
+ # In-memory
34
+ "CacheMixin",
35
+ "InMemoryByteStore",
36
+ "InMemoryRepository",
37
+ "KeyValueStore",
38
+ # SQL
39
+ "MsSqlRepository",
40
+ "SqliteRepository",
41
+ ]
@@ -0,0 +1,27 @@
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 ItemT, 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
+ "ItemT",
25
+ "Repository",
26
+ "RepositoryBase",
27
+ ]
@@ -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 Any, Generic
3
+ from typing import Generic
4
4
 
5
- from apexdevkit.repository.interface import ItemT, Repository
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,68 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable, Iterable, Iterator
4
+ from dataclasses import dataclass, field
5
+ from typing import Generic, Protocol, TypeVar
6
+ from uuid import uuid4
7
+
8
+
9
+ def _uuid() -> str:
10
+ return str(uuid4())
11
+
12
+
13
+ @dataclass(frozen=True, kw_only=True)
14
+ class Entity:
15
+ id: str = field(default_factory=_uuid)
16
+ idempotency_id: str | None = field(default=None)
17
+
18
+
19
+ ItemT = TypeVar("ItemT", bound=Entity)
20
+ KeyFn = Callable[[ItemT], str]
21
+
22
+
23
+ class Repository(Protocol[ItemT]): # pragma: no cover
24
+ def create(self, item: ItemT) -> ItemT:
25
+ pass
26
+
27
+ def read(self, item_id: str) -> ItemT:
28
+ pass
29
+
30
+ def update(self, item: ItemT) -> None:
31
+ pass
32
+
33
+ def delete(self, item_id: str) -> None:
34
+ pass
35
+
36
+ def __iter__(self) -> Iterator[ItemT]:
37
+ pass
38
+
39
+ def __len__(self) -> int:
40
+ pass
41
+
42
+
43
+ class BatchRepository(Repository[ItemT], Protocol[ItemT]): # pragma: no cover
44
+ def create_many(self, items: Iterable[ItemT]) -> Iterable[ItemT]:
45
+ pass
46
+
47
+ def update_many(self, items: Iterable[ItemT]) -> None:
48
+ pass
49
+
50
+
51
+ class RepositoryBase(Generic[ItemT]): # pragma: no cover
52
+ def create(self, item: ItemT) -> ItemT:
53
+ raise NotImplementedError
54
+
55
+ def read(self, item_id: str) -> ItemT:
56
+ raise NotImplementedError
57
+
58
+ def update(self, item: ItemT) -> None:
59
+ raise NotImplementedError
60
+
61
+ def delete(self, item_id: str) -> None:
62
+ raise NotImplementedError
63
+
64
+ def __iter__(self) -> Iterator[ItemT]:
65
+ raise NotImplementedError
66
+
67
+ def __len__(self) -> int:
68
+ 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, TypeVar
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 = TypeVar("ItemT")
10
+ from .interface import ItemT, Repository, RepositoryBase
12
11
 
13
12
 
14
13
  @dataclass(frozen=True)
@@ -0,0 +1,10 @@
1
+ from .mixin import CacheMixin
2
+ from .repository import InMemoryRepository
3
+ from .store import InMemoryByteStore, KeyValueStore
4
+
5
+ __all__ = [
6
+ "CacheMixin",
7
+ "InMemoryRepository",
8
+ "InMemoryByteStore",
9
+ "KeyValueStore",
10
+ ]
@@ -0,0 +1,20 @@
1
+ from collections import defaultdict
2
+ from collections.abc import MutableMapping
3
+ from dataclasses import dataclass
4
+ from functools import cached_property
5
+ from typing import Any
6
+
7
+ from .store import InMemoryByteStore, KeyValueStore
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class CacheMixin:
12
+ @cached_property
13
+ def _entries(self) -> MutableMapping[str, KeyValueStore[Any]]:
14
+ return defaultdict(InMemoryByteStore)
15
+
16
+ def store_for(self, name: str) -> KeyValueStore[Any]:
17
+ return self._entries[name]
18
+
19
+ def clear(self) -> None:
20
+ self._entries.clear()
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterator
4
+ from contextlib import suppress
5
+ from dataclasses import dataclass, field
6
+
7
+ from apexdevkit.error import DoesNotExistError, ExistsError
8
+ from apexdevkit.key_fn import AttributeKey
9
+ from apexdevkit.repository.core import ItemT, RepositoryBase
10
+ from apexdevkit.repository.core.interface import KeyFn
11
+
12
+ from .store import InMemoryByteStore, KeyValueStore
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class InMemoryRepository(RepositoryBase[ItemT]):
17
+ store: KeyValueStore[ItemT] = field(default_factory=InMemoryByteStore)
18
+ keys: list[KeyFn[ItemT]] = field(default_factory=lambda: [AttributeKey("id")])
19
+
20
+ def and_key(self, function: KeyFn[ItemT]) -> InMemoryRepository[ItemT]:
21
+ return self.with_key(function)
22
+
23
+ def with_key(self, function: KeyFn[ItemT]) -> InMemoryRepository[ItemT]:
24
+ self.keys.append(function)
25
+
26
+ return self
27
+
28
+ def and_seeded(self, *items: ItemT) -> InMemoryRepository[ItemT]:
29
+ return self.with_seeded(*items)
30
+
31
+ def with_seeded(self, *items: ItemT) -> InMemoryRepository[ItemT]:
32
+ for seed in items:
33
+ with suppress(ExistsError):
34
+ self.create(seed)
35
+
36
+ return self
37
+
38
+ def create(self, item: ItemT) -> ItemT:
39
+ self._ensure_does_not_exist(item)
40
+ self.store.set(item.id, item)
41
+
42
+ return item
43
+
44
+ def _ensure_does_not_exist(self, new: ItemT) -> None:
45
+ for existing in self:
46
+ for key in self.keys:
47
+ if key(new) == key(existing):
48
+ ExistsError(existing).with_duplicate(key).fire()
49
+
50
+ def update(self, item: ItemT) -> None:
51
+ self.delete(item.id)
52
+ self.create(item)
53
+
54
+ def delete(self, item_id: str) -> None:
55
+ item = self.read(item_id)
56
+ self.store.drop(item.id)
57
+
58
+ def read(self, item_id: str) -> ItemT:
59
+ for key in self.keys:
60
+ for item in self:
61
+ if key(item) == str(item_id):
62
+ return item
63
+
64
+ raise DoesNotExistError(item_id)
65
+
66
+ def __iter__(self) -> Iterator[ItemT]:
67
+ return iter(self.store.values())
68
+
69
+ def __len__(self) -> int:
70
+ return self.store.count()
@@ -0,0 +1,48 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable
4
+ from dataclasses import dataclass, field
5
+ from typing import Generic, Protocol
6
+
7
+ from apexdevkit.formatter import Formatter, PickleFormatter
8
+ from apexdevkit.repository.core.interface import ItemT
9
+
10
+
11
+ class KeyValueStore(Protocol[ItemT]): # pragma: no cover
12
+ def count(self) -> int:
13
+ pass
14
+
15
+ def set(self, key: str, value: ItemT) -> None:
16
+ pass
17
+
18
+ def get(self, key: str) -> ItemT:
19
+ pass
20
+
21
+ def drop(self, key: str) -> None:
22
+ pass
23
+
24
+ def values(self) -> Iterable[ItemT]:
25
+ pass
26
+
27
+
28
+ @dataclass
29
+ class InMemoryByteStore(Generic[ItemT]):
30
+ formatter: Formatter[bytes, ItemT] = field(default_factory=PickleFormatter)
31
+
32
+ items: dict[str, bytes] = field(default_factory=dict)
33
+
34
+ def count(self) -> int:
35
+ return len(self.items)
36
+
37
+ def set(self, key: str, value: ItemT) -> None:
38
+ self.items[key] = self.formatter.dump(value)
39
+
40
+ def get(self, key: str) -> ItemT:
41
+ return self.formatter.load(self.items[key])
42
+
43
+ def drop(self, key: str) -> None:
44
+ del self.items[key]
45
+
46
+ def values(self) -> Iterable[ItemT]:
47
+ for raw in self.items.values():
48
+ yield self.formatter.load(raw)
@@ -0,0 +1,11 @@
1
+ from .field import NotNone, SqlFieldBuilder, SqlFieldManager
2
+ from .mssql import MsSqlRepository
3
+ from .sqlite import SqliteRepository
4
+
5
+ __all__ = [
6
+ "NotNone",
7
+ "SqlFieldBuilder",
8
+ "SqlFieldManager",
9
+ "MsSqlRepository",
10
+ "SqliteRepository",
11
+ ]
@@ -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]
@@ -2,16 +2,14 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Iterable, Iterator, Mapping
4
4
  from dataclasses import dataclass
5
- from typing import Any, Generic, TypeVar
5
+ from typing import Any, Generic
6
6
 
7
7
  from pymssql.exceptions import DatabaseError, OperationalError
8
8
 
9
9
  from apexdevkit.error import DoesNotExistError, ExistsError
10
10
  from apexdevkit.formatter import Formatter
11
- from apexdevkit.repository import Database, DatabaseCommand, RepositoryBase
12
- from apexdevkit.repository.sql import NotNone, SqlFieldManager, _SqlField
13
-
14
- ItemT = TypeVar("ItemT")
11
+ from apexdevkit.repository.core import Database, DatabaseCommand, ItemT, RepositoryBase
12
+ from apexdevkit.repository.sql.field import NotNone, SqlFieldManager, _SqlField
15
13
 
16
14
 
17
15
  @dataclass
@@ -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.28.2"
3
+ version = "1.29.2"
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,29 +0,0 @@
1
- from apexdevkit.repository.base import RepositoryBase
2
- from apexdevkit.repository.database import (
3
- Connection,
4
- Connector,
5
- Cursor,
6
- Database,
7
- DatabaseCommand,
8
- )
9
- from apexdevkit.repository.in_memory import (
10
- InMemoryByteStore,
11
- InMemoryRepository,
12
- KeyValueStore,
13
- )
14
- from apexdevkit.repository.interface import Repository
15
- from apexdevkit.repository.mssql import MsSqlRepository
16
-
17
- __all__ = [
18
- "Connection",
19
- "Connector",
20
- "Cursor",
21
- "Database",
22
- "DatabaseCommand",
23
- "InMemoryRepository",
24
- "InMemoryByteStore",
25
- "KeyValueStore",
26
- "Repository",
27
- "RepositoryBase",
28
- "MsSqlRepository",
29
- ]
@@ -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