Add bounds filtering to nodes query for map-based selection
All checks were successful
Build Docker Image / build (push) Successful in 1m10s
All checks were successful
Build Docker Image / build (push) Successful in 1m10s
This commit is contained in:
@@ -153,11 +153,19 @@ class Query(graphene.ObjectType):
|
|||||||
transport_type=graphene.String(),
|
transport_type=graphene.String(),
|
||||||
country=graphene.String(description="Filter by country name"),
|
country=graphene.String(description="Filter by country name"),
|
||||||
search=graphene.String(description="Search by node name (case-insensitive)"),
|
search=graphene.String(description="Search by node name (case-insensitive)"),
|
||||||
|
west=graphene.Float(description="Bounding box west longitude"),
|
||||||
|
south=graphene.Float(description="Bounding box south latitude"),
|
||||||
|
east=graphene.Float(description="Bounding box east longitude"),
|
||||||
|
north=graphene.Float(description="Bounding box north latitude"),
|
||||||
)
|
)
|
||||||
nodes_count = graphene.Int(
|
nodes_count = graphene.Int(
|
||||||
transport_type=graphene.String(),
|
transport_type=graphene.String(),
|
||||||
country=graphene.String(description="Filter by country name"),
|
country=graphene.String(description="Filter by country name"),
|
||||||
description="Get total count of nodes (with optional transport/country filter)",
|
west=graphene.Float(description="Bounding box west longitude"),
|
||||||
|
south=graphene.Float(description="Bounding box south latitude"),
|
||||||
|
east=graphene.Float(description="Bounding box east longitude"),
|
||||||
|
north=graphene.Float(description="Bounding box north latitude"),
|
||||||
|
description="Get total count of nodes (with optional transport/country/bounds filter)",
|
||||||
)
|
)
|
||||||
|
|
||||||
hub_countries = graphene.List(
|
hub_countries = graphene.List(
|
||||||
@@ -402,18 +410,29 @@ class Query(graphene.ObjectType):
|
|||||||
edges=[EdgeType(**e) for e in edges],
|
edges=[EdgeType(**e) for e in edges],
|
||||||
)
|
)
|
||||||
|
|
||||||
def resolve_nodes(self, info, limit=None, offset=None, transport_type=None, country=None, search=None):
|
def resolve_nodes(self, info, limit=None, offset=None, transport_type=None, country=None, search=None,
|
||||||
|
west=None, south=None, east=None, north=None):
|
||||||
"""Get all logistics nodes (without edges for list view)."""
|
"""Get all logistics nodes (without edges for list view)."""
|
||||||
db = get_db()
|
db = get_db()
|
||||||
|
|
||||||
|
# Build bounds filter if all bounds are provided
|
||||||
|
bounds_filter = ""
|
||||||
|
if west is not None and south is not None and east is not None and north is not None:
|
||||||
|
bounds_filter = """
|
||||||
|
FILTER node.latitude != null AND node.longitude != null
|
||||||
|
FILTER node.latitude >= @south AND node.latitude <= @north
|
||||||
|
FILTER node.longitude >= @west AND node.longitude <= @east
|
||||||
|
"""
|
||||||
|
|
||||||
# Only return logistics nodes (not buyer/seller addresses)
|
# Only return logistics nodes (not buyer/seller addresses)
|
||||||
aql = """
|
aql = f"""
|
||||||
FOR node IN nodes
|
FOR node IN nodes
|
||||||
FILTER node.node_type == 'logistics' OR node.node_type == null
|
FILTER node.node_type == 'logistics' OR node.node_type == null
|
||||||
LET types = node.transport_types != null ? node.transport_types : []
|
LET types = node.transport_types != null ? node.transport_types : []
|
||||||
FILTER @transport_type == null OR @transport_type IN types
|
FILTER @transport_type == null OR @transport_type IN types
|
||||||
FILTER @country == null OR node.country == @country
|
FILTER @country == null OR node.country == @country
|
||||||
FILTER @search == null OR CONTAINS(LOWER(node.name), LOWER(@search)) OR CONTAINS(LOWER(node.country), LOWER(@search))
|
FILTER @search == null OR CONTAINS(LOWER(node.name), LOWER(@search)) OR CONTAINS(LOWER(node.country), LOWER(@search))
|
||||||
|
{bounds_filter}
|
||||||
SORT node.name ASC
|
SORT node.name ASC
|
||||||
LIMIT @offset, @limit
|
LIMIT @offset, @limit
|
||||||
RETURN node
|
RETURN node
|
||||||
@@ -426,6 +445,10 @@ class Query(graphene.ObjectType):
|
|||||||
'search': search,
|
'search': search,
|
||||||
'offset': 0 if offset is None else offset,
|
'offset': 0 if offset is None else offset,
|
||||||
'limit': 1000000 if limit is None else limit,
|
'limit': 1000000 if limit is None else limit,
|
||||||
|
'west': west,
|
||||||
|
'south': south,
|
||||||
|
'east': east,
|
||||||
|
'north': north,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -446,18 +469,37 @@ class Query(graphene.ObjectType):
|
|||||||
logger.info("Returning %d nodes", len(nodes))
|
logger.info("Returning %d nodes", len(nodes))
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def resolve_nodes_count(self, info, transport_type=None, country=None):
|
def resolve_nodes_count(self, info, transport_type=None, country=None,
|
||||||
|
west=None, south=None, east=None, north=None):
|
||||||
db = get_db()
|
db = get_db()
|
||||||
aql = """
|
|
||||||
|
# Build bounds filter if all bounds are provided
|
||||||
|
bounds_filter = ""
|
||||||
|
if west is not None and south is not None and east is not None and north is not None:
|
||||||
|
bounds_filter = """
|
||||||
|
FILTER node.latitude != null AND node.longitude != null
|
||||||
|
FILTER node.latitude >= @south AND node.latitude <= @north
|
||||||
|
FILTER node.longitude >= @west AND node.longitude <= @east
|
||||||
|
"""
|
||||||
|
|
||||||
|
aql = f"""
|
||||||
FOR node IN nodes
|
FOR node IN nodes
|
||||||
FILTER node.node_type == 'logistics' OR node.node_type == null
|
FILTER node.node_type == 'logistics' OR node.node_type == null
|
||||||
LET types = node.transport_types != null ? node.transport_types : []
|
LET types = node.transport_types != null ? node.transport_types : []
|
||||||
FILTER @transport_type == null OR @transport_type IN types
|
FILTER @transport_type == null OR @transport_type IN types
|
||||||
FILTER @country == null OR node.country == @country
|
FILTER @country == null OR node.country == @country
|
||||||
|
{bounds_filter}
|
||||||
COLLECT WITH COUNT INTO length
|
COLLECT WITH COUNT INTO length
|
||||||
RETURN length
|
RETURN length
|
||||||
"""
|
"""
|
||||||
cursor = db.aql.execute(aql, bind_vars={'transport_type': transport_type, 'country': country})
|
cursor = db.aql.execute(aql, bind_vars={
|
||||||
|
'transport_type': transport_type,
|
||||||
|
'country': country,
|
||||||
|
'west': west,
|
||||||
|
'south': south,
|
||||||
|
'east': east,
|
||||||
|
'north': north,
|
||||||
|
})
|
||||||
return next(cursor, 0)
|
return next(cursor, 0)
|
||||||
|
|
||||||
def resolve_hub_countries(self, info):
|
def resolve_hub_countries(self, info):
|
||||||
|
|||||||
Reference in New Issue
Block a user