diff --git a/db/init.sql b/db/init.sql index 4c3cee7..de6a8ec 100644 --- a/db/init.sql +++ b/db/init.sql @@ -15,6 +15,6 @@ CREATE TABLE records ( id SERIAL PRIMARY KEY, dataset_id INTEGER NOT NULL REFERENCES datasets(id), location_id INTEGER REFERENCES locations(id), - timestamp TIMESTAMPTZ NOT NULL, + timestamp TIMESTAMPTZ NOT NULL DEFAULT now(), data JSONB ); diff --git a/src/resolvers.rs b/src/resolvers.rs index 5b4c0b7..2fd7607 100644 --- a/src/resolvers.rs +++ b/src/resolvers.rs @@ -18,7 +18,7 @@ impl QueryRoot { .fetch_all(pool) .await?; - return Ok(rows.into_iter().map(|r| Dataset::from(r)).collect()); + Ok(rows.into_iter().map(Dataset::from).collect()) } pub async fn query_dataset( @@ -56,3 +56,77 @@ impl QueryRoot { Ok(row.into()) } } + +pub struct MutationRoot; + +#[Object] +impl MutationRoot { + pub async fn create_dataset( + &self, + ctx: &Context<'_>, + name: String, + description: Option, + ) -> anyhow::Result { + let pool = get_pg_pool(ctx); + + let id: i32 = sqlx::query_scalar( + r#"INSERT INTO datasets (name, description) + VALUES ($1, $2) + RETURNING id;"#, + ) + .bind(name) + .bind(description) + .fetch_one(pool) + .await?; + + Ok(id) + } + + pub async fn create_location( + &self, + ctx: &Context<'_>, + name: String, + lat: f64, + lon: f64, + ) -> anyhow::Result { + let pool = get_pg_pool(ctx); + + let id: i32 = sqlx::query_scalar( + r#"INSERT INTO locations (name, lat, lon) + VALUES ($1, $2) + RETURNING id;"#, + ) + .bind(name) + .bind(lat) + .bind(lon) + .fetch_one(pool) + .await?; + + Ok(id) + } + + pub async fn record_into_dataset( + &self, + ctx: &Context<'_>, + dataset_id: i32, + location_id: Option, + data: serde_json::Value, + ) -> anyhow::Result { + let pool = get_pg_pool(ctx); + + let row: RecordRow = sqlx::query_as( + r#" + INSERT INTO records (dataset_id, location_id, data) + VALUES ($1, $2, $3) + RETURNING *; + "#, + ) + .bind(dataset_id) + .bind(location_id) + .bind(data) + .fetch_one(pool) + .await?; + + Ok(Record::from(row)) + } +} diff --git a/src/schema.rs b/src/schema.rs index 3e1554d..859ee1d 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -1,14 +1,14 @@ -use crate::resolvers::QueryRoot; -use async_graphql::{EmptyMutation, EmptySubscription, Schema}; +use crate::resolvers::{MutationRoot, QueryRoot}; +use async_graphql::{EmptySubscription, Schema}; use sqlx::{PgPool, postgres::PgPoolOptions}; use std::{env, time::Duration}; use tokio::time::timeout; -pub type AppSchema = Schema; +pub type AppSchema = Schema; pub async fn build_schema() -> anyhow::Result { let pool = create_pool().await?; - Ok(Schema::build(QueryRoot, EmptyMutation, EmptySubscription) + Ok(Schema::build(QueryRoot, MutationRoot, EmptySubscription) .data(pool) .finish()) }