api/modules/database/services/neo4j_service.py
2025-11-14 14:47:19 +00:00

199 lines
8.7 KiB
Python

import os
from typing import Dict, Any
from modules.logger_tool import initialise_logger
import modules.database.tools.neo4j_driver_tools as driver_tools
import modules.database.tools.neo4j_session_tools as session_tools
class Neo4jService:
"""Service for managing Neo4j database operations"""
def __init__(self):
self.logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
self.driver = driver_tools.get_driver()
def check_database_exists(self, database_name: str) -> Dict[str, Any]:
"""Check if a Neo4j database exists
Args:
database_name (str): Name of the database to check
Returns:
Dict[str, Any]: Result containing existence status and operation status
"""
try:
with self.driver.session() as session:
result = session.run(
"SHOW DATABASES YIELD name WHERE name = $name",
name=database_name
)
exists = bool(result.single())
return {
"exists": exists,
"status": "success"
}
except Exception as e:
self.logger.error(f"Error checking database {database_name}: {str(e)}")
return {
"exists": False,
"status": "error",
"message": str(e)
}
def create_database(self, db_name: str) -> Dict[str, Any]:
"""Creates a Neo4j database with the given name
Args:
db_name (str): Name of the database to create
Returns:
Dict[str, Any]: Result containing operation status and message
"""
try:
# First check if database exists
exists_result = self.check_database_exists(db_name)
if exists_result["status"] == "error":
return exists_result
if not exists_result["exists"]:
with self.driver.session() as session:
session_tools.create_database(session, db_name)
self.logger.info(f"Created database {db_name}")
return {
"status": "success",
"message": f"Database {db_name} created successfully"
}
else:
self.logger.info(f"Database {db_name} already exists")
return {
"status": "success",
"message": f"Database {db_name} already exists"
}
except Exception as e:
self.logger.error(f"Error creating database {db_name}: {str(e)}")
return {"status": "error", "message": str(e)}
def initialize_schema(self, database_name: str) -> Dict[str, Any]:
"""Initialize Neo4j schema (constraints and indexes) for a database
Args:
database_name (str): Name of the database to initialize schema for
Returns:
Dict[str, Any]: Result containing operation status and message
"""
try:
with self.driver.session(database=database_name) as session:
# Create constraints
constraints = [
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:School) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Department) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Subject) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:YearGroup) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Class) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Teacher) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Student) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Calendar) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Term) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Week) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Day) REQUIRE n.uuid_string IS UNIQUE",
"CREATE CONSTRAINT IF NOT EXISTS FOR (n:Period) REQUIRE n.uuid_string IS UNIQUE"
]
# Create indexes
indexes = [
"CREATE INDEX IF NOT EXISTS FOR (n:School) ON (n.urn)",
"CREATE INDEX IF NOT EXISTS FOR (n:Department) ON (n.department_name)",
"CREATE INDEX IF NOT EXISTS FOR (n:Subject) ON (n.subject_name)",
"CREATE INDEX IF NOT EXISTS FOR (n:YearGroup) ON (n.year_group)",
"CREATE INDEX IF NOT EXISTS FOR (n:Class) ON (n.class_name)",
"CREATE INDEX IF NOT EXISTS FOR (n:Teacher) ON (n.email)",
"CREATE INDEX IF NOT EXISTS FOR (n:Student) ON (n.email)",
"CREATE INDEX IF NOT EXISTS FOR (n:Calendar) ON (n.calendar_name)",
"CREATE INDEX IF NOT EXISTS FOR (n:Term) ON (n.term_name)",
"CREATE INDEX IF NOT EXISTS FOR (n:Week) ON (n.week_number)",
"CREATE INDEX IF NOT EXISTS FOR (n:Day) ON (n.date)",
"CREATE INDEX IF NOT EXISTS FOR (n:Period) ON (n.period_name)"
]
# Execute all constraints
for constraint in constraints:
session.run(constraint)
# Execute all indexes
for index in indexes:
session.run(index)
self.logger.info(f"Successfully initialized schema for database {database_name}")
return {
"status": "success",
"message": f"Schema initialized successfully for database {database_name}"
}
except Exception as e:
self.logger.error(f"Error initializing schema for database {database_name}: {str(e)}")
return {
"status": "error",
"message": str(e)
}
def delete_database(self, db_name: str) -> Dict[str, Any]:
"""Deletes a Neo4j database
Args:
db_name (str): Name of the database to delete
Returns:
Dict[str, Any]: Result containing operation status and message
"""
try:
exists_result = self.check_database_exists(db_name)
if exists_result["status"] == "error":
return exists_result
if exists_result["exists"]:
with self.driver.session() as session:
session_tools.reset_database_in_session(session)
self.logger.info(f"Deleted database {db_name}")
return {
"status": "success",
"message": f"Database {db_name} deleted successfully"
}
else:
return {
"status": "success",
"message": f"Database {db_name} does not exist"
}
except Exception as e:
self.logger.error(f"Error deleting database {db_name}: {str(e)}")
return {"status": "error", "message": str(e)}
def check_node_exists(self, database_name: str, node_label: str) -> Dict[str, Any]:
"""Check if any nodes with the given label exist in the specified database
Args:
database_name (str): Name of the database to check
node_label (str): Label of the node type to check for
Returns:
Dict[str, Any]: Result containing count and operation status
"""
try:
with self.driver.session(database=database_name) as session:
nodes = session_tools.find_nodes_by_label(session, node_label)
count = len(nodes)
return {
"exists": count > 0,
"count": count,
"status": "success"
}
except Exception as e:
self.logger.error(f"Error checking for {node_label} nodes in database {database_name}: {str(e)}")
return {
"exists": False,
"count": 0,
"status": "error",
"message": str(e)
}