Compare commits

...

6 Commits

Author SHA1 Message Date
2eb027754b fmt tests 2023-02-11 15:27:37 +01:00
19b46b6cf0 add tests 2023-02-11 15:23:41 +01:00
c4edd29f50 pull out args wip 2023-02-11 14:38:58 +01:00
04526c052b add async roadmap item 2023-02-11 14:13:49 +01:00
52a0db3e31 context and querier done 2023-02-11 14:03:06 +01:00
3b5b59ba1c unpack response 2023-02-11 14:02:20 +01:00
8 changed files with 123 additions and 50 deletions

View File

@@ -15,15 +15,16 @@ Work in progress. This is not ready for usage yet
- [x] Enums - [x] Enums
- [x] Input - [x] Input
- [x] Objects - [x] Objects
- [ ] Implement context and querier - [x] Implement context and querier
- [x] Marshaller - [x] Marshaller
- [x] Querier - [x] Querier
- [x] Context - [x] Context
- [ ] Deserializer for nested response (bind) - [x] Deserializer for nested response (bind)
- [ ] Add codegen to hook into querier - [ ] Add codegen to hook into querier
- [ ] fix build / release cycle - [ ] fix build / release cycle
- [ ] general api stabilisation - [ ] general api stabilisation
- [ ] document usage - [ ] document usage
- [ ] make async variant
## Architecture ## Architecture

View File

@@ -19,27 +19,31 @@ pub fn render_fields(fields: &Vec<FullTypeFields>) -> eyre::Result<Option<rust::
}; };
let mut tkns = rust::Tokens::new(); let mut tkns = rust::Tokens::new();
if let Some(desc) = &description {
tkns.append(desc);
tkns.push()
}
if let Some(args) = args.as_ref() { if let Some(args) = args.as_ref() {
if let Some(desc) = args.description.as_ref() { tkns.append(quote! {
tkns.append("/// # Arguments"); $description
tkns.push(); pub struct $(&name)Args {
tkns.append("///"); $(&args.args)
tkns.push();
tkns.append(desc);
tkns.push();
} }
});
tkns.push();
} }
tkns.append(quote! { tkns.append(quote! {
pub fn $name( pub fn $(&name)(
&self, &self,
$(if let Some(args) = args.as_ref() => $(&args.args)) $(if let Some(_) = args.as_ref() => args: $(&name)Args)
) -> $output { ) -> $(&output) {
let query = self.selection.select($(field.name.as_ref().map(|n| format!("\"{}\"", n))));
$(if let Some(_) = args.as_ref() => query.args(args);)
$output {
conn: self.conn.clone(),
proc: self.proc.clone(),
selection: query,
}
todo!() todo!()
} }
}); });

View File

@@ -20,7 +20,7 @@ impl Handler for Input {
.ok_or(eyre::anyhow!("could not find name"))?; .ok_or(eyre::anyhow!("could not find name"))?;
let description = render_description(t); let description = render_description(t);
let input = rust::import("dagger_core", "Input"); //let input = rust::import("dagger_core", "Input");
let fields = match t.input_fields.as_ref() { let fields = match t.input_fields.as_ref() {
Some(i) => render_input_fields(i)?, Some(i) => render_input_fields(i)?,
@@ -32,8 +32,6 @@ impl Handler for Input {
pub struct $name { pub struct $name {
$(if fields.is_some() => $fields) $(if fields.is_some() => $fields)
} }
impl $input for $name {}
}; };
Ok(out) Ok(out)
@@ -98,15 +96,11 @@ mod tests {
fields: None, fields: None,
}; };
let expected = r#"use dagger_core::Input; let expected = r#"pub struct BuildArg {
pub name: String,
pub struct BuildArg { pub value: String,
pub name: Option<String>,
pub value: Option<String>,
} }
impl Input for BuildArg {}
"#; "#;
let output = input.render(&t).unwrap(); let output = input.render(&t).unwrap();

View File

@@ -19,8 +19,6 @@ impl Handler for Object {
.ok_or(eyre::anyhow!("could not find name"))?; .ok_or(eyre::anyhow!("could not find name"))?;
let description = render_description(t); let description = render_description(t);
let input = rust::import("dagger_core", "Input");
let fields = match t.fields.as_ref() { let fields = match t.fields.as_ref() {
Some(i) => fields::render_fields(i)?, Some(i) => fields::render_fields(i)?,
None => None, None => None,
@@ -40,8 +38,6 @@ impl Handler for Object {
impl $name { impl $name {
$(if fields.is_some() => $fields) $(if fields.is_some() => $fields)
} }
impl $input for $name {}
}; };
Ok(out) Ok(out)
@@ -51,7 +47,8 @@ impl Handler for Object {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use dagger_core::introspection::{ use dagger_core::introspection::{
FullType, FullTypeFields, FullTypeFieldsType, TypeRef, __TypeKind, FullType, FullTypeFields, FullTypeFieldsArgs, FullTypeFieldsType, InputValue, TypeRef,
__TypeKind,
}; };
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
@@ -88,21 +85,78 @@ mod tests {
enum_values: None, enum_values: None,
possible_types: None, possible_types: None,
}; };
let expected = r#"use dagger_core::Input; let expected = r#"
/// A directory whose contents persists across sessions /// A directory whose contents persists across sessions
pub struct CacheVolume {} pub struct CacheVolume {}
impl CacheVolume { impl CacheVolume {
pub fn id( pub fn id(
&self, &self,
) -> Option<CacheID> { ) -> CacheID {
let query = self.selection.select("id");
CacheID {
conn: self.conn.clone(),
proc: self.proc.clone(),
selection: query,
}
todo!() todo!()
} }
} }
"#;
let handler = Object {};
let obj = handler.render(&t).unwrap();
let actual = obj.to_file_string().unwrap();
impl Input for CacheVolume {} assert_eq!(actual, expected);
}
#[test]
fn can_render_query_container() {
let t: FullType = FullType {
kind: Some(__TypeKind::OBJECT),
name: Some("Query".into()),
description: None,
fields: Some(vec![FullTypeFields {
name: Some("container".into()),
description: Some("Loads a container from ID.\nNull ID returns an empty container (scratch).\nOptional platform argument initializes new containers to execute and publish as that platform. Platform defaults to that of the builder's host.".into()),
args: Some(
vec![
Some(
FullTypeFieldsArgs
{
input_value: InputValue { name: "id".into(), description: None, type_: TypeRef { kind: Some(__TypeKind::SCALAR), name: Some("ContainerID".into()), of_type: None }, default_value: None }
}
),
Some(
FullTypeFieldsArgs {
input_value: InputValue {
name: "platform".into(), description: None, type_: TypeRef { kind: Some(__TypeKind::SCALAR), name: Some("Platform".into()), of_type: None },
default_value: None }
})
]),
type_: Some(FullTypeFieldsType {
type_ref: TypeRef {
kind: Some(__TypeKind::NON_NULL),
name: None,
of_type: Some(Box::new(TypeRef {
kind: Some(__TypeKind::SCALAR),
name: Some("CacheID".into()),
of_type: None,
})),
},
}),
is_deprecated: Some(false),
deprecation_reason: None,
}
]),
input_fields: None,
interfaces: None,
enum_values: None,
possible_types: None,
};
let expected = r#"
"#; "#;
let handler = Object {}; let handler = Object {};
let obj = handler.render(&t).unwrap(); let obj = handler.render(&t).unwrap();

View File

@@ -6,14 +6,6 @@ use crate::predicates::{
is_custom_scalar_type_ref, is_list_type, is_required_type_ref, is_scalar_type_ref, is_custom_scalar_type_ref, is_list_type, is_required_type_ref, is_scalar_type_ref,
}; };
//fn optional(t: rust::Tokens) -> impl FormatInto<Rust> {
// quote_fn! {"Option<$[const](t)>"}
//}
//
//fn required(t: rust::Tokens) -> impl FormatInto<Rust> {
// quote_fn! {"$[const](t)"}
//}
pub fn render_type_ref(inner: &TypeRef) -> eyre::Result<rust::Tokens> { pub fn render_type_ref(inner: &TypeRef) -> eyre::Result<rust::Tokens> {
let extract_of_type = |t: &TypeRef| -> Option<TypeRef> { let extract_of_type = |t: &TypeRef| -> Option<TypeRef> {
return t.clone().of_type.map(|t| *t); return t.clone().of_type.map(|t| *t);

View File

@@ -1,4 +1,3 @@
use std::{ use std::{
fs::canonicalize, fs::canonicalize,
io::{BufRead, BufReader}, io::{BufRead, BufReader},
@@ -101,7 +100,7 @@ impl InnerCliSession {
let stderr_bufr = BufReader::new(stderr); let stderr_bufr = BufReader::new(stderr);
for line in stderr_bufr.lines() { for line in stderr_bufr.lines() {
let out = line.unwrap(); let out = line.unwrap();
panic!("could not start dagger session: {}", out) //panic!("could not start dagger session: {}", out)
} }
}); });

View File

@@ -1,7 +1,7 @@
use std::{collections::HashMap, ops::Add, sync::Arc}; use std::{collections::HashMap, ops::Add, sync::Arc};
use eyre::Context;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::task::block_in_place;
pub fn query() -> Selection { pub fn query() -> Selection {
Selection::default() Selection::default()
@@ -106,11 +106,13 @@ impl Selection {
dbg!(&query); dbg!(&query);
let resp: Option<D> = match basic.block_on(gql_client.query(&query)) { let resp: Option<serde_json::Value> = match basic.block_on(gql_client.query(&query)) {
Ok(r) => r, Ok(r) => r,
Err(e) => eyre::bail!(e), Err(e) => eyre::bail!(e),
}; };
let resp: Option<D> = self.unpack_resp(resp)?;
Ok(resp) Ok(resp)
} }
@@ -129,6 +131,33 @@ impl Selection {
selections.reverse(); selections.reverse();
selections selections
} }
pub(crate) fn unpack_resp<D>(&self, resp: Option<serde_json::Value>) -> eyre::Result<Option<D>>
where
D: for<'de> Deserialize<'de>,
{
match resp {
Some(r) => self.unpack_resp_value::<D>(r).map(|v| Some(v)),
None => Ok(None),
}
}
fn unpack_resp_value<D>(&self, r: serde_json::Value) -> eyre::Result<D>
where
D: for<'de> Deserialize<'de>,
{
if let Some(o) = r.as_object() {
let keys = o.keys();
if keys.len() != 1 {
eyre::bail!("too many nested objects inside graphql response")
}
let first = keys.into_iter().next().unwrap();
return self.unpack_resp_value(o.get(first).unwrap().clone());
}
serde_json::from_value::<D>(r).context("could not deserialize response")
}
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -16,5 +16,5 @@ fn test_example_container() {
) )
.stdout(); .stdout();
assert_eq!(out, Some("3.16.2".to_string())) assert_eq!(out, Some("3.16.2\n".to_string()))
} }