|
31 | 31 | Access as _Access,
|
32 | 32 | AccessLevel,
|
33 | 33 | Anchor,
|
34 |
| - Architype, |
35 | 34 | DSFunc,
|
36 | 35 | EdgeAnchor as _EdgeAnchor,
|
37 | 36 | EdgeArchitype as _EdgeArchitype,
|
38 | 37 | NodeAnchor as _NodeAnchor,
|
39 | 38 | NodeArchitype as _NodeArchitype,
|
| 39 | + ObjectAnchor as _ObjectAnchor, |
| 40 | + ObjectArchitype as _ObjectArchitype, |
40 | 41 | Permission as _Permission,
|
41 | 42 | TANCH,
|
42 | 43 | WalkerAnchor as _WalkerAnchor,
|
|
53 | 54 | from ..jaseci.utils import logger
|
54 | 55 |
|
55 | 56 | MANUAL_SAVE = getenv("MANUAL_SAVE")
|
56 |
| -GENERIC_ID_REGEX = compile(r"^(n|e|w):([^:]*):([a-f\d]{24})$", IGNORECASE) |
| 57 | +GENERIC_ID_REGEX = compile(r"^(n|e|w|o):([^:]*):([a-f\d]{24})$", IGNORECASE) |
57 | 58 | NODE_ID_REGEX = compile(r"^n:([^:]*):([a-f\d]{24})$", IGNORECASE)
|
58 | 59 | EDGE_ID_REGEX = compile(r"^e:([^:]*):([a-f\d]{24})$", IGNORECASE)
|
59 | 60 | WALKER_ID_REGEX = compile(r"^w:([^:]*):([a-f\d]{24})$", IGNORECASE)
|
| 61 | +OBJECT_ID_REGEX = compile(r"^o:([^:]*):([a-f\d]{24})$", IGNORECASE) |
60 | 62 | T = TypeVar("T")
|
61 | 63 | TBA = TypeVar("TBA", bound="BaseArchitype")
|
62 | 64 |
|
@@ -167,12 +169,14 @@ class BulkWrite:
|
167 | 169 | NodeAnchor: [],
|
168 | 170 | EdgeAnchor: [],
|
169 | 171 | WalkerAnchor: [],
|
| 172 | + ObjectAnchor: [], |
170 | 173 | }
|
171 | 174 | )
|
172 | 175 |
|
173 | 176 | del_ops_nodes: list[ObjectId] = field(default_factory=list)
|
174 | 177 | del_ops_edges: list[ObjectId] = field(default_factory=list)
|
175 | 178 | del_ops_walker: list[ObjectId] = field(default_factory=list)
|
| 179 | + del_ops_object: list[ObjectId] = field(default_factory=list) |
176 | 180 |
|
177 | 181 | def del_node(self, id: ObjectId) -> None:
|
178 | 182 | """Add node to delete many operations."""
|
@@ -201,6 +205,15 @@ def del_walker(self, id: ObjectId) -> None:
|
201 | 205 |
|
202 | 206 | self.del_ops_walker.append(id)
|
203 | 207 |
|
| 208 | + def del_object(self, id: ObjectId) -> None: |
| 209 | + """Add walker to delete many operations.""" |
| 210 | + if not self.del_ops_object: |
| 211 | + self.operations[ObjectAnchor].append( |
| 212 | + DeleteMany({"_id": {"$in": self.del_ops_object}}) |
| 213 | + ) |
| 214 | + |
| 215 | + self.del_ops_object.append(id) |
| 216 | + |
204 | 217 | @property
|
205 | 218 | def has_operations(self) -> bool:
|
206 | 219 | """Check if has operations."""
|
@@ -244,6 +257,8 @@ def execute(self, session: ClientSession) -> None:
|
244 | 257 | EdgeAnchor.Collection.bulk_write(edge_operation, False, session)
|
245 | 258 | if walker_operation := self.operations[WalkerAnchor]:
|
246 | 259 | WalkerAnchor.Collection.bulk_write(walker_operation, False, session)
|
| 260 | + if object_operation := self.operations[ObjectAnchor]: |
| 261 | + ObjectAnchor.Collection.bulk_write(object_operation, False, session) |
247 | 262 | self.commit(session)
|
248 | 263 | break
|
249 | 264 | except (ConnectionFailure, OperationFailure) as ex:
|
@@ -346,13 +361,15 @@ def ref(ref_id: str) -> "BaseAnchor | Anchor":
|
346 | 361 | cls = EdgeAnchor
|
347 | 362 | case "w":
|
348 | 363 | cls = WalkerAnchor
|
| 364 | + case "o": |
| 365 | + cls = ObjectAnchor |
349 | 366 | case _:
|
350 |
| - raise ValueError(f"{ref_id}] is not a valid reference!") |
| 367 | + raise ValueError(f"[{ref_id}] is not a valid reference!") |
351 | 368 | anchor = object.__new__(cls)
|
352 | 369 | anchor.name = str(match.group(2))
|
353 | 370 | anchor.id = ObjectId(match.group(3))
|
354 | 371 | return anchor
|
355 |
| - raise ValueError(f"{ref_id}] is not a valid reference!") |
| 372 | + raise ValueError(f"[{ref_id}] is not a valid reference!") |
356 | 373 |
|
357 | 374 | ####################################################
|
358 | 375 | # QUERY OPERATIONS #
|
@@ -857,9 +874,61 @@ def delete(self, bulk_write: BulkWrite) -> None:
|
857 | 874 |
|
858 | 875 |
|
859 | 876 | @dataclass(eq=False, repr=False, kw_only=True)
|
860 |
| -class ObjectAnchor(BaseAnchor, Anchor): # type: ignore[misc] |
| 877 | +class ObjectAnchor(BaseAnchor, _ObjectAnchor): # type: ignore[misc] |
861 | 878 | """Object Anchor."""
|
862 | 879 |
|
| 880 | + architype: "ObjectArchitype" |
| 881 | + |
| 882 | + class Collection(BaseCollection["ObjectAnchor"]): |
| 883 | + """ObjectAnchor collection interface.""" |
| 884 | + |
| 885 | + __collection__: str | None = "object" |
| 886 | + __default_indexes__: list[dict] = [ |
| 887 | + {"keys": [("_id", ASCENDING), ("name", ASCENDING), ("root", ASCENDING)]} |
| 888 | + ] |
| 889 | + |
| 890 | + @classmethod |
| 891 | + def __document__(cls, doc: Mapping[str, Any]) -> "ObjectAnchor": |
| 892 | + """Parse document to NodeAnchor.""" |
| 893 | + doc = cast(dict, doc) |
| 894 | + |
| 895 | + architype = architype_to_dataclass( |
| 896 | + ObjectArchitype.__get_class__(doc.get("name") or "Root"), |
| 897 | + doc.pop("architype"), |
| 898 | + ) |
| 899 | + anchor = ObjectAnchor( |
| 900 | + architype=architype, |
| 901 | + id=doc.pop("_id"), |
| 902 | + access=Permission.deserialize(doc.pop("access")), |
| 903 | + state=AnchorState(connected=True), |
| 904 | + persistent=True, |
| 905 | + **doc, |
| 906 | + ) |
| 907 | + architype.__jac__ = anchor |
| 908 | + anchor.sync_hash() |
| 909 | + return anchor |
| 910 | + |
| 911 | + @classmethod |
| 912 | + def ref(cls, ref_id: str) -> "ObjectAnchor": |
| 913 | + """Return NodeAnchor instance if existing.""" |
| 914 | + if match := NODE_ID_REGEX.search(ref_id): |
| 915 | + anchor = object.__new__(cls) |
| 916 | + anchor.name = str(match.group(1)) |
| 917 | + anchor.id = ObjectId(match.group(2)) |
| 918 | + return anchor |
| 919 | + raise ValueError(f"[{ref_id}] is not a valid reference!") |
| 920 | + |
| 921 | + def insert( |
| 922 | + self, |
| 923 | + bulk_write: BulkWrite, |
| 924 | + ) -> None: |
| 925 | + """Append Insert Query.""" |
| 926 | + bulk_write.operations[ObjectAnchor].append(InsertOne(self.serialize())) |
| 927 | + |
| 928 | + def delete(self, bulk_write: BulkWrite) -> None: |
| 929 | + """Append Delete Query.""" |
| 930 | + bulk_write.del_node(self.id) |
| 931 | + |
863 | 932 |
|
864 | 933 | class BaseArchitype:
|
865 | 934 | """Architype Protocol."""
|
@@ -960,7 +1029,7 @@ def __ref_cls__(cls) -> str:
|
960 | 1029 | return f"w:{cls.__name__}"
|
961 | 1030 |
|
962 | 1031 |
|
963 |
| -class ObjectArchitype(BaseArchitype, Architype): |
| 1032 | +class ObjectArchitype(BaseArchitype, _ObjectArchitype): |
964 | 1033 | """Object Architype Protocol."""
|
965 | 1034 |
|
966 | 1035 | __jac__: ObjectAnchor
|
|
0 commit comments