Create automatic query response unwrapping trait

This commit is contained in:
Kiana Sheibani 2023-08-27 04:32:55 -04:00
parent 349d63946c
commit d5c3a7685f
Signed by: toki
GPG key ID: 6CB106C25E86A9F7
3 changed files with 74 additions and 25 deletions

View file

@ -1,6 +1,8 @@
#![feature(iterator_try_collect)]
use futures::executor::block_on;
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::Path; use std::path::Path;
use futures::executor::block_on;
mod queries; mod queries;
use queries::*; use queries::*;
@ -24,7 +26,6 @@ fn get_auth_key(config_dir: &Path) -> Option<String> {
} }
} }
fn main() { fn main() {
let mut config_dir = dirs::config_dir().unwrap(); let mut config_dir = dirs::config_dir().unwrap();
config_dir.push("ggelo"); config_dir.push("ggelo");
@ -34,13 +35,16 @@ fn main() {
let mut search = String::new(); let mut search = String::new();
print!("Search for game: "); print!("Search for game: ");
let _ = io::stdout().flush(); let _ = io::stdout().flush();
io::stdin().read_line(&mut search).expect("Error reading from stdin"); io::stdin()
.read_line(&mut search)
.expect("Error reading from stdin");
if let Some(response) = block_on( if let Some(response) = block_on(run_query::<VideogameSearch, _>(
run_query::<VideogameSearch,_>(VideogameSearchVars { name: search }, &auth_key)).data { VideogameSearchVars { name: search },
for maybe_game in response.videogames.unwrap().nodes.unwrap().into_iter() { &auth_key,
let game = maybe_game.unwrap(); )) {
println!("{:?} - {}", game.id.unwrap(), game.name.unwrap()); for game in response.into_iter() {
println!("{} - {}", game.id, game.name);
} }
} else { } else {
println!("No response"); println!("No response");

View file

@ -1,22 +1,36 @@
use cynic::QueryBuilder; use std::fmt::{Display, Formatter};
use serde::{Serialize, Deserialize};
use cynic::{GraphQlResponse, QueryBuilder};
use serde::{Deserialize, Serialize};
pub mod search_games; pub mod search_games;
use schema::schema; use schema::schema;
/// HACK: Unfortunately, start.gg seems to use integers for its ID type, whereas // HACK: Unfortunately, start.gg seems to use integers for its ID type, whereas
/// cynic always assumes that IDs are strings. To get around that, we define a // cynic always assumes that IDs are strings. To get around that, we define a
/// new scalar type that serializes to u64. // new scalar type that serializes to u64.
#[derive(cynic::Scalar, Debug)] #[derive(cynic::Scalar, Debug, Copy, Clone)]
pub struct ID(u64); pub struct ID(pub u64);
impl Display for ID {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
<u64 as Display>::fmt(&self.0, f)
}
}
pub async fn run_query<Builder: 'static, Vars>(vars: Vars, auth: &str) -> cynic::GraphQlResponse<Builder> pub trait QueryUnwrap<Vars>: QueryBuilder<Vars> {
where Builder: QueryBuilder<Vars>, type Unwrapped;
Vars: Serialize,
for<'de> Builder: Deserialize<'de>
fn unwrap_response(response: GraphQlResponse<Self>) -> Option<Self::Unwrapped>;
}
// Generic function for running start.gg queries
pub async fn run_query<Builder: 'static, Vars>(vars: Vars, auth: &str) -> Option<Builder::Unwrapped>
where
Builder: QueryUnwrap<Vars>,
Vars: Serialize,
for<'de> Builder: Deserialize<'de>,
{ {
use cynic::http::SurfExt; use cynic::http::SurfExt;
@ -27,5 +41,5 @@ pub async fn run_query<Builder: 'static, Vars>(vars: Vars, auth: &str) -> cynic:
.run_graphql(query) .run_graphql(query)
.await; .await;
response.unwrap() <Builder as QueryUnwrap<Vars>>::unwrap_response(response.unwrap())
} }

View file

@ -1,15 +1,15 @@
use super::{QueryUnwrap, ID};
use cynic::GraphQlResponse;
use schema::schema; use schema::schema;
use super::ID;
// VARIABLES // Query
#[derive(cynic::QueryVariables)] #[derive(cynic::QueryVariables)]
pub struct VideogameSearchVars { pub struct VideogameSearchVars {
pub name: String pub name: String,
} }
// QUERY // Query
#[derive(cynic::QueryFragment, Debug)] #[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Query", variables = "VideogameSearchVars")] #[cynic(graphql_type = "Query", variables = "VideogameSearchVars")]
@ -28,3 +28,34 @@ pub struct Videogame {
pub id: Option<ID>, pub id: Option<ID>,
pub name: Option<String>, pub name: Option<String>,
} }
// Unwrapping
pub struct VideogameResponse {
pub id: ID,
pub name: String,
}
impl QueryUnwrap<VideogameSearchVars> for VideogameSearch {
type Unwrapped = Vec<VideogameResponse>;
fn unwrap_response(
response: GraphQlResponse<VideogameSearch>,
) -> Option<Vec<VideogameResponse>> {
Some(
response
.data?
.videogames?
.nodes?
.into_iter()
.map(|game| {
let game_ = game?;
Some(VideogameResponse {
id: game_.id?,
name: game_.name?,
})
})
.try_collect()?,
)
}
}