Слияние записей для Mnesia

Я пытаюсь реорганизовать некоторый код, который у меня есть для программного обеспечения, которое собирает текущий статус агентов в очереди вызовов. В настоящее время для каждого из 6 или около того событий, которые я слушаю, я проверяю в таблице Mnesia, существует ли агент, и меняю некоторые значения в строке в зависимости от события или добавляю его как новые, если агент не существует. В настоящее время у меня есть эта транзакция Mnesia в каждом событии, и, конечно же, это набор повторяющегося кода для проверки существования агентов и так далее.

Я пытаюсь изменить его так, чтобы была одна функция, например change_agent / 2, которую я вызываю из событий, которые обрабатывают это за меня.

Мои проблемы - это, конечно, записи ... Я не нахожу способа динамически создавать их или объединять 2 из них вместе или что-то в этом роде. Желательно, чтобы была функция, которую я мог бы назвать следующим образом:

change_agent("001", #agent(id = "001", name = "Steve")).
change_agent("001", #agent(id = "001", paused = 0, talking_to = "None")).

person Jon Gretar    schedule 15.09.2008    source источник


Ответы (2)


Некоторое время назад я написал код, объединяющий две записи. Не совсем динамический, но с макросами вы можете легко использовать его для нескольких записей.

Это работает следующим образом: функция merge / 2 принимает две записи и преобразует их в списки вместе с пустой записью для ссылки (тип записи определяется во время компиляции и должен быть таким. Это «нединамическая» часть). Затем они запускаются через общую функцию merge / 4, которая работает со списками и берет элементы из A, если они определены, в противном случае из B, если они определены, или, наконец, из Default (который всегда определяется).

Вот код (прошу прощения за плохую подсветку синтаксиса Erlang в StackOverflow):

%%%----------------------------------------------------------------------------
%%% @spec merge(RecordA, RecordB) -> #my_record{}
%%%     RecordA = #my_record{}
%%%     RecordB = #my_record{}
%%%
%%% @doc Merges two #my_record{} instances. The first takes precedence.
%%% @end
%%%----------------------------------------------------------------------------
merge(RecordA, RecordB) when is_record(RecordA, my_record),
                             is_record(RecordB, my_record) ->
    list_to_tuple(
        lists:append([my_record],
                     merge(tl(tuple_to_list(RecordA)),
                           tl(tuple_to_list(RecordB)),
                           tl(tuple_to_list(#my_record{})),
                           []))).

%%%----------------------------------------------------------------------------
%%% @spec merge(A, B, Default, []) -> [term()]
%%%     A = [term()]
%%%     B = [term()]
%%%     Default = [term()]
%%%
%%% @doc Merges the lists `A' and `B' into to a new list taking
%%% default values from `Default'.
%%%
%%% Each element of `A' and `B' are compared against the elements in
%%% `Default'. If they match the default, the default is used. If one
%%% of them differs from the other and the default value, that element is
%%% chosen. If both differs, the element from `A' is chosen.
%%% @end
%%%----------------------------------------------------------------------------
merge([D|ATail], [D|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [D|To]); % If default, take from D
merge([D|ATail], [B|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [B|To]); % If only A default, take from B
merge([A|ATail], [_|BTail], [_|DTail], To) ->
    merge(ATail, BTail, DTail, [A|To]); % Otherwise take from A
merge([],        [],        [],        To) ->
    lists:reverse(To).

Не стесняйтесь использовать его как хотите.

person Adam Lindberg    schedule 15.09.2008

Трудно написать универсальные функции доступа для записей. Одним из способов решения этой проблемы является библиотека 'exprecs', которая генерирует код для низкоуровневых функций доступа к записям.

Вам нужно добавить в модуль следующие строки:

-compile({parse_transform, exprecs}).
-export_records([...]).  % name the records that you want to 'export'

Соглашение об именах для функций доступа может показаться странным, но оно основано на предложении Ричарда О'Кифа. Он, по крайней мере, согласован и вряд ли будет конфликтовать с существующими функциями. (:

person uwiger    schedule 15.09.2008
comment
Быстро взглянуть на это могло быть не совсем то, что я искал. Но тем не менее интересно и кое-что проверю позже. - person Jon Gretar; 15.09.2008