-module(themis@internal@store). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -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]). -type store_error() :: metric_name_already_exists | insert_error | {decode_errors, list(gleam@dynamic@decode:decode_error())} | {old_decode_errors, list(gleam@dynamic: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("/git/Themis/src/themis/internal/store.gleam", 213). -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("/git/Themis/src/themis/internal/store.gleam", 226). -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("/git/Themis/src/themis/internal/store.gleam", 246). -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, _assert_subject = gleam@float:modulo(Float_value, 1.0), {ok, Float_decimal} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"themis/internal/store"/utf8>>, function => <<"parse_record"/utf8>>, line => 263}) end, Numeric_value = case Float_decimal =:= +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) -> _assert_subject@1 = gleam@string:split_once( Label_string, <<":"/utf8>> ), {ok, {Key, Value@1}} = case _assert_subject@1 of {ok, {_, _}} -> _assert_subject@1; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail@1, module => <<"themis/internal/store"/utf8>>, function => <<"parse_record"/utf8>>, line => 277}) end, {Key, Value@1} end ), maps:from_list(_pipe@4) end, _assert_subject@2 = themis@internal@label:from_dict(Labels@1), {ok, Labels@2} = case _assert_subject@2 of {ok, _} -> _assert_subject@2; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail@2, module => <<"themis/internal/store"/utf8>>, function => <<"parse_record"/utf8>>, line => 281}) end, _pipe@5 = {Labels@2, Value}, {ok, _pipe@5} end ). -file("/git/Themis/src/themis/internal/store.gleam", 53). -spec new_metric( themis@internal@metric:metric_name(), binary(), binary(), list(float()) ) -> {ok, nil} | {error, store_error()}. new_metric(Name, Description, Kind, Buckets) -> _pipe@2 = themis@internal@erlang@ets:insert_new_raw( <<"themis_metrics"/utf8>>, begin _pipe@1 = {begin _pipe = Name, themis@internal@metric:name_to_string(_pipe) end, Description, Kind, Buckets}, gleam_stdlib:identity(_pipe@1) end ), gleam@result:replace_error(_pipe@2, metric_name_already_exists). -file("/git/Themis/src/themis/internal/store.gleam", 69). -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), _assert_subject = themis@internal@erlang@ets:lookup( <<"themis_metrics"/utf8>>, Name_string ), {ok, Metrics} = case _assert_subject of {ok, _} -> _assert_subject; _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>>), value => _assert_fail, module => <<"themis/internal/store"/utf8>>, function => <<"find_metric"/utf8>>, line => 76}) end, gleam@result:'try'( case begin _pipe = Metrics, 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("/git/Themis/src/themis/internal/store.gleam", 97). -spec match_metrics(binary()) -> {ok, list({binary(), binary(), list(float())})} | {error, store_error()}. match_metrics(Kind) -> _assert_subject = themis@internal@erlang@ets:match_metric( <<"themis_metrics"/utf8>>, Kind ), {ok, Metrics} = case _assert_subject of {ok, _} -> _assert_subject; _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>>, value => _assert_fail, module => <<"themis/internal/store"/utf8>>, function => <<"match_metrics"/utf8>>, line => 102}) end, _pipe@2 = gleam@list:map( Metrics, 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("/git/Themis/src/themis/internal/store.gleam", 40). -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("/git/Themis/src/themis/internal/store.gleam", 48). -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("/git/Themis/src/themis/internal/store.gleam", 117). -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), _assert_subject = themis@internal@erlang@ets:counter_increment_by( <<"themis_records"/utf8>>, {Name@1, Labels@1}, Value ), {ok, R} = case _assert_subject of {ok, _} -> _assert_subject; _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>>, value => _assert_fail, module => <<"themis/internal/store"/utf8>>, function => <<"increment_record_by"/utf8>>, line => 129}) end, R end, {ok, _pipe}; {int, _} -> _pipe = begin Labels@1 = themis@internal@label:to_strings(Labels), Name@1 = themis@internal@metric:name_to_string(Name), _assert_subject = themis@internal@erlang@ets:counter_increment_by( <<"themis_records"/utf8>>, {Name@1, Labels@1}, Value ), {ok, R} = case _assert_subject of {ok, _} -> _assert_subject; _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>>, value => _assert_fail, module => <<"themis/internal/store"/utf8>>, function => <<"increment_record_by"/utf8>>, line => 129}) end, R end, {ok, _pipe}; na_n -> {error, invalid_increment}; neg_inf -> {error, invalid_increment}; pos_inf -> {error, invalid_increment} end. -file("/git/Themis/src/themis/internal/store.gleam", 139). -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("/git/Themis/src/themis/internal/store.gleam", 147). -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, _assert_subject = 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} ), {ok, R} = case _assert_subject of {ok, _} -> _assert_subject; _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>>, value => _assert_fail, module => <<"themis/internal/store"/utf8>>, function => <<"insert_record"/utf8>>, line => 162}) end, case R of false -> {error, insert_error}; true -> {ok, nil} end. -file("/git/Themis/src/themis/internal/store.gleam", 177). -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) -> _assert_subject = themis@internal@erlang@ets:match_record( <<"themis_records"/utf8>>, begin _pipe = Name, themis@internal@metric:name_to_string(_pipe) end ), {ok, Records} = case _assert_subject of {ok, _} -> _assert_subject; _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>>, value => _assert_fail, module => <<"themis/internal/store"/utf8>>, function => <<"match_records"/utf8>>, line => 182}) end, _pipe@1 = Records, _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("/git/Themis/src/themis/internal/store.gleam", 192). -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) -> _assert_subject = 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} ), {ok, Entries} = case _assert_subject of {ok, _} -> _assert_subject; _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>>, value => _assert_fail, module => <<"themis/internal/store"/utf8>>, function => <<"find_record"/utf8>>, line => 199}) end, _pipe@2 = case Entries of [Entry] -> {ok, Entry}; _ -> {error, single_result_expected} end, gleam@result:'try'(_pipe@2, fun parse_record/1).