feat(geo): filter clustered nodes by product/hub/supplier
All checks were successful
Build Docker Image / build (push) Successful in 2m42s
All checks were successful
Build Docker Image / build (push) Successful in 2m42s
This commit is contained in:
@@ -17,7 +17,18 @@ ZOOM_TO_RES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _fetch_nodes(db, west, south, east, north, transport_type=None, node_type=None):
|
def _fetch_nodes(
|
||||||
|
db,
|
||||||
|
west,
|
||||||
|
south,
|
||||||
|
east,
|
||||||
|
north,
|
||||||
|
transport_type=None,
|
||||||
|
node_type=None,
|
||||||
|
product_uuid=None,
|
||||||
|
hub_uuid=None,
|
||||||
|
supplier_uuid=None,
|
||||||
|
):
|
||||||
"""Fetch nodes from database for a bounding box.
|
"""Fetch nodes from database for a bounding box.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -31,6 +42,9 @@ def _fetch_nodes(db, west, south, east, north, transport_type=None, node_type=No
|
|||||||
'south': south,
|
'south': south,
|
||||||
'east': east,
|
'east': east,
|
||||||
'north': north,
|
'north': north,
|
||||||
|
'product_uuid': product_uuid,
|
||||||
|
'hub_uuid': hub_uuid,
|
||||||
|
'supplier_uuid': supplier_uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Select AQL query based on node_type
|
# Select AQL query based on node_type
|
||||||
@@ -41,6 +55,19 @@ def _fetch_nodes(db, west, south, east, north, transport_type=None, node_type=No
|
|||||||
FILTER node.latitude != null AND node.longitude != null
|
FILTER node.latitude != null AND node.longitude != null
|
||||||
FILTER node.latitude >= @south AND node.latitude <= @north
|
FILTER node.latitude >= @south AND node.latitude <= @north
|
||||||
FILTER node.longitude >= @west AND node.longitude <= @east
|
FILTER node.longitude >= @west AND node.longitude <= @east
|
||||||
|
FILTER @product_uuid == null OR node.product_uuid == @product_uuid
|
||||||
|
FILTER @supplier_uuid == null OR node.supplier_uuid == @supplier_uuid
|
||||||
|
LET has_hub = @hub_uuid == null ? true : LENGTH(
|
||||||
|
FOR edge IN edges
|
||||||
|
FILTER edge.transport_type == 'offer'
|
||||||
|
FILTER (
|
||||||
|
(edge._from == CONCAT('nodes/', node._key) AND edge._to == CONCAT('nodes/', @hub_uuid)) OR
|
||||||
|
(edge._to == CONCAT('nodes/', node._key) AND edge._from == CONCAT('nodes/', @hub_uuid))
|
||||||
|
)
|
||||||
|
LIMIT 1
|
||||||
|
RETURN 1
|
||||||
|
) > 0
|
||||||
|
FILTER has_hub
|
||||||
RETURN node
|
RETURN node
|
||||||
"""
|
"""
|
||||||
elif node_type == 'supplier':
|
elif node_type == 'supplier':
|
||||||
@@ -49,6 +76,19 @@ def _fetch_nodes(db, west, south, east, north, transport_type=None, node_type=No
|
|||||||
FOR offer IN nodes
|
FOR offer IN nodes
|
||||||
FILTER offer.node_type == 'offer'
|
FILTER offer.node_type == 'offer'
|
||||||
FILTER offer.supplier_uuid != null
|
FILTER offer.supplier_uuid != null
|
||||||
|
FILTER @product_uuid == null OR offer.product_uuid == @product_uuid
|
||||||
|
FILTER @supplier_uuid == null OR offer.supplier_uuid == @supplier_uuid
|
||||||
|
LET has_hub = @hub_uuid == null ? true : LENGTH(
|
||||||
|
FOR edge IN edges
|
||||||
|
FILTER edge.transport_type == 'offer'
|
||||||
|
FILTER (
|
||||||
|
(edge._from == CONCAT('nodes/', offer._key) AND edge._to == CONCAT('nodes/', @hub_uuid)) OR
|
||||||
|
(edge._to == CONCAT('nodes/', offer._key) AND edge._from == CONCAT('nodes/', @hub_uuid))
|
||||||
|
)
|
||||||
|
LIMIT 1
|
||||||
|
RETURN 1
|
||||||
|
) > 0
|
||||||
|
FILTER has_hub
|
||||||
LET supplier = DOCUMENT(CONCAT('nodes/', offer.supplier_uuid))
|
LET supplier = DOCUMENT(CONCAT('nodes/', offer.supplier_uuid))
|
||||||
FILTER supplier != null
|
FILTER supplier != null
|
||||||
FILTER supplier.latitude != null AND supplier.longitude != null
|
FILTER supplier.latitude != null AND supplier.longitude != null
|
||||||
@@ -74,6 +114,20 @@ def _fetch_nodes(db, west, south, east, north, transport_type=None, node_type=No
|
|||||||
FILTER node.latitude != null AND node.longitude != null
|
FILTER node.latitude != null AND node.longitude != null
|
||||||
FILTER node.latitude >= @south AND node.latitude <= @north
|
FILTER node.latitude >= @south AND node.latitude <= @north
|
||||||
FILTER node.longitude >= @west AND node.longitude <= @east
|
FILTER node.longitude >= @west AND node.longitude <= @east
|
||||||
|
FILTER @hub_uuid == null OR node._key == @hub_uuid
|
||||||
|
LET has_offer = (@product_uuid == null AND @supplier_uuid == null) ? true : LENGTH(
|
||||||
|
FOR edge IN edges
|
||||||
|
FILTER edge.transport_type == 'offer'
|
||||||
|
FILTER edge._from == CONCAT('nodes/', node._key) OR edge._to == CONCAT('nodes/', node._key)
|
||||||
|
LET offer_id = edge._from == CONCAT('nodes/', node._key) ? edge._to : edge._from
|
||||||
|
LET offer = DOCUMENT(offer_id)
|
||||||
|
FILTER offer != null AND offer.node_type == 'offer'
|
||||||
|
FILTER @product_uuid == null OR offer.product_uuid == @product_uuid
|
||||||
|
FILTER @supplier_uuid == null OR offer.supplier_uuid == @supplier_uuid
|
||||||
|
LIMIT 1
|
||||||
|
RETURN 1
|
||||||
|
) > 0
|
||||||
|
FILTER has_offer
|
||||||
RETURN node
|
RETURN node
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -97,7 +151,19 @@ def _fetch_nodes(db, west, south, east, north, transport_type=None, node_type=No
|
|||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
def get_clustered_nodes(db, west, south, east, north, zoom, transport_type=None, node_type=None):
|
def get_clustered_nodes(
|
||||||
|
db,
|
||||||
|
west,
|
||||||
|
south,
|
||||||
|
east,
|
||||||
|
north,
|
||||||
|
zoom,
|
||||||
|
transport_type=None,
|
||||||
|
node_type=None,
|
||||||
|
product_uuid=None,
|
||||||
|
hub_uuid=None,
|
||||||
|
supplier_uuid=None,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Get clustered nodes for given bounding box and zoom level.
|
Get clustered nodes for given bounding box and zoom level.
|
||||||
|
|
||||||
@@ -111,7 +177,18 @@ def get_clustered_nodes(db, west, south, east, north, zoom, transport_type=None,
|
|||||||
node_type: Type of nodes ('logistics', 'offer', 'supplier')
|
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, west, south, east, north, transport_type, node_type)
|
nodes = _fetch_nodes(
|
||||||
|
db,
|
||||||
|
west,
|
||||||
|
south,
|
||||||
|
east,
|
||||||
|
north,
|
||||||
|
transport_type,
|
||||||
|
node_type,
|
||||||
|
product_uuid,
|
||||||
|
hub_uuid,
|
||||||
|
supplier_uuid,
|
||||||
|
)
|
||||||
|
|
||||||
if not nodes:
|
if not nodes:
|
||||||
return []
|
return []
|
||||||
@@ -157,4 +234,3 @@ def get_clustered_nodes(db, west, south, east, north, zoom, transport_type=None,
|
|||||||
|
|
||||||
logger.info("Returning %d clusters/points for zoom=%d res=%d", len(results), zoom, resolution)
|
logger.info("Returning %d clusters/points for zoom=%d res=%d", len(results), zoom, resolution)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|||||||
@@ -248,6 +248,9 @@ class Query(graphene.ObjectType):
|
|||||||
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"),
|
node_type=graphene.String(description="Node type: logistics, offer, supplier"),
|
||||||
|
product_uuid=graphene.String(description="Filter by product UUID"),
|
||||||
|
hub_uuid=graphene.String(description="Filter by hub UUID"),
|
||||||
|
supplier_uuid=graphene.String(description="Filter by supplier UUID"),
|
||||||
description="Get clustered nodes for map display (server-side clustering)",
|
description="Get clustered nodes for map display (server-side clustering)",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -848,10 +851,35 @@ class Query(graphene.ObjectType):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def resolve_clustered_nodes(self, info, west, south, east, north, zoom, transport_type=None, node_type=None):
|
def resolve_clustered_nodes(
|
||||||
|
self,
|
||||||
|
info,
|
||||||
|
west,
|
||||||
|
south,
|
||||||
|
east,
|
||||||
|
north,
|
||||||
|
zoom,
|
||||||
|
transport_type=None,
|
||||||
|
node_type=None,
|
||||||
|
product_uuid=None,
|
||||||
|
hub_uuid=None,
|
||||||
|
supplier_uuid=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, node_type)
|
clusters = get_clustered_nodes(
|
||||||
|
db,
|
||||||
|
west,
|
||||||
|
south,
|
||||||
|
east,
|
||||||
|
north,
|
||||||
|
zoom,
|
||||||
|
transport_type,
|
||||||
|
node_type,
|
||||||
|
product_uuid,
|
||||||
|
hub_uuid,
|
||||||
|
supplier_uuid,
|
||||||
|
)
|
||||||
return [ClusterPointType(**c) for c in clusters]
|
return [ClusterPointType(**c) for c in clusters]
|
||||||
|
|
||||||
def resolve_products(self, info):
|
def resolve_products(self, info):
|
||||||
|
|||||||
Reference in New Issue
Block a user