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 dagger_core::introspection::{TypeRef, __TypeKind};
use dagger_core::introspection::{FullType, InputValue, TypeRef, __TypeKind};
use crate::utility::OptionExt;
pub trait FormatTypeFuncs {
fn format_kind_list(&self, representation: &str) -> String;
@ -44,62 +46,66 @@ impl CommonFunctions {
let mut representation = String::new();
let mut r = Some(t.clone());
while r.is_some() {
match r.as_ref() {
return match r.as_ref() {
Some(rf) => match rf.kind.as_ref() {
Some(k) => match k {
__TypeKind::SCALAR => match Scalar::from(rf) {
Scalar::Int => {
self.format_type_funcs
.format_kind_scalar_int(&mut representation);
}
Scalar::Float => {
self.format_type_funcs
.format_kind_scalar_float(&mut representation);
}
Scalar::String => {
self.format_type_funcs
.format_kind_scalar_string(&mut representation);
}
Scalar::Boolean => {
self.format_type_funcs
.format_kind_scalar_boolean(&mut representation);
}
Scalar::Default => {
self.format_type_funcs.format_kind_scalar_default(
&mut representation,
rf.name.as_ref().unwrap(),
input,
);
}
Scalar::Int => self
.format_type_funcs
.format_kind_scalar_int(&mut representation),
Scalar::Float => self
.format_type_funcs
.format_kind_scalar_float(&mut representation),
Scalar::String => self
.format_type_funcs
.format_kind_scalar_string(&mut representation),
Scalar::Boolean => self
.format_type_funcs
.format_kind_scalar_boolean(&mut representation),
Scalar::Default => self.format_type_funcs.format_kind_scalar_default(
&mut representation,
rf.name.as_ref().unwrap(),
input,
),
},
__TypeKind::OBJECT => {
self.format_type_funcs
.format_kind_object(&mut representation, rf.name.as_ref().unwrap());
}
__TypeKind::ENUM => {
self.format_type_funcs
.format_kind_enum(&mut representation, rf.name.as_ref().unwrap());
}
__TypeKind::OBJECT => self
.format_type_funcs
.format_kind_object(&mut representation, rf.name.as_ref().unwrap()),
__TypeKind::ENUM => self
.format_type_funcs
.format_kind_enum(&mut representation, rf.name.as_ref().unwrap()),
__TypeKind::INPUT_OBJECT => {
self.format_type_funcs.format_kind_input_object(
&mut representation,
&rf.name.as_ref().unwrap(),
);
)
}
__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(_) => {
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,
}
};
}
println!("rep: {}", representation);
println!("{:?}", t);
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 generator;
pub mod rust;
pub mod utility;
mod visitor;
use dagger_core::introspection::Schema;

View File

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

View File

@ -1,13 +1,35 @@
use dagger_core::introspection::FullType;
use dagger_core::introspection::{FullType, FullTypeInputFields};
use genco::prelude::rust;
use genco::quote;
use crate::functions::CommonFunctions;
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! {
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::quote;
use crate::rust::functions::format_name;
use crate::utility::OptionExt;
pub fn render_object(t: &FullType) -> eyre::Result<rust::Tokens> {
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,
}
}
}