Add Python CultMesh global document facade
This commit is contained in:
parent
59ddafe473
commit
4d9474036d
3 changed files with 60 additions and 3 deletions
|
|
@ -24,9 +24,12 @@ CultCache, CultNet, and CultMesh. It is evidence, not confetti.
|
|||
- Python CultMesh database facade:
|
||||
`node.database` owns the local typed document read/write/snapshot/sync surface
|
||||
so Python callers do not need to reach through the node composition wrapper.
|
||||
It also exposes local `watch(...)`, `watch_record(...)`, `watch_by_name(...)`,
|
||||
and `watch_by_index(...)` callbacks for database changes, including
|
||||
authoritative shard-log reconciliation applied through the session facade.
|
||||
It includes global document helpers that delegate through the same singleton
|
||||
key invariant as `CultCache`.
|
||||
It also exposes local `watch(...)`, `watch_record(...)`, `watch_global(...)`,
|
||||
`watch_by_name(...)`, and `watch_by_index(...)` callbacks for database changes,
|
||||
including authoritative shard-log reconciliation applied through the session
|
||||
facade.
|
||||
Change notifications carry previous values when the database can observe the
|
||||
old record before local or replicated application.
|
||||
- Python CultMesh committed simulation facts:
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ class CultMeshNode:
|
|||
def put(self, document: DocumentDefinition[Any], key: str, value: Any) -> None:
|
||||
self.database.put(document, key, value)
|
||||
|
||||
def put_global(self, document: DocumentDefinition[Any], value: Any) -> None:
|
||||
self.database.put_global(document, value)
|
||||
|
||||
def put_raw_message(
|
||||
self,
|
||||
document: DocumentDefinition[Any],
|
||||
|
|
@ -69,9 +72,18 @@ class CultMeshNode:
|
|||
def get_required(self, document: DocumentDefinition[Any], key: str) -> Any:
|
||||
return self.database.get_required(document, key)
|
||||
|
||||
def get_global(self, document: DocumentDefinition[Any]) -> Any:
|
||||
return self.database.get_global(document)
|
||||
|
||||
def get_required_global(self, document: DocumentDefinition[Any]) -> Any:
|
||||
return self.database.get_required_global(document)
|
||||
|
||||
def delete(self, document: DocumentDefinition[Any], key: str) -> None:
|
||||
self.database.delete(document, key)
|
||||
|
||||
def delete_global(self, document: DocumentDefinition[Any]) -> None:
|
||||
self.database.delete_global(document)
|
||||
|
||||
def delete_raw_message(
|
||||
self,
|
||||
document: DocumentDefinition[Any],
|
||||
|
|
@ -171,6 +183,13 @@ class CultMeshDatabase:
|
|||
) -> Callable[[], None]:
|
||||
return self.watch(callback, document=document, key=key)
|
||||
|
||||
def watch_global(
|
||||
self,
|
||||
document: DocumentDefinition[Any],
|
||||
callback: Callable[[CultMeshDatabaseChange], None],
|
||||
) -> Callable[[], None]:
|
||||
return self.watch_record(document, self.cache.GLOBAL_KEY, callback)
|
||||
|
||||
def watch_by_name(
|
||||
self,
|
||||
document: DocumentDefinition[Any],
|
||||
|
|
@ -224,6 +243,9 @@ class CultMeshDatabase:
|
|||
self.cache.put(document, key, value)
|
||||
self._publish_local_change(document, key, "added" if previous is None else "updated", value, previous)
|
||||
|
||||
def put_global(self, document: DocumentDefinition[Any], value: Any) -> None:
|
||||
self.put(document, self.cache.GLOBAL_KEY, value)
|
||||
|
||||
def put_raw_message(
|
||||
self,
|
||||
document: DocumentDefinition[Any],
|
||||
|
|
@ -262,12 +284,21 @@ class CultMeshDatabase:
|
|||
def get_required(self, document: DocumentDefinition[Any], key: str) -> Any:
|
||||
return self.cache.get_required(document, key)
|
||||
|
||||
def get_global(self, document: DocumentDefinition[Any]) -> Any:
|
||||
return self.cache.get_global(document)
|
||||
|
||||
def get_required_global(self, document: DocumentDefinition[Any]) -> Any:
|
||||
return self.cache.get_required_global(document)
|
||||
|
||||
def delete(self, document: DocumentDefinition[Any], key: str) -> None:
|
||||
previous = self.cache.get(document, key)
|
||||
self.cache.delete(document, key)
|
||||
if previous is not None:
|
||||
self._publish_local_change(document, key, "removed", None, previous)
|
||||
|
||||
def delete_global(self, document: DocumentDefinition[Any]) -> None:
|
||||
self.delete(document, self.cache.GLOBAL_KEY)
|
||||
|
||||
def delete_raw_message(
|
||||
self,
|
||||
document: DocumentDefinition[Any],
|
||||
|
|
|
|||
|
|
@ -917,6 +917,29 @@ class CultCacheTests(unittest.TestCase):
|
|||
with self.assertRaises(ValueError):
|
||||
node.database.register_document(conflicting)
|
||||
|
||||
def test_cultmesh_database_global_document_facade_uses_singleton_key_and_watchers(self) -> None:
|
||||
document = define_database_entry_type(
|
||||
"mesh.global_settings",
|
||||
[("theme", 0)],
|
||||
global_document=True,
|
||||
)
|
||||
node = CultMesh.create_node(runtime_id="mesh-global")
|
||||
node.database.register_document(document)
|
||||
changes: list[CultMeshDatabaseChange] = []
|
||||
|
||||
node.database.watch_global(document, changes.append)
|
||||
node.database.put_global(document, {"theme": "ash"})
|
||||
node.put_global(document, {"theme": "ember"})
|
||||
node.delete_global(document)
|
||||
|
||||
self.assertIsNone(node.database.get_global(document))
|
||||
self.assertEqual([change.record_key for change in changes], [node.cache.GLOBAL_KEY] * 3)
|
||||
self.assertEqual([change.change_kind for change in changes], ["added", "updated", "removed"])
|
||||
self.assertEqual(changes[1].previous_value, {"theme": "ash"})
|
||||
self.assertEqual(changes[2].previous_value, {"theme": "ember"})
|
||||
with self.assertRaises(Exception):
|
||||
node.database.put(document, "settings:wrong", {"theme": "bad"})
|
||||
|
||||
def test_cultmesh_database_watchers_observe_name_and_index_changes(self) -> None:
|
||||
document = define_database_entry_type(
|
||||
"mesh.named_watch",
|
||||
|
|
|
|||
Loading…
Reference in a new issue