Поиск: case-insensitive сравнение в logic_search
- сопоставление имени/описания календарей приведено к lowercase - юнит-тесты: 20/20
This commit is contained in:
@@ -232,14 +232,33 @@ apply_calendar_filters(Calendars, Query, Params) ->
|
|||||||
filter_by_text(Items, undefined) -> Items;
|
filter_by_text(Items, undefined) -> Items;
|
||||||
filter_by_text(Items, <<>>) -> Items;
|
filter_by_text(Items, <<>>) -> Items;
|
||||||
filter_by_text(Items, Query) ->
|
filter_by_text(Items, Query) ->
|
||||||
QueryLower = string:lowercase(binary_to_list(Query)),
|
QueryLower = unicode_lower(Query),
|
||||||
lists:filter(fun(Item) ->
|
lists:filter(fun(Item) ->
|
||||||
Title = binary_to_list(get_title(Item)),
|
contains_ci(get_title(Item), QueryLower) orelse
|
||||||
Description = binary_to_list(get_description(Item)),
|
contains_ci(get_description(Item), QueryLower)
|
||||||
string:find(string:lowercase(Title), QueryLower) =/= nomatch orelse
|
|
||||||
string:find(string:lowercase(Description), QueryLower) =/= nomatch
|
|
||||||
end, Items).
|
end, Items).
|
||||||
|
|
||||||
|
%% @doc Case-insensitive contains: бинарники UTF-8 приводим к юникод-
|
||||||
|
%% кодпоинтам. string:lowercase(binary_to_list/1) работал по байтам
|
||||||
|
%% (latin-1) и ломал кириллицу: «аврора» не находила «Аврора».
|
||||||
|
-spec contains_ci(binary() | undefined, string()) -> boolean().
|
||||||
|
contains_ci(undefined, _) -> false;
|
||||||
|
contains_ci(Bin, QueryLower) ->
|
||||||
|
case unicode:characters_to_list(Bin, utf8) of
|
||||||
|
Text when is_list(Text) ->
|
||||||
|
string:find(string:lowercase(Text), QueryLower) =/= nomatch;
|
||||||
|
_ ->
|
||||||
|
%% Битый UTF-8: фолбэк на побайтовое сравнение.
|
||||||
|
string:find(binary_to_list(Bin), QueryLower) =/= nomatch
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec unicode_lower(binary()) -> string().
|
||||||
|
unicode_lower(Query) ->
|
||||||
|
case unicode:characters_to_list(Query, utf8) of
|
||||||
|
Q when is_list(Q) -> string:lowercase(Q);
|
||||||
|
_ -> string:lowercase(binary_to_list(Query))
|
||||||
|
end.
|
||||||
|
|
||||||
%% --- Фильтр по тегам ---
|
%% --- Фильтр по тегам ---
|
||||||
-spec filter_by_tags([#event{} | #calendar{}], map()) -> [#event{} | #calendar{}].
|
-spec filter_by_tags([#event{} | #calendar{}], map()) -> [#event{} | #calendar{}].
|
||||||
filter_by_tags(Items, Params) ->
|
filter_by_tags(Items, Params) ->
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ logic_search_test_() ->
|
|||||||
fun cleanup/1,
|
fun cleanup/1,
|
||||||
[
|
[
|
||||||
{"Search events by text", fun test_search_events_by_text/0},
|
{"Search events by text", fun test_search_events_by_text/0},
|
||||||
|
{"Cyrillic case-insensitive search", fun test_search_cyrillic_case_insensitive/0},
|
||||||
{"Search events by tags", fun test_search_events_by_tags/0},
|
{"Search events by tags", fun test_search_events_by_tags/0},
|
||||||
{"Search events by date range", fun test_search_events_by_date/0},
|
{"Search events by date range", fun test_search_events_by_date/0},
|
||||||
{"Search events by location", fun test_search_events_by_location/0},
|
{"Search events by location", fun test_search_events_by_location/0},
|
||||||
@@ -106,6 +107,21 @@ test_search_events_by_text() ->
|
|||||||
{Total2, _} = events_from(logic_search:search(<<"event">>, <<"conference">>, OwnerId, Params)),
|
{Total2, _} = events_from(logic_search:search(<<"event">>, <<"conference">>, OwnerId, Params)),
|
||||||
?assertEqual(1, Total2).
|
?assertEqual(1, Total2).
|
||||||
|
|
||||||
|
%% UX26-20260822: «аврора» должна находить «Аврора» (юникод-lowercase,
|
||||||
|
%% а не побайтовый latin-1).
|
||||||
|
test_search_cyrillic_case_insensitive() ->
|
||||||
|
OwnerId = create_test_user(user),
|
||||||
|
CalendarId = create_test_calendar(OwnerId, commercial, []),
|
||||||
|
StartTime = eh_test_support:future_start(),
|
||||||
|
create_test_event(CalendarId, <<"Аврора Йога"/utf8>>, <<"Утренняя практика"/utf8>>, StartTime, [], undefined),
|
||||||
|
Params = #{},
|
||||||
|
{Total, _} = events_from(logic_search:search(<<"event">>, <<"аврора"/utf8>>, OwnerId, Params)),
|
||||||
|
?assertEqual(1, Total),
|
||||||
|
{Total2, _} = events_from(logic_search:search(<<"event">>, <<"АВРОРА"/utf8>>, OwnerId, Params)),
|
||||||
|
?assertEqual(1, Total2),
|
||||||
|
{Total3, _} = calendars_from(logic_search:search(<<"calendar">>, <<"test calendar">>, OwnerId, Params)),
|
||||||
|
?assertEqual(1, Total3).
|
||||||
|
|
||||||
test_search_events_by_tags() ->
|
test_search_events_by_tags() ->
|
||||||
OwnerId = create_test_user(user),
|
OwnerId = create_test_user(user),
|
||||||
CalendarId = create_test_calendar(OwnerId, commercial, []),
|
CalendarId = create_test_calendar(OwnerId, commercial, []),
|
||||||
|
|||||||
Reference in New Issue
Block a user