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): def _fetch_nodes(db, transport_type=None, node_type=None):
"""Fetch nodes from database with caching.""" """Fetch nodes from database with caching.
cache_key = f"nodes:{transport_type or 'all'}"
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: with _cache_lock:
if cache_key not in _nodes_cache: if cache_key not in _nodes_cache:
aql = """ # Select AQL query based on node_type
FOR node IN nodes if node_type == 'offer':
FILTER node.node_type == 'logistics' OR node.node_type == null aql = """
FILTER node.latitude != null AND node.longitude != null FOR node IN nodes
RETURN node 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) cursor = db.aql.execute(aql)
all_nodes = list(cursor) all_nodes = list(cursor)
# Filter by transport type if specified # Filter by transport type if specified (only for logistics nodes)
if transport_type: if transport_type and node_type in (None, 'logistics'):
all_nodes = [ all_nodes = [
n for n in all_nodes n for n in all_nodes
if transport_type in (n.get('transport_types') or []) 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] 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. Get clustered nodes for given bounding box and zoom level.
Uses H3 hexagonal grid to group nearby nodes. 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) 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: if not nodes:
return [] return []

View File

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