Packages
caffeine_lang
4.4.4
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_query_language@generator.erl
-module(caffeine_query_language@generator).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_query_language/generator.gleam").
-export([substitute_words/2, extract_words/1, resolve_slo_query_typed/2, resolve_slo_to_expression/2, resolve_slo_to_hcl/2]).
-export_type([named_query/0, resolved_slo_query/0, slo_type/0, resolved_slo_hcl/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type named_query() :: {named_query, binary(), binary()}.
-type resolved_slo_query() :: {resolved_good_over_total, binary(), binary()} |
{resolved_time_slice,
binary(),
integer(),
float(),
binary(),
list(named_query())}.
-type slo_type() :: metric_slo | time_slice_slo.
-type resolved_slo_hcl() :: {resolved_slo_hcl,
slo_type(),
list(terra_madre@hcl:block())}.
-file("src/caffeine_query_language/generator.gleam", 48).
?DOC(false).
-spec substitute_words(
caffeine_query_language@ast:exp(),
gleam@dict:dict(binary(), binary())
) -> caffeine_query_language@ast:exp().
substitute_words(Exp, Substitutions) ->
case Exp of
{primary, {primary_word, {word, Name}}} ->
Value = begin
_pipe = gleam_stdlib:map_get(Substitutions, Name),
gleam@result:unwrap(_pipe, Name)
end,
{primary, {primary_word, {word, Value}}};
{primary, {primary_exp, Inner}} ->
{primary, {primary_exp, substitute_words(Inner, Substitutions)}};
{time_slice_expr, Spec} ->
Query = begin
_pipe@1 = gleam_stdlib:map_get(
Substitutions,
erlang:element(2, Spec)
),
gleam@result:unwrap(_pipe@1, erlang:element(2, Spec))
end,
{time_slice_expr,
{time_slice_exp,
Query,
erlang:element(3, Spec),
erlang:element(4, Spec),
erlang:element(5, Spec)}};
{operator_expr, Left, Right, Op} ->
{operator_expr,
substitute_words(Left, Substitutions),
substitute_words(Right, Substitutions),
Op}
end.
-file("src/caffeine_query_language/generator.gleam", 76).
?DOC(false).
-spec extract_words(caffeine_query_language@ast:exp()) -> list(binary()).
extract_words(Exp) ->
case Exp of
{primary, {primary_word, {word, Name}}} ->
[Name];
{primary, {primary_exp, Inner}} ->
extract_words(Inner);
{time_slice_expr, _} ->
[];
{operator_expr, Left, Right, _} ->
_pipe = lists:append(extract_words(Left), extract_words(Right)),
gleam@list:unique(_pipe)
end.
-file("src/caffeine_query_language/generator.gleam", 90).
?DOC(false).
-spec resolve_slo_query_typed(binary(), gleam@dict:dict(binary(), binary())) -> {ok,
resolved_slo_query()} |
{error, binary()}.
resolve_slo_query_typed(Value_expr, Substitutions) ->
case caffeine_query_language@parser:parse_expr(Value_expr) of
{error, Err} ->
{error, <<"Parse error: "/utf8, Err/binary>>};
{ok, Exp} ->
case caffeine_query_language@resolver:resolve_primitives(Exp) of
{ok, {good_over_total, Numerator_exp, Denominator_exp}} ->
Numerator_str = begin
_pipe = substitute_words(Numerator_exp, Substitutions),
caffeine_query_language@printer:exp_to_string(_pipe)
end,
Denominator_str = begin
_pipe@1 = substitute_words(
Denominator_exp,
Substitutions
),
caffeine_query_language@printer:exp_to_string(_pipe@1)
end,
{ok,
{resolved_good_over_total,
Numerator_str,
Denominator_str}};
{ok,
{time_slice, Comparator, Interval_seconds, Threshold, Query}} ->
Comparator_str = case Comparator of
less_than ->
<<"<"/utf8>>;
less_than_or_equal_to ->
<<"<="/utf8>>;
greater_than ->
<<">"/utf8>>;
greater_than_or_equal_to ->
<<">="/utf8>>
end,
case caffeine_query_language@parser:parse_expr(Query) of
{ok, Query_exp} ->
Words = extract_words(Query_exp),
Named_queries = begin
_pipe@2 = Words,
gleam@list:filter_map(
_pipe@2,
fun(Word) ->
case gleam_stdlib:map_get(
Substitutions,
Word
) of
{ok, Resolved} ->
{ok,
{named_query,
Word,
Resolved}};
{error, _} ->
{error, nil}
end
end
)
end,
case Named_queries of
[] ->
{ok,
{resolved_time_slice,
Comparator_str,
Interval_seconds,
Threshold,
<<"query1"/utf8>>,
[{named_query,
<<"query1"/utf8>>,
Query}]}};
_ ->
Formula_expr = caffeine_query_language@printer:strip_outer_parens(
Query
),
{ok,
{resolved_time_slice,
Comparator_str,
Interval_seconds,
Threshold,
Formula_expr,
Named_queries}}
end;
{error, _} ->
Resolved_query = begin
_pipe@3 = gleam_stdlib:map_get(
Substitutions,
Query
),
gleam@result:unwrap(_pipe@3, Query)
end,
{ok,
{resolved_time_slice,
Comparator_str,
Interval_seconds,
Threshold,
<<"query1"/utf8>>,
[{named_query,
<<"query1"/utf8>>,
Resolved_query}]}}
end;
{error, Err@1} ->
{error,
<<"Resolution error: "/utf8,
(caffeine_lang@errors:to_message(Err@1))/binary>>}
end
end.
-file("src/caffeine_query_language/generator.gleam", 197).
?DOC(
" Validate that all words in an expression exist in the substitutions dict.\n"
" Returns an error listing any missing indicator names.\n"
).
-spec validate_words_exist(
caffeine_query_language@ast:exp(),
gleam@dict:dict(binary(), binary()),
fun(() -> {ok, binary()} | {error, binary()})
) -> {ok, binary()} | {error, binary()}.
validate_words_exist(Exp, Substitutions, Next) ->
Missing = begin
_pipe = extract_words(Exp),
gleam@list:filter(
_pipe,
fun(Word) -> case gleam_stdlib:map_get(Substitutions, Word) of
{ok, _} ->
false;
{error, _} ->
true
end end
)
end,
case Missing of
[] ->
Next();
_ ->
{error,
<<"evaluation references undefined indicators: "/utf8,
(gleam@string:join(Missing, <<", "/utf8>>))/binary>>}
end.
-file("src/caffeine_query_language/generator.gleam", 173).
?DOC(false).
-spec resolve_slo_to_expression(binary(), gleam@dict:dict(binary(), binary())) -> {ok,
binary()} |
{error, binary()}.
resolve_slo_to_expression(Value_expr, Substitutions) ->
gleam@result:'try'(
begin
_pipe = caffeine_query_language@parser:parse_expr(Value_expr),
gleam@result:map_error(
_pipe,
fun(Err) -> <<"Parse error: "/utf8, Err/binary>> end
)
end,
fun(Parsed) ->
Exp = case caffeine_query_language@resolver:resolve_primitives(
Parsed
) of
{ok, {good_over_total, Num, Den}} ->
{ok, {operator_expr, Num, Den, 'div'}};
{ok, {time_slice, _, _, _, _}} ->
{error,
<<"time_slice expressions are not supported for expression resolution"/utf8>>};
{error, _} ->
{ok, Parsed}
end,
gleam@result:'try'(
Exp,
fun(Exp@1) ->
validate_words_exist(
Exp@1,
Substitutions,
fun() ->
{ok,
begin
_pipe@1 = substitute_words(
Exp@1,
Substitutions
),
caffeine_query_language@printer:exp_to_string(
_pipe@1
)
end}
end
)
end
)
end
).
-file("src/caffeine_query_language/generator.gleam", 223).
?DOC(false).
-spec resolve_slo_to_hcl(binary(), gleam@dict:dict(binary(), binary())) -> {ok,
resolved_slo_hcl()} |
{error, binary()}.
resolve_slo_to_hcl(Value_expr, Substitutions) ->
case resolve_slo_query_typed(Value_expr, Substitutions) of
{ok, {resolved_good_over_total, Numerator, Denominator}} ->
Query_block = terra_madre@hcl:simple_block(
<<"query"/utf8>>,
[{<<"numerator"/utf8>>, {string_literal, Numerator}},
{<<"denominator"/utf8>>, {string_literal, Denominator}}]
),
{ok, {resolved_slo_hcl, metric_slo, [Query_block]}};
{ok,
{resolved_time_slice,
Comparator,
Interval_seconds,
Threshold,
Formula_expression,
Named_queries}} ->
Inner_query_blocks = begin
_pipe = Named_queries,
gleam@list:map(
_pipe,
fun(Nq) ->
Metric_query_block = {block,
<<"metric_query"/utf8>>,
[],
maps:from_list(
[{<<"data_source"/utf8>>,
{string_literal, <<"metrics"/utf8>>}},
{<<"name"/utf8>>,
{string_literal, erlang:element(2, Nq)}},
{<<"query"/utf8>>,
{string_literal, erlang:element(3, Nq)}}]
),
[]},
{block,
<<"query"/utf8>>,
[],
maps:new(),
[Metric_query_block]}
end
)
end,
Formula_block = {block,
<<"formula"/utf8>>,
[],
maps:from_list(
[{<<"formula_expression"/utf8>>,
{string_literal, Formula_expression}}]
),
[]},
Outer_query_block = {block,
<<"query"/utf8>>,
[],
maps:new(),
[Formula_block | Inner_query_blocks]},
Time_slice_block = {block,
<<"time_slice"/utf8>>,
[],
maps:from_list(
[{<<"comparator"/utf8>>, {string_literal, Comparator}},
{<<"query_interval_seconds"/utf8>>,
{int_literal, Interval_seconds}},
{<<"threshold"/utf8>>, {float_literal, Threshold}}]
),
[Outer_query_block]},
Sli_specification_block = {block,
<<"sli_specification"/utf8>>,
[],
maps:new(),
[Time_slice_block]},
{ok, {resolved_slo_hcl, time_slice_slo, [Sli_specification_block]}};
{error, Err} ->
{error, Err}
end.