From 596bdbf1c5a8131b072578a76f4ba680096ce9c5 Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev <572431+veikab@users.noreply.github.com> Date: Fri, 16 Jan 2026 17:29:42 +0700 Subject: [PATCH] Add node_type parameter to clusteredNodes for unified server-side clustering --- geo_app/cluster_index.py | 56 ++++++++++++++++++++++++++++++---------- geo_app/schema.py | 5 ++-- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/geo_app/cluster_index.py b/geo_app/cluster_index.py index 6fafea4..3153e27 100644 --- a/geo_app/cluster_index.py +++ b/geo_app/cluster_index.py @@ -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: - 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 - """ + # 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 [] diff --git a/geo_app/schema.py b/geo_app/schema.py index fc6d3e9..d9ac744 100644 --- a/geo_app/schema.py +++ b/geo_app/schema.py @@ -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):