From 09dadfd98be868a25d06a98fd92aba3344abec37 Mon Sep 17 00:00:00 2001 From: James Holman Date: Thu, 30 Jan 2020 12:55:27 +1100 Subject: [PATCH] :sparkles: can view all now --- api/src/data/cult/create_cult.rs | 3 +- api/src/data/cult/get_cult_all.rs | 16 +++++ api/src/data/cult/get_cult_by_id.rs | 28 ++++---- api/src/data/cult/mod.rs | 30 ++++---- api/src/data/mod.rs | 4 +- api/src/data/person/create_person.rs | 5 +- api/src/data/person/get_person_all.rs | 20 ++++++ api/src/data/person/get_person_by_id.rs | 21 +++--- api/src/data/person/get_persons_by_cult_id.rs | 70 +++++++++---------- api/src/data/person/mod.rs | 42 ++++++----- api/src/db/mod.rs | 5 +- api/src/graphql/handler.rs | 40 +++++------ api/src/graphql/mod.rs | 12 ++-- api/src/graphql/mutation.rs | 12 ++-- api/src/graphql/query.rs | 21 ++++-- api/src/graphql/schema.rs | 16 ++--- api/src/main.rs | 18 ++--- api/src/type_defs/cults.rs | 33 +++++---- api/src/type_defs/mod.rs | 2 +- api/src/type_defs/person.rs | 53 +++++++------- 20 files changed, 243 insertions(+), 208 deletions(-) create mode 100644 api/src/data/cult/get_cult_all.rs create mode 100644 api/src/data/person/get_person_all.rs diff --git a/api/src/data/cult/create_cult.rs b/api/src/data/cult/create_cult.rs index 76e2206..4995d36 100644 --- a/api/src/data/cult/create_cult.rs +++ b/api/src/data/cult/create_cult.rs @@ -1,6 +1,5 @@ - -use crate::type_defs::{Cult,NewCult}; use crate::db::get_db_conn; +use crate::type_defs::{Cult, NewCult}; pub fn create_cult(data: NewCult) -> Cult { let conn = get_db_conn(); diff --git a/api/src/data/cult/get_cult_all.rs b/api/src/data/cult/get_cult_all.rs new file mode 100644 index 0000000..975621a --- /dev/null +++ b/api/src/data/cult/get_cult_all.rs @@ -0,0 +1,16 @@ +extern crate postgres; +use crate::db::get_db_conn; +use crate::type_defs::Cult; + +pub fn get_cult_all() -> Vec { + let mut vec = Vec::new(); + let conn = get_db_conn(); + for row in &conn.query("SELECT id, name, cult FROM cults", &[]).unwrap() { + let cult = Cult { + id: row.get(0), + name: row.get(1), + }; + vec.push(cult); + } + vec +} diff --git a/api/src/data/cult/get_cult_by_id.rs b/api/src/data/cult/get_cult_by_id.rs index afd146e..dc50a4e 100644 --- a/api/src/data/cult/get_cult_by_id.rs +++ b/api/src/data/cult/get_cult_by_id.rs @@ -9,10 +9,7 @@ use std::collections::HashMap; pub fn get_cult_by_ids(hashmap: &mut HashMap, ids: Vec) { let conn = get_db_conn(); for row in &conn - .query( - "SELECT id, name FROM cults WHERE id = ANY($1)", - &[&ids], - ) + .query("SELECT id, name FROM cults WHERE id = ANY($1)", &[&ids]) .unwrap() { let cult = Cult { @@ -39,24 +36,23 @@ pub fn get_cult_by_ids(hashmap: &mut HashMap, ids: Vec) { // } // } - pub struct CultBatcher; impl BatchFn for CultBatcher { - type Error = (); - - fn load(&self, keys: &[i32]) -> BatchFuture { - println!("load batch {:?}", keys); - let mut cult_hashmap = HashMap::new(); - get_cult_by_ids(&mut cult_hashmap, keys.to_vec()); - future::ready(keys.iter().map(|key| cult_hashmap[key].clone()).collect()) - .unit_error() - .boxed() - } + type Error = (); + + fn load(&self, keys: &[i32]) -> BatchFuture { + println!("load batch {:?}", keys); + let mut cult_hashmap = HashMap::new(); + get_cult_by_ids(&mut cult_hashmap, keys.to_vec()); + future::ready(keys.iter().map(|key| cult_hashmap[key].clone()).collect()) + .unit_error() + .boxed() + } } pub type CultLoader = Loader; pub fn get_loader() -> CultLoader { - Loader::new(CultBatcher) + Loader::new(CultBatcher) } diff --git a/api/src/data/cult/mod.rs b/api/src/data/cult/mod.rs index e77c580..3b990d5 100644 --- a/api/src/data/cult/mod.rs +++ b/api/src/data/cult/mod.rs @@ -1,24 +1,28 @@ use crate::type_defs::{Cult, NewCult}; -pub mod get_cult_by_id; pub mod create_cult; +pub mod get_cult_all; +pub mod get_cult_by_id; use get_cult_by_id::{get_loader, CultLoader}; #[derive(Clone)] pub struct CultData { - cult_by_id: CultLoader, + cult_by_id: CultLoader, } impl CultData { - pub fn new() -> CultData { - CultData { - cult_by_id: get_loader(), + pub fn new() -> CultData { + CultData { + cult_by_id: get_loader(), + } + } + pub async fn cult_by_id(&self, id: i32) -> Cult { + self.cult_by_id.load(id).await.unwrap() } - } - pub async fn cult_by_id(&self, id: i32) -> Cult { - self.cult_by_id.load(id).await.unwrap() - } - pub async fn create_cult(&self, data: NewCult) -> Cult { - create_cult::create_cult(data) - } -} \ No newline at end of file + pub async fn create_cult(&self, data: NewCult) -> Cult { + create_cult::create_cult(data) + } + pub async fn get_all_cults(&self) -> Vec { + get_cult_all::get_cult_all() + } +} diff --git a/api/src/data/mod.rs b/api/src/data/mod.rs index 6b6ff81..a2a3f09 100644 --- a/api/src/data/mod.rs +++ b/api/src/data/mod.rs @@ -1,5 +1,5 @@ -mod person; mod cult; +mod person; +pub use cult::CultData; pub use person::PersonData; -pub use cult::CultData; \ No newline at end of file diff --git a/api/src/data/person/create_person.rs b/api/src/data/person/create_person.rs index 7c408df..47939f6 100644 --- a/api/src/data/person/create_person.rs +++ b/api/src/data/person/create_person.rs @@ -1,6 +1,5 @@ - -use crate::type_defs::{Person,NewPerson}; use crate::db::get_db_conn; +use crate::type_defs::{NewPerson, Person}; pub fn create_person(data: NewPerson) -> Person { let conn = get_db_conn(); @@ -14,6 +13,6 @@ pub fn create_person(data: NewPerson) -> Person { Person { id: row.get(0), name: row.get(1), - cult: row.get(2) + cult: row.get(2), } } diff --git a/api/src/data/person/get_person_all.rs b/api/src/data/person/get_person_all.rs new file mode 100644 index 0000000..a41bb64 --- /dev/null +++ b/api/src/data/person/get_person_all.rs @@ -0,0 +1,20 @@ +extern crate postgres; +use crate::db::get_db_conn; +use crate::type_defs::Person; + +pub fn get_person_all() -> Vec { + let mut vec = Vec::new(); + let conn = get_db_conn(); + for row in &conn + .query("SELECT id, name, cult FROM persons", &[]) + .unwrap() + { + let person = Person { + id: row.get(0), + name: row.get(1), + cult: row.get(2), + }; + vec.push(person); + } + vec +} diff --git a/api/src/data/person/get_person_by_id.rs b/api/src/data/person/get_person_by_id.rs index 8f9f56a..51c7068 100644 --- a/api/src/data/person/get_person_by_id.rs +++ b/api/src/data/person/get_person_by_id.rs @@ -24,24 +24,23 @@ pub fn get_person_by_ids(hashmap: &mut HashMap, ids: Vec) { } } - pub struct PersonBatcher; impl BatchFn for PersonBatcher { - type Error = (); + type Error = (); - fn load(&self, keys: &[i32]) -> BatchFuture { - println!("load batch {:?}", keys); - let mut person_hashmap = HashMap::new(); - get_person_by_ids(&mut person_hashmap, keys.to_vec()); - future::ready(keys.iter().map(|key| person_hashmap[key].clone()).collect()) - .unit_error() - .boxed() - } + fn load(&self, keys: &[i32]) -> BatchFuture { + println!("load batch {:?}", keys); + let mut person_hashmap = HashMap::new(); + get_person_by_ids(&mut person_hashmap, keys.to_vec()); + future::ready(keys.iter().map(|key| person_hashmap[key].clone()).collect()) + .unit_error() + .boxed() + } } pub type PersonLoader = Loader; pub fn get_loader() -> PersonLoader { - Loader::new(PersonBatcher) + Loader::new(PersonBatcher) } diff --git a/api/src/data/person/get_persons_by_cult_id.rs b/api/src/data/person/get_persons_by_cult_id.rs index c279d14..c79cc71 100644 --- a/api/src/data/person/get_persons_by_cult_id.rs +++ b/api/src/data/person/get_persons_by_cult_id.rs @@ -6,21 +6,21 @@ use dataloader::{BatchFn, BatchFuture}; use futures::{future, FutureExt as _}; pub fn get_persons_by_cult_ids(person_vec: &mut Vec, cult_ids: Vec) { - let conn = get_db_conn(); - for row in &conn - .query( - "SELECT id, name, cult FROM persons WHERE cult = ANY($1)", - &[&cult_ids], - ) - .unwrap() - { - let person = Person { - id: row.get(0), - name: row.get(1), - cult: row.get(2), - }; - person_vec.push(person); - } + let conn = get_db_conn(); + for row in &conn + .query( + "SELECT id, name, cult FROM persons WHERE cult = ANY($1)", + &[&cult_ids], + ) + .unwrap() + { + let person = Person { + id: row.get(0), + name: row.get(1), + cult: row.get(2), + }; + person_vec.push(person); + } } // pub fn create_person(data: NewPerson) -> Person { @@ -40,38 +40,36 @@ pub fn get_persons_by_cult_ids(person_vec: &mut Vec, cult_ids: Vec) // } fn copy_by_cult_id(vec: &Vec, id: i32) -> Vec { - let mut res = Vec::new(); - for p in vec { - if p.cult == Some(id) { - res.push(p.clone()); + let mut res = Vec::new(); + for p in vec { + if p.cult == Some(id) { + res.push(p.clone()); + } } - } - res + res } - pub struct PersonsBatcher; impl BatchFn> for PersonsBatcher { - type Error = (); + type Error = (); - fn load(&self, keys: &[i32]) -> BatchFuture, Self::Error> { - println!("load batch {:?}", keys); - let mut person_vec = Vec::new(); - get_persons_by_cult_ids(&mut person_vec, keys.to_vec()); - future::ready( - keys.iter() - .map(|&key| - copy_by_cult_id(&person_vec, key) + fn load(&self, keys: &[i32]) -> BatchFuture, Self::Error> { + println!("load batch {:?}", keys); + let mut person_vec = Vec::new(); + get_persons_by_cult_ids(&mut person_vec, keys.to_vec()); + future::ready( + keys.iter() + .map(|&key| copy_by_cult_id(&person_vec, key)) + .collect(), ) - .collect()) - .unit_error() - .boxed() - } + .unit_error() + .boxed() + } } pub type PersonsLoader = Loader, (), PersonsBatcher>; pub fn get_loader() -> PersonsLoader { - Loader::new(PersonsBatcher) + Loader::new(PersonsBatcher) } diff --git a/api/src/data/person/mod.rs b/api/src/data/person/mod.rs index e5df65a..a06ee89 100644 --- a/api/src/data/person/mod.rs +++ b/api/src/data/person/mod.rs @@ -1,29 +1,33 @@ -use crate::type_defs::{Person, NewPerson}; +use crate::type_defs::{NewPerson, Person}; +pub mod create_person; +pub mod get_person_all; pub mod get_person_by_id; pub mod get_persons_by_cult_id; -pub mod create_person; #[derive(Clone)] pub struct PersonData { - person_by_id: get_person_by_id::PersonLoader, - persons_by_cult_id: get_persons_by_cult_id::PersonsLoader, + person_by_id: get_person_by_id::PersonLoader, + persons_by_cult_id: get_persons_by_cult_id::PersonsLoader, } impl PersonData { - pub fn new() -> PersonData { - PersonData { - person_by_id: get_person_by_id::get_loader(), - persons_by_cult_id: get_persons_by_cult_id::get_loader(), + pub fn new() -> PersonData { + PersonData { + person_by_id: get_person_by_id::get_loader(), + persons_by_cult_id: get_persons_by_cult_id::get_loader(), + } + } + pub async fn person_by_id(&self, id: i32) -> Person { + self.person_by_id.load(id).await.unwrap() + } + pub async fn persons_by_cult_id(&self, id: i32) -> Vec { + self.persons_by_cult_id.load(id).await.unwrap() } - } - pub async fn person_by_id(&self, id: i32) -> Person { - self.person_by_id.load(id).await.unwrap() - } - pub async fn persons_by_cult_id(&self, id: i32) -> Vec { - self.persons_by_cult_id.load(id).await.unwrap() - } - pub async fn create_person(&self, data: NewPerson) -> Person { - create_person::create_person(data) - } -} \ No newline at end of file + pub async fn create_person(&self, data: NewPerson) -> Person { + create_person::create_person(data) + } + pub async fn get_all_persons(&self) -> Vec { + get_person_all::get_person_all() + } +} diff --git a/api/src/db/mod.rs b/api/src/db/mod.rs index f866d1f..7d13fa9 100644 --- a/api/src/db/mod.rs +++ b/api/src/db/mod.rs @@ -1,6 +1,5 @@ - extern crate postgres; -use postgres::{ Connection, TlsMode }; +use postgres::{Connection, TlsMode}; use std::env; pub fn get_db_conn() -> Connection { @@ -9,4 +8,4 @@ pub fn get_db_conn() -> Connection { let conn = Connection::connect(&pg_connection_string[..], TlsMode::None).unwrap(); println!("Connection is fine"); conn -} \ No newline at end of file +} diff --git a/api/src/graphql/handler.rs b/api/src/graphql/handler.rs index 39afad4..bc7e8f7 100644 --- a/api/src/graphql/handler.rs +++ b/api/src/graphql/handler.rs @@ -5,32 +5,30 @@ use juniper::http::{playground::playground_source, GraphQLRequest}; use std::sync::Arc; pub async fn graphql( - st: web::Data>, - data: web::Json, + st: web::Data>, + data: web::Json, ) -> Result { - let mut rt = futures::executor::LocalPool::new(); + let mut rt = futures::executor::LocalPool::new(); - // Context setup - let person_data = PersonData::new(); - let cult_data = CultData::new(); - let ctx = Context::new(person_data, cult_data); + // Context setup + let person_data = PersonData::new(); + let cult_data = CultData::new(); + let ctx = Context::new(person_data, cult_data); - // Execute - let future_execute = data.execute_async(&st, &ctx); - let res = rt.run_until(future_execute); - let json = serde_json::to_string(&res).map_err(error::ErrorInternalServerError)?; + // Execute + let future_execute = data.execute_async(&st, &ctx); + let res = rt.run_until(future_execute); + let json = serde_json::to_string(&res).map_err(error::ErrorInternalServerError)?; - Ok( - HttpResponse::Ok() - .content_type("application/json") - .body(json), - ) + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(json)) } pub fn playground() -> HttpResponse { - // I prefer playground but you can use graphiql as well - let html = playground_source("http://localhost:8000/graphql"); - HttpResponse::Ok() - .content_type("text/html; charset=utf-8") - .body(html) + // I prefer playground but you can use graphiql as well + let html = playground_source("http://localhost:8000/graphql"); + HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(html) } diff --git a/api/src/graphql/mod.rs b/api/src/graphql/mod.rs index 69e87bd..8cae1a1 100644 --- a/api/src/graphql/mod.rs +++ b/api/src/graphql/mod.rs @@ -1,14 +1,14 @@ use actix_web::web; mod handler; -pub mod schema; pub mod mutation; pub mod query; +pub mod schema; pub fn route(cfg: &mut web::ServiceConfig) { - cfg.service( - web::resource("/graphql") - .route(web::post().to(handler::graphql)) - .route(web::get().to(handler::playground)), - ); + cfg.service( + web::resource("/graphql") + .route(web::post().to(handler::graphql)) + .route(web::get().to(handler::playground)), + ); } diff --git a/api/src/graphql/mutation.rs b/api/src/graphql/mutation.rs index 4a9067d..08a2d9f 100644 --- a/api/src/graphql/mutation.rs +++ b/api/src/graphql/mutation.rs @@ -6,10 +6,10 @@ pub struct Mutation; #[juniper::graphql_object(Context = Context)] impl Mutation { - pub async fn create_person(ctx: &Context, data: NewPerson) -> FieldResult { - Ok(ctx.person_data.create_person(data).await) - } - pub async fn create_cult(ctx: &Context, data: NewCult) -> FieldResult { - Ok(ctx.cult_data.create_cult(data).await) - } + pub async fn create_person(ctx: &Context, data: NewPerson) -> FieldResult { + Ok(ctx.person_data.create_person(data).await) + } + pub async fn create_cult(ctx: &Context, data: NewCult) -> FieldResult { + Ok(ctx.cult_data.create_cult(data).await) + } } diff --git a/api/src/graphql/query.rs b/api/src/graphql/query.rs index f6dda9c..601d085 100644 --- a/api/src/graphql/query.rs +++ b/api/src/graphql/query.rs @@ -5,10 +5,19 @@ use juniper::FieldResult; #[juniper::graphql_object(Context = Context)] impl Query { - async fn person_by_id(context: &Context, id: i32) -> FieldResult { - Ok(context.person_data.person_by_id(id).await) - } - async fn cult_by_id(context: &Context, id: i32) -> FieldResult { - Ok(context.cult_data.cult_by_id(id).await) - } + async fn person_by_id(context: &Context, id: i32) -> FieldResult { + Ok(context.person_data.person_by_id(id).await) + } + + async fn persons(context: &Context) -> FieldResult> { + Ok(context.person_data.get_all_persons().await) + } + + async fn cult_by_id(context: &Context, id: i32) -> FieldResult { + Ok(context.cult_data.cult_by_id(id).await) + } + + async fn cults(context: &Context) -> FieldResult> { + Ok(context.cult_data.get_all_cults().await) + } } diff --git a/api/src/graphql/schema.rs b/api/src/graphql/schema.rs index 5f44669..8a4f8a7 100644 --- a/api/src/graphql/schema.rs +++ b/api/src/graphql/schema.rs @@ -5,23 +5,23 @@ use juniper; #[derive(Clone)] pub struct Context { - pub person_data: PersonData, - pub cult_data: CultData, + pub person_data: PersonData, + pub cult_data: CultData, } impl juniper::Context for Context {} impl Context { - pub fn new(person_data: PersonData, cult_data: CultData) -> Self { - Self { - person_data, - cult_data, + pub fn new(person_data: PersonData, cult_data: CultData) -> Self { + Self { + person_data, + cult_data, + } } - } } pub type Schema = juniper::RootNode<'static, Query, Mutation>; pub fn create_schema() -> Schema { - Schema::new(Query {}, Mutation {}) + Schema::new(Query {}, Mutation {}) } diff --git a/api/src/main.rs b/api/src/main.rs index 4d8e91c..d8fa446 100644 --- a/api/src/main.rs +++ b/api/src/main.rs @@ -1,26 +1,20 @@ - extern crate serde_derive; -mod graphql; -mod db; mod data; +mod db; +mod graphql; mod type_defs; use actix_web::{App, HttpServer}; - #[actix_rt::main] async fn main() -> std::io::Result<()> { let schema = std::sync::Arc::new(crate::graphql::schema::create_schema()); - let server = HttpServer::new(move || { - App::new() - .data(schema.clone()) - .configure(graphql::route) - }) - .bind(("0.0.0.0", 8000)) - .unwrap() - .run(); + let server = HttpServer::new(move || App::new().data(schema.clone()).configure(graphql::route)) + .bind(("0.0.0.0", 8000)) + .unwrap() + .run(); eprintln!("Listening on 0.0.0.0:8000"); diff --git a/api/src/type_defs/cults.rs b/api/src/type_defs/cults.rs index f6a482f..abc8fa7 100644 --- a/api/src/type_defs/cults.rs +++ b/api/src/type_defs/cults.rs @@ -1,32 +1,31 @@ +use super::person::Person; +use crate::graphql::schema::Context; use juniper; use juniper::FieldResult; -use crate::graphql::schema::Context; -use super::person::Person; - #[derive(Debug, Clone)] pub struct Cult { - pub id: i32, - pub name: String, + pub id: i32, + pub name: String, } #[derive(juniper::GraphQLInputObject, Debug, Clone)] -#[graphql(name="NewPerson", description="A creating a person!")] +#[graphql(name = "NewCult", description = "Start your own cult!")] pub struct NewCult { - pub name: String, + pub name: String, } #[juniper::graphql_object(Context = Context)] impl Cult { - pub fn id(&self) -> i32 { - self.id - } + pub fn id(&self) -> i32 { + self.id + } - pub fn name(&self) -> &str { - self.name.as_str() - } + pub fn name(&self) -> &str { + self.name.as_str() + } - pub async fn members(&self, ctx: &Context) -> FieldResult> { - Ok(ctx.person_data.persons_by_cult_id(self.id).await) - } -} \ No newline at end of file + pub async fn members(&self, ctx: &Context) -> FieldResult> { + Ok(ctx.person_data.persons_by_cult_id(self.id).await) + } +} diff --git a/api/src/type_defs/mod.rs b/api/src/type_defs/mod.rs index 9dbb28f..11b5630 100644 --- a/api/src/type_defs/mod.rs +++ b/api/src/type_defs/mod.rs @@ -4,5 +4,5 @@ mod person; pub use cults::Cult; pub use cults::NewCult; +pub use person::NewPerson; pub use person::Person; -pub use person::NewPerson; \ No newline at end of file diff --git a/api/src/type_defs/person.rs b/api/src/type_defs/person.rs index 5f482ee..f9c454d 100644 --- a/api/src/type_defs/person.rs +++ b/api/src/type_defs/person.rs @@ -1,42 +1,43 @@ +use super::cults::Cult; +use crate::graphql::schema::Context; use juniper; -use juniper::FieldError; use juniper::FieldResult; -use juniper::graphql_value; -use crate::graphql::schema::Context; -use super::cults::Cult; - #[derive(Debug, Clone)] pub struct Person { - pub id: i32, - pub name: String, - pub cult: Option, + pub id: i32, + pub name: String, + pub cult: Option, } #[derive(juniper::GraphQLInputObject, Debug, Clone)] -#[graphql(name="NewPerson", description="A creating a person!")] +#[graphql(name = "NewPerson", description = "A creating a person!")] pub struct NewPerson { - pub name: String, - pub cult: Option, + pub name: String, + pub cult: Option, } #[juniper::graphql_object(Context = Context)] impl Person { - pub fn id(&self) -> i32 { - self.id - } + pub fn id(&self) -> i32 { + self.id + } - pub fn name(&self) -> &str { - self.name.as_str() - } + pub fn name(&self) -> &str { + self.name.as_str() + } - pub async fn cult(&self, ctx: &Context) -> FieldResult { - match self.cult { - Some(cult_id) => Ok(ctx.cult_data.cult_by_id(cult_id).await), - None => Err(FieldError::new( - "No cult", - graphql_value!({ "internal_error": "No cult found" }), - )), + pub async fn cult(&self, ctx: &Context) -> FieldResult> { + match self.cult { + Some(cult_id) => Ok(Some(ctx.cult_data.cult_by_id(cult_id).await)), + None => Ok(None), /* ## If I had wanted it to error instead + ```rust + None => Err(FieldError::new( + "No cult", + graphql_value!({ "internal_error": "No cult found" }), + )), + ``` + */ + } } - } -} \ No newline at end of file +}