diff options
author | Santo Cariotti <santo@dcariotti.me> | 2024-10-18 15:06:12 +0200 |
---|---|---|
committer | Santo Cariotti <santo@dcariotti.me> | 2024-10-18 15:06:12 +0200 |
commit | 874e85a8b1a6c5d9c5bbc1f4429785563a1f7426 (patch) | |
tree | e1a65d6d3f3fff18c04f0f686676c96c4e72b5a0 | |
parent | f252e471b911e4921174b5c1c451f33d1979e04f (diff) |
Filter positions by list of moving activities
-rw-r--r-- | src/graphql/query.rs | 2 | ||||
-rw-r--r-- | src/graphql/types/position.rs | 72 |
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)) } |