apexdevkit 1.17.1__tar.gz → 1.17.3__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 (48) hide show
  1. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/PKG-INFO +1 -1
  2. apexdevkit-1.17.3/apexdevkit/repository/sqlite.py +277 -0
  3. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/pyproject.toml +1 -1
  4. apexdevkit-1.17.1/apexdevkit/repository/sqlite.py +0 -97
  5. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/LICENSE +0 -0
  6. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/README.md +0 -0
  7. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/__init__.py +0 -0
  8. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/annotation/__init__.py +0 -0
  9. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/annotation/deprecate.py +0 -0
  10. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/environment.py +0 -0
  11. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/error.py +0 -0
  12. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/__init__.py +0 -0
  13. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/builder.py +0 -0
  14. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/dependable.py +0 -0
  15. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/docs.py +0 -0
  16. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/name.py +0 -0
  17. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/request.py +0 -0
  18. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/resource.py +0 -0
  19. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/response.py +0 -0
  20. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/router.py +0 -0
  21. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/schema.py +0 -0
  22. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fastapi/service.py +0 -0
  23. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/fluent.py +0 -0
  24. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/formatter.py +0 -0
  25. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/http/__init__.py +0 -0
  26. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/http/fake.py +0 -0
  27. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/http/fluent.py +0 -0
  28. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/http/httpx.py +0 -0
  29. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/http/json.py +0 -0
  30. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/http/url.py +0 -0
  31. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/key_fn.py +0 -0
  32. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/py.typed +0 -0
  33. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/__init__.py +0 -0
  34. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/base.py +0 -0
  35. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/connector.py +0 -0
  36. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/database.py +0 -0
  37. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/decorator.py +0 -0
  38. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/in_memory.py +0 -0
  39. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/interface.py +0 -0
  40. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/mongo.py +0 -0
  41. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/repository/mssql.py +0 -0
  42. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/server.py +0 -0
  43. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/synchronization.py +0 -0
  44. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/testing/__init__.py +0 -0
  45. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/testing/database.py +0 -0
  46. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/testing/fake.py +0 -0
  47. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/testing/rest.py +0 -0
  48. {apexdevkit-1.17.1 → apexdevkit-1.17.3}/apexdevkit/value.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apexdevkit
3
- Version: 1.17.1
3
+ Version: 1.17.3
4
4
  Summary: Apex Development Tools for python.
5
5
  Author: Apex Dev
6
6
  Author-email: dev@apex.ge
@@ -0,0 +1,277 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from sqlite3 import IntegrityError
5
+ from typing import Any, Generic, Iterable, Iterator
6
+
7
+ from apexdevkit.error import DoesNotExistError, ExistsError
8
+ from apexdevkit.formatter import Formatter
9
+ from apexdevkit.repository import Database, DatabaseCommand, RepositoryBase
10
+ from apexdevkit.repository.interface import ItemT
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class SqliteRepository(RepositoryBase[ItemT]):
15
+ db: Database
16
+ table: SqlTable[ItemT]
17
+
18
+ def bind(self, **kwargs: Any) -> SqliteRepository[ItemT]:
19
+ return SqliteRepository(self.db, self.table.bind(**kwargs))
20
+
21
+ def __iter__(self) -> Iterator[ItemT]:
22
+ for raw in self.db.execute(self.table.select_all()).fetch_all():
23
+ yield self.table.load(raw)
24
+
25
+ def __len__(self) -> int:
26
+ raw = self.db.execute(self.table.count_all()).fetch_one()
27
+
28
+ try:
29
+ return int(raw["n_items"])
30
+ except KeyError:
31
+ raise UnknownError(raw)
32
+
33
+ def create(self, item: ItemT) -> ItemT:
34
+ try:
35
+ return self.table.load(self.db.execute(self.table.insert(item)).fetch_one())
36
+ except IntegrityError: # pragma: no cover
37
+ item = self.table.load(
38
+ self.db.execute(self.table.select_duplicate(item)).fetch_one()
39
+ )
40
+ self.table.duplicate(item).fire()
41
+ return item
42
+
43
+ def read(self, item_id: str) -> ItemT:
44
+ raw = self.db.execute(self.table.select(str(item_id))).fetch_one()
45
+
46
+ if not raw:
47
+ raise DoesNotExistError(item_id)
48
+
49
+ return self.table.load(raw)
50
+
51
+ def update(self, item: ItemT) -> None:
52
+ self.db.execute(self.table.update(item)).fetch_none()
53
+
54
+ def delete(self, item_id: str) -> None:
55
+ self.db.execute(self.table.delete(str(item_id))).fetch_none()
56
+
57
+ def delete_all(self) -> None:
58
+ self.db.execute(self.table.delete_all()).fetch_none()
59
+
60
+
61
+ class SqlTable(Generic[ItemT]): # pragma: no cover
62
+ def bind(self, **kwargs: Any) -> SqlTable[ItemT]:
63
+ return self
64
+
65
+ def count_all(self) -> DatabaseCommand:
66
+ raise NotImplementedError
67
+
68
+ def insert(self, item: ItemT) -> DatabaseCommand:
69
+ raise NotImplementedError
70
+
71
+ def select(self, item_id: str) -> DatabaseCommand:
72
+ raise NotImplementedError
73
+
74
+ def select_duplicate(self, item: ItemT) -> DatabaseCommand:
75
+ raise NotImplementedError
76
+
77
+ def select_all(self) -> DatabaseCommand:
78
+ raise NotImplementedError
79
+
80
+ def update(self, item: ItemT) -> DatabaseCommand:
81
+ raise NotImplementedError
82
+
83
+ def delete(self, item_id: str) -> DatabaseCommand:
84
+ raise NotImplementedError
85
+
86
+ def delete_all(self) -> DatabaseCommand:
87
+ raise NotImplementedError
88
+
89
+ def load(self, data: dict[str, Any]) -> ItemT:
90
+ raise NotImplementedError
91
+
92
+ def duplicate(self, item: ItemT) -> ExistsError:
93
+ return ExistsError(item).with_duplicate(lambda i: "Unknown")
94
+
95
+
96
+ @dataclass
97
+ class UnknownError(Exception):
98
+ raw: dict[str, Any]
99
+
100
+
101
+ @dataclass(frozen=True)
102
+ class SqliteTableBuilder(Generic[ItemT]):
103
+ table_name: str | None = None
104
+ formatter: Formatter[dict[str, Any], ItemT] | None = None
105
+ fields: list[SqliteField] | None = None
106
+
107
+ def with_name(self, value: str) -> SqliteTableBuilder[ItemT]:
108
+ return SqliteTableBuilder[ItemT](value, self.formatter, self.fields)
109
+
110
+ def with_formatter(
111
+ self, value: Formatter[dict[str, Any], ItemT]
112
+ ) -> SqliteTableBuilder[ItemT]:
113
+ return SqliteTableBuilder[ItemT](self.table_name, value, self.fields)
114
+
115
+ def with_fields(self, fields: Iterable[str]) -> SqliteTableBuilder[ItemT]:
116
+ return SqliteTableBuilder[ItemT](
117
+ self.table_name,
118
+ self.formatter,
119
+ [SqliteField(field, field == "id", False) for field in list(fields)],
120
+ )
121
+
122
+ def with_id(self, identifier: str) -> SqliteTableBuilder[ItemT]:
123
+ assert self.fields is not None, "Set fields first."
124
+ if identifier not in [field.name for field in self.fields]:
125
+ raise ValueError("Missing fields in the table.")
126
+
127
+ return SqliteTableBuilder[ItemT](
128
+ self.table_name,
129
+ self.formatter,
130
+ [
131
+ SqliteField(field.name, field.name == identifier, field.is_composite)
132
+ for field in self.fields
133
+ ],
134
+ )
135
+
136
+ def with_composite_key(
137
+ self, composites: Iterable[str]
138
+ ) -> SqliteTableBuilder[ItemT]:
139
+ assert self.fields is not None, "Set fields first."
140
+
141
+ names = [field.name for field in self.fields]
142
+ if not all(field in names for field in list(composites)):
143
+ raise ValueError("Missing fields in the table.")
144
+
145
+ return SqliteTableBuilder[ItemT](
146
+ self.table_name,
147
+ self.formatter,
148
+ [
149
+ SqliteField(field.name, field.is_id, field.name in list(composites))
150
+ for field in self.fields
151
+ ],
152
+ )
153
+
154
+ def build(self) -> SqlTable[ItemT]:
155
+ if not self.table_name or not self.formatter or not self.fields:
156
+ raise ValueError("Cannot build sql table.")
157
+
158
+ return _DefaultSqlTable(self.table_name, self.formatter, self.fields)
159
+
160
+
161
+ @dataclass(frozen=True)
162
+ class _DefaultSqlTable(SqlTable[ItemT]):
163
+ table_name: str
164
+ formatter: Formatter[dict[str, Any], ItemT]
165
+ fields: list[SqliteField]
166
+
167
+ def count_all(self) -> DatabaseCommand:
168
+ return DatabaseCommand(f"""
169
+ SELECT count(*) as n_items
170
+ FROM {self.table_name.capitalize()};
171
+ """)
172
+
173
+ def insert(self, item: ItemT) -> DatabaseCommand:
174
+ columns = ", ".join([field.name for field in self.fields])
175
+ placeholders = ", ".join([f":{key.name}" for key in self.fields])
176
+
177
+ return DatabaseCommand(f"""
178
+ INSERT INTO {self.table_name.capitalize()} (
179
+ {columns}
180
+ ) VALUES (
181
+ {placeholders}
182
+ )
183
+ RETURNING {columns};
184
+ """).with_data(self.formatter.dump(item))
185
+
186
+ def select(self, item_id: str) -> DatabaseCommand:
187
+ columns = ", ".join([field.name for field in self.fields])
188
+
189
+ return DatabaseCommand(f"""
190
+ SELECT
191
+ {columns}
192
+ FROM {self.table_name.capitalize()}
193
+ WHERE {self._id} = :{self._id};
194
+ """).with_data({self._id: item_id})
195
+
196
+ def select_duplicate(self, item: ItemT) -> DatabaseCommand:
197
+ raw = self.formatter.dump(item)
198
+ columns = ", ".join([field.name for field in self.fields])
199
+
200
+ duplicates = " AND ".join([f"{field} = :{field}" for field in self._composite])
201
+
202
+ return DatabaseCommand(f"""
203
+ SELECT
204
+ {columns}
205
+ FROM {self.table_name.capitalize()}
206
+ WHERE {duplicates};
207
+ """).with_data({key: raw[key] for key in raw if key in self._composite})
208
+
209
+ def select_all(self) -> DatabaseCommand:
210
+ columns = ", ".join([field.name for field in self.fields])
211
+
212
+ return DatabaseCommand(f"""
213
+ SELECT
214
+ {columns}
215
+ FROM {self.table_name.capitalize()};
216
+ """)
217
+
218
+ def update(self, item: ItemT) -> DatabaseCommand:
219
+ updates = ", ".join(
220
+ [
221
+ f"{field.name} = :{field.name}"
222
+ for field in self.fields
223
+ if not field.is_id
224
+ ]
225
+ )
226
+
227
+ return DatabaseCommand(f"""
228
+ UPDATE {self.table_name.capitalize()}
229
+ SET
230
+ {updates}
231
+ WHERE
232
+ {self._id} = :{self._id};
233
+ """).with_data(self.formatter.dump(item))
234
+
235
+ def delete(self, item_id: str) -> DatabaseCommand:
236
+ return DatabaseCommand(f"""
237
+ DELETE
238
+ FROM {self.table_name.capitalize()}
239
+ WHERE
240
+ {self._id} = :{self._id};
241
+ """).with_data({self._id: item_id})
242
+
243
+ def delete_all(self) -> DatabaseCommand:
244
+ return DatabaseCommand(f"""
245
+ DELETE
246
+ FROM {self.table_name.capitalize()};
247
+ """)
248
+
249
+ def load(self, data: dict[str, Any]) -> ItemT:
250
+ return self.formatter.load(data)
251
+
252
+ def duplicate(self, item: ItemT) -> ExistsError:
253
+ raw = self.formatter.dump(item)
254
+ return ExistsError(item).with_duplicate(
255
+ lambda i: ",".join(
256
+ [f"{key}<{raw[key]}>" for key in raw if key in self._composite]
257
+ )
258
+ )
259
+
260
+ @property
261
+ def _id(self) -> str:
262
+ result = next((field for field in self.fields if field.is_id), None)
263
+ if result is None:
264
+ raise ValueError("Id field is required.")
265
+ return result.name
266
+
267
+ @property
268
+ def _composite(self) -> list[str]:
269
+ names = [field.name for field in self.fields if field.is_composite]
270
+ return [self._id] if len(names) == 0 else names
271
+
272
+
273
+ @dataclass(frozen=True)
274
+ class SqliteField:
275
+ name: str
276
+ is_id: bool
277
+ is_composite: bool
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "apexdevkit"
3
- version = "1.17.1"
3
+ version = "1.17.3"
4
4
  description = "Apex Development Tools for python."
5
5
  authors = ["Apex Dev <dev@apex.ge>"]
6
6
  readme = "README.md"
@@ -1,97 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from dataclasses import dataclass
4
- from sqlite3 import IntegrityError
5
- from typing import Any, Generic, Iterator
6
-
7
- from apexdevkit.error import DoesNotExistError, ExistsError
8
- from apexdevkit.repository import Database, DatabaseCommand, RepositoryBase
9
- from apexdevkit.repository.interface import ItemT
10
-
11
-
12
- @dataclass(frozen=True)
13
- class SqliteRepository(RepositoryBase[ItemT]):
14
- db: Database
15
- table: SqlTable[ItemT]
16
-
17
- def bind(self, **kwargs: Any) -> SqliteRepository[ItemT]:
18
- return SqliteRepository(self.db, self.table.bind(**kwargs))
19
-
20
- def __iter__(self) -> Iterator[ItemT]:
21
- for raw in self.db.execute(self.table.select_all()).fetch_all():
22
- yield self.table.load(raw)
23
-
24
- def __len__(self) -> int:
25
- raw = self.db.execute(self.table.count_all()).fetch_one()
26
-
27
- try:
28
- return int(raw["n_items"])
29
- except KeyError:
30
- raise UnknownError(raw)
31
-
32
- def create(self, item: ItemT) -> ItemT:
33
- try:
34
- return self.table.load(self.db.execute(self.table.insert(item)).fetch_one())
35
- except IntegrityError: # pragma: no cover
36
- item = self.table.load(
37
- self.db.execute(self.table.select_duplicate(item)).fetch_one()
38
- )
39
- self.table.duplicate(item).fire()
40
- return item
41
-
42
- def read(self, item_id: str) -> ItemT:
43
- raw = self.db.execute(self.table.select(str(item_id))).fetch_one()
44
-
45
- if not raw:
46
- raise DoesNotExistError(item_id)
47
-
48
- return self.table.load(raw)
49
-
50
- def update(self, item: ItemT) -> None:
51
- self.db.execute(self.table.update(item)).fetch_none()
52
-
53
- def delete(self, item_id: str) -> None:
54
- self.db.execute(self.table.delete(str(item_id))).fetch_none()
55
-
56
- def delete_all(self) -> None:
57
- self.db.execute(self.table.delete_all()).fetch_none()
58
-
59
-
60
- class SqlTable(Generic[ItemT]): # pragma: no cover
61
- def bind(self, **kwargs: Any) -> SqlTable[ItemT]:
62
- return self
63
-
64
- def count_all(self) -> DatabaseCommand:
65
- raise NotImplementedError
66
-
67
- def insert(self, item: ItemT) -> DatabaseCommand:
68
- raise NotImplementedError
69
-
70
- def select(self, item_id: str) -> DatabaseCommand:
71
- raise NotImplementedError
72
-
73
- def select_duplicate(self, item: ItemT) -> DatabaseCommand:
74
- raise NotImplementedError
75
-
76
- def select_all(self) -> DatabaseCommand:
77
- raise NotImplementedError
78
-
79
- def update(self, item: ItemT) -> DatabaseCommand:
80
- raise NotImplementedError
81
-
82
- def delete(self, item_id: str) -> DatabaseCommand:
83
- raise NotImplementedError
84
-
85
- def delete_all(self) -> DatabaseCommand:
86
- raise NotImplementedError
87
-
88
- def load(self, data: dict[str, Any]) -> ItemT:
89
- raise NotImplementedError
90
-
91
- def duplicate(self, item: ItemT) -> ExistsError:
92
- return ExistsError(item).with_duplicate(lambda i: "Unknown")
93
-
94
-
95
- @dataclass
96
- class UnknownError(Exception):
97
- raw: dict[str, Any]
File without changes
File without changes