scruby 0.9.2__py3-none-any.whl → 0.10.0__py3-none-any.whl

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.

Potentially problematic release.


This version of scruby might be problematic. Click here for more details.

scruby/db.py CHANGED
@@ -6,6 +6,7 @@ __all__ = ("Scruby",)
6
6
 
7
7
  import concurrent.futures
8
8
  import contextlib
9
+ import datetime
9
10
  import logging
10
11
  import zlib
11
12
  from collections.abc import Callable
@@ -15,6 +16,7 @@ from typing import Any, Never, TypeVar, assert_never
15
16
 
16
17
  import orjson
17
18
  from anyio import Path, to_thread
19
+ from pydantic import BaseModel
18
20
 
19
21
  from scruby import constants
20
22
 
@@ -23,6 +25,14 @@ logger = logging.getLogger(__name__)
23
25
  T = TypeVar("T")
24
26
 
25
27
 
28
+ class _Meta(BaseModel):
29
+ """Metadata of collection."""
30
+
31
+ count_documents: int
32
+ created_at: datetime.datetime
33
+ updated_at: datetime.datetime
34
+
35
+
26
36
  class Scruby[T]:
27
37
  """Creation and management of database.
28
38
 
@@ -34,6 +44,7 @@ class Scruby[T]:
34
44
  self,
35
45
  class_model: T,
36
46
  ) -> None:
47
+ self.__meta = _Meta
37
48
  self.__class_model = class_model
38
49
  self.__db_root = constants.DB_ROOT
39
50
  self.__length_reduction_hash = constants.LENGTH_REDUCTION_HASH
@@ -51,10 +62,76 @@ class Scruby[T]:
51
62
  msg: str = f"{unreachable} - Unacceptable value for LENGTH_REDUCTION_HASH."
52
63
  logger.critical(msg)
53
64
  assert_never(Never(unreachable))
65
+ # Create metadata if absent.
66
+ self._create_metadata()
67
+
68
+ def _create_metadata(self) -> None:
69
+ """Create metadata for collection if absent.
70
+
71
+ This method is for internal use.
72
+ """
73
+ key: int = 0
74
+ key_as_hash: str = f"{key:08x}"[self.__length_reduction_hash :]
75
+ separated_hash: str = "/".join(list(key_as_hash))
76
+ branch_path = SyncPath(
77
+ *(
78
+ self.__db_root,
79
+ self.__class_model.__name__,
80
+ separated_hash,
81
+ ),
82
+ )
83
+ if not branch_path.exists():
84
+ branch_path.mkdir(parents=True)
85
+ meta = _Meta(
86
+ count_documents=0,
87
+ created_at=datetime.datetime.now(), # noqa: DTZ005
88
+ updated_at=datetime.datetime.now(), # noqa: DTZ005
89
+ )
90
+ meta_json = meta.model_dump_json()
91
+ meta_path = SyncPath(*(branch_path, "meta.json"))
92
+ meta_path.write_text(meta_json, "utf-8")
93
+
94
+ async def _get_meta_path(self) -> Path:
95
+ """Asynchronous method for getting path to metadata of collection.
96
+
97
+ This method is for internal use.
98
+ """
99
+ key: int = 0
100
+ key_as_hash: str = f"{key:08x}"[self.__length_reduction_hash :]
101
+ separated_hash: str = "/".join(list(key_as_hash))
102
+ return Path(
103
+ *(
104
+ self.__db_root,
105
+ self.__class_model.__name__,
106
+ separated_hash,
107
+ "meta.json",
108
+ ),
109
+ )
54
110
 
55
- async def get_leaf_path(self, key: str) -> Path:
111
+ async def _get_meta(self) -> _Meta:
112
+ """Asynchronous method for getting metadata of collection.
113
+
114
+ This method is for internal use.
115
+ """
116
+ meta_path = await self._get_meta_path()
117
+ meta_json = await meta_path.read_text()
118
+ meta: _Meta = self.__meta.model_validate_json(meta_json)
119
+ return meta
120
+
121
+ async def _set_meta(self, meta: _Meta) -> None:
122
+ """Asynchronous method for updating metadata of collection.
123
+
124
+ This method is for internal use.
125
+ """
126
+ meta_path = await self._get_meta_path()
127
+ meta_json = meta.model_dump_json()
128
+ await meta_path.write_text(meta_json, "utf-8")
129
+
130
+ async def _get_leaf_path(self, key: str) -> Path:
56
131
  """Asynchronous method for getting path to collection cell by key.
57
132
 
133
+ This method is for internal use.
134
+
58
135
  Args:
59
136
  key: Key name.
60
137
  """
@@ -95,7 +172,7 @@ class Scruby[T]:
95
172
  value: Value of key.
96
173
  """
97
174
  # The path to the database cell.
98
- leaf_path: Path = await self.get_leaf_path(key)
175
+ leaf_path: Path = await self._get_leaf_path(key)
99
176
  value_json: str = value.model_dump_json()
100
177
  # Write key-value to the database.
101
178
  if await leaf_path.exists():
@@ -115,7 +192,7 @@ class Scruby[T]:
115
192
  key: Key name.
116
193
  """
117
194
  # The path to the database cell.
118
- leaf_path: Path = await self.get_leaf_path(key)
195
+ leaf_path: Path = await self._get_leaf_path(key)
119
196
  # Get value of key.
120
197
  if await leaf_path.exists():
121
198
  data_json: bytes = await leaf_path.read_bytes()
@@ -133,7 +210,7 @@ class Scruby[T]:
133
210
  key: Key name.
134
211
  """
135
212
  # The path to the database cell.
136
- leaf_path: Path = await self.get_leaf_path(key)
213
+ leaf_path: Path = await self._get_leaf_path(key)
137
214
  # Checking whether there is a key.
138
215
  if await leaf_path.exists():
139
216
  data_json: bytes = await leaf_path.read_bytes()
@@ -152,7 +229,7 @@ class Scruby[T]:
152
229
  key: Key name.
153
230
  """
154
231
  # The path to the database cell.
155
- leaf_path: Path = await self.get_leaf_path(key)
232
+ leaf_path: Path = await self._get_leaf_path(key)
156
233
  # Deleting key.
157
234
  if await leaf_path.exists():
158
235
  data_json: bytes = await leaf_path.read_bytes()
@@ -178,14 +255,17 @@ class Scruby[T]:
178
255
  return
179
256
 
180
257
  @staticmethod
181
- def search_task(
258
+ def _search_task(
182
259
  key: int,
183
260
  filter_fn: Callable,
184
261
  length_reduction_hash: str,
185
262
  db_root: str,
186
263
  class_model: T,
187
264
  ) -> dict[str, Any] | None:
188
- """Search task."""
265
+ """Task for searching for documents.
266
+
267
+ This method is for internal use.
268
+ """
189
269
  key_as_hash: str = f"{key:08x}"[length_reduction_hash:]
190
270
  separated_hash: str = "/".join(list(key_as_hash))
191
271
  leaf_path: SyncPath = SyncPath(
@@ -226,7 +306,7 @@ class Scruby[T]:
226
306
  If None, then there is no limit on the wait time.
227
307
  """
228
308
  keys: range = range(1, self.__max_num_keys)
229
- search_task_fn: Callable = self.search_task
309
+ search_task_fn: Callable = self._search_task
230
310
  length_reduction_hash: int = self.__length_reduction_hash
231
311
  db_root: str = self.__db_root
232
312
  class_model: T = self.__class_model
@@ -245,7 +325,7 @@ class Scruby[T]:
245
325
  return doc
246
326
  return None
247
327
 
248
- def find_many(
328
+ def find(
249
329
  self,
250
330
  filter_fn: Callable,
251
331
  db_query_docs_limit: int = 1000,
@@ -268,7 +348,7 @@ class Scruby[T]:
268
348
  If None, then there is no limit on the wait time.
269
349
  """
270
350
  keys: range = range(1, self.__max_num_keys)
271
- search_task_fn: Callable = self.search_task
351
+ search_task_fn: Callable = self._search_task
272
352
  length_reduction_hash: int = self.__length_reduction_hash
273
353
  db_root: str = self.__db_root
274
354
  class_model: T = self.__class_model
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scruby
3
- Version: 0.9.2
3
+ Version: 0.10.0
4
4
  Summary: A fast key-value storage library.
5
5
  Project-URL: Homepage, https://github.com/kebasyaty/scruby
6
6
  Project-URL: Repository, https://github.com/kebasyaty/scruby
@@ -274,7 +274,7 @@ async def main() -> None:
274
274
  await db.set_key(f"+44798612345{num}", user)
275
275
 
276
276
  # Find users by email.
277
- users: list[User] | None = user_coll.find_many(
277
+ users: list[User] | None = user_coll.find(
278
278
  filter_fn=lambda doc: doc.email == "John_Smith_5@gmail.com" or doc.email == "John_Smith_8@gmail.com",
279
279
  )
280
280
  if users is not None:
@@ -0,0 +1,8 @@
1
+ scruby/__init__.py,sha256=wFwUS1KcLxfIopXOVS8gPue9fNzIIU2cVj_RgK5drz4,849
2
+ scruby/constants.py,sha256=GbB-O0qaVdi5EHUp-zRAppFXLR-oHxpXUFVAOCpS0C8,1022
3
+ scruby/db.py,sha256=kwF1X_HB2CaNGNY0DVrC6s8OQ5Iix1azQOmfA_10JBo,13563
4
+ scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ scruby-0.10.0.dist-info/METADATA,sha256=seuAAwZHI-iso9O4durUh4dSye1KQrSZ8MjTkyOvCq8,10829
6
+ scruby-0.10.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ scruby-0.10.0.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
8
+ scruby-0.10.0.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- scruby/__init__.py,sha256=wFwUS1KcLxfIopXOVS8gPue9fNzIIU2cVj_RgK5drz4,849
2
- scruby/constants.py,sha256=GbB-O0qaVdi5EHUp-zRAppFXLR-oHxpXUFVAOCpS0C8,1022
3
- scruby/db.py,sha256=W3VvC3ss1NXonQnFI6Yw2MobBARMgus5Acw-k5uL3TE,10946
4
- scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- scruby-0.9.2.dist-info/METADATA,sha256=vZab1ietT1of_GXLHEISYhIkXZJuBIp3vk_rAFGeNPA,10833
6
- scruby-0.9.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- scruby-0.9.2.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
8
- scruby-0.9.2.dist-info/RECORD,,