scruby 2.0.2__py3-none-any.whl → 2.0.4__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.
scruby/cache.py CHANGED
@@ -7,7 +7,7 @@ __all__ = ("DocCache",)
7
7
 
8
8
  import string
9
9
  from pathlib import Path
10
- from typing import Any, ClassVar, Literal, Never, assert_never, final
10
+ from typing import Any, ClassVar, Literal, final
11
11
 
12
12
  import orjson
13
13
 
@@ -35,8 +35,9 @@ class DocCache:
35
35
  cls.cache[collection_name] = {
36
36
  key: {key: {key: {} for key in hexdigits} for key in hexdigits} for key in hexdigits
37
37
  }
38
- case _ as unreachable:
39
- assert_never(Never(unreachable)) # pyrefly: ignore[not-callable]
38
+ case _:
39
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
40
+ raise AssertionError(msg)
40
41
 
41
42
  @classmethod
42
43
  def load_cache(cls, subclasses: list[Any]) -> None:
scruby/mixins/count.py CHANGED
@@ -34,7 +34,7 @@ class Count:
34
34
  self,
35
35
  filter_fn: Callable,
36
36
  ) -> int:
37
- """Asynchronous method.
37
+ """Synchronous method.
38
38
 
39
39
  Count the number of documents a matching the filter in this collection.
40
40
 
scruby/mixins/delete.py CHANGED
@@ -68,6 +68,9 @@ class Delete:
68
68
  del DocCache.cache[collection_name][branch_number_as_hash[0]][branch_number_as_hash[1]][
69
69
  branch_number_as_hash[2]
70
70
  ][doc_name]
71
+ case _:
72
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
73
+ raise AssertionError(msg)
71
74
  else:
72
75
  new_state[doc_name] = doc_json
73
76
  await leaf_path.write_bytes(orjson.dumps(new_state))
scruby/mixins/find.py CHANGED
@@ -68,6 +68,9 @@ class Find:
68
68
  docs = DocCache.cache[collection_name][branch_number_as_hash[0]][branch_number_as_hash[1]][
69
69
  branch_number_as_hash[2]
70
70
  ]
71
+ case _:
72
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
73
+ raise AssertionError(msg)
71
74
 
72
75
  for _, doc in docs.items():
73
76
  if stop_event.is_set():
scruby/mixins/keys.py CHANGED
@@ -79,6 +79,9 @@ class Keys:
79
79
  DocCache.cache[collection_name][key_as_hash[0]][key_as_hash[1]][prepared_key] = doc
80
80
  case 5:
81
81
  DocCache.cache[collection_name][key_as_hash[0]][key_as_hash[1]][key_as_hash[2]][prepared_key] = doc
82
+ case _:
83
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
84
+ raise AssertionError(msg)
82
85
 
83
86
  @final
84
87
  async def update_doc(self, doc: Any) -> None:
@@ -126,6 +129,9 @@ class Keys:
126
129
  DocCache.cache[collection_name][key_as_hash[0]][key_as_hash[1]][key_as_hash[2]][
127
130
  prepared_key
128
131
  ] = doc
132
+ case _:
133
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
134
+ raise AssertionError(msg)
129
135
  else:
130
136
  raise KeyNotExistsError()
131
137
  else:
@@ -162,6 +168,9 @@ class Keys:
162
168
  return DocCache.cache[collection_name][key_as_hash[0]][key_as_hash[1]].get(prepared_key)
163
169
  case 5:
164
170
  return DocCache.cache[collection_name][key_as_hash[0]][key_as_hash[1]][key_as_hash[2]].get(prepared_key)
171
+ case _:
172
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
173
+ raise AssertionError(msg)
165
174
 
166
175
  @final
167
176
  def has_key(self, key: str) -> bool:
@@ -199,6 +208,9 @@ class Keys:
199
208
  DocCache.cache[collection_name][key_as_hash[0]][key_as_hash[1]][key_as_hash[2]].get(prepared_key)
200
209
  is not None
201
210
  )
211
+ case _:
212
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
213
+ raise AssertionError(msg)
202
214
  return is_exists
203
215
 
204
216
  @final
@@ -234,6 +246,9 @@ class Keys:
234
246
  del DocCache.cache[collection_name][key_as_hash[0]][key_as_hash[1]][key_as_hash[2]][
235
247
  prepared_key
236
248
  ]
249
+ case _:
250
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
251
+ raise AssertionError(msg)
237
252
  else:
238
253
  raise KeyNotExistsError()
239
254
  else:
scruby/mixins/update.py CHANGED
@@ -74,6 +74,9 @@ class Update:
74
74
  DocCache.cache[collection_name][branch_number_as_hash[0]][branch_number_as_hash[1]][
75
75
  branch_number_as_hash[2]
76
76
  ][doc_name] = doc
77
+ case _:
78
+ msg = "Scruby.run() > Parameter: `hash_reduce_left` -> Valid values are Literal[7, 6, 5]."
79
+ raise AssertionError(msg)
77
80
  # Update counter
78
81
  counter += 1
79
82
  else:
@@ -88,7 +91,7 @@ class Update:
88
91
  new_data: dict[str, Any],
89
92
  filter_fn: Callable = lambda _: True,
90
93
  ) -> int:
91
- """Asynchronous method for updates many documents matching the filter.
94
+ """Asynchronous method for updates one or more documents matching the filter.
92
95
 
93
96
  Attention:
94
97
  - For a complex case, a custom task may be needed.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scruby
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Asynchronous library for building and managing a hybrid database, by scheme of key-value.
5
5
  Project-URL: Bug Tracker, https://github.com/kebasyaty/scruby/issues
6
6
  Project-URL: Changelog, https://github.com/kebasyaty/scruby/blob/v2/CHANGELOG.md
@@ -96,6 +96,10 @@ Description-Content-Type: text/markdown
96
96
  6 = 256 branches in collection -> ~256000+ docs (for small projects).
97
97
  <br>
98
98
  5 = 4096 branches in collection -> ~4096000+ docs (for large projects).
99
+ <br>
100
+ <br>
101
+ <b>If you notice the production server slowing down,</b><br>
102
+ <b>you will need to add RAM and CPU.</b>
99
103
  </p>
100
104
 
101
105
  <br>
@@ -137,7 +141,6 @@ from typing import Annotated
137
141
  from pydantic import EmailStr, Field
138
142
  from pydantic_extra_types.phone_numbers import PhoneNumber, PhoneNumberValidator
139
143
  from scruby import Scruby, ScrubyModel, ScrubyConfig
140
- from pprint import pprint as pp
141
144
 
142
145
 
143
146
  class User(ScrubyModel):
@@ -180,7 +183,6 @@ async def main() -> None:
180
183
 
181
184
  # Get user details
182
185
  user = user_coll.get_doc("+447986123456")
183
- pp(user)
184
186
  user_coll.get_doc("key missing") # => None
185
187
 
186
188
  # Check for the presence of a key in the collection
@@ -189,6 +191,21 @@ async def main() -> None:
189
191
  # Delete a document by key
190
192
  await user_coll.delete_doc("+447986123456")
191
193
 
194
+ # Get collection name
195
+ user_coll.collection_name() # => User
196
+
197
+ # Get collection list
198
+ coll_list = await Scruby.collection_list() # => ["User"]
199
+
200
+ # Get the number of documents in the collection from metadata
201
+ await user_coll.estimated_document_count() # => 1
202
+
203
+ # Get the number of documents comparable to the filter
204
+ user_coll.count_documents(filter_fn=lambda doc: doc.first_name == "John") == 1
205
+
206
+ # Delete collection
207
+ await Scruby.delete_collection("User")
208
+
192
209
  # Full database deletion
193
210
  # Hint: The main purpose is tests
194
211
  Scruby.napalm()
@@ -208,7 +225,6 @@ The search effectiveness depends on the number of processor threads.
208
225
  import anyio
209
226
  from pydantic import Field
210
227
  from scruby import ReturnType, Scruby, ScrubyConfig, ScrubyModel
211
- from pprint import pprint as pp
212
228
 
213
229
 
214
230
  class Phone(ScrubyModel):
@@ -248,19 +264,11 @@ async def main() -> None:
248
264
  phone_details: Phone | None = phone_coll.find_one(
249
265
  filter_fn=lambda doc: doc.brand == "Samsung",
250
266
  )
251
- if phone_details is not None:
252
- pp(phone_details)
253
- else:
254
- print("No Phone!")
255
267
 
256
268
  # Find phone by model
257
269
  phone_details: Phone | None = phone_coll.find_one(
258
270
  filter_fn=lambda doc: doc.model == "Galaxy A26",
259
271
  )
260
- if phone_details is not None:
261
- pp(phone_details)
262
- else:
263
- print("No Phone!")
264
272
 
265
273
  # Return phone in JSON format
266
274
  phone_details: str | None = phone_coll.find_one(
@@ -268,7 +276,7 @@ async def main() -> None:
268
276
  return_type=ReturnType.JSON,
269
277
  )
270
278
 
271
- # Return phone in Dict format
279
+ # Return phone in Dictionary format
272
280
  phone_details: dict | None = phone_coll.find_one(
273
281
  filter_fn=lambda doc: doc.model == "Galaxy A26",
274
282
  return_type=ReturnType.DICT,
@@ -294,7 +302,6 @@ import anyio
294
302
  from typing import Annotated
295
303
  from pydantic import Field
296
304
  from scruby import ReturnType, Scruby, ScrubyConfig, ScrubyModel
297
- from pprint import pprint as pp
298
305
 
299
306
 
300
307
  class Car(ScrubyModel):
@@ -331,19 +338,11 @@ async def main() -> None:
331
338
 
332
339
  # Find all cars
333
340
  car_list: list[Car] | None = car_coll.find_many()
334
- if car_list is not None:
335
- pp(car_list)
336
- else:
337
- print("No cars!")
338
341
 
339
342
  # Find cars by brand and year
340
343
  car_list: list[Car] | None = car_coll.find_many(
341
344
  filter_fn=lambda doc: doc.brand == "Mazda" and doc.year == 2025,
342
345
  )
343
- if car_list is not None:
344
- pp(car_list)
345
- else:
346
- print("No cars!")
347
346
 
348
347
  # Pagination
349
348
  car_list: list[Car] | None = car_coll.find_many(
@@ -351,10 +350,6 @@ async def main() -> None:
351
350
  limit_docs=5,
352
351
  page_number=2,
353
352
  )
354
- if car_list is not None:
355
- pp(car_list)
356
- else:
357
- print("No cars!")
358
353
 
359
354
  # Sorting
360
355
  car_list: list[Car] | None = car_coll.find_many(
@@ -362,10 +357,6 @@ async def main() -> None:
362
357
  sort_fn=lambda doc: (doc.brand, doc.updated_at),
363
358
  sort_reverse=True,
364
359
  )
365
- if car_list is not None:
366
- pp(car_list)
367
- else:
368
- print("No cars!")
369
360
 
370
361
  # Return cars in JSON format
371
362
  car_list: str | None = car_coll.find_many(
@@ -373,12 +364,23 @@ async def main() -> None:
373
364
  return_type=ReturnType.JSON,
374
365
  )
375
366
 
376
- # Return cars in Dict format
367
+ # Return cars in Dictionary format
377
368
  car_list: list[dict] | None = car_coll.find_many(
378
369
  filter_fn=lambda doc: doc.brand == "Mazda",
379
370
  return_type=ReturnType.DICT,
380
371
  )
381
372
 
373
+ # Update one or more documents matching the filter
374
+ count_updated = await car_coll.update_many(
375
+ new_data={"brand": "BMW"},
376
+ filter_fn=lambda doc: doc.brand == "Mazda",
377
+ )
378
+
379
+ # Delete one or more documents matching the filter
380
+ count_deleted = await car_coll.delete_many(
381
+ filter_fn=lambda doc: doc.brand == "BMW",
382
+ )
383
+
382
384
  # Full database deletion
383
385
  # Hint: The main purpose is tests
384
386
  Scruby.napalm()
@@ -1,6 +1,6 @@
1
1
  scruby/__init__.py,sha256=40UhjME7WRJ-kHmqju4tMx9t1t6Sq6-EtL1LwgbTbcA,1280
2
2
  scruby/aggregation.py,sha256=NBFxQqyRqUG2KIuD9fbl4uzSHJWTaskjiZ1YNBa-Zbo,3575
3
- scruby/cache.py,sha256=rwCnttMVTEjb813OGWFoMSu2likdqAvFw_9gRlcJGUA,3356
3
+ scruby/cache.py,sha256=Et3NpeMDCNHa2B8H1El4QwIrlW4Cysf3ODeqkR2rGO4,3387
4
4
  scruby/config.py,sha256=RzCk4oLO4LeTQEuNljWKh9QxQ-6-mXmUpn9AmlpISCU,3514
5
5
  scruby/db.py,sha256=np6WFjjlXrDnA5nwRDb7Nscwvvn4r2CXvydXnRWeSS0,10194
6
6
  scruby/errors.py,sha256=lTWiHzyO5Es9Nkf7quODJjONGn6ifcL95qlpA4epQQM,1386
@@ -8,14 +8,14 @@ scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  scruby/utils.py,sha256=ZwWxSyh_BAOQkXlIqXFOlX2lHVk9rfYGQiVqtTk8PpE,1865
9
9
  scruby/mixins/__init__.py,sha256=nT79e80zXliuTGhR9CFosI2-3PQUCKwXbR7wPiFwgrU,669
10
10
  scruby/mixins/collection.py,sha256=VrFadQimpWLHaNcmS-dl6CC94CiOE2w_crxewOdZfvQ,1741
11
- scruby/mixins/count.py,sha256=asqDsKzjdZHiXybFYTSZje9yhum1atYkBzXddnC2Efw,2391
11
+ scruby/mixins/count.py,sha256=1tcQVxIxjlMNDG2XbI9QHKNjo5FbMlezIA80l0UE3Ac,2390
12
12
  scruby/mixins/custom_task.py,sha256=MCelgM8GNBkO6INaWQ5h5NX53zrgV90QWIZDl8Ygmrw,1412
13
- scruby/mixins/delete.py,sha256=7m7s1NKlFCgVPGyiGcWqXGD_0esgPckdTicl0WTT_Wo,4053
14
- scruby/mixins/find.py,sha256=Wly-94cqnVizcw6YLfcog2ygxzSNrApEly_OjgG5pMk,8677
15
- scruby/mixins/keys.py,sha256=vZ_TdLjq0YYinoXocyVKbGSDvf3esPzJe2bIw8nFZrA,9695
16
- scruby/mixins/update.py,sha256=-gyPQrr358W5pPslI2ZTVAeP12IXvXqqxvt1dqSFmG0,4627
17
- scruby-2.0.2.dist-info/METADATA,sha256=2SotkEcbKEj0oY0tzmxNDc7nWCz4tdpR3XRlSznTyvQ,13009
18
- scruby-2.0.2.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
19
- scruby-2.0.2.dist-info/licenses/GPL-3.0-LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
20
- scruby-2.0.2.dist-info/licenses/MIT-LICENSE,sha256=mS0Wz0yGNB63gEcWEnuIb_lldDYV0sjRaO-o_GL6CWE,1074
21
- scruby-2.0.2.dist-info/RECORD,,
13
+ scruby/mixins/delete.py,sha256=Q-FPJGm6pqJzoyEdd48M8o_kwYdYWLoceRuzcNXc_uw,4258
14
+ scruby/mixins/find.py,sha256=25LqXTHvzEIsB3KxUYGW-dOL_yYRBx7bVwcO5t9DPgo,8846
15
+ scruby/mixins/keys.py,sha256=kI8F_Q0q_V7FnyQUn7RatRMj4UaBuARY1qxsS8ey8oM,10588
16
+ scruby/mixins/update.py,sha256=syRUy2MvxKcUAjqn9ZTXzl3KGWO2PUbQoI0NeiAW-Bg,4839
17
+ scruby-2.0.4.dist-info/METADATA,sha256=WQQxRqWC5dS__uqQoUN1bdDEBUFsM0HWRim4H93oj2E,13335
18
+ scruby-2.0.4.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
19
+ scruby-2.0.4.dist-info/licenses/GPL-3.0-LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
20
+ scruby-2.0.4.dist-info/licenses/MIT-LICENSE,sha256=mS0Wz0yGNB63gEcWEnuIb_lldDYV0sjRaO-o_GL6CWE,1074
21
+ scruby-2.0.4.dist-info/RECORD,,
File without changes