Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/commands/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,17 @@ impl CommandRunner {
templating::render_inline_template(&self.engine, resource_name, sql, full_context)
}

/// Render a single query template JIT with the current context.
pub fn render_query(
&self,
resource_name: &str,
anchor: &str,
template: &str,
full_context: &HashMap<String, String>,
) -> String {
templating::render_query(&self.engine, resource_name, anchor, template, full_context)
}

/// Check if a resource exists using the exists query.
#[allow(clippy::too_many_arguments)]
pub fn check_if_resource_exists(
Expand Down
122 changes: 71 additions & 51 deletions src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ fn run_build(
continue;
}

// Get resource queries
// Get resource queries (templates only, not yet rendered)
let (resource_queries, inline_query) = if let Some(sql_val) = resource
.sql
.as_ref()
Expand All @@ -164,20 +164,36 @@ fn run_build(
if res_type == "resource" || res_type == "multi" {
if let Some(cou) = resource_queries.get("createorupdate") {
has_createorupdate = true;
create_query = Some(cou.rendered.clone());
let rendered = runner.render_query(
&resource.name,
"createorupdate",
&cou.template,
&full_context,
);
create_query = Some(rendered.clone());
create_retries = cou.options.retries;
create_retry_delay = cou.options.retry_delay;
update_query = Some(cou.rendered.clone());
update_query = Some(rendered);
update_retries = cou.options.retries;
update_retry_delay = cou.options.retry_delay;
} else {
if let Some(cq) = resource_queries.get("create") {
create_query = Some(cq.rendered.clone());
create_query = Some(runner.render_query(
&resource.name,
"create",
&cq.template,
&full_context,
));
create_retries = cq.options.retries;
create_retry_delay = cq.options.retry_delay;
}
if let Some(uq) = resource_queries.get("update") {
update_query = Some(uq.rendered.clone());
update_query = Some(runner.render_query(
&resource.name,
"update",
&uq.template,
&full_context,
));
update_retries = uq.options.retries;
update_retry_delay = uq.options.retry_delay;
}
Expand All @@ -190,11 +206,20 @@ fn run_build(
}
}

// Test queries
let exists_query = resource_queries.get("exists");
let statecheck_query = resource_queries.get("statecheck");
let mut exports_query_str: Option<String> =
resource_queries.get("exports").map(|q| q.rendered.clone());
// Test queries - render only the ones we need
let exists_query = resource_queries.get("exists").map(|q| {
let rendered =
runner.render_query(&resource.name, "exists", &q.template, &full_context);
(rendered, q.options.clone())
});
let statecheck_query = resource_queries.get("statecheck").map(|q| {
let rendered =
runner.render_query(&resource.name, "statecheck", &q.template, &full_context);
(rendered, q.options.clone())
});
let mut exports_query_str: Option<String> = resource_queries
.get("exports")
.map(|q| runner.render_query(&resource.name, "exports", &q.template, &full_context));
let exports_opts = resource_queries.get("exports");
let exports_retries = exports_opts.map_or(1, |q| q.options.retries);
let exports_retry_delay = exports_opts.map_or(0, |q| q.options.retry_delay);
Expand Down Expand Up @@ -222,24 +247,26 @@ fn run_build(
// Skip all existence and state checks for createorupdate
} else if statecheck_query.is_some() {
// Flow 1: Traditional flow when statecheck exists
if let Some(eq) = exists_query {
if let Some(ref eq) = exists_query {
let eq_opts = resource_queries.get("exists").unwrap();
resource_exists = runner.check_if_resource_exists(
resource,
&eq.rendered,
eq.options.retries,
eq.options.retry_delay,
&eq.0,
eq_opts.options.retries,
eq_opts.options.retry_delay,
dry_run,
show_queries,
false,
);
} else {
// Use statecheck as exists check
let sq = statecheck_query.unwrap();
let sq = statecheck_query.as_ref().unwrap();
let sq_opts = resource_queries.get("statecheck").unwrap();
is_correct_state = runner.check_if_resource_is_correct_state(
resource,
&sq.rendered,
sq.options.retries,
sq.options.retry_delay,
&sq.0,
sq_opts.options.retries,
sq_opts.options.retry_delay,
dry_run,
show_queries,
);
Expand All @@ -255,18 +282,19 @@ fn run_build(
);
is_correct_state = true;
} else {
let sq = statecheck_query.unwrap();
let sq = statecheck_query.as_ref().unwrap();
let sq_opts = resource_queries.get("statecheck").unwrap();
is_correct_state = runner.check_if_resource_is_correct_state(
resource,
&sq.rendered,
sq.options.retries,
sq.options.retry_delay,
&sq.0,
sq_opts.options.retries,
sq_opts.options.retry_delay,
dry_run,
show_queries,
);
}
}
} else if let Some(eq_str) = exports_query_str.as_ref() {
} else if let Some(ref eq_str) = exports_query_str {
// Flow 2: Optimized flow using exports as proxy
info!(
"trying exports query first (fast-fail) for optimal validation for [{}]",
Expand Down Expand Up @@ -296,12 +324,13 @@ fn run_build(
);
exports_result_from_proxy = None;

if let Some(eq) = exists_query {
if let Some(ref eq) = exists_query {
let eq_opts = resource_queries.get("exists").unwrap();
resource_exists = runner.check_if_resource_exists(
resource,
&eq.rendered,
eq.options.retries,
eq.options.retry_delay,
&eq.0,
eq_opts.options.retries,
eq_opts.options.retry_delay,
dry_run,
show_queries,
false,
Expand All @@ -310,13 +339,14 @@ fn run_build(
resource_exists = false;
}
}
} else if let Some(eq) = exists_query {
} else if let Some(ref eq) = exists_query {
// Flow 3: Basic flow with only exists query
let eq_opts = resource_queries.get("exists").unwrap();
resource_exists = runner.check_if_resource_exists(
resource,
&eq.rendered,
eq.options.retries,
eq.options.retry_delay,
&eq.0,
eq_opts.options.retries,
eq_opts.options.retry_delay,
dry_run,
show_queries,
false,
Expand Down Expand Up @@ -356,12 +386,13 @@ fn run_build(

// Post-deploy state check
if is_created_or_updated {
if let Some(sq) = statecheck_query {
if let Some(ref sq) = statecheck_query {
let sq_opts = resource_queries.get("statecheck").unwrap();
is_correct_state = runner.check_if_resource_is_correct_state(
resource,
&sq.rendered,
sq.options.retries,
sq.options.retry_delay,
&sq.0,
sq_opts.options.retries,
sq_opts.options.retry_delay,
dry_run,
show_queries,
);
Expand All @@ -370,17 +401,8 @@ fn run_build(
"using exports query as post-deploy statecheck for [{}]",
resource.name
);
let post_retries = if statecheck_query.is_some_and(|sq| sq.options.retries > 1)
{
statecheck_query.unwrap().options.retries
} else {
exports_retries
};
let post_delay = if statecheck_query.is_some_and(|sq| sq.options.retries > 1) {
statecheck_query.unwrap().options.retry_delay
} else {
exports_retry_delay
};
let post_retries = exports_retries;
let post_delay = exports_retry_delay;

let (state, proxy) = runner.check_state_using_exports_proxy(
resource,
Expand Down Expand Up @@ -412,11 +434,9 @@ fn run_build(
{
(iq.clone(), 1u32, 0u32)
} else if let Some(cq) = resource_queries.get("command") {
(
cq.rendered.clone(),
cq.options.retries,
cq.options.retry_delay,
)
let rendered =
runner.render_query(&resource.name, "command", &cq.template, &full_context);
(rendered, cq.options.retries, cq.options.retry_delay)
} else {
catch_error_and_exit(
"'sql' should be defined in the resource or the 'command' anchor needs to be supplied in the corresponding iql file for command type resources.",
Expand Down
30 changes: 15 additions & 15 deletions src/commands/teardown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,9 @@ fn collect_exports(runner: &mut CommandRunner, show_queries: bool, dry_run: bool
} else {
let queries = runner.get_queries(resource, &full_context);
if let Some(eq) = queries.get("exports") {
(
Some(eq.rendered.clone()),
eq.options.retries,
eq.options.retry_delay,
)
let rendered =
runner.render_query(&resource.name, "exports", &eq.template, &full_context);
(Some(rendered), eq.options.retries, eq.options.retry_delay)
} else {
(None, 1u32, 0u32)
}
Expand Down Expand Up @@ -195,19 +193,21 @@ fn run_teardown(runner: &mut CommandRunner, dry_run: bool, show_queries: bool, _
}
}

// Get resource queries
// Get resource queries (templates only)
let resource_queries = runner.get_queries(resource, &full_context);

// Get exists query (fallback to statecheck)
// Get exists query (fallback to statecheck) - render JIT
let (
exists_query_str,
exists_retries,
exists_retry_delay,
postdelete_retries,
postdelete_retry_delay,
) = if let Some(eq) = resource_queries.get("exists") {
let rendered =
runner.render_query(&resource.name, "exists", &eq.template, &full_context);
(
eq.rendered.clone(),
rendered,
eq.options.retries,
eq.options.retry_delay,
eq.options.postdelete_retries,
Expand All @@ -218,8 +218,10 @@ fn run_teardown(runner: &mut CommandRunner, dry_run: bool, show_queries: bool, _
"exists query not defined for [{}], trying statecheck query as exists query.",
resource.name
);
let rendered =
runner.render_query(&resource.name, "statecheck", &sq.template, &full_context);
(
sq.rendered.clone(),
rendered,
sq.options.retries,
sq.options.retry_delay,
sq.options.postdelete_retries,
Expand All @@ -233,14 +235,12 @@ fn run_teardown(runner: &mut CommandRunner, dry_run: bool, show_queries: bool, _
continue;
};

// Get delete query
// Get delete query - render JIT
let (delete_query, delete_retries, delete_retry_delay) =
if let Some(dq) = resource_queries.get("delete") {
(
dq.rendered.clone(),
dq.options.retries,
dq.options.retry_delay,
)
let rendered =
runner.render_query(&resource.name, "delete", &dq.template, &full_context);
(rendered, dq.options.retries, dq.options.retry_delay)
} else {
info!(
"delete query not defined for [{}], skipping...",
Expand Down
30 changes: 21 additions & 9 deletions src/commands/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ fn run_test(

let full_context = runner.get_full_context(resource);

// Get test queries
// Get test queries (templates only, not yet rendered)
let (test_queries, inline_query) =
if let Some(sql_val) = resource.sql.as_ref().filter(|_| res_type == "query") {
let iq = runner.render_inline_template(&resource.name, sql_val, &full_context);
Expand All @@ -140,11 +140,23 @@ fn run_test(
(runner.get_queries(resource, &full_context), None)
};

let statecheck_query = test_queries.get("statecheck");
let statecheck_retries = statecheck_query.map_or(1, |q| q.options.retries);
let statecheck_retry_delay = statecheck_query.map_or(0, |q| q.options.retry_delay);
// Render statecheck JIT if present
let statecheck_rendered = test_queries.get("statecheck").map(|q| {
let rendered =
runner.render_query(&resource.name, "statecheck", &q.template, &full_context);
(rendered, q.options.clone())
});
let statecheck_retries = test_queries
.get("statecheck")
.map_or(1, |q| q.options.retries);
let statecheck_retry_delay = test_queries
.get("statecheck")
.map_or(0, |q| q.options.retry_delay);

let mut exports_query_str = test_queries.get("exports").map(|q| q.rendered.clone());
// Render exports JIT if present
let mut exports_query_str = test_queries
.get("exports")
.map(|q| runner.render_query(&resource.name, "exports", &q.template, &full_context));
let exports_opts = test_queries.get("exports");
let exports_retries = exports_opts.map_or(1, |q| q.options.retries);
let exports_retry_delay = exports_opts.map_or(0, |q| q.options.retry_delay);
Expand All @@ -168,12 +180,12 @@ fn run_test(
if resource.skip_validation.unwrap_or(false) {
info!("Skipping statecheck for {}", resource.name);
is_correct_state = true;
} else if let Some(sq) = statecheck_query {
} else if let Some(ref sq) = statecheck_rendered {
is_correct_state = runner.check_if_resource_is_correct_state(
resource,
&sq.rendered,
sq.options.retries,
sq.options.retry_delay,
&sq.0,
sq.1.retries,
sq.1.retry_delay,
dry_run,
show_queries,
);
Expand Down
Loading
Loading