Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to define nested variables for evaluation? #150

Closed
vlad-ivanov-name opened this issue Jan 3, 2023 · 3 comments
Closed

Is it possible to define nested variables for evaluation? #150

vlad-ivanov-name opened this issue Jan 3, 2023 · 3 comments

Comments

@vlad-ivanov-name
Copy link

Hello, thank you for the awesome library!

I tried to look around but couldn't find this: is it possible to define nested identifiers and objects when evaluating with hcl::eval::Context?

For example, I'd like to evaluate the value of the following property:

  stages = stage.project_test.id

So I would need to make stage object available to context, then I would need to add project_test property, etc. Pretty much the same way it's done in terraform

@martinohmann
Copy link
Owner

martinohmann commented Jan 4, 2023

Hi @vlad-ivanov-name,

your use case is already supported, just use a nested map and serialize it as a hcl::Value via hcl::to_value(map).

Here is a example (i'm using IndexMap here, but other maps like HashMap will also do):

use hcl::eval::Context;
use indexmap::indexmap;
use serde::Deserialize;

#[derive(Deserialize, Debug, PartialEq, Eq)]
struct Config {
    stages: u64,
}

let stages = indexmap! {
    "project_test" => indexmap! {
        "id" => 1,
    }
};

let mut ctx = Context::new();
ctx.declare_var("stage", hcl::to_value(stages).unwrap());

let input = "stages = stage.project_test.id";

let config: Config = hcl::eval::from_str(input, &ctx).unwrap();

assert_eq!(config, Config { stages: 1 });

It's also possible to do this with a map of structs or even just a struct as long as the struct implements Serialize:

use hcl::eval::Context;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Deserialize, Debug, PartialEq, Eq)]
struct Config {
    stages: u64,
}

#[derive(Serialize)]
struct Stage {
    id: u64,
}

let mut stages = HashMap::new();
stages.insert("project_test", Stage { id: 1 });

let mut ctx = Context::new();
ctx.declare_var("stage", hcl::to_value(stages).unwrap());

let input = "stages = stage.project_test.id";

let config: Config = hcl::eval::from_str(input, &ctx).unwrap();

assert_eq!(config, Config { stages: 1 });

@martinohmann
Copy link
Owner

I'm planning to add some testable examples for use cases like this, but I'm currently short on time, so not sure when I will get to this.

@vlad-ivanov-name
Copy link
Author

Thank you! I've also found that declaring variables as "body" also works:

        let mut ctx = hcl::eval::Context::new();

        let inner_body = hcl::Body::builder()
            .add_attribute(("id", 1))
            .build();

        let body = hcl::Body::builder()
            .add_attribute(("project_test", inner_body))
            .build();

        ctx.declare_var("stage", body);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants