Commit 37cf2d00 authored by Tim Bleimehl's avatar Tim Bleimehl 🤸🏼
Browse files

wip

parent 3a3f81d3
......@@ -2,32 +2,59 @@ from typing import Union, Dict, List
import time
import py2neo
class CapturePoint():
class CapturePoint:
"""The state of a Neo4j database in terms of relationship and node count at a certain time"""
def __init__(self,labels:Dict[str,int],relations:Dict[str,int]):
self.timestamp:float = time.time()
self.labels = labels
self.relations = relations
class NeoMetaLogger():
def __init__(self,connection: Union[py2neo.Graph,Dict]):
self.capture_points:List[CapturePoint] = []
def __init__(
self, labels_count: Dict[str, int], relations_count: Dict[str, int], schema
):
self.timestamp: float = time.time()
self.labels = labels_count
self.relations = relations_count
self.schema = schema
tn = schema["nodes"][0]
print(tn, tn.relationships)
exit()
def __hash__(self):
return hash(self.timestamp)
def __eq__(self, other: "CapturePoint") -> bool:
return type(other) is type(self) and self.timestamp == other.timestamp
class NeoMetaLogger:
def __init__(self, connection: Union[py2neo.Graph, Dict]):
self.capture_points: List[CapturePoint] = []
if isinstance(connection, dict):
self.graph: py2neo.Graph = py2neo.Graph(**connection)
elif isinstance(connection,py2neo.Graph):
elif isinstance(connection, py2neo.Graph):
self.graph = connection
else:
raise TypeError(f"Expected 'py2neo.Graph' or 'dict'. Got '{type(connection)}'")
raise TypeError(
f"Expected 'py2neo.Graph' or 'dict'. Got '{type(connection)}'"
)
def capture(self):
labels_count = self._count_labels()
relations_count = self._count_relations()
self.capture_points.append(CapturePoint(labels_count, relations_count))
def _count_labels(self) -> Dict[str,int]:
all_labels: List[str] = self.graph.run("CALL db.labels() yield label return collect(label) as res").data()[0]["res"]
labels_count: Dict[str,int] = {}
self.capture_points.append(
CapturePoint(labels_count, relations_count, self._query_schema())
)
def _query_schema(self):
# call db.schema.visualization
return self.graph.run(
"call db.schema.visualization yield nodes, relationships"
).data()[0]
def _count_labels(self) -> Dict[str, int]:
all_labels: List[str] = self.graph.run(
"CALL db.labels() yield label return collect(label) as res"
).data()[0]["res"][0]
labels_count: Dict[str, int] = {}
for label in all_labels:
query_label_count = f"""
......@@ -36,22 +63,91 @@ class NeoMetaLogger():
"""
labels_count[label] = self.graph.run(query_label_count).data()[0]["res"]
return labels_count
def _count_relations(self) -> Dict[str,int]:
def _count_relations(self) -> Dict[str, int]:
all_rels: List[str] = self.graph.run(
"CALL db.relationshipTypes() yield relationshipType return collect(relationshipType) as res"
).data()[0]["res"]
rels_count: Dict[str, int] = {}
for rel in all_rels:
query_rel_count = f"""
MATCH ()-[:{rel}]->()
return count(*) AS res
"""
rels_count[rel] = self.graph.run(query_rel_count).data()[0]["res"]
return rels_count
pass
def get_last_changes(self) -> Dict[str,Dict[str,int]]:
def get_last_changes(self) -> Dict[str, Dict[str, int]]:
"""Get changes, in terms of quantity, of labels and relations since the last capture compared to the current capture
Returns:
Dict[str,Dict[str,int]]: A base dictonary "{'labels':{...},'relation':{...}}" containing two dictoniries listing changes (in terms of quantity) for labels and relations.
"""
pass
def get_changes_since(self,capture:CapturePoint=None,capture_index:int=None,time:float=None) -> Dict[str,Dict[str,int]]:
return self.get_changes_since(capture_point_index=-2)
def get_changes_since(
self,
capture_point: CapturePoint = None,
capture_point_index: int = None,
capture_point_time: float = None,
) -> Dict[str, Dict[str, int]]:
"""Get changes, in terms of quantity, of labels and relations since the last capture compared to the current capture
Returns:
Dict[str,Dict[str,int]]: A base dictonary "{'labels':{...},'relation':{...}}" containing two dictoniries listing changes (in terms of quantity) for labels and relations.
"""
pass
current_capture_point: CapturePoint = (
self.capture_points[-1] if self.capture_points else None
)
compare_capture_point: CapturePoint = None
if capture_point_time:
raise NotImplementedError()
elif capture_point_index:
compare_capture_point = self.capture_points[capture_point_index]
elif capture_point:
compare_capture_point = capture_point
return self.get_changes(
from_capture=compare_capture_point, to_capture=current_capture_point
)
def get_changes(self, from_capture: CapturePoint, to_capture: CapturePoint):
if len(self.capture_points) <= 1:
raise ValueError(
f"You need at least 2 capture points to compare any changes. Got only {len(self.capture_points)} points"
)
# Compare labels
result: Dict = {"labels": {}, "relations": {}}
if to_capture.labels or from_capture.labels:
diff_labels = set(to_capture.labels.items()) ^ set(
from_capture.labels.items()
)
for diff_label in set([lbl[0] for lbl in diff_labels]):
result["labels"][diff_label] = (
to_capture.labels[diff_label]
if diff_label in to_capture.labels
else 0
) - (
from_capture.labels[diff_label]
if diff_label in from_capture.labels
else 0
)
# Compare relations
if not to_capture.relations and not from_capture.relations:
return result
diff_relations = set(to_capture.relations.items()) ^ set(
from_capture.relations.items()
)
for diff_rel in set([lbl[0] for lbl in diff_relations]):
result["relations"][diff_rel] = (
to_capture.relations[diff_rel]
if diff_rel in to_capture.relations
else 0
) - (
from_capture.relations[diff_rel]
if diff_rel in from_capture.relations
else 0
)
return result
py2neo
\ No newline at end of file
py2neo
DZDUtils
\ No newline at end of file
import sys
import os
from typing import Dict,List
import json
import py2neo
from DZDutils.neo4j import wait_for_db_boot
if __name__ == "__main__":
SCRIPT_DIR = os.path.dirname(
os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__)))
......@@ -10,6 +13,12 @@ if __name__ == "__main__":
sys.path.insert(0, os.path.normpath(SCRIPT_DIR))
from neo_meta_logger import NeoMetaLogger
NEO4J: Dict = json.loads(os.getenv("NEO4J","{}"))
wait_for_db_boot(NEO4J)
graph = py2neo.Graph(**NEO4J)
mlog = NeoMetaLogger({})
graph.run("CREATE p = (:NEO_META_LOG_TESTNODE{name:'1'})-[:NEO_META_LOG_TESTREL]->(:NEO_META_LOG_TARGET_TESTNODE {name: '2'})")
mlog.capture()
graph.run("CREATE p = (:NEO_META_LOG_TESTNODE{name:'3'})-[:NEO_META_LOG_TESTREL]->(:NEO_META_LOG_TARGET_TESTNODE {name: '4'})")
mlog.capture()
print(mlog.get_last_changes())
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment