Skip to content

Commit a6c182f

Browse files
committed
get_neighbors endpoint
1 parent 7f4339a commit a6c182f

File tree

2 files changed

+114
-35
lines changed

2 files changed

+114
-35
lines changed

code_graph/graph.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import time
22
from .entities import *
3-
from typing import List, Optional
3+
from typing import Dict, List, Optional
44
from falkordb import FalkorDB, Path, Node, QueryResult
55

66
FALKORDB_HOST = "localhost"
@@ -109,6 +109,54 @@ def get_sub_graph(self, l: int) -> dict:
109109

110110
return sub_graph
111111

112+
113+
def get_neighbors(self, node_id: int, rel: Optional[str] = None, lbl: Optional[str] = None) -> Dict[str, List[dict]]:
114+
"""
115+
Fetch the neighbors of a given node in the graph based on relationship type and/or label.
116+
117+
Args:
118+
node_id (int): The ID of the source node.
119+
rel (str, optional): The type of relationship to filter by. Defaults to None.
120+
lbl (str, optional): The label of the destination node to filter by. Defaults to None.
121+
122+
Returns:
123+
dict: A dictionary with lists of 'nodes' and 'edges' for the neighbors.
124+
"""
125+
126+
# Validate inputs
127+
if not isinstance(node_id, int):
128+
raise ValueError("node_id must be an integer")
129+
130+
# Build relationship and label query parts
131+
rel_query = f":{rel}" if rel else ""
132+
lbl_query = f":{lbl}" if lbl else ""
133+
134+
# Parameterized Cypher query to find neighbors
135+
query = f"""
136+
MATCH (n)-[e{rel_query}]->(dest{lbl_query})
137+
WHERE ID(n) = $node_id
138+
RETURN e, dest
139+
"""
140+
141+
# Initialize the neighbors structure
142+
neighbors = {'nodes': [], 'edges': []}
143+
144+
try:
145+
# Execute the graph query with node_id parameter
146+
result_set = self.g.query(query, {'node_id': node_id}).result_set
147+
148+
# Iterate over the result set and process nodes and edges
149+
for edge, destination_node in result_set:
150+
neighbors['nodes'].append(encode_node(destination_node))
151+
neighbors['edges'].append(encode_edge(edge))
152+
153+
return neighbors
154+
155+
except Exception as e:
156+
logging.error(f"Error fetching neighbors for node {node_id}: {e}")
157+
return {'nodes': [], 'edges': []}
158+
159+
112160
def add_class(self, c: Class) -> None:
113161
"""
114162
Adds a class node to the graph database.

main.py

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
from code_graph import *
55
from typing import Optional
66
from falkordb import FalkorDB
7+
from dotenv import load_dotenv
78
from urllib.parse import urlparse
89
from flask import Flask, request, jsonify, abort
910

10-
# Configuration
11-
FALKORDB_HOST = 'localhost'
12-
FALKORDB_PORT = 6379
13-
FALKORDB_USERNAME = None
14-
FALKORDB_PASSWORD = None
11+
# Load environment variables from .env file
12+
load_dotenv()
13+
14+
# Access environment variables
15+
FALKORDB_HOST = os.getenv('FALKORDB_HOST')
16+
FALKORDB_PORT = os.getenv('FALKORDB_PORT')
17+
FALKORDB_USERNAME = os.getenv('FALKORDB_USERNAME')
18+
FALKORDB_PASSWORD = os.getenv('FALKORDB_PASSWORD')
1519

1620
app = Flask(__name__, static_folder='static')
1721

@@ -34,50 +38,77 @@ def extract_org_name_from_url(url: str) -> Optional[tuple[str, str]]:
3438

3539
@app.route('/graph_entities', methods=['GET'])
3640
def graph_entities():
41+
"""
42+
Endpoint to fetch sub-graph entities from a given repository.
43+
The repository is specified via the 'repo' query parameter.
44+
45+
Returns:
46+
- 200: Successfully returns the sub-graph.
47+
- 400: Missing or invalid 'repo' parameter.
48+
- 500: Internal server error or database connection issue.
49+
"""
50+
3751
# Access the 'repo' parameter from the GET request
3852
repo = request.args.get('repo')
3953

40-
g = Graph(repo, host=FALKORDB_HOST, port=FALKORDB_PORT,
41-
username=FALKORDB_USERNAME, password=FALKORDB_PASSWORD)
54+
if not repo:
55+
logging.error("Missing 'repo' parameter in request.")
56+
return jsonify({"error": "Missing 'repo' parameter"}), 400
57+
58+
try:
59+
# Initialize the graph with the provided repo and credentials
60+
g = Graph(repo, host=FALKORDB_HOST, port=FALKORDB_PORT,
61+
username=FALKORDB_USERNAME, password=FALKORDB_PASSWORD)
62+
63+
# Retrieve a sub-graph of up to 100 entities
64+
sub_graph = g.get_sub_graph(100)
4265

43-
sub_graph = g.get_sub_graph(100)
66+
logging.info(f"Successfully retrieved sub-graph for repo: {repo}")
67+
return jsonify(sub_graph), 200
4468

45-
return jsonify(sub_graph), 200
69+
except Exception as e:
70+
logging.error(f"Error retrieving sub-graph for repo '{repo}': {e}")
71+
return jsonify({"error": "Internal server error"}), 500
4672

4773
@app.route('/get_neighbors', methods=['GET'])
4874
def get_neighbors():
49-
# Access the 'node_id' parameter from the GET request
50-
node_id = int(request.args.get('node_id'))
51-
graph_id = request.args.get('graph_id')
75+
"""
76+
Endpoint to get neighbors of a specific node in the graph.
77+
Expects 'repo' and 'node_id' as query parameters.
78+
"""
79+
repo = request.args.get('repo')
80+
node_id = request.args.get('node_id')
5281

53-
# Connect to FalkorDB
54-
db = FalkorDB(host=FALKORDB_HOST, port=FALKORDB_PORT,
55-
username=FALKORDB_USERNAME, password=FALKORDB_PASSWORD)
82+
if not repo:
83+
logging.error("Repository name is missing in the request.")
84+
return jsonify({"error": "Repository name is required."}), 400
5685

57-
# Select graph
58-
g = db.select_graph(graph_id)
86+
if not node_id:
87+
logging.error("Node ID is missing in the request.")
88+
return jsonify({"error": "Node ID is required."}), 400
5989

60-
query = """MATCH (n)
61-
WHERE ID(n) = $node_id
62-
MATCH (n)-[e]-(neighbor)
63-
RETURN neighbor, e"""
90+
try:
91+
# Validate and convert node_id to integer
92+
node_id = int(node_id)
93+
except ValueError:
94+
logging.error(f"Invalid node ID: {node_id}. It must be an integer.")
95+
return jsonify({"error": "Invalid node ID. It must be an integer."}), 400
6496

65-
data = []
66-
res = g.query(query, {'node_id': node_id}).result_set
67-
for row in res:
68-
neighbor = row[0]
69-
e = row[1]
97+
try:
98+
# Initialize the graph with the provided repo and credentials
99+
g = Graph(repo, host=FALKORDB_HOST, port=FALKORDB_PORT,
100+
username=FALKORDB_USERNAME, password=FALKORDB_PASSWORD)
70101

71-
data.append({'data': {'id': neighbor.id,
72-
'label': neighbor.labels[0]} })
73-
data.append({'data': {'source': node_id, 'target': neighbor.id, 'relation': e.relation} })
102+
# Get neighbors of the given node
103+
neighbors = g.get_neighbors(node_id)
74104

75-
# [
76-
# { data: { id: 'e' } },
77-
# { data: { source: 'a', target: 'b' } }
78-
# ]
105+
logging.info(f"Successfully retrieved neighbors for node ID {node_id} in repo '{repo}'.")
106+
return jsonify(neighbors), 200
107+
108+
except Exception as e:
109+
logging.error(f"Error retrieving node neighbors for repo '{repo}': {e}")
110+
return jsonify({"error": "Internal server error"}), 500
79111

80-
return jsonify(data), 200
81112

82113
@app.route('/process_repo', methods=['POST'])
83114
def process_repo():

0 commit comments

Comments
 (0)