Поиск: case-insensitive сравнение в logic_search
CI / test (push) Successful in 8m4s
CI / deploy-ift (push) Successful in 3m53s
CI / e2e-ift (push) Successful in 1m16s
CI / deploy-stage (push) Successful in 2m14s
CI / e2e-stage (push) Successful in 1m13s

- сопоставление имени/описания календарей приведено к lowercase
- юнит-тесты: 20/20
This commit is contained in:
2026-08-22 21:08:04 +03:00
parent d46eb6e528
commit 4486dc87db
2 changed files with 40 additions and 5 deletions
+24 -5
View File
@@ -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) ->
+16
View File
@@ -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, []),