Packages

Client for the Sphinx search engine

Current section

Files

Jump to
giza src giza_update.erl
Raw

src/giza_update.erl

%% Copyright (c) 2009 Electronic Arts, Inc.
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%%
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%%
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(giza_update).
-include("giza.hrl").
-compile([export_all]).
-export([new/1, new/3, attributes/1, add_attribute/2, add_attributes/2, remove_attribute/2]).
-export([docs/1, add_doc/3, remove_doc/2]).
-export([host/1, host/2, port/1, port/2]).
-export([to_bytes/1]).
new(IndexName) ->
#giza_update{index=IndexName}.
new(IndexName, Host, Port) when is_list(Host),
is_number(Port) ->
#giza_update{index=IndexName, host=Host, port=Port}.
attributes(#giza_update{attributes=Fields}=_Update) ->
Fields.
add_attribute(Update, FieldName) when is_list(FieldName) ->
add_attribute(Update, list_to_binary(FieldName));
add_attribute(#giza_update{attributes=Fields}=Update, FieldName) ->
case giza_util:index(Fields, FieldName) of
-1 ->
Update#giza_update{attributes=lists:flatten([Fields, FieldName])};
_ ->
Update
end.
add_attributes(Update, FieldNames) ->
lists:foldl(fun(Field, U) ->
add_attribute(U, Field) end,
Update,
FieldNames).
remove_attribute(Update, FieldName) when is_list(FieldName) ->
remove_attribute(Update, list_to_binary(FieldName));
remove_attribute(#giza_update{attributes=Fields, updates=Updates}=Update, FieldName) ->
case giza_util:index(Fields, FieldName) of
-1 ->
Update;
FieldPos ->
Update#giza_update{attributes=lists:filter(fun(F) -> not(F =:= FieldName) =:= true end,
Fields),
updates=clean_updates(FieldPos, Updates)}
end.
docs(#giza_update{updates=Updates}=_Update) ->
Updates.
add_doc(#giza_update{attributes=Fields, updates=Updates}=Update, DocId, Attributes) when is_number(DocId),
is_list(Attributes) ->
if
length(Attributes) == length(Fields) ->
Update#giza_update{updates=[{DocId, Attributes}|Updates]};
true ->
throw({error, missing_fields})
end.
remove_doc(#giza_update{updates=Updates}=Update, DocId) when is_number(DocId) ->
Update#giza_update{updates=proplists:delete(DocId, Updates)}.
to_bytes(Update) ->
Commands = to_commands(Update),
giza_protocol:commands_to_bytes(Commands).
%% @spec host(Update) -> Result
%% Update = any()
%% Result = string()
%% @doc Get the current target host
host(Update) ->
Update#giza_update.host.
%% @spec host(Update, Host) -> Result
%% Update = any()
%% Host = string()
%% Result = any()
%% @doc Set the target host
host(Update, Host) when is_list(Host) ->
Update#giza_update{host=Host}.
%% @spec port(Update) -> Result
%% Update = any()
%% Result = integer()
%% @doc Get the current target port
port(Update) ->
Update#giza_update.port.
%% @spec port(Update, Port) -> Result
%% Update = any()
%% Port = integer()
%% Result = any()
%% @doc Set the current target port
port(Update, Port) when is_number(Port) ->
Update#giza_update{port=Port}.
%% Internal functions
clean_updates(FieldPos, Updates) ->
clean_updates(FieldPos, Updates, []).
clean_updates(_FieldPos, [], Accum) ->
Accum;
clean_updates(FieldPos, [{DocId, Values}|T], Accum) ->
Before = lists:sublist(Values, FieldPos - 1),
After = lists:sublist(Values, FieldPos + 1, length(Values)),
case Before =:= [] andalso After =:= [] of
true ->
clean_updates(FieldPos, T, Accum);
false ->
clean_updates(FieldPos, T, [{DocId, lists:flatten([Before, After])}|Accum])
end.
to_commands(Update) ->
lists:flatten([{string, Update#giza_update.index},
process_attributes(Update#giza_update.attributes),
{32, length(Update#giza_update.updates)},
process_updates(Update#giza_update.updates)]).
process_attributes(Attributes) ->
[{32, length(Attributes)},
lists:map(fun(A) -> {string, A} end, Attributes)].
process_updates([]) ->
[{32, 0}];
process_updates(Updates) ->
process_updates(Updates, []).
process_updates([], Accum) ->
lists:flatten(lists:reverse(Accum));
process_updates([{DocId, Updates}|T], Accum) ->
PU = lists:reverse(lists:foldl(fun(U, Acc) -> [{32, U}|Acc] end,
[{64, DocId}], Updates)),
process_updates(T, [PU|Accum]).