source: flexoentity/flexoentity/composite_backend.py@ 3389960

unify_backends
Last change on this file since 3389960 was 3389960, checked in by Enrico Schwass <ennoausberlin@…>, 3 days ago

redesign of Identity and PersistanceBackends - this is a breaking change.

  • Property mode set to 100644
File size: 3.5 KB
Line 
1from .persistance_backend import PersistanceBackend
2from .flexo_entity import FlexoEntity
3
4
5class CompositeBackend(PersistanceBackend):
6 """
7 Backend wrapper.
8
9 Option A semantics:
10 - Reads come from the primary backend only.
11 - Writes propagate to primary and all sync backends.
12 - All backends store/return dicts.
13 """
14
15 def __init__(self, authoritative_backend, sync_backends=None):
16 # Validate entity_class existence and compatibility
17 entity_class = getattr(authoritative_backend, "entity_class", None)
18 if entity_class is None:
19 raise TypeError("primary_backend must expose .entity_class")
20
21 if not issubclass(entity_class, FlexoEntity):
22 raise TypeError("entity_class must be a subclass of FlexoEntity")
23
24 super().__init__(entity_class)
25
26 self._primary = authoritative_backend
27 self.sync_backends = list(sync_backends or [])
28
29 for b in self.sync_backends:
30 if b.entity_class != self._primary.entity_class:
31 raise TypeError(
32 f"Backend {b} does not match entity_class={self.entity_class.__name__}"
33 )
34
35 @property
36 def primary(self):
37 return self._primary
38
39 def add_sync_backend(self, backend, clear=False):
40 if backend.entity_class != self.primary.entity_class:
41 raise TypeError("Backend entity_class mismatch")
42
43 if clear:
44 backend.clear()
45
46 # Sync current data into backend
47 for d in self.primary.load_all():
48 backend.save(d)
49
50 self.sync_backends.append(backend)
51
52 def remove_backend(self, backend):
53 if backend is self.primary:
54 raise ValueError("Cannot remove the primary backend")
55 self.sync_backends.remove(backend)
56
57 # ---------------------------------------------------------
58 # Write operations propagate to *all* backends (dicts)
59 # ---------------------------------------------------------
60
61 def save(self, entity_dict: dict):
62 self.primary.save(entity_dict)
63 for b in self.sync_backends:
64 b.save(entity_dict)
65
66 def update(self, entity_dict: dict):
67 self.primary.update(entity_dict)
68 for b in self.sync_backends:
69 b.update(entity_dict)
70
71 def delete(self, flexo_id: str):
72 self.primary.delete(flexo_id)
73 for b in self.sync_backends:
74 b.delete(flexo_id)
75
76 # ---------------------------------------------------------
77 # Read operations from primary only
78 # ---------------------------------------------------------
79
80 def load(self, flexo_id: str):
81 return self.primary.load(flexo_id)
82
83 def load_all(self):
84 return self.primary.load_all()
85
86 # ---------------------------------------------------------
87 # Sync helpers
88 # ---------------------------------------------------------
89
90 def sync_all(self, clear_targets=False):
91 """
92 Push all data from primary backend to the other backends.
93 If clear_targets=True, wipe sync backends first.
94 """
95 if clear_targets:
96 for b in self.sync_backends:
97 b.clear()
98
99 for d in self.primary.load_all():
100 for b in self.sync_backends:
101 b.save(d)
102
103 def clear(self):
104 self.primary.clear()
105 for b in self.sync_backends:
106 b.clear()
107
108 def __repr__(self):
109 names = ", ".join(b.__class__.__name__ for b in self.sync_backends)
110 return f"<CompositeBackend primary={self.primary.__class__.__name__} sync=[{names}]>"
Note: See TracBrowser for help on using the repository browser.