# app/neo4j_utils.py from neo4j import GraphDatabase from flask import current_app class Neo4jHandler: def __init__(self, uri=None, user=None, password=None): # We read from current_app.config if nothing is passed in explicitly. # If you already set NEO4J_URI / NEO4J_USER / NEO4J_PASSWORD in your config.py, # these defaults will be overridden by those values automatically. uri = uri or current_app.config.get("NEO4J_URI", "bolt://nip_neo4j:7687") user = user or current_app.config.get("NEO4J_USER", "neo4j") pw = password or current_app.config.get("NEO4J_PASSWORD", "your_password_here") self.driver = GraphDatabase.driver(uri, auth=(user, pw)) def close(self): self.driver.close() def create_plant_node(self, uuid: str, name: str = "Unknown"): """ MERGE a Plant node by UUID. On create, set its name. We strip() and strip('"') in case the CSV had extra quotes or spaces around the UUID. """ if not uuid: print("[⚠️] Skipped node creation: missing UUID") return # Remove surrounding quotes or whitespace uuid_clean = uuid.strip().strip('"') name_clean = (name or "Unknown").strip() print(f"[ℹ️] (Neo4j) MERGE Plant node → uuid='{uuid_clean}', name='{name_clean}'") try: with self.driver.session() as session: session.run( """ MERGE (p:Plant {uuid: $uuid}) ON CREATE SET p.name = $name """, uuid=uuid_clean, name=name_clean ) except Exception as e: print(f"[❌] Neo4j node creation failed for UUID={uuid_clean}: {e}") def create_lineage(self, child_uuid: str, parent_uuid: str): """ MATCH both child and parent by UUID, then MERGE a LINEAGE relationship. Again, strip() any extraneous quotes or whitespace. """ if not child_uuid or not parent_uuid: print(f"[⚠️] Skipped lineage creation: missing UUID(s) ({child_uuid!r} → {parent_uuid!r})") return child_clean = child_uuid.strip().strip('"') parent_clean = parent_uuid.strip().strip('"') print(f"[ℹ️] (Neo4j) Attempting to MERGE LINEAGE → child='{child_clean}', parent='{parent_clean}'") try: with self.driver.session() as session: result = session.run( """ MATCH (c:Plant {uuid: $child_uuid}) MATCH (p:Plant {uuid: $parent_uuid}) MERGE (c)-[r:LINEAGE]->(p) RETURN type(r) AS rel_type """, child_uuid=child_clean, parent_uuid=parent_clean ) record = result.single() if record and record.get("rel_type") == "LINEAGE": print(f"[✅] (Neo4j) Created LINEAGE → {child_clean} → {parent_clean}") else: print(f"[⚠️] (Neo4j) No LINEAGE created (nodes may not match) → {child_clean} → {parent_clean}") except Exception as e: print(f"[❌] Neo4j lineage creation failed: {e}") def debug_check_node(self, uuid: str): """ Utility: check whether a Plant node with this UUID exists in Neo4j. """ uuid_clean = uuid.strip().strip('"') with self.driver.session() as session: result = session.run( "MATCH (p:Plant {uuid: $uuid}) RETURN p", uuid=uuid_clean ) record = result.single() if record: print(f"[✅] (Neo4j) Node '{uuid_clean}' exists.") else: print(f"[❌] (Neo4j) Node '{uuid_clean}' NOT found.") def get_neo4j_handler() -> Neo4jHandler: """ Factory: read NEO4J_URI / NEO4J_USER / NEO4J_PASSWORD from current_app.config. """ uri = current_app.config.get("NEO4J_URI", "bolt://nip_neo4j:7687") user = current_app.config.get("NEO4J_USER", "neo4j") password = current_app.config.get("NEO4J_PASSWORD", "your_password_here") return Neo4jHandler(uri, user, password)