3 files changed, 56 insertions(+), 8 deletions(-)
M quark/__init__.py
R quark/{quark.py => db.py}
R quark/{test_quark.py => test_db.py}
M quark/__init__.py => quark/__init__.py +1 -1
@@ 1,4 1,4 @@
from .squuid import squuid, squuid_time_millis
-from .quark import Quark, Entity
+from .db import Quark, Entity
__all__ = ["squuid", "squuid_time_millis", "Quark", "Entity"]
R quark/quark.py => quark/db.py +7 -7
@@ 10,7 10,7 @@ from logging import getLogger
from typing import Any, Dict, Generator, List, Optional, Tuple, Union
from uuid import UUID
-import quark.sql as sql
+from quark import sql
from quark.errors import (
DBError,
IntegrityError,
@@ 130,7 130,7 @@ class Entity(UserDict):
self.data = properties
self.db = db
self.modified = set()
- self.deleted = set()
+ self.deleted = dict()
def detach(self) -> None:
self.db = None
@@ 162,6 162,7 @@ class Entity(UserDict):
def __setitem__(self, key, value):
self.modified.add(key)
self.data[key] = value
+ self.deleted.pop(key, None)
def commit(self) -> TX:
if self.db is None:
@@ 169,13 170,12 @@ class Entity(UserDict):
assertions: List[Assertion] = []
for key in self.modified:
assertions.append((":db/add", self.eid, key, self[key]))
- for key in self.deleted:
- assertions.append((":db/retract", self.eid, key, self[key]))
+ for key, value in self.deleted.items():
+ assertions.append((":db/retract", self.eid, key, value))
return self.db.transact(assertions)
def __delitem__(self, key):
- self.deleted.add(key)
- self.pop(key)
+ self.deleted[key] = self.data.pop(key)
class Quark:
@@ 375,7 375,7 @@ class Quark:
def _update_entity_refs(self, assertion: Assertion):
e = self._entity_refs.get(assertion[1])
- if e:
+ if e and e.db:
e.data[assertion[2]] = assertion[3]
def _normalize(
R quark/test_quark.py => quark/test_db.py +48 -0
@@ 138,6 138,54 @@ def test_cardinality_many(quark):
assert entity[':user/email'] == 'noah@packetlost.dev'
assert isinstance(entity[':user/reportsTo'], Entity)
+@pytest.fixture
+def db_with_entity(quark):
+ schema = [
+ {":db/ident": ":user/email", ":db/unique": ":db.unique/identity"},
+ {":db/ident": ":user/firstname", ":db/valueType": ":db.type/string"},
+ {":db/ident": ":user/lastname", ":db/valueType": ":db.type/string"},
+ {":db/ident": ":user/address", ":db/valueType": ":db.type/string"},
+ {":db/ident": ":user/job", ":db/valueType": ":db.type/string"},
+ ]
+ tx = quark.transact(schema)
+ temp_id = "abc"
+ assertion = {
+ ":db/id": temp_id,
+ ":user/email": "noah@packetlost.dev",
+ ":user/firstname": "Noah",
+ ":user/lastname": "Pederson",
+ ":user/address": "Fake address",
+ ":user/job": "Software Engineer",
+ }
+ tx = quark.transact([assertion])
+ return quark, tx.temp_ids[temp_id]
+
+def test_entity_sync_update(db_with_entity):
+ quark, eid = db_with_entity
+ noah = quark.get_entity(eid)
+ # Check that we have the right entity
+ assert noah[":user/job"] == "Software Engineer"
+ other_noah = quark.get_entity(eid)
+ assert noah[':user/job'] == other_noah[':user/job']
+ noah[':user/job'] = 'CEO'
+ assert noah[':user/job'] == 'CEO'
+ assert other_noah[":user/job"] == "Software Engineer"
+ noah.commit()
+ assert other_noah[":user/job"] == "CEO"
+
+def test_entity_sync_del(db_with_entity):
+ quark, eid = db_with_entity
+ noah = quark.get_entity(eid)
+ other_noah = quark.get_entity(eid)
+ assert noah[':user/job'] == 'Software Engineer'
+ del noah[':user/job']
+ with pytest.raises(KeyError):
+ noah[':user/job']
+ assert other_noah[':user/job'] == 'Software Engineer'
+ noah.commit()
+ with pytest.raises(KeyError):
+ other_noah[':user/job']
+
if __name__ == "__main__":