summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2024-08-22 22:45:15 +0200
committerSanto Cariotti <santo@dcariotti.me>2024-08-22 22:45:15 +0200
commitecb99e08531ff4d22e1a2204989e848347b3a756 (patch)
treea6273fe1e2d5ca1ef19aad71fa659a42961e8da4
parentfc51ff9e22a809e257ae92f12272f1dbcb31f594 (diff)
Add field `moving activity`
Following https://developers.google.com/android/reference/com/google/android/gms/location/DetectedActivity
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--schema/init.sql3
-rw-r--r--src/graphql/types/position.rs71
4 files changed, 74 insertions, 2 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3a7dd05..2b8331e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -398,6 +398,7 @@ dependencies = [
"async-graphql-axum",
"axum",
"axum-extra",
+ "bytes",
"chrono",
"config",
"futures-util",
diff --git a/Cargo.toml b/Cargo.toml
index 4570036..ed3c51d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,3 +23,4 @@ once_cell = "1.19.0"
chrono = { version = "0.4.38", features = ["serde"] }
sha256 = "1.5.0"
axum-extra = { version = "0.9.3", features = ["typed-header"] }
+bytes = "1"
diff --git a/schema/init.sql b/schema/init.sql
index f2bc431..682431c 100644
--- a/schema/init.sql
+++ b/schema/init.sql
@@ -6,11 +6,14 @@ CREATE TABLE users(
PRIMARY KEY (id)
);
+CREATE TYPE moving_activity AS ENUM ('InVehicle', 'OnFoot', 'Running', 'Walking', 'Still');
+
CREATE TABLE positions(
id SERIAL NOT NULL,
user_id INTEGER NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
location GEOGRAPHY(Point, 4326) NOT NULL,
+ activity moving_activity NOT NULL,
PRIMARY KEY(id),
CONSTRAINT fk_users_id
FOREIGN KEY(user_id) REFERENCES users(id)
diff --git a/src/graphql/types/position.rs b/src/graphql/types/position.rs
index e5ea8cd..bdcb24f 100644
--- a/src/graphql/types/position.rs
+++ b/src/graphql/types/position.rs
@@ -1,10 +1,71 @@
use crate::{dates::GraphQLDate, state::AppState};
-use async_graphql::{Context, Object};
+use async_graphql::{Context, Enum, Object};
use chrono::Utc;
use serde::{Deserialize, Serialize};
+use std::error::Error;
+use tokio_postgres::types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
use super::jwt::Authentication;
+#[derive(Enum, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
+pub enum MovingActivity {
+ // "Car" of the doc
+ InVehicle,
+
+ // Walking or running
+ OnFoot,
+
+ // Running
+ Running,
+
+ // Walking
+ Walking,
+
+ // Device is not moving
+ 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)? {
+ "InVehicle" => Ok(MovingActivity::InVehicle),
+ "OnFoot" => Ok(MovingActivity::OnFoot),
+ "Running" => Ok(MovingActivity::Running),
+ "Walking" => Ok(MovingActivity::Walking),
+ "Still" => Ok(MovingActivity::Still),
+ other => Err(format!("Unknown variant: {}", other).into()),
+ }
+ }
+
+ fn accepts(ty: &Type) -> bool {
+ ty.name() == "moving_activity"
+ }
+}
+
+impl ToSql for MovingActivity {
+ fn to_sql(
+ &self,
+ _ty: &Type,
+ out: &mut bytes::BytesMut,
+ ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
+ let value = match *self {
+ MovingActivity::InVehicle => "InVehicle",
+ MovingActivity::OnFoot => "OnFoot",
+ MovingActivity::Running => "Running",
+ MovingActivity::Walking => "Walking",
+ MovingActivity::Still => "Still",
+ };
+ out.extend_from_slice(value.as_bytes());
+ Ok(IsNull::No)
+ }
+
+ fn accepts(ty: &Type) -> bool {
+ ty.name() == "moving_activity"
+ }
+
+ to_sql_checked!();
+}
+
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Position {
pub id: i32,
@@ -12,6 +73,7 @@ pub struct Position {
pub created_at: GraphQLDate,
pub latitude: f64,
pub longitude: f64,
+ pub moving_activity: MovingActivity,
}
#[Object]
@@ -35,6 +97,10 @@ impl Position {
async fn longitude(&self) -> f64 {
self.longitude
}
+
+ async fn moving_activity(&self) -> MovingActivity {
+ self.moving_activity
+ }
}
pub async fn get_positions<'ctx>(
@@ -49,7 +115,7 @@ pub async fn get_positions<'ctx>(
Authentication::NotLogged => Err("Unauthorized".to_string()),
Authentication::Logged(claims) => {
let rows = client.query("
- SELECT id, user_id, created_at, ST_Y(location::geometry) AS latitude, ST_X(location::geometry) AS longitude
+ SELECT id, user_id, created_at, ST_Y(location::geometry) AS latitude, ST_X(location::geometry) AS longitude, activity
FROM positions
WHERE user_id = $1
ORDER BY id DESC
@@ -65,6 +131,7 @@ pub async fn get_positions<'ctx>(
created_at: GraphQLDate(Utc::now()),
latitude: row.get("latitude"),
longitude: row.get("longitude"),
+ moving_activity: row.get("activity"),
})
.collect();