nedb-engine 2.1.0__tar.gz → 2.2.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.
Files changed (28) hide show
  1. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/PKG-INFO +1 -1
  2. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/pyproject.toml +1 -1
  3. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/__init__.py +1 -1
  4. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/wrap_redis.py +64 -17
  5. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/.gitignore +0 -0
  6. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/LICENSE +0 -0
  7. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/README.md +0 -0
  8. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/client/node/README.md +0 -0
  9. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/client/python/README.md +0 -0
  10. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/autoindex.py +0 -0
  11. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/backends/__init__.py +0 -0
  12. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/backends/redis_backend.py +0 -0
  13. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/cascade.py +0 -0
  14. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/concurrent.py +0 -0
  15. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/crypto.py +0 -0
  16. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/engine.py +0 -0
  17. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/index.py +0 -0
  18. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/log.py +0 -0
  19. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/merkle.py +0 -0
  20. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/mongo.py +0 -0
  21. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/query.py +0 -0
  22. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/redis_compat.py +0 -0
  23. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/relations.py +0 -0
  24. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/resp2.py +0 -0
  25. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/server.py +0 -0
  26. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/snapshot.py +0 -0
  27. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/sql.py +0 -0
  28. {nedb_engine-2.1.0 → nedb_engine-2.2.1}/python/nedb/store.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nedb-engine
3
- Version: 2.1.0
3
+ Version: 2.2.1
4
4
  Summary: NEDB — a versioned, self-compressing, time-traveling embedded database (replay-protected, idempotent, relational, searchable) with durable AOF persistence and a server daemon (nedbd).
5
5
  Project-URL: Homepage, https://github.com/aiassistsecure/nedb
6
6
  Project-URL: Repository, https://github.com/aiassistsecure/nedb
@@ -10,7 +10,7 @@ build-backend = "hatchling.build"
10
10
 
11
11
  [project]
12
12
  name = "nedb-engine"
13
- version = "2.1.0"
13
+ version = "2.2.1"
14
14
  description = "NEDB — a versioned, self-compressing, time-traveling embedded database (replay-protected, idempotent, relational, searchable) with durable AOF persistence and a server daemon (nedbd)."
15
15
  readme = "README.md"
16
16
  requires-python = ">=3.8"
@@ -47,4 +47,4 @@ __all__ = [
47
47
  "wrap_redis", "WrappedRedis",
48
48
  "_native", "__has_native__",
49
49
  ]
50
- __version__ = "2.1.0"
50
+ __version__ = "2.2.1"
@@ -151,12 +151,31 @@ class NedBdProxy:
151
151
  self._req("DELETE", f"/v1/databases/{self._name}/rows/{coll}/{id}")
152
152
 
153
153
  def link(self, frm: str, rel: str, to: str, **_kw) -> None:
154
- self._req("POST", self._db("/link"), {"frm": frm, "rel": rel, "to": to})
154
+ # v1 nedbd has POST /link; v2 DAG stores relations as NQL-queryable docs
155
+ # in a __links__ collection — compatible with TRAVERSE queries.
156
+ try:
157
+ self._req("POST", self._db("/link"), {"frm": frm, "rel": rel, "to": to})
158
+ except RuntimeError as e:
159
+ if "404" in str(e) or "not found" in str(e).lower():
160
+ # v2 DAG: store as a document so NQL can traverse it
161
+ self._req("POST", self._db("/put"), {
162
+ "coll": "__links__",
163
+ "id": f"{frm}|{rel}|{to}",
164
+ "doc": {"_from": frm, "_rel": rel, "_to": to},
165
+ })
166
+ else:
167
+ raise
155
168
 
156
169
  def unlink(self, frm: str, rel: str, to: str, **_kw) -> None:
157
- # nedbd doesn't have a dedicated unlink endpoint yet — use NQL delete
158
- # fallback: store as a tombstone via link with _unlinked flag
159
- pass # no-op; future: DELETE /v1/databases/{name}/links/{frm}/{rel}/{to}
170
+ try:
171
+ self._req("DELETE", f"/v1/databases/{self._name}/links/{frm}/{rel}/{to}")
172
+ except RuntimeError:
173
+ # v2 fallback: tombstone the __links__ doc
174
+ try:
175
+ self._req("DELETE",
176
+ f"/v1/databases/{self._name}/rows/__links__/{frm}|{rel}|{to}")
177
+ except RuntimeError:
178
+ pass
160
179
 
161
180
  def neighbors(self, frm: str, rel: str, as_of: Optional[int] = None) -> List[str]:
162
181
  frm_coll, frm_id = (frm.split(":", 1) + [""])[:2]
@@ -423,9 +442,28 @@ class NEDBSurface:
423
442
  return total
424
443
 
425
444
  def _backfill_one(self, mapping: CollectionMapping, batch_size: int) -> int:
426
- """Import all keys matching one mapping from Redis into NEDB."""
427
- count = 0
428
- cursor = 0
445
+ """Import all keys matching one mapping from Redis into NEDB.
446
+
447
+ In nedbd mode uses /batch for high throughput (v2 DAG: ~4000 ops/s).
448
+ In-process mode falls back to individual puts.
449
+ """
450
+ count = 0
451
+ cursor = 0
452
+ pending: List[dict] = []
453
+
454
+ def _flush() -> int:
455
+ if not pending or not self._nedbd_mode:
456
+ return 0
457
+ proxy: NedBdProxy = self._db # type: ignore[assignment]
458
+ try:
459
+ r = proxy._req("POST", proxy._db("/batch"), {"ops": list(pending)})
460
+ n = r.get("count", len(pending))
461
+ pending.clear()
462
+ return n
463
+ except Exception:
464
+ pending.clear()
465
+ return 0
466
+
429
467
  while True:
430
468
  cursor, keys = self._r.scan(cursor, match=mapping.pattern,
431
469
  count=batch_size)
@@ -441,16 +479,24 @@ class NEDBSurface:
441
479
  continue
442
480
  doc = mapping.parse_value(raw_val)
443
481
  doc.setdefault("_source", "backfill")
444
- self._db.put(mapping.collection, doc_id, doc,
445
- client="__backfill__",
446
- evidence="backfill",
447
- confidence=1.0)
448
- self._persist_last_op()
449
- count += 1
482
+ if self._nedbd_mode:
483
+ pending.append({"op": "put", "coll": mapping.collection,
484
+ "id": doc_id, "doc": doc})
485
+ if len(pending) >= 500:
486
+ count += _flush()
487
+ else:
488
+ self._db.put(mapping.collection, doc_id, doc,
489
+ client="__backfill__",
490
+ evidence="backfill",
491
+ confidence=1.0)
492
+ self._persist_last_op()
493
+ count += 1
450
494
  except Exception:
451
495
  pass # skip unreadable keys
452
496
  if cursor == 0:
453
497
  break
498
+
499
+ count += _flush() # flush remainder
454
500
  return count
455
501
 
456
502
  # ── Write shadowing ───────────────────────────────────────────────────────
@@ -641,10 +687,11 @@ def wrap_redis(r: Any, db_name: str = "default",
641
687
  Args:
642
688
  r: An existing ``redis.Redis`` (or compatible) connection.
643
689
  db_name: Logical database name. NEDB uses ``nedb:{db_name}:*``.
644
- nedbd_url: Optional URL of a running nedbd server, e.g.
645
- ``"http://localhost:8421"``. When set, all ``r.nedb.*``
646
- calls are forwarded to nedbd instead of running in-process.
647
- nedbd handles its own durable AOF persistence on disk.
690
+ nedbd_url: Optional URL of a running nedbd server.
691
+ v1 AOF: ``"http://localhost:7070"`` (nedbd, no flag)
692
+ v2 DAG: ``"http://localhost:7070"`` (nedbd --dag)
693
+ When set, all r.nedb.* calls go to nedbd over HTTP.
694
+ v2 DAG backfill uses /batch for ~4000 ops/s throughput.
648
695
  nedbd_token: Optional bearer token for nedbd authentication
649
696
  (set via ``NEDBD_TOKEN`` env on the server).
650
697
 
File without changes
File without changes
File without changes