one query for pois
This commit is contained in:
parent
08ea09a347
commit
2e326b8cd7
2 changed files with 56 additions and 40 deletions
|
|
@ -16,10 +16,21 @@ pub struct PoiRow {
|
|||
pub wheelchair: Option<String>,
|
||||
}
|
||||
|
||||
/// Count row for total matching POIs.
|
||||
/// POI row with window-function total (replaces separate COUNT query).
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
pub struct CountRow {
|
||||
pub count: Option<i64>,
|
||||
pub struct PoiRowWithTotal {
|
||||
pub osm_id: i64,
|
||||
pub osm_type: String,
|
||||
pub name: String,
|
||||
pub category: String,
|
||||
pub geometry: serde_json::Value,
|
||||
pub address: Option<serde_json::Value>,
|
||||
pub tags: Option<serde_json::Value>,
|
||||
pub opening_hours: Option<String>,
|
||||
pub phone: Option<String>,
|
||||
pub website: Option<String>,
|
||||
pub wheelchair: Option<String>,
|
||||
pub total: Option<i64>,
|
||||
}
|
||||
|
||||
/// Address sub-object in the API response.
|
||||
|
|
@ -86,6 +97,39 @@ pub struct PaginationMetadata {
|
|||
}
|
||||
|
||||
/// Converts a database row into a GeoJSON Feature.
|
||||
impl PoiRowWithTotal {
|
||||
pub fn into_feature(self) -> PoiFeature {
|
||||
let address: Option<PoiAddress> = self
|
||||
.address
|
||||
.as_ref()
|
||||
.and_then(|v| serde_json::from_value(v.clone()).ok());
|
||||
|
||||
let opening_hours_parsed = self.opening_hours.as_ref().map(|_oh| OpeningHoursParsed {
|
||||
is_open: true,
|
||||
today: None,
|
||||
next_change: None,
|
||||
});
|
||||
|
||||
PoiFeature {
|
||||
r#type: "Feature".into(),
|
||||
geometry: self.geometry,
|
||||
properties: PoiProperties {
|
||||
osm_id: self.osm_id,
|
||||
osm_type: self.osm_type,
|
||||
name: self.name,
|
||||
category: self.category,
|
||||
address,
|
||||
opening_hours: self.opening_hours,
|
||||
opening_hours_parsed,
|
||||
phone: self.phone,
|
||||
website: self.website,
|
||||
wheelchair: self.wheelchair,
|
||||
tags: self.tags,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PoiRow {
|
||||
pub fn into_feature(self) -> PoiFeature {
|
||||
let address: Option<PoiAddress> = self
|
||||
|
|
|
|||
|
|
@ -72,43 +72,13 @@ pub async fn list_pois(
|
|||
None
|
||||
};
|
||||
|
||||
// Build and execute the count query
|
||||
let total = if let Some(ref cats) = categories {
|
||||
sqlx::query_as::<_, CountRow>(
|
||||
"SELECT COUNT(*) as count FROM pois \
|
||||
WHERE geometry && ST_MakeEnvelope($1, $2, $3, $4, 4326) \
|
||||
AND category = ANY($5)",
|
||||
)
|
||||
.bind(min_lon)
|
||||
.bind(min_lat)
|
||||
.bind(max_lon)
|
||||
.bind(max_lat)
|
||||
.bind(cats)
|
||||
.fetch_one(pool.get_ref())
|
||||
.await?
|
||||
.count
|
||||
.unwrap_or(0)
|
||||
} else {
|
||||
sqlx::query_as::<_, CountRow>(
|
||||
"SELECT COUNT(*) as count FROM pois \
|
||||
WHERE geometry && ST_MakeEnvelope($1, $2, $3, $4, 4326)",
|
||||
)
|
||||
.bind(min_lon)
|
||||
.bind(min_lat)
|
||||
.bind(max_lon)
|
||||
.bind(max_lat)
|
||||
.fetch_one(pool.get_ref())
|
||||
.await?
|
||||
.count
|
||||
.unwrap_or(0)
|
||||
};
|
||||
|
||||
// Build and execute the data query
|
||||
let rows: Vec<PoiRow> = if let Some(ref cats) = categories {
|
||||
sqlx::query_as::<_, PoiRow>(
|
||||
// Single query: window function computes total within the same spatial scan.
|
||||
let rows: Vec<PoiRowWithTotal> = if let Some(ref cats) = categories {
|
||||
sqlx::query_as::<_, PoiRowWithTotal>(
|
||||
"SELECT osm_id, osm_type, name, category, \
|
||||
ST_AsGeoJSON(geometry)::json AS geometry, \
|
||||
address, tags, opening_hours, phone, website, wheelchair \
|
||||
address, tags, opening_hours, phone, website, wheelchair, \
|
||||
COUNT(*) OVER() AS total \
|
||||
FROM pois \
|
||||
WHERE geometry && ST_MakeEnvelope($1, $2, $3, $4, 4326) \
|
||||
AND category = ANY($5) \
|
||||
|
|
@ -125,10 +95,11 @@ pub async fn list_pois(
|
|||
.fetch_all(pool.get_ref())
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query_as::<_, PoiRow>(
|
||||
sqlx::query_as::<_, PoiRowWithTotal>(
|
||||
"SELECT osm_id, osm_type, name, category, \
|
||||
ST_AsGeoJSON(geometry)::json AS geometry, \
|
||||
address, tags, opening_hours, phone, website, wheelchair \
|
||||
address, tags, opening_hours, phone, website, wheelchair, \
|
||||
COUNT(*) OVER() AS total \
|
||||
FROM pois \
|
||||
WHERE geometry && ST_MakeEnvelope($1, $2, $3, $4, 4326) \
|
||||
ORDER BY name \
|
||||
|
|
@ -144,6 +115,7 @@ pub async fn list_pois(
|
|||
.await?
|
||||
};
|
||||
|
||||
let total = rows.first().and_then(|r| r.total).unwrap_or(0);
|
||||
let features: Vec<PoiFeature> = rows.into_iter().map(|r| r.into_feature()).collect();
|
||||
|
||||
let response = PoiFeatureCollection {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue