-module(themis@internal@store). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/themis/internal/store.gleam"). -export([new_metric/4, find_metric/2, match_metrics/1, init/0, clear/0, increment_record_by/3, increment_record/2, insert_record/3, match_records/1, find_record/2]). -export_type([store_error/0, store/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. ?MODULEDOC(false). -type store_error() :: metric_name_already_exists | insert_error | {decode_errors, list(gleam@dynamic@decode:decode_error())} | table_error | invalid_increment | single_result_expected | invalid_type | metric_not_found. -type store() :: {store, themis@internal@erlang@ets:table(), themis@internal@erlang@ets:table()}. -file("src/themis/internal/store.gleam", 215). ?DOC(false). -spec decode_metric(gleam@dynamic:dynamic_()) -> {ok, {binary(), binary(), binary(), list(float())}} | {error, list(gleam@dynamic@decode:decode_error())}. decode_metric(Metric) -> gleam@result:'try'( gleam@dynamic@decode:run( Metric, gleam@dynamic@decode:at( [0], {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), fun(Field_1) -> gleam@result:'try'( gleam@dynamic@decode:run( Metric, gleam@dynamic@decode:at( [1], {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), fun(Field_2) -> gleam@result:'try'( gleam@dynamic@decode:run( Metric, gleam@dynamic@decode:at( [2], {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), fun(Field_3) -> gleam@result:'try'( gleam@dynamic@decode:run( Metric, gleam@dynamic@decode:at( [3], gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_float/1} ) ) ), fun(Field_4) -> {ok, {Field_1, Field_2, Field_3, Field_4}} end ) end ) end ) end ). -file("src/themis/internal/store.gleam", 228). ?DOC(false). -spec decode_record(gleam@dynamic:dynamic_()) -> {ok, {{binary(), list(binary())}, integer(), float(), binary()}} | {error, list(gleam@dynamic@decode:decode_error())}. decode_record(Record) -> gleam@result:'try'( gleam@dynamic@decode:run( Record, gleam@dynamic@decode:at( [0, 0], {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), fun(Field_1_1) -> gleam@result:'try'( gleam@dynamic@decode:run( Record, gleam@dynamic@decode:at( [0, 1], gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_string/1} ) ) ), fun(Field_1_2) -> gleam@result:'try'( gleam@dynamic@decode:run( Record, gleam@dynamic@decode:at( [1], {decoder, fun gleam@dynamic@decode:decode_int/1} ) ), fun(Field_2) -> gleam@result:'try'( gleam@dynamic@decode:run( Record, gleam@dynamic@decode:at( [2], {decoder, fun gleam@dynamic@decode:decode_float/1} ) ), fun(Field_3) -> gleam@result:'try'( gleam@dynamic@decode:run( Record, gleam@dynamic@decode:at( [3], {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), fun(Field_4) -> {ok, {{Field_1_1, Field_1_2}, Field_2, Field_3, Field_4}} end ) end ) end ) end ) end ). -file("src/themis/internal/store.gleam", 248). ?DOC(false). -spec parse_record(gleam@dynamic:dynamic_()) -> {ok, {themis@internal@label:label_set(), themis@number:number_()}} | {error, store_error()}. parse_record(Record) -> Record_result = begin _pipe = decode_record(Record), gleam@result:try_recover( _pipe, fun(E) -> {error, {decode_errors, E}} end ) end, gleam@result:'try'( Record_result, fun(Record@1) -> {{_, Labels}, Int_value, Float_value, Flag} = Record@1, Float_decimal@1 = case gleam@float:modulo(Float_value, 1.0) of {ok, Float_decimal} -> Float_decimal; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"parse_record"/utf8>>, line => 265, value => _assert_fail, start => 8008, 'end' => 8069, pattern_start => 8019, pattern_end => 8036}) end, Numeric_value = case Float_decimal@1 =:= +0.0 of false -> themis@number:decimal( begin _pipe@1 = Int_value, _pipe@2 = erlang:float(_pipe@1), gleam@float:add(_pipe@2, Float_value) end ); true -> themis@number:integer(Int_value) end, Value = case Flag of <<"-Inf"/utf8>> -> themis@number:negative_infinity(); <<"+Inf"/utf8>> -> themis@number:positive_infinity(); <<"NaN"/utf8>> -> themis@number:not_a_number(); _ -> Numeric_value end, Labels@1 = begin _pipe@3 = Labels, _pipe@4 = gleam@list:map( _pipe@3, fun(Label_string) -> {Key@1, Value@2} = case gleam@string:split_once( Label_string, <<":"/utf8>> ) of {ok, {Key, Value@1}} -> {Key, Value@1}; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"parse_record"/utf8>>, line => 279, value => _assert_fail@1, start => 8480, 'end' => 8547, pattern_start => 8491, pattern_end => 8508}) end, {Key@1, Value@2} end ), maps:from_list(_pipe@4) end, Labels@3 = case themis@internal@label:from_dict(Labels@1) of {ok, Labels@2} -> Labels@2; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"parse_record"/utf8>>, line => 283, value => _assert_fail@2, start => 8599, 'end' => 8646, pattern_start => 8610, pattern_end => 8620}) end, _pipe@5 = {Labels@3, Value}, {ok, _pipe@5} end ). -file("src/themis/internal/store.gleam", 52). ?DOC(false). -spec new_metric( themis@internal@metric:metric_name(), binary(), binary(), list(float()) ) -> {ok, nil} | {error, store_error()}. new_metric(Name, Description, Kind, Buckets) -> _pipe@1 = themis@internal@erlang@ets:insert_new_raw( <<"themis_metrics"/utf8>>, {begin _pipe = Name, themis@internal@metric:name_to_string(_pipe) end, Description, Kind, Buckets} ), gleam@result:replace_error(_pipe@1, metric_name_already_exists). -file("src/themis/internal/store.gleam", 69). ?DOC(false). -spec find_metric(themis@internal@metric:metric_name(), binary()) -> {ok, {binary(), binary(), list(float())}} | {error, store_error()}. find_metric(Name, Given_kind) -> Name_string = themis@internal@metric:name_to_string(Name), Metrics@1 = case themis@internal@erlang@ets:lookup( <<"themis_metrics"/utf8>>, Name_string ) of {ok, Metrics} -> Metrics; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => (<<<<"could not find metric \""/utf8, Name_string/binary>>/binary, "\". should only return an error if the given table name string is not found as an atom. Are you sure you initialized the Themis store ?"/utf8>>), file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"find_metric"/utf8>>, line => 76, value => _assert_fail, start => 1880, 'end' => 1948, pattern_start => 1891, pattern_end => 1902}) end, gleam@result:'try'( case begin _pipe = Metrics@1, gleam@list:map(_pipe, fun(Found) -> decode_metric(Found) end) end of [{ok, {_, Description, Kind, Buckets}}] -> {ok, {Description, Kind, Buckets}}; [] -> {error, metric_not_found}; _ -> {error, table_error} end, fun(_use0) -> {Description@1, Kind@1, Buckets@1} = _use0, case Kind@1 =:= Given_kind of false -> {error, invalid_type}; true -> {ok, {Description@1, Kind@1, Buckets@1}} end end ). -file("src/themis/internal/store.gleam", 99). ?DOC(false). -spec match_metrics(binary()) -> {ok, list({binary(), binary(), list(float())})} | {error, store_error()}. match_metrics(Kind) -> Metrics@1 = case themis@internal@erlang@ets:match_metric( <<"themis_metrics"/utf8>>, Kind ) of {ok, Metrics} -> Metrics; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"should only return an error if the given table name string is not found as an atom. Are you sure you initialized the Themis store ?"/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"match_metrics"/utf8>>, line => 104, value => _assert_fail, start => 2737, 'end' => 2804, pattern_start => 2748, pattern_end => 2759}) end, _pipe@2 = gleam@list:map( Metrics@1, fun(Found) -> R = begin _pipe = decode_metric(Found), gleam@result:try_recover( _pipe, fun(E) -> {error, {decode_errors, E}} end ) end, gleam@result:'try'( R, fun(_use0) -> {Name, Description, _, Buckets} = _use0, _pipe@1 = {Name, Description, Buckets}, {ok, _pipe@1} end ) end ), gleam@result:all(_pipe@2). -file("src/themis/internal/store.gleam", 39). ?DOC(false). -spec init() -> gleam@erlang@atom:atom_(). init() -> _ = themis@internal@erlang@ets:new( {table_builder, set, public}, <<"themis_metrics"/utf8>> ), _ = themis@internal@erlang@ets:new( {table_builder, set, public}, <<"themis_records"/utf8>> ). -file("src/themis/internal/store.gleam", 47). ?DOC(false). -spec clear() -> {ok, boolean()} | {error, themis@internal@erlang@ets:table_error()}. clear() -> _ = themis@internal@erlang@ets:delete_table(<<"themis_metrics"/utf8>>), _ = themis@internal@erlang@ets:delete_table(<<"themis_records"/utf8>>). -file("src/themis/internal/store.gleam", 119). ?DOC(false). -spec increment_record_by( themis@internal@metric:metric_name(), themis@internal@label:label_set(), themis@number:number_() ) -> {ok, nil} | {error, store_error()}. increment_record_by(Name, Labels, Value) -> case Value of {dec, _} -> _pipe = begin Labels@1 = themis@internal@label:to_strings(Labels), Name@1 = themis@internal@metric:name_to_string(Name), R@1 = case themis@internal@erlang@ets:counter_increment_by( <<"themis_records"/utf8>>, {Name@1, Labels@1}, Value ) of {ok, R} -> R; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"should only return an error if the given table name string is not found as an atom. Are you sure you initialized the Themis store ?"/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"increment_record_by"/utf8>>, line => 131, value => _assert_fail, start => 3659, 'end' => 3756, pattern_start => 3670, pattern_end => 3675}) end, R@1 end, {ok, _pipe}; {int, _} -> _pipe = begin Labels@1 = themis@internal@label:to_strings(Labels), Name@1 = themis@internal@metric:name_to_string(Name), R@1 = case themis@internal@erlang@ets:counter_increment_by( <<"themis_records"/utf8>>, {Name@1, Labels@1}, Value ) of {ok, R} -> R; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"should only return an error if the given table name string is not found as an atom. Are you sure you initialized the Themis store ?"/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"increment_record_by"/utf8>>, line => 131, value => _assert_fail, start => 3659, 'end' => 3756, pattern_start => 3670, pattern_end => 3675}) end, R@1 end, {ok, _pipe}; na_n -> {error, invalid_increment}; neg_inf -> {error, invalid_increment}; pos_inf -> {error, invalid_increment} end. -file("src/themis/internal/store.gleam", 141). ?DOC(false). -spec increment_record( themis@internal@metric:metric_name(), themis@internal@label:label_set() ) -> {ok, nil} | {error, store_error()}. increment_record(Name, Labels) -> increment_record_by(Name, Labels, themis@number:integer(1)). -file("src/themis/internal/store.gleam", 149). ?DOC(false). -spec insert_record( themis@internal@metric:metric_name(), themis@internal@label:label_set(), themis@number:number_() ) -> {ok, nil} | {error, store_error()}. insert_record(Name, Labels, Value) -> Labels@1 = themis@internal@label:to_strings(Labels), {Int_value, Float_value, Flag_value} = case Value of {dec, Val} -> {0, Val, <<""/utf8>>}; {int, Val@1} -> {Val@1, +0.0, <<""/utf8>>}; pos_inf -> {0, +0.0, <<"+Inf"/utf8>>}; neg_inf -> {0, +0.0, <<"-Inf"/utf8>>}; na_n -> {0, +0.0, <<"NaN"/utf8>>} end, R@1 = case themis@internal@erlang@ets:insert_raw( <<"themis_records"/utf8>>, {{begin _pipe = Name, themis@internal@metric:name_to_string(_pipe) end, Labels@1}, Int_value, Float_value, Flag_value} ) of {ok, R} -> R; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"should only return an error if the given table name string is not found as an atom. Are you sure you initialized the Themis store ?"/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"insert_record"/utf8>>, line => 164, value => _assert_fail, start => 4684, 'end' => 4853, pattern_start => 4695, pattern_end => 4700}) end, case R@1 of false -> {error, insert_error}; true -> {ok, nil} end. -file("src/themis/internal/store.gleam", 179). ?DOC(false). -spec match_records(themis@internal@metric:metric_name()) -> {ok, gleam@dict:dict(themis@internal@label:label_set(), themis@number:number_())} | {error, store_error()}. match_records(Name) -> Records@1 = case themis@internal@erlang@ets:match_record( <<"themis_records"/utf8>>, begin _pipe = Name, themis@internal@metric:name_to_string(_pipe) end ) of {ok, Records} -> Records; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"should only return an error if the given table name string is not found as an atom. Are you sure you initialized the Themis store ?"/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"match_records"/utf8>>, line => 184, value => _assert_fail, start => 5235, 'end' => 5331, pattern_start => 5246, pattern_end => 5257}) end, _pipe@1 = Records@1, _pipe@2 = gleam@list:map(_pipe@1, fun parse_record/1), _pipe@3 = gleam@result:all(_pipe@2), gleam@result:map(_pipe@3, fun maps:from_list/1). -file("src/themis/internal/store.gleam", 194). ?DOC(false). -spec find_record( themis@internal@metric:metric_name(), themis@internal@label:label_set() ) -> {ok, {themis@internal@label:label_set(), themis@number:number_()}} | {error, store_error()}. find_record(Name, Labels) -> Entries@1 = case themis@internal@erlang@ets:lookup( <<"themis_records"/utf8>>, {begin _pipe = Name, themis@internal@metric:name_to_string(_pipe) end, begin _pipe@1 = Labels, themis@internal@label:to_strings(_pipe@1) end} ) of {ok, Entries} -> Entries; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"should only return an error if the given table name string is not found as an atom. Are you sure you initialized the Themis store ?"/utf8>>, file => <>, module => <<"themis/internal/store"/utf8>>, function => <<"find_record"/utf8>>, line => 201, value => _assert_fail, start => 5762, 'end' => 5902, pattern_start => 5773, pattern_end => 5784}) end, _pipe@2 = case Entries@1 of [Entry] -> {ok, Entry}; _ -> {error, single_result_expected} end, gleam@result:'try'(_pipe@2, fun parse_record/1).