split out codegen parts

This commit is contained in:
Kasper Juul Hermansen 2023-01-29 12:58:57 +01:00
parent 9dccb83d94
commit 3263f1d589
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
12 changed files with 429 additions and 102 deletions

37
Cargo.lock generated
View File

@ -165,12 +165,13 @@ dependencies = [
[[package]] [[package]]
name = "dagger-rs" name = "dagger-rs"
version = "0.1.1" version = "0.1.2"
dependencies = [ dependencies = [
"clap", "clap",
"dirs", "dirs",
"eyre", "eyre",
"flate2", "flate2",
"genco",
"graphql-introspection-query", "graphql-introspection-query",
"graphql_client", "graphql_client",
"hex", "hex",
@ -383,6 +384,28 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "genco"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43de41c8ce1ed5ac84a1b11fb3e4ef604bf6773068798490eaa95e8151abad20"
dependencies = [
"genco-macros",
"relative-path",
"smallvec",
]
[[package]]
name = "genco-macros"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85fd34848b1f708e6344a4af6f7bfc05172ae20ce4b35c8e417efffb4f306aa"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.6" version = "0.14.6"
@ -892,6 +915,12 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "relative-path"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3bf6b372449361333ac1f498b7edae4dd5e70dccd7c0c2a7c7bce8f05ede648"
[[package]] [[package]]
name = "remove_dir_all" name = "remove_dir_all"
version = "0.5.3" version = "0.5.3"
@ -1056,6 +1085,12 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.7" version = "0.4.7"

View File

@ -13,6 +13,7 @@ clap = "4.1.4"
dirs = "4.0.0" dirs = "4.0.0"
eyre = "0.6.8" eyre = "0.6.8"
flate2 = { version = "1.0.25", features = ["zlib"] } flate2 = { version = "1.0.25", features = ["zlib"] }
genco = "0.17.3"
graphql-introspection-query = "0.2.0" graphql-introspection-query = "0.2.0"
graphql_client = { version = "0.12.0", features = [ graphql_client = { version = "0.12.0", features = [
"reqwest", "reqwest",

157
crates/dagger-codegen/Cargo.lock generated Normal file
View File

@ -0,0 +1,157 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "dagger-codegen"
version = "0.1.0"
dependencies = [
"eyre",
"genco",
"graphql-introspection-query",
"serde",
"serde_json",
]
[[package]]
name = "eyre"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
dependencies = [
"indenter",
"once_cell",
]
[[package]]
name = "genco"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43de41c8ce1ed5ac84a1b11fb3e4ef604bf6773068798490eaa95e8151abad20"
dependencies = [
"genco-macros",
"relative-path",
"smallvec",
]
[[package]]
name = "genco-macros"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85fd34848b1f708e6344a4af6f7bfc05172ae20ce4b35c8e417efffb4f306aa"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "graphql-introspection-query"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2a4732cf5140bd6c082434494f785a19cfb566ab07d1382c3671f5812fed6d"
dependencies = [
"serde",
]
[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "itoa"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "once_cell"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "proc-macro2"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "relative-path"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3bf6b372449361333ac1f498b7edae4dd5e70dccd7c0c2a7c7bce8f05ede648"
[[package]]
name = "ryu"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "serde"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "syn"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"

View File

@ -0,0 +1,13 @@
[package]
name = "dagger-codegen"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
eyre = "0.6.8"
genco = "0.17.3"
graphql-introspection-query = "0.2.0"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"

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()
);
}
}

View File

@ -1,109 +1,18 @@
use graphql_introspection_query::introspection_response::{ mod codegen;
self, FullType, IntrospectionResponse, Schema, SchemaTypes, mod handlers;
}; mod models;
mod predicates;
pub struct CodeGeneration;
impl CodeGeneration {
pub fn generate(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(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!()
}
}
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)
}
fn type_name(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 is_scalar_type(t: &FullType) -> bool {
if let Some(introspection_response::__TypeKind::SCALAR) = t.kind {
return true;
}
false
}
enum Scalars {
ID(String),
Int(usize),
String(String),
Float(f64),
Boolean(bool),
Date(String),
DateTime(String),
Time(String),
Decimal(f64),
}
fn is_custom_scalar_type(t: &FullType) -> bool {
if is_scalar_type(t) {
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
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use graphql_introspection_query::introspection_response::IntrospectionResponse; use graphql_introspection_query::introspection_response::IntrospectionResponse;
use super::CodeGeneration; use crate::codegen::CodeGeneration;
#[test] #[test]
fn can_generate_from_schema() { fn can_generate_from_schema() {
let schema: IntrospectionResponse = serde_json::from_str(INTROSPECTION_QUERY).unwrap(); let schema: IntrospectionResponse = serde_json::from_str(INTROSPECTION_QUERY).unwrap();
let code = CodeGeneration::generate(&schema).unwrap(); let code = CodeGeneration::new().generate(&schema).unwrap();
assert_eq!("some-code", code); assert_eq!("some-code", code);
} }

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
}

View File

@ -9,3 +9,4 @@ description = "A dagger sdk for rust, written in rust"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
genco = "0.17.3"

View File

@ -1,6 +1,6 @@
use clap::{Arg, ArgMatches}; use clap::{Arg, ArgMatches};
use crate::{code_generation::CodeGeneration, config::Config, engine::Engine, session::Session}; use crate::{config::Config, engine::Engine, session::Session};
#[allow(dead_code)] #[allow(dead_code)]
pub struct GenerateCommand; pub struct GenerateCommand;
@ -17,12 +17,12 @@ impl GenerateCommand {
let session = Session::new(); let session = Session::new();
let req = session.start(&cfg, &conn)?; let req = session.start(&cfg, &conn)?;
let schema = session.schema(req)?; let schema = session.schema(req)?;
let code = CodeGeneration::generate(&schema)?; //let code = CodeGeneration::generate(&schema)?;
if let Some(output) = arg_matches.get_one::<String>("output") { if let Some(output) = arg_matches.get_one::<String>("output") {
// TODO: Write to file // TODO: Write to file
} else { } else {
println!("{}", code); //println!("{}", code);
} }
Ok(()) Ok(())

View File

@ -1,7 +1,6 @@
pub mod cli; pub mod cli;
mod cli_generate; mod cli_generate;
mod cli_session; mod cli_session;
mod code_generation;
mod config; mod config;
mod connect_params; mod connect_params;
pub mod dagger; pub mod dagger;