split out codegen parts

This commit is contained in:
2023-01-29 12:58:57 +01:00
parent 9dccb83d94
commit 3263f1d589
12 changed files with 429 additions and 102 deletions

View File

@@ -0,0 +1,89 @@
use graphql_introspection_query::introspection_response::{
FullType, IntrospectionResponse, Schema,
};
use crate::{
handlers::{DynHandler, Handlers},
predicates::is_custom_scalar_type,
};
#[allow(dead_code)]
pub struct CodeGeneration {
handlers: Handlers,
}
impl CodeGeneration {
pub fn new() -> Self {
Self { handlers: vec![] }
}
pub fn generate(&self, schema: &IntrospectionResponse) -> eyre::Result<String> {
let code = self.generate_from_schema(
schema
.as_schema()
.schema
.as_ref()
.ok_or(eyre::anyhow!("could not get schema to generate code from"))?,
)?;
Ok(code)
}
fn generate_from_schema(&self, schema: &Schema) -> eyre::Result<String> {
let mut output = String::new();
output.push_str("# code generated by dagger. DO NOT EDIT.");
let types = get_types(schema)?;
//let remaining: Vec<Option<String>> = types.into_iter().map(type_name).collect();
todo!()
}
pub fn type_name(&self, t: &FullType) -> Option<String> {
let name = t.name.as_ref();
if let Some(name) = name {
if name.starts_with("_") || !is_custom_scalar_type(t) {
return None;
}
return Some(name.replace("Query", "Client"));
}
None
}
fn group_key(&self, t: &FullType) -> Option<DynHandler> {
for handler in self.handlers.iter() {
if handler.predicate(&t) {
return Some(handler.clone());
}
}
None
}
fn sort_key(&self, t: &FullType) -> (isize, String) {
for (i, handler) in self.handlers.iter().enumerate() {
if handler.predicate(t) {
return (i as isize, t.name.as_ref().unwrap().clone());
}
}
return (-1, t.name.as_ref().unwrap().clone());
}
}
fn get_types(schema: &Schema) -> eyre::Result<Vec<&FullType>> {
let types = schema
.types
.as_ref()
.ok_or(eyre::anyhow!("types not found on schema"))?;
// 1. Get a list of all types and map it to handlers
let types: Vec<&FullType> = types
.iter()
.map(|t| t.as_ref().map(|t| &t.full_type))
.flatten()
.collect();
Ok(types)
}

View File

@@ -0,0 +1,82 @@
use std::sync::Arc;
use genco::prelude::rust::Tokens;
use genco::prelude::*;
use graphql_introspection_query::introspection_response::FullType;
pub trait Handler {
fn predicate(&self, t: &FullType) -> bool {
false
}
fn render(&self, t: &FullType) -> eyre::Result<String> {
let mut s = String::new();
s.push_str("\n");
s.push_str(self.render_struct(t)?.to_string()?.as_str());
s.push_str("\n");
s.push_str(self.render_impl(t)?.to_string()?.as_str());
s.push_str("\n");
Ok(s)
}
fn render_struct(&self, t: &FullType) -> eyre::Result<Tokens> {
let name = t.name.as_ref().ok_or(eyre::anyhow!("name not found"))?;
Ok(quote! {
pub $name {} {
// TODO: Add fields
}
})
}
fn render_impl(&self, t: &FullType) -> eyre::Result<Tokens> {
let name = t.name.as_ref().ok_or(eyre::anyhow!("name not found"))?;
Ok(quote! {
pub $name {} {
// TODO: Add fields
}
})
}
}
pub type DynHandler = Arc<dyn Handler + Send + Sync>;
pub type Handlers = Vec<DynHandler>;
#[cfg(test)]
mod tests {
use graphql_introspection_query::introspection_response::FullType;
use super::Handler;
struct DefaultHandler;
impl Handler for DefaultHandler {}
#[test]
fn render_returns_expected() {
let handler = DefaultHandler {};
let t = FullType {
kind: None,
name: Some("SomeName".into()),
description: None,
fields: None,
input_fields: None,
interfaces: None,
enum_values: None,
possible_types: None,
};
let res = handler.render(&t).unwrap();
assert_eq!(
res,
"
pub SomeName {} { }
pub SomeName {} { }
"
.to_string()
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
pub enum Scalars {
ID(String),
Int(usize),
String(String),
Float(f64),
Boolean(bool),
Date(String),
DateTime(String),
Time(String),
Decimal(f64),
}

View File

@@ -0,0 +1,30 @@
use graphql_introspection_query::introspection_response::{self, FullType};
use crate::models::Scalars;
pub fn is_scalar_type(t: &FullType) -> bool {
if let Some(introspection_response::__TypeKind::SCALAR) = t.kind {
return true;
}
false
}
pub fn is_custom_scalar_type(t: &FullType) -> bool {
if is_scalar_type(t) {
// TODO: Insert scalar
let _ = match t.name.as_ref().map(|s| s.as_str()) {
Some("ID") => Scalars::ID("ID".into()),
Some("Int") => Scalars::Int(0),
Some("String") => Scalars::String("ID".into()),
Some("Float") => Scalars::Float(0.0),
Some("Boolean") => Scalars::Boolean(false),
Some("Date") => Scalars::Date("ID".into()),
Some("DateTime") => Scalars::DateTime("ID".into()),
Some("Time") => Scalars::Time("ID".into()),
Some("Decimal") => Scalars::Decimal(0.0),
Some(_) => return true,
None => return false,
};
}
false
}