summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2024-10-18 15:06:12 +0200
committerSanto Cariotti <santo@dcariotti.me>2024-10-18 15:06:12 +0200
commit874e85a8b1a6c5d9c5bbc1f4429785563a1f7426 (patch)
treee1a65d6d3f3fff18c04f0f686676c96c4e72b5a0
parentf252e471b911e4921174b5c1c451f33d1979e04f (diff)
Filter positions by list of moving activities
-rw-r--r--src/graphql/query.rs2
-rw-r--r--src/graphql/types/position.rs72
2 files changed, 52 insertions, 22 deletions
diff --git a/src/graphql/query.rs b/src/graphql/query.rs
index 2ab26ec..96b8a5b 100644
--- a/src/graphql/query.rs
+++ b/src/graphql/query.rs
@@ -59,7 +59,7 @@ impl Query {
&self,
ctx: &Context<'ctx>,
#[graphql(desc = "Filter by moving activity")] moving_activity: Option<
- position::MovingActivity,
+ Vec<position::MovingActivity>,
>,
#[graphql(desc = "Limit results")] limit: Option<i64>,
#[graphql(desc = "Offset results")] offset: Option<i64>,
diff --git a/src/graphql/types/position.rs b/src/graphql/types/position.rs
index 958edfd..3d0c38f 100644
--- a/src/graphql/types/position.rs
+++ b/src/graphql/types/position.rs
@@ -4,6 +4,7 @@ use crate::{
state::AppState,
};
use async_graphql::{Context, Enum, FieldResult, InputObject, SimpleObject};
+use core::fmt;
use serde::{Deserialize, Serialize};
use std::error::Error;
use tokio_postgres::{
@@ -27,6 +28,23 @@ pub enum MovingActivity {
Still,
}
+/// Implement `Display` trait for `MovingActivity` since we have to use it on format! function
+/// call.
+impl fmt::Display for MovingActivity {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{}",
+ match *self {
+ MovingActivity::InVehicle => "InVehicle",
+ MovingActivity::Running => "Running",
+ MovingActivity::Walking => "Walking",
+ MovingActivity::Still => "Still",
+ }
+ )
+ }
+}
+
impl<'a> FromSql<'a> for MovingActivity {
fn from_sql(_ty: &Type, raw: &'a [u8]) -> Result<MovingActivity, Box<dyn Error + Sync + Send>> {
match std::str::from_utf8(raw)? {
@@ -124,8 +142,8 @@ pub mod query {
pub async fn get_positions<'ctx>(
ctx: &Context<'ctx>,
- // Optional filter by moving activity
- moving_activity: Option<MovingActivity>,
+ // Optional filter by list of moving activity
+ moving_activity: Option<Vec<MovingActivity>>,
// Optional limit results
limit: Option<i64>,
@@ -150,34 +168,46 @@ pub mod query {
return Err(AppError::Unauthorized);
}
+ // Create filter for `movingActivity` field. If not passed by the user, just
+ // returns all kinda activities.
+ let moving_activity_filters: Vec<String> = if moving_activity.is_some() {
+ moving_activity
+ .unwrap()
+ .into_iter()
+ .map(|i| format!("'{}'", i))
+ .collect()
+ } else {
+ vec![
+ "'InVehicle'".to_string(),
+ "'Running'".to_string(),
+ "'Walking'".to_string(),
+ "'Still'".to_string(),
+ ]
+ };
+
let rows = client
- .query("
+ .query(&format!("
SELECT id, user_id, extract(epoch from created_at)::double precision as created_at, ST_Y(location::geometry) AS latitude, ST_X(location::geometry) AS longitude, activity
FROM positions
+ WHERE activity IN ({})
LIMIT $1
OFFSET $2
- ",
+ ", moving_activity_filters.join(", ")),
&[&limit, &offset],
)
.await?;
- let mapped_positions = rows.iter().map(|row| Position {
- id: row.get("id"),
- user_id: row.get("user_id"),
- created_at: row.get::<_, f64>("created_at") as i64,
- latitude: row.get("latitude"),
- longitude: row.get("longitude"),
- moving_activity: row.get("activity"),
- });
-
- let positions: Vec<Position>;
- if let Some(activity) = moving_activity {
- positions = mapped_positions
- .filter(|x| x.moving_activity == activity)
- .collect();
- } else {
- positions = mapped_positions.collect();
- }
+ let positions: Vec<Position> = rows
+ .iter()
+ .map(|row| Position {
+ id: row.get("id"),
+ user_id: row.get("user_id"),
+ created_at: row.get::<_, f64>("created_at") as i64,
+ latitude: row.get("latitude"),
+ longitude: row.get("longitude"),
+ moving_activity: row.get("activity"),
+ })
+ .collect();
Ok(Some(positions))
}