Add node_type parameter to clusteredNodes for unified server-side clustering
All checks were successful
Build Docker Image / build (push) Successful in 1m31s

This commit is contained in:
Ruslan Bakiev
2026-01-16 17:29:42 +07:00
parent 07f89ba5fb
commit 596bdbf1c5
2 changed files with 46 additions and 15 deletions

View File

@@ -22,23 +22,46 @@ ZOOM_TO_RES = {
}
def _fetch_nodes(db, transport_type=None):
"""Fetch nodes from database with caching."""
cache_key = f"nodes:{transport_type or 'all'}"
def _fetch_nodes(db, transport_type=None, node_type=None):
"""Fetch nodes from database with caching.
Args:
db: Database connection
transport_type: Filter by transport type (auto, rail, sea, air)
node_type: Type of nodes to fetch ('logistics', 'offer', 'supplier')
"""
cache_key = f"nodes:{transport_type or 'all'}:{node_type or 'logistics'}"
with _cache_lock:
if cache_key not in _nodes_cache:
# Select AQL query based on node_type
if node_type == 'offer':
aql = """
FOR node IN nodes
FILTER node.node_type == 'offer'
FILTER node.latitude != null AND node.longitude != null
RETURN node
"""
elif node_type == 'supplier':
aql = """
FOR node IN nodes
FILTER node.node_type == 'supplier'
FILTER node.latitude != null AND node.longitude != null
RETURN node
"""
else: # logistics (default)
aql = """
FOR node IN nodes
FILTER node.node_type == 'logistics' OR node.node_type == null
FILTER node.latitude != null AND node.longitude != null
RETURN node
"""
cursor = db.aql.execute(aql)
all_nodes = list(cursor)
# Filter by transport type if specified
if transport_type:
# Filter by transport type if specified (only for logistics nodes)
if transport_type and node_type in (None, 'logistics'):
all_nodes = [
n for n in all_nodes
if transport_type in (n.get('transport_types') or [])
@@ -50,14 +73,21 @@ def _fetch_nodes(db, transport_type=None):
return _nodes_cache[cache_key]
def get_clustered_nodes(db, west, south, east, north, zoom, transport_type=None):
def get_clustered_nodes(db, west, south, east, north, zoom, transport_type=None, node_type=None):
"""
Get clustered nodes for given bounding box and zoom level.
Uses H3 hexagonal grid to group nearby nodes.
Args:
db: Database connection
west, south, east, north: Bounding box coordinates
zoom: Map zoom level
transport_type: Filter by transport type (for logistics nodes)
node_type: Type of nodes ('logistics', 'offer', 'supplier')
"""
resolution = ZOOM_TO_RES.get(int(zoom), 5)
nodes = _fetch_nodes(db, transport_type)
nodes = _fetch_nodes(db, transport_type, node_type)
if not nodes:
return []

View File

@@ -191,6 +191,7 @@ class Query(graphene.ObjectType):
north=graphene.Float(required=True, description="Bounding box north latitude"),
zoom=graphene.Int(required=True, description="Map zoom level (0-16)"),
transport_type=graphene.String(description="Filter by transport type"),
node_type=graphene.String(description="Node type: logistics, offer, supplier"),
description="Get clustered nodes for map display (server-side clustering)",
)
@@ -641,10 +642,10 @@ class Query(graphene.ObjectType):
return None
def resolve_clustered_nodes(self, info, west, south, east, north, zoom, transport_type=None):
def resolve_clustered_nodes(self, info, west, south, east, north, zoom, transport_type=None, node_type=None):
"""Get clustered nodes for map display using server-side SuperCluster."""
db = get_db()
clusters = get_clustered_nodes(db, west, south, east, north, zoom, transport_type)
clusters = get_clustered_nodes(db, west, south, east, north, zoom, transport_type, node_type)
return [ClusterPointType(**c) for c in clusters]
def resolve_products(self, info):