Current section

Files

Jump to
caffeine_lang src caffeine_lang@common@validations.erl
Raw

src/caffeine_lang@common@validations.erl

-module(caffeine_lang@common@validations).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/common/validations.gleam").
-export([validate_value_type/3, inputs_validator/2, validate_relevant_uniqueness/3, validate_inputs_for_collection/3, check_collection_key_overshadowing/3]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/caffeine_lang/common/validations.gleam", 107).
-spec validate_value_type_helper(
gleam@dynamic:dynamic_(),
gleam@dynamic@decode:decoder(any()),
binary()
) -> {ok, gleam@dynamic:dynamic_()} |
{error, caffeine_lang@common@errors:compilation_error()}.
validate_value_type_helper(Value, Decoder, Type_key_identifier) ->
case gleam@dynamic@decode:run(Value, Decoder) of
{ok, _} ->
{ok, Value};
{error, Err} ->
{error,
{parser_json_parser_error,
caffeine_lang@common@errors:format_decode_error_message(
Err,
{some, Type_key_identifier}
)}}
end.
-file("src/caffeine_lang/common/validations.gleam", 20).
?DOC(
" Validates that a dynamic value matches the expected AcceptedType.\n"
" Returns the original value if valid, or a CompilationError describing the type mismatch.\n"
).
-spec validate_value_type(
gleam@dynamic:dynamic_(),
caffeine_lang@common@accepted_types:accepted_types(),
binary()
) -> {ok, gleam@dynamic:dynamic_()} |
{error, caffeine_lang@common@errors:compilation_error()}.
validate_value_type(Value, Expected_type, Type_key_identifier) ->
case Expected_type of
boolean ->
validate_value_type_helper(
Value,
{decoder, fun gleam@dynamic@decode:decode_bool/1},
Type_key_identifier
);
integer ->
validate_value_type_helper(
Value,
{decoder, fun gleam@dynamic@decode:decode_int/1},
Type_key_identifier
);
float ->
validate_value_type_helper(
Value,
{decoder, fun gleam@dynamic@decode:decode_float/1},
Type_key_identifier
);
string ->
validate_value_type_helper(
Value,
{decoder, fun gleam@dynamic@decode:decode_string/1},
Type_key_identifier
);
{dict, _, Value_type} ->
case gleam@dynamic@decode:run(
Value,
gleam@dynamic@decode:dict(
{decoder, fun gleam@dynamic@decode:decode_string/1},
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
) of
{ok, Dict_val} ->
_pipe = Dict_val,
_pipe@1 = maps:values(_pipe),
_pipe@2 = gleam@list:try_map(
_pipe@1,
fun(V) ->
validate_value_type(
V,
Value_type,
Type_key_identifier
)
end
),
gleam@result:map(_pipe@2, fun(_) -> Value end);
{error, Err} ->
{error,
{parser_json_parser_error,
caffeine_lang@common@errors:format_decode_error_message(
Err,
{some, Type_key_identifier}
)}}
end;
{list, Inner_type} ->
case gleam@dynamic@decode:run(
Value,
gleam@dynamic@decode:list(
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
) of
{ok, List_val} ->
_pipe@3 = List_val,
_pipe@4 = gleam@list:try_map(
_pipe@3,
fun(V@1) ->
validate_value_type(
V@1,
Inner_type,
Type_key_identifier
)
end
),
gleam@result:map(_pipe@4, fun(_) -> Value end);
{error, Err@1} ->
{error,
{parser_json_parser_error,
caffeine_lang@common@errors:format_decode_error_message(
Err@1,
{some, Type_key_identifier}
)}}
end;
{modifier, Modifier_type} ->
case Modifier_type of
{optional, Inner_type@1} ->
case gleam@dynamic@decode:run(
Value,
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
) of
{ok, {some, Inner_val}} ->
validate_value_type(
Inner_val,
Inner_type@1,
Type_key_identifier
);
{ok, none} ->
{ok, Value};
{error, Err@2} ->
{error,
{parser_json_parser_error,
caffeine_lang@common@errors:format_decode_error_message(
Err@2,
{some, Type_key_identifier}
)}}
end;
{defaulted, Inner_type@2, _} ->
case gleam@dynamic@decode:run(
Value,
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
) of
{ok, {some, Inner_val@1}} ->
validate_value_type(
Inner_val@1,
Inner_type@2,
Type_key_identifier
);
{ok, none} ->
{ok, Value};
{error, Err@3} ->
{error,
{parser_json_parser_error,
caffeine_lang@common@errors:format_decode_error_message(
Err@3,
{some, Type_key_identifier}
)}}
end
end
end.
-file("src/caffeine_lang/common/validations.gleam", 127).
?DOC(
" Validates that inputs match the expected params in both keys and types.\n"
" Returns an error if there are missing keys, extra keys, or type mismatches.\n"
" Note: Optional and Defaulted params are allowed to be omitted from inputs.\n"
).
-spec inputs_validator(
gleam@dict:dict(binary(), caffeine_lang@common@accepted_types:accepted_types()),
gleam@dict:dict(binary(), gleam@dynamic:dynamic_())
) -> {ok, boolean()} | {error, binary()}.
inputs_validator(Params, Inputs) ->
Required_params = begin
_pipe = Params,
gleam@dict:filter(_pipe, fun(_, Typ) -> case Typ of
{modifier, {optional, _}} ->
false;
{modifier, {defaulted, _, _}} ->
false;
_ ->
true
end end)
end,
Required_param_keys = begin
_pipe@1 = Required_params,
_pipe@2 = maps:keys(_pipe@1),
gleam@set:from_list(_pipe@2)
end,
Param_keys = begin
_pipe@3 = Params,
_pipe@4 = maps:keys(_pipe@3),
gleam@set:from_list(_pipe@4)
end,
Input_keys = begin
_pipe@5 = Inputs,
_pipe@6 = maps:keys(_pipe@5),
gleam@set:from_list(_pipe@6)
end,
Missing_required_keys = begin
_pipe@7 = gleam@set:difference(Required_param_keys, Input_keys),
gleam@set:to_list(_pipe@7)
end,
Keys_only_in_inputs = begin
_pipe@8 = gleam@set:difference(Input_keys, Param_keys),
gleam@set:to_list(_pipe@8)
end,
gleam@result:'try'(case {Missing_required_keys, Keys_only_in_inputs} of
{[], []} ->
{ok, true};
{_, []} ->
{error,
<<"Missing keys in input: "/utf8,
(begin
_pipe@9 = Missing_required_keys,
gleam@string:join(_pipe@9, <<", "/utf8>>)
end)/binary>>};
{[], _} ->
{error,
<<"Extra keys in input: "/utf8,
(begin
_pipe@10 = Keys_only_in_inputs,
gleam@string:join(_pipe@10, <<", "/utf8>>)
end)/binary>>};
{_, _} ->
{error,
<<<<<<"Extra keys in input: "/utf8,
(begin
_pipe@11 = Keys_only_in_inputs,
gleam@string:join(_pipe@11, <<", "/utf8>>)
end)/binary>>/binary,
" and missing keys in input: "/utf8>>/binary,
(begin
_pipe@12 = Missing_required_keys,
gleam@string:join(_pipe@12, <<", "/utf8>>)
end)/binary>>}
end, fun(_) ->
Type_validation_errors = begin
_pipe@13 = Inputs,
_pipe@14 = maps:to_list(_pipe@13),
_pipe@16 = gleam@list:filter_map(
_pipe@14,
fun(Pair) ->
{Key, Value} = Pair,
Expected_type@1 = case begin
_pipe@15 = Params,
gleam_stdlib:map_get(_pipe@15, Key)
end of
{ok, Expected_type} -> Expected_type;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"caffeine_lang/common/validations"/utf8>>,
function => <<"inputs_validator"/utf8>>,
line => 179,
value => _assert_fail,
start => 5739,
'end' => 5793,
pattern_start => 5750,
pattern_end => 5767})
end,
case validate_value_type(Value, Expected_type@1, Key) of
{ok, _} ->
{error, nil};
{error, Errs} ->
{ok, Errs}
end
end
),
_pipe@17 = gleam@list:map(
_pipe@16,
fun(Err) -> erlang:element(2, Err) end
),
gleam@string:join(_pipe@17, <<", "/utf8>>)
end,
case Type_validation_errors of
<<""/utf8>> ->
{ok, true};
_ ->
{error, Type_validation_errors}
end
end).
-file("src/caffeine_lang/common/validations.gleam", 197).
?DOC(
" Validates that all items in a list have unique values for a given property.\n"
" Returns a ParserDuplicateError listing any duplicate values found.\n"
).
-spec validate_relevant_uniqueness(list(HHH), fun((HHH) -> binary()), binary()) -> {ok,
boolean()} |
{error, caffeine_lang@common@errors:compilation_error()}.
validate_relevant_uniqueness(
Things_to_validate_uniqueness_for,
Fetch_property,
Thing_label
) ->
Dupe_names = begin
_pipe = Things_to_validate_uniqueness_for,
_pipe@1 = gleam@list:group(
_pipe,
fun(Thing) -> Fetch_property(Thing) end
),
_pipe@2 = gleam@dict:filter(
_pipe@1,
fun(_, Occurrences) -> erlang:length(Occurrences) > 1 end
),
maps:keys(_pipe@2)
end,
case Dupe_names of
[] ->
{ok, true};
_ ->
{error,
{parser_duplicate_error,
<<<<<<"Duplicate "/utf8, Thing_label/binary>>/binary,
": "/utf8>>/binary,
(begin
_pipe@3 = Dupe_names,
gleam@string:join(_pipe@3, <<", "/utf8>>)
end)/binary>>}}
end.
-file("src/caffeine_lang/common/validations.gleam", 222).
?DOC(
" Validates inputs against params for a collection of paired items.\n"
" Aggregates all validation errors across the collection into a single result.\n"
).
-spec validate_inputs_for_collection(
list({HHL, HHM}),
fun((HHL) -> gleam@dict:dict(binary(), gleam@dynamic:dynamic_())),
fun((HHM) -> gleam@dict:dict(binary(), caffeine_lang@common@accepted_types:accepted_types()))
) -> {ok, boolean()} | {error, caffeine_lang@common@errors:compilation_error()}.
validate_inputs_for_collection(Input_param_collections, Get_inputs, Get_params) ->
Errors = begin
_pipe = Input_param_collections,
_pipe@1 = gleam@list:filter_map(
_pipe,
fun(Collection) ->
{Input_collection, Param_collection} = Collection,
case inputs_validator(
Get_params(Param_collection),
Get_inputs(Input_collection)
) of
{ok, _} ->
{error, nil};
{error, Msg} ->
{ok, Msg}
end
end
),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
case Errors of
<<""/utf8>> ->
{ok, true};
_ ->
{error,
{parser_json_parser_error,
<<"Input validation errors: "/utf8, Errors/binary>>}}
end.
-file("src/caffeine_lang/common/validations.gleam", 251).
?DOC(
" Checks if any keys in the referrer collection overlap with the reference collection.\n"
" Returns an error with the overlapping keys if overshadowing is detected.\n"
).
-spec check_collection_key_overshadowing(
gleam@dict:dict(binary(), any()),
gleam@dict:dict(binary(), any()),
binary()
) -> {ok, boolean()} | {error, binary()}.
check_collection_key_overshadowing(
Reference_collection,
Referrer_collection,
Error_msg
) ->
Reference_names = begin
_pipe = Reference_collection,
_pipe@1 = maps:keys(_pipe),
gleam@set:from_list(_pipe@1)
end,
Referrer_names = begin
_pipe@2 = Referrer_collection,
_pipe@3 = maps:keys(_pipe@2),
gleam@set:from_list(_pipe@3)
end,
Overshadowing_params = begin
_pipe@4 = gleam@set:intersection(Reference_names, Referrer_names),
gleam@set:to_list(_pipe@4)
end,
case Overshadowing_params of
[] ->
{ok, true};
_ ->
{error,
<<Error_msg/binary,
(begin
_pipe@5 = Overshadowing_params,
gleam@string:join(_pipe@5, <<", "/utf8>>)
end)/binary>>}
end.