zrald
Version:
Advanced Graph RAG MCP Server with sophisticated graph structures, operators, and agentic capabilities for AI agents
217 lines • 8.1 kB
JavaScript
import neo4j from 'neo4j-driver';
export class GraphDatabase {
driver;
session = null;
constructor(uri, username, password) {
this.driver = neo4j.driver(uri, neo4j.auth.basic(username, password));
}
async connect() {
try {
await this.driver.verifyConnectivity();
this.session = this.driver.session();
console.log('Connected to Neo4j database');
}
catch (error) {
console.error('Failed to connect to Neo4j:', error);
throw error;
}
}
async disconnect() {
if (this.session) {
await this.session.close();
}
await this.driver.close();
}
getSession() {
if (!this.session) {
throw new Error('Database not connected. Call connect() first.');
}
return this.session;
}
// Node Operations
async createNode(node) {
const session = this.getSession();
const query = `
CREATE (n:${node.type} {
id: $id,
label: $label,
properties: $properties,
embedding: $embedding,
metadata: $metadata,
created_at: datetime($created_at),
updated_at: datetime($updated_at)
})
`;
await session.run(query, {
id: node.id,
label: node.label,
properties: node.properties,
embedding: node.embedding || [],
metadata: node.metadata || {},
created_at: node.created_at.toISOString(),
updated_at: node.updated_at.toISOString()
});
}
async getNode(id) {
const session = this.getSession();
const query = 'MATCH (n {id: $id}) RETURN n';
const result = await session.run(query, { id });
if (result.records.length === 0) {
return null;
}
const record = result.records[0];
const node = record.get('n');
return {
id: node.properties.id,
type: node.labels[0].toLowerCase(),
label: node.properties.label,
properties: node.properties.properties || {},
embedding: node.properties.embedding || undefined,
metadata: node.properties.metadata || undefined,
created_at: new Date(node.properties.created_at),
updated_at: new Date(node.properties.updated_at)
};
}
async getNodesByType(type) {
const session = this.getSession();
const query = `MATCH (n:${type}) RETURN n`;
const result = await session.run(query);
return result.records.map(record => {
const node = record.get('n');
return {
id: node.properties.id,
type: node.labels[0].toLowerCase(),
label: node.properties.label,
properties: node.properties.properties || {},
embedding: node.properties.embedding || undefined,
metadata: node.properties.metadata || undefined,
created_at: new Date(node.properties.created_at),
updated_at: new Date(node.properties.updated_at)
};
});
}
// Relationship Operations
async createRelationship(relationship) {
const session = this.getSession();
const query = `
MATCH (a {id: $source_id}), (b {id: $target_id})
CREATE (a)-[r:${relationship.type} {
id: $id,
properties: $properties,
weight: $weight,
confidence: $confidence,
metadata: $metadata,
created_at: datetime($created_at)
}]->(b)
`;
await session.run(query, {
source_id: relationship.source_id,
target_id: relationship.target_id,
id: relationship.id,
properties: relationship.properties,
weight: relationship.weight,
confidence: relationship.confidence,
metadata: relationship.metadata || {},
created_at: relationship.created_at.toISOString()
});
}
async getRelationships(nodeId, direction = 'both') {
const session = this.getSession();
let query;
switch (direction) {
case 'incoming':
query = 'MATCH (n)-[r]->(m {id: $nodeId}) RETURN r, n.id as source_id, m.id as target_id';
break;
case 'outgoing':
query = 'MATCH (n {id: $nodeId})-[r]->(m) RETURN r, n.id as source_id, m.id as target_id';
break;
default:
query = 'MATCH (n)-[r]-(m) WHERE n.id = $nodeId OR m.id = $nodeId RETURN r, n.id as source_id, m.id as target_id';
}
const result = await session.run(query, { nodeId });
return result.records.map(record => {
const rel = record.get('r');
return {
id: rel.properties.id,
source_id: record.get('source_id'),
target_id: record.get('target_id'),
type: rel.type,
properties: rel.properties.properties || {},
weight: rel.properties.weight || 1.0,
confidence: rel.properties.confidence || 1.0,
metadata: rel.properties.metadata || {},
created_at: new Date(rel.properties.created_at)
};
});
}
// Path Finding
async findPaths(sourceId, targetId, maxHops = 3) {
const session = this.getSession();
const query = `
MATCH path = (start {id: $sourceId})-[*1..${maxHops}]-(end {id: $targetId})
RETURN path
LIMIT 10
`;
const result = await session.run(query, { sourceId, targetId });
return result.records.map(record => {
const path = record.get('path');
const nodes = path.segments.flatMap((segment) => [
this.convertNeo4jNode(segment.start),
this.convertNeo4jNode(segment.end)
]);
const relationships = path.segments.map((segment) => this.convertNeo4jRelationship(segment.relationship));
return { nodes: [...new Map(nodes.map(n => [n.id, n])).values()], relationships };
});
}
// Utility methods
convertNeo4jNode(neo4jNode) {
return {
id: neo4jNode.properties.id,
type: neo4jNode.labels[0].toLowerCase(),
label: neo4jNode.properties.label,
properties: neo4jNode.properties.properties || {},
embedding: neo4jNode.properties.embedding || undefined,
metadata: neo4jNode.properties.metadata || undefined,
created_at: new Date(neo4jNode.properties.created_at),
updated_at: new Date(neo4jNode.properties.updated_at)
};
}
convertNeo4jRelationship(neo4jRel) {
return {
id: neo4jRel.properties.id,
source_id: neo4jRel.start.toString(),
target_id: neo4jRel.end.toString(),
type: neo4jRel.type,
properties: neo4jRel.properties.properties || {},
weight: neo4jRel.properties.weight || 1.0,
confidence: neo4jRel.properties.confidence || 1.0,
metadata: neo4jRel.properties.metadata || {},
created_at: new Date(neo4jRel.properties.created_at)
};
}
// Batch operations
async createGraph(graph) {
const session = this.getSession();
const tx = session.beginTransaction();
try {
// Create nodes
for (const node of graph.nodes) {
await this.createNode(node);
}
// Create relationships
for (const relationship of graph.relationships) {
await this.createRelationship(relationship);
}
await tx.commit();
}
catch (error) {
await tx.rollback();
throw error;
}
}
async clearGraph() {
const session = this.getSession();
await session.run('MATCH (n) DETACH DELETE n');
}
}
//# sourceMappingURL=graph-database.js.map