mirror of
https://github.com/Noratrieb/terustform.git
synced 2026-01-14 08:30:13 +01:00
Support nested object
This commit is contained in:
parent
55506d3748
commit
b50fa51e9c
8 changed files with 143 additions and 96 deletions
|
|
@ -1,5 +1,3 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use terustform::{
|
use terustform::{
|
||||||
resource::Resource, AttrPath, Attribute, DResult, EyreExt, Mode, Schema, Value, ValueModel,
|
resource::Resource, AttrPath, Attribute, DResult, EyreExt, Mode, Schema, Value, ValueModel,
|
||||||
};
|
};
|
||||||
|
|
@ -78,41 +76,28 @@ impl Resource for ClassResource {
|
||||||
fn schema() -> terustform::Schema {
|
fn schema() -> terustform::Schema {
|
||||||
Schema {
|
Schema {
|
||||||
description: "A class".into(),
|
description: "A class".into(),
|
||||||
attributes: HashMap::from([
|
attributes: terustform::attrs! {
|
||||||
(
|
"id" => Attribute::String {
|
||||||
"id".to_owned(),
|
description: "The UUID".to_owned(),
|
||||||
// TODO: UUID validation :3
|
mode: Mode::Computed,
|
||||||
Attribute::String {
|
sensitive: false,
|
||||||
description: "The UUID".to_owned(),
|
},
|
||||||
mode: Mode::Computed,
|
"name" => Attribute::String {
|
||||||
sensitive: false,
|
description: "The description".to_owned(),
|
||||||
},
|
mode: Mode::Required,
|
||||||
),
|
sensitive: false,
|
||||||
(
|
},
|
||||||
"name".to_owned(),
|
"description" => Attribute::String {
|
||||||
Attribute::String {
|
description: "The description".to_owned(),
|
||||||
description: "The description".to_owned(),
|
mode: Mode::Required,
|
||||||
mode: Mode::Required,
|
sensitive: false,
|
||||||
sensitive: false,
|
},
|
||||||
},
|
"discord_id" => Attribute::String {
|
||||||
),
|
description: "The discord ID of the class".to_owned(),
|
||||||
(
|
mode: Mode::Optional,
|
||||||
"description".to_owned(),
|
sensitive: false,
|
||||||
Attribute::String {
|
},
|
||||||
description: "The description".to_owned(),
|
},
|
||||||
mode: Mode::Required,
|
|
||||||
sensitive: false,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"discord_id".to_owned(),
|
|
||||||
Attribute::String {
|
|
||||||
description: "The discord ID of the class".to_owned(),
|
|
||||||
mode: Mode::Optional,
|
|
||||||
sensitive: false,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use eyre::Context;
|
use eyre::Context;
|
||||||
use terustform::{
|
use terustform::{
|
||||||
datasource::DataSource, Attribute, DResult, EyreExt, Mode, Schema, StringValue, Value,
|
datasource::DataSource, Attribute, DResult, EyreExt, Mode, Schema, StringValue, Value,
|
||||||
|
|
@ -41,14 +39,13 @@ impl DataSource for HugoDataSource {
|
||||||
fn schema() -> Schema {
|
fn schema() -> Schema {
|
||||||
Schema {
|
Schema {
|
||||||
description: "Get Hugo Boss".to_owned(),
|
description: "Get Hugo Boss".to_owned(),
|
||||||
attributes: HashMap::from([(
|
attributes: terustform::attrs! {
|
||||||
"hugo".to_owned(),
|
"hugo" => Attribute::String {
|
||||||
Attribute::String {
|
|
||||||
description: "Hugo Boss".to_owned(),
|
description: "Hugo Boss".to_owned(),
|
||||||
mode: Mode::Computed,
|
mode: Mode::Computed,
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
},
|
},
|
||||||
)]),
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use terustform::{
|
use terustform::{
|
||||||
datasource::DataSource, AttrPath, Attribute, DResult, Mode, Schema, StringValue, Value,
|
datasource::DataSource, AttrPath, Attribute, DResult, Mode, Schema, StringValue, Value,
|
||||||
ValueModel,
|
ValueModel,
|
||||||
|
|
@ -13,7 +11,13 @@ pub struct ExampleDataSource {}
|
||||||
struct ExampleDataSourceModel {
|
struct ExampleDataSourceModel {
|
||||||
name: StringValue,
|
name: StringValue,
|
||||||
meow: StringValue,
|
meow: StringValue,
|
||||||
id: StringValue,
|
paws: ExampleDataSourceModelPaws,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(terustform::Model)]
|
||||||
|
struct ExampleDataSourceModelPaws {
|
||||||
|
left: StringValue,
|
||||||
|
right: StringValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataSource for ExampleDataSource {
|
impl DataSource for ExampleDataSource {
|
||||||
|
|
@ -26,32 +30,35 @@ impl DataSource for ExampleDataSource {
|
||||||
fn schema() -> Schema {
|
fn schema() -> Schema {
|
||||||
Schema {
|
Schema {
|
||||||
description: "an example".to_owned(),
|
description: "an example".to_owned(),
|
||||||
attributes: HashMap::from([
|
attributes: terustform::attrs! {
|
||||||
(
|
"name" => Attribute::String {
|
||||||
"name".to_owned(),
|
description: "a cool name".to_owned(),
|
||||||
Attribute::String {
|
mode: Mode::Required,
|
||||||
description: "a cool name".to_owned(),
|
sensitive: false,
|
||||||
mode: Mode::Required,
|
},
|
||||||
sensitive: false,
|
"meow" => Attribute::String {
|
||||||
|
description: "the meow of the cat".to_owned(),
|
||||||
|
mode: Mode::Computed,
|
||||||
|
sensitive: false,
|
||||||
|
},
|
||||||
|
"paws" => Attribute::Object {
|
||||||
|
description: "the ID of the meowy cat".to_owned(),
|
||||||
|
mode: Mode::Required,
|
||||||
|
sensitive: false,
|
||||||
|
attrs: terustform::attrs! {
|
||||||
|
"left" => Attribute::String {
|
||||||
|
description: "meow".to_owned(),
|
||||||
|
mode: Mode::Required,
|
||||||
|
sensitive: false,
|
||||||
|
},
|
||||||
|
"right" => Attribute::String {
|
||||||
|
description: "meow".to_owned(),
|
||||||
|
mode: Mode::Required,
|
||||||
|
sensitive: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
},
|
||||||
(
|
},
|
||||||
"meow".to_owned(),
|
|
||||||
Attribute::String {
|
|
||||||
description: "the meow of the cat".to_owned(),
|
|
||||||
mode: Mode::Computed,
|
|
||||||
sensitive: false,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"id".to_owned(),
|
|
||||||
Attribute::String {
|
|
||||||
description: "the ID of the meowy cat".to_owned(),
|
|
||||||
mode: Mode::Computed,
|
|
||||||
sensitive: false,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,7 +74,7 @@ impl DataSource for ExampleDataSource {
|
||||||
let meow = format!("mrrrrr i am {name_str}");
|
let meow = format!("mrrrrr i am {name_str}");
|
||||||
|
|
||||||
model.meow = StringValue::Known(meow);
|
model.meow = StringValue::Known(meow);
|
||||||
model.id = StringValue::Known("0".to_owned());
|
model.paws.right = StringValue::Known("O".to_owned());
|
||||||
|
|
||||||
Ok(model.to_value())
|
Ok(model.to_value())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,18 @@ data "corsschool_class" "test" {
|
||||||
output "class" {
|
output "class" {
|
||||||
value = data.corsschool_class.test
|
value = data.corsschool_class.test
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
resource "corsschool_class" "myclass" {
|
resource "corsschool_class" "myclass" {
|
||||||
name = "meow"
|
name = "meow"
|
||||||
description = "???"
|
description = "???"
|
||||||
|
}*/
|
||||||
|
data "corsschool_kitty" "name" {
|
||||||
|
name = "a"
|
||||||
|
paws = {
|
||||||
|
left = "x"
|
||||||
|
right = "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output "kitty_paw" {
|
||||||
|
value = data.corsschool_kitty.name.paws.right
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +50,7 @@ fn data_source_model_inner(
|
||||||
let #tf::Some(#name) = obj.remove(#name_str) else {
|
let #tf::Some(#name) = obj.remove(#name_str) else {
|
||||||
return #tf::Err(
|
return #tf::Err(
|
||||||
#tf::Diagnostics::from(#tf::Diagnostic::error_string(
|
#tf::Diagnostics::from(#tf::Diagnostic::error_string(
|
||||||
format!("Expected property '{}', which was not present", #name_str),
|
format!("Expected property '{}' when deserializing value, which was not present in the value", #name_str),
|
||||||
).with_path(path.clone()))
|
).with_path(path.clone()))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,12 @@ use provider::Provider;
|
||||||
|
|
||||||
pub async fn start<P: Provider>(provider: P) -> eyre::Result<()> {
|
pub async fn start<P: Provider>(provider: P) -> eyre::Result<()> {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(EnvFilter::builder().parse_lossy(
|
.with_env_filter(
|
||||||
std::env::var("RUST_LOG").unwrap_or_else(|_| "h2=info,rustls=info,hyper_util=info,debug".into()),
|
EnvFilter::builder().parse_lossy(
|
||||||
))
|
std::env::var("RUST_LOG")
|
||||||
|
.unwrap_or_else(|_| "h2=info,rustls=info,hyper_util=info,debug".into()),
|
||||||
|
),
|
||||||
|
)
|
||||||
.with_writer(std::io::stderr)
|
.with_writer(std::io::stderr)
|
||||||
.without_time()
|
.without_time()
|
||||||
.init();
|
.init();
|
||||||
|
|
@ -39,6 +42,28 @@ pub async fn start<P: Provider>(provider: P) -> eyre::Result<()> {
|
||||||
server::serve(provider).await
|
server::serve(provider).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ```rust
|
||||||
|
/// # use std::collections::HashMap;
|
||||||
|
/// let x: HashMap<String, u8> = terustform::attrs! {
|
||||||
|
/// "hello" => 0,
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! attrs {
|
||||||
|
(
|
||||||
|
$( $name:literal => $rhs:expr ,)*
|
||||||
|
) => {
|
||||||
|
<$crate::__derive_private::HashMap<_, _> as $crate::__derive_private::FromIterator<(_, _)>>::from_iter([
|
||||||
|
$(
|
||||||
|
(
|
||||||
|
$name.into(),
|
||||||
|
$rhs,
|
||||||
|
),
|
||||||
|
)*
|
||||||
|
])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Private, only for use for with the derive macro.
|
/// Private, only for use for with the derive macro.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod __derive_private {
|
pub mod __derive_private {
|
||||||
|
|
@ -46,7 +71,7 @@ pub mod __derive_private {
|
||||||
AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, Value, ValueKind,
|
AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, Value, ValueKind,
|
||||||
ValueModel,
|
ValueModel,
|
||||||
};
|
};
|
||||||
pub use {Clone, Option::Some, Result::Err, ToOwned};
|
pub use {std::collections::HashMap, Clone, FromIterator, Option::Some, Result::Err, ToOwned};
|
||||||
|
|
||||||
pub fn new_object<const N: usize>(elems: [(&str, Value); N]) -> Value {
|
pub fn new_object<const N: usize>(elems: [(&str, Value); N]) -> Value {
|
||||||
Value::Known(ValueKind::Object(std::collections::BTreeMap::from_iter(
|
Value::Known(ValueKind::Object(std::collections::BTreeMap::from_iter(
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,12 @@ pub enum Attribute {
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
sensitive: bool,
|
sensitive: bool,
|
||||||
},
|
},
|
||||||
|
Object {
|
||||||
|
description: String,
|
||||||
|
mode: Mode,
|
||||||
|
sensitive: bool,
|
||||||
|
attrs: HashMap<String, Attribute>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
@ -35,6 +41,7 @@ impl Attribute {
|
||||||
match *self {
|
match *self {
|
||||||
Self::Int64 { mode, .. } => mode,
|
Self::Int64 { mode, .. } => mode,
|
||||||
Self::String { mode, .. } => mode,
|
Self::String { mode, .. } => mode,
|
||||||
|
Self::Object { mode, .. } => mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,22 +62,28 @@ impl Mode {
|
||||||
|
|
||||||
impl Schema {
|
impl Schema {
|
||||||
pub fn typ(&self) -> Type {
|
pub fn typ(&self) -> Type {
|
||||||
let attrs = self
|
attrs_typ(&self.attributes)
|
||||||
.attributes
|
}
|
||||||
.iter()
|
}
|
||||||
.map(|(name, attr)| {
|
|
||||||
let attr_type = match attr {
|
|
||||||
Attribute::Int64 { .. } => Type::Number,
|
|
||||||
Attribute::String { .. } => Type::String,
|
|
||||||
};
|
|
||||||
|
|
||||||
(name.clone(), attr_type)
|
impl Attribute {
|
||||||
})
|
pub fn typ(&self) -> Type {
|
||||||
.collect();
|
match self {
|
||||||
|
Attribute::Int64 { .. } => Type::Number,
|
||||||
Type::Object {
|
Attribute::String { .. } => Type::String,
|
||||||
attrs,
|
Attribute::Object { attrs, .. } => attrs_typ(attrs),
|
||||||
optionals: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attrs_typ(attrs: &HashMap<String, Attribute>) -> Type {
|
||||||
|
let attrs = attrs
|
||||||
|
.iter()
|
||||||
|
.map(|(name, attr)| (name.clone(), attr.typ()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Type::Object {
|
||||||
|
attrs,
|
||||||
|
optionals: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{values::Type, AttrPathSegment, Attribute, Diagnostics, Mode, Schema, Value};
|
use crate::{AttrPathSegment, Attribute, Diagnostics, Mode, Schema, Value};
|
||||||
|
|
||||||
use super::grpc::tfplugin6;
|
use super::grpc::tfplugin6;
|
||||||
|
|
||||||
|
|
@ -43,13 +43,14 @@ impl Attribute {
|
||||||
attr.computed = mode.computed();
|
attr.computed = mode.computed();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
attr.r#type = self.typ().to_json().into_bytes();
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Attribute::String {
|
Attribute::String {
|
||||||
description,
|
description,
|
||||||
mode,
|
mode,
|
||||||
sensitive,
|
sensitive,
|
||||||
} => {
|
} => {
|
||||||
attr.r#type = Type::String.to_json().into_bytes();
|
|
||||||
attr.description = description;
|
attr.description = description;
|
||||||
set_modes(&mut attr, mode);
|
set_modes(&mut attr, mode);
|
||||||
attr.sensitive = sensitive;
|
attr.sensitive = sensitive;
|
||||||
|
|
@ -59,7 +60,16 @@ impl Attribute {
|
||||||
mode,
|
mode,
|
||||||
sensitive,
|
sensitive,
|
||||||
} => {
|
} => {
|
||||||
attr.r#type = Type::Number.to_json().into_bytes();
|
attr.description = description;
|
||||||
|
set_modes(&mut attr, mode);
|
||||||
|
attr.sensitive = sensitive;
|
||||||
|
}
|
||||||
|
Attribute::Object {
|
||||||
|
description,
|
||||||
|
mode,
|
||||||
|
sensitive,
|
||||||
|
attrs: _,
|
||||||
|
} => {
|
||||||
attr.description = description;
|
attr.description = description;
|
||||||
set_modes(&mut attr, mode);
|
set_modes(&mut attr, mode);
|
||||||
attr.sensitive = sensitive;
|
attr.sensitive = sensitive;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue