add object

This commit is contained in:
Kasper Juul Hermansen 2023-02-15 19:09:37 +01:00
parent 46f0b4d841
commit 4ebd1b4b17
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
6 changed files with 353 additions and 44 deletions

View File

@ -1,6 +1,8 @@
use std::sync::Arc; use std::sync::Arc;
use dagger_core::introspection::{TypeRef, __TypeKind}; use dagger_core::introspection::{FullType, InputValue, TypeRef, __TypeKind};
use crate::utility::OptionExt;
pub trait FormatTypeFuncs { pub trait FormatTypeFuncs {
fn format_kind_list(&self, representation: &str) -> String; fn format_kind_list(&self, representation: &str) -> String;
@ -44,62 +46,66 @@ impl CommonFunctions {
let mut representation = String::new(); let mut representation = String::new();
let mut r = Some(t.clone()); let mut r = Some(t.clone());
while r.is_some() { while r.is_some() {
match r.as_ref() { return match r.as_ref() {
Some(rf) => match rf.kind.as_ref() { Some(rf) => match rf.kind.as_ref() {
Some(k) => match k { Some(k) => match k {
__TypeKind::SCALAR => match Scalar::from(rf) { __TypeKind::SCALAR => match Scalar::from(rf) {
Scalar::Int => { Scalar::Int => self
self.format_type_funcs .format_type_funcs
.format_kind_scalar_int(&mut representation); .format_kind_scalar_int(&mut representation),
} Scalar::Float => self
Scalar::Float => { .format_type_funcs
self.format_type_funcs .format_kind_scalar_float(&mut representation),
.format_kind_scalar_float(&mut representation); Scalar::String => self
} .format_type_funcs
Scalar::String => { .format_kind_scalar_string(&mut representation),
self.format_type_funcs Scalar::Boolean => self
.format_kind_scalar_string(&mut representation); .format_type_funcs
} .format_kind_scalar_boolean(&mut representation),
Scalar::Boolean => { Scalar::Default => self.format_type_funcs.format_kind_scalar_default(
self.format_type_funcs &mut representation,
.format_kind_scalar_boolean(&mut representation); rf.name.as_ref().unwrap(),
} input,
Scalar::Default => { ),
self.format_type_funcs.format_kind_scalar_default(
&mut representation,
rf.name.as_ref().unwrap(),
input,
);
}
}, },
__TypeKind::OBJECT => { __TypeKind::OBJECT => self
self.format_type_funcs .format_type_funcs
.format_kind_object(&mut representation, rf.name.as_ref().unwrap()); .format_kind_object(&mut representation, rf.name.as_ref().unwrap()),
} __TypeKind::ENUM => self
__TypeKind::ENUM => { .format_type_funcs
self.format_type_funcs .format_kind_enum(&mut representation, rf.name.as_ref().unwrap()),
.format_kind_enum(&mut representation, rf.name.as_ref().unwrap());
}
__TypeKind::INPUT_OBJECT => { __TypeKind::INPUT_OBJECT => {
self.format_type_funcs.format_kind_input_object( self.format_type_funcs.format_kind_input_object(
&mut representation, &mut representation,
&rf.name.as_ref().unwrap(), &rf.name.as_ref().unwrap(),
); )
} }
__TypeKind::LIST => { __TypeKind::LIST => {
self.format_type_funcs.format_kind_list(&mut representation); representation =
self.format_type_funcs.format_kind_list(&mut representation);
r = rf.of_type.as_ref().map(|t| t.clone()).map(|t| *t);
continue;
}
__TypeKind::NON_NULL => {
r = rf.of_type.as_ref().map(|t| t.clone()).map(|t| *t);
continue;
} }
__TypeKind::Other(_) => { __TypeKind::Other(_) => {
r = rf.of_type.as_ref().map(|t| t.clone()).map(|t| *t) r = rf.of_type.as_ref().map(|t| t.clone()).map(|t| *t);
continue;
} }
_ => {} __TypeKind::INTERFACE => break,
__TypeKind::UNION => break,
}, },
None => break, None => break,
}, },
None => break, None => break,
} };
} }
println!("rep: {}", representation);
println!("{:?}", t);
representation representation
} }
} }
@ -124,3 +130,222 @@ impl From<&TypeRef> for Scalar {
} }
} }
} }
pub fn get_type_from_name<'t>(types: &'t [FullType], name: &'t str) -> Option<&'t FullType> {
types
.into_iter()
.find(|t| t.name.as_ref().map(|s| s.as_str()) == Some(name))
}
pub fn type_ref_is_optional(type_ref: &TypeRef) -> bool {
type_ref
.kind
.pipe(|k| *k != __TypeKind::NON_NULL)
.unwrap_or(false)
}
pub fn type_ref_is_scalar(type_ref: &TypeRef) -> bool {
type_ref
.kind
.pipe(|k| *k == __TypeKind::SCALAR)
.unwrap_or(false)
}
pub fn type_ref_is_object(type_ref: &TypeRef) -> bool {
type_ref
.kind
.pipe(|k| *k == __TypeKind::OBJECT)
.unwrap_or(false)
}
pub fn type_ref_is_list(type_ref: &TypeRef) -> bool {
type_ref
.kind
.pipe(|k| *k == __TypeKind::LIST)
.unwrap_or(false)
}
pub fn input_values_has_optionals(input_values: &[InputValue]) -> bool {
input_values
.into_iter()
.map(|k| type_ref_is_optional(&k.type_))
.filter(|k| *k)
.collect::<Vec<_>>()
.len()
> 0
}
pub fn input_values_is_empty(input_values: &[InputValue]) -> bool {
input_values.len() > 0
}
#[cfg(test)]
mod test {
use dagger_core::introspection::{FullType, InputValue, TypeRef, __TypeKind};
use pretty_assertions::assert_eq;
use crate::functions::{input_values_has_optionals, type_ref_is_optional};
use super::get_type_from_name;
#[test]
fn get_type_from_name_has_no_item() {
let input = vec![];
let output = get_type_from_name(&input, "some-name");
assert_eq!(output.is_none(), true);
}
#[test]
fn get_type_from_name_has_item() {
let name = "some-name";
let input = vec![FullType {
kind: None,
name: Some(name.to_string()),
description: None,
fields: None,
input_fields: None,
interfaces: None,
enum_values: None,
possible_types: None,
}];
let output = get_type_from_name(&input, name);
assert_eq!(output.is_some(), true);
}
#[test]
fn get_type_from_name_has_item_multiple_entries() {
let name = "some-name";
let input = vec![
FullType {
kind: None,
name: Some(name.to_string()),
description: None,
fields: None,
input_fields: None,
interfaces: None,
enum_values: None,
possible_types: None,
},
FullType {
kind: None,
name: Some(name.to_string()),
description: None,
fields: None,
input_fields: None,
interfaces: None,
enum_values: None,
possible_types: None,
},
];
let output = get_type_from_name(&input, name);
assert_eq!(output.is_some(), true);
}
#[test]
fn type_ref_is_optional_has_none() {
let input = TypeRef {
kind: None,
name: None,
of_type: None,
};
let output = type_ref_is_optional(&input);
assert_eq!(output, false);
}
#[test]
fn type_ref_is_optional_is_required() {
let input = TypeRef {
kind: Some(__TypeKind::NON_NULL),
name: None,
of_type: None,
};
let output = type_ref_is_optional(&input);
assert_eq!(output, false);
}
#[test]
fn type_ref_is_optional_is_optional() {
let input = TypeRef {
kind: Some(__TypeKind::OBJECT),
name: None,
of_type: None,
};
let output = type_ref_is_optional(&input);
assert_eq!(output, true);
}
#[test]
fn input_values_has_optionals_none() {
let input = vec![];
let output = input_values_has_optionals(&input);
assert_eq!(output, false);
}
#[test]
fn input_values_has_optionals_has_optional() {
let input = vec![
InputValue {
name: "some-name".to_string(),
description: None,
type_: TypeRef {
kind: Some(__TypeKind::NON_NULL),
name: None,
of_type: None,
},
default_value: None,
},
InputValue {
name: "some-other-name".to_string(),
description: None,
type_: TypeRef {
kind: Some(__TypeKind::OBJECT),
name: None,
of_type: None,
},
default_value: None,
},
];
let output = input_values_has_optionals(&input);
assert_eq!(output, true);
}
#[test]
fn input_values_has_optionals_is_required() {
let input = vec![
InputValue {
name: "some-name".to_string(),
description: None,
type_: TypeRef {
kind: Some(__TypeKind::NON_NULL),
name: None,
of_type: None,
},
default_value: None,
},
InputValue {
name: "some-other-name".to_string(),
description: None,
type_: TypeRef {
kind: Some(__TypeKind::NON_NULL),
name: None,
of_type: None,
},
default_value: None,
},
];
let output = input_values_has_optionals(&input);
assert_eq!(output, false);
}
}

View File

@ -1,6 +1,7 @@
mod functions; mod functions;
mod generator; mod generator;
pub mod rust; pub mod rust;
pub mod utility;
mod visitor; mod visitor;
use dagger_core::introspection::Schema; use dagger_core::introspection::Schema;

View File

@ -8,9 +8,11 @@ use dagger_core::introspection::Schema;
use eyre::Context; use eyre::Context;
use genco::prelude::rust; use genco::prelude::rust;
use crate::functions::CommonFunctions;
use crate::generator::Generator; use crate::generator::Generator;
use crate::visitor::{VisitHandlers, Visitor}; use crate::visitor::{VisitHandlers, Visitor};
use self::format::FormatTypeFunc;
use self::templates::enum_tmpl::render_enum; use self::templates::enum_tmpl::render_enum;
use self::templates::input_tmpl::render_input; use self::templates::input_tmpl::render_input;
use self::templates::object_tmpl::render_object; use self::templates::object_tmpl::render_object;
@ -21,6 +23,8 @@ pub struct RustGenerator {}
impl Generator for RustGenerator { impl Generator for RustGenerator {
fn generate(&self, schema: Schema) -> eyre::Result<String> { fn generate(&self, schema: Schema) -> eyre::Result<String> {
let render = Arc::new(Mutex::new(rust::Tokens::new())); let render = Arc::new(Mutex::new(rust::Tokens::new()));
let common_funcs = CommonFunctions::new(Arc::new(FormatTypeFunc {}));
println!("generating dagger for rust");
let visitor = Visitor { let visitor = Visitor {
schema, schema,
@ -28,6 +32,7 @@ impl Generator for RustGenerator {
visit_scalar: Arc::new({ visit_scalar: Arc::new({
let render = render.clone(); let render = render.clone();
move |t| { move |t| {
println!("generating scalar");
let rendered_scalar = render_scalar(t)?; let rendered_scalar = render_scalar(t)?;
let mut render = render.lock().unwrap(); let mut render = render.lock().unwrap();
@ -35,6 +40,8 @@ impl Generator for RustGenerator {
render.append(rendered_scalar); render.append(rendered_scalar);
render.push(); render.push();
println!("generated scalar");
Ok(()) Ok(())
} }
}), }),
@ -42,12 +49,14 @@ impl Generator for RustGenerator {
let render = render.clone(); let render = render.clone();
move |t| { move |t| {
println!("generating object");
let rendered_scalar = render_object(t)?; let rendered_scalar = render_object(t)?;
let mut render = render.lock().unwrap(); let mut render = render.lock().unwrap();
render.append(rendered_scalar); render.append(rendered_scalar);
render.push(); render.push();
println!("generated object");
Ok(()) Ok(())
} }
@ -56,12 +65,14 @@ impl Generator for RustGenerator {
let render = render.clone(); let render = render.clone();
move |t| { move |t| {
let rendered_scalar = render_input(t)?; println!("generating input");
let rendered_scalar = render_input(&common_funcs, t)?;
let mut render = render.lock().unwrap(); let mut render = render.lock().unwrap();
render.append(rendered_scalar); render.append(rendered_scalar);
render.push(); render.push();
println!("generated input");
Ok(()) Ok(())
} }
@ -70,12 +81,14 @@ impl Generator for RustGenerator {
let render = render.clone(); let render = render.clone();
move |t| { move |t| {
println!("generating enum");
let rendered_scalar = render_enum(t)?; let rendered_scalar = render_enum(t)?;
let mut render = render.lock().unwrap(); let mut render = render.lock().unwrap();
render.append(rendered_scalar); render.append(rendered_scalar);
render.push(); render.push();
println!("generated enum");
Ok(()) Ok(())
} }
@ -85,6 +98,8 @@ impl Generator for RustGenerator {
visitor.run()?; visitor.run()?;
println!("done generating objects");
let rendered = render.lock().unwrap(); let rendered = render.lock().unwrap();
rendered rendered

View File

@ -1,13 +1,35 @@
use dagger_core::introspection::FullType; use dagger_core::introspection::{FullType, FullTypeInputFields};
use genco::prelude::rust; use genco::prelude::rust;
use genco::quote; use genco::quote;
use crate::functions::CommonFunctions;
use crate::rust::functions::format_name; use crate::rust::functions::format_name;
pub fn render_input(t: &FullType) -> eyre::Result<rust::Tokens> { pub fn render_input(funcs: &CommonFunctions, t: &FullType) -> eyre::Result<rust::Tokens> {
Ok(quote! { Ok(quote! {
pub struct $(format_name(t.name.as_ref().unwrap())) { pub struct $(format_name(t.name.as_ref().unwrap())) {
$(render_input_fields(funcs, t.input_fields.as_ref().unwrap_or(&Vec::new()) ))
} }
}) })
} }
pub fn render_input_fields(
funcs: &CommonFunctions,
fields: &[FullTypeInputFields],
) -> Option<rust::Tokens> {
let rendered_fields = fields.iter().map(|f| render_input_field(funcs, f));
if rendered_fields.len() == 0 {
None
} else {
Some(quote! {
$(for field in rendered_fields join ($['\r']) => $field)
})
}
}
pub fn render_input_field(funcs: &CommonFunctions, field: &FullTypeInputFields) -> rust::Tokens {
quote! {
$(&field.input_value.name): $(funcs.format_input_type(&field.input_value.type_))
}
}

View File

@ -1,12 +1,40 @@
use dagger_core::introspection::FullType; use dagger_core::introspection::{FullType, FullTypeFields};
use genco::prelude::rust; use genco::prelude::rust;
use genco::quote; use genco::quote;
use crate::rust::functions::format_name; use crate::rust::functions::format_name;
use crate::utility::OptionExt;
pub fn render_object(t: &FullType) -> eyre::Result<rust::Tokens> { pub fn render_object(t: &FullType) -> eyre::Result<rust::Tokens> {
Ok(quote! { Ok(quote! {
pub struct $(format_name(t.name.as_ref().unwrap())) { pub struct $(t.name.pipe(|s| format_name(s))) {
}
$(t.fields.pipe(render_optional_args))
impl $(t.name.pipe(|s| format_name(s))) {
} }
}) })
} }
fn render_optional_args(fields: &Vec<FullTypeFields>) -> Option<rust::Tokens> {
let rendered_fields = fields
.iter()
.map(render_optional_arg)
.flatten()
.collect::<Vec<_>>();
if rendered_fields.len() == 0 {
None
} else {
Some(quote! {
$(for field in rendered_fields join ($['\r']) => $field)
})
}
}
fn render_optional_arg(field: &FullTypeFields) -> Option<rust::Tokens> {
todo!()
}

View File

@ -0,0 +1,18 @@
pub trait OptionExt<'t, T: 't> {
fn pipe<U, F>(&'t self, f: F) -> Option<U>
where
F: FnOnce(&'t T) -> U;
}
impl<'t, T: 't> OptionExt<'t, T> for Option<T> {
#[inline]
fn pipe<U, F>(&'t self, f: F) -> Option<U>
where
F: FnOnce(&'t T) -> U,
{
match *self {
Some(ref x) => Some(f(x)),
None => None,
}
}
}