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::path::Path;
use futures::executor::block_on;
mod queries;
use queries::*;
@ -24,7 +26,6 @@ fn get_auth_key(config_dir: &Path) -> Option<String> {
}
}
fn main() {
let mut config_dir = dirs::config_dir().unwrap();
config_dir.push("ggelo");
@ -34,13 +35,16 @@ fn main() {
let mut search = String::new();
print!("Search for game: ");
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(
run_query::<VideogameSearch,_>(VideogameSearchVars { name: search }, &auth_key)).data {
for maybe_game in response.videogames.unwrap().nodes.unwrap().into_iter() {
let game = maybe_game.unwrap();
println!("{:?} - {}", game.id.unwrap(), game.name.unwrap());
if let Some(response) = block_on(run_query::<VideogameSearch, _>(
VideogameSearchVars { name: search },
&auth_key,
)) {
for game in response.into_iter() {
println!("{} - {}", game.id, game.name);
}
} else {
println!("No response");

View file

@ -1,22 +1,36 @@
use cynic::QueryBuilder;
use serde::{Serialize, Deserialize};
use std::fmt::{Display, Formatter};
use cynic::{GraphQlResponse, QueryBuilder};
use serde::{Deserialize, Serialize};
pub mod search_games;
use schema::schema;
/// 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
/// new scalar type that serializes to u64.
#[derive(cynic::Scalar, Debug)]
pub struct ID(u64);
// 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
// new scalar type that serializes to u64.
#[derive(cynic::Scalar, Debug, Copy, Clone)]
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>
where Builder: QueryBuilder<Vars>,
Vars: Serialize,
for<'de> Builder: Deserialize<'de>
pub trait QueryUnwrap<Vars>: QueryBuilder<Vars> {
type Unwrapped;
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;
@ -27,5 +41,5 @@ pub async fn run_query<Builder: 'static, Vars>(vars: Vars, auth: &str) -> cynic:
.run_graphql(query)
.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 super::ID;
// VARIABLES
// Query
#[derive(cynic::QueryVariables)]
pub struct VideogameSearchVars {
pub name: String
pub name: String,
}
// QUERY
// Query
#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Query", variables = "VideogameSearchVars")]
@ -28,3 +28,34 @@ pub struct Videogame {
pub id: Option<ID>,
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()?,
)
}
}