From a4a75188bd17e31b39a02511bbd6d628bab5c909 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 25 Apr 2021 21:20:04 +0800 Subject: ... --- BackEnd/Timeline/Services/Api/SearchService.cs | 104 +++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 BackEnd/Timeline/Services/Api/SearchService.cs (limited to 'BackEnd/Timeline/Services/Api/SearchService.cs') diff --git a/BackEnd/Timeline/Services/Api/SearchService.cs b/BackEnd/Timeline/Services/Api/SearchService.cs new file mode 100644 index 00000000..eec5001f --- /dev/null +++ b/BackEnd/Timeline/Services/Api/SearchService.cs @@ -0,0 +1,104 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Timeline.Entities; + +namespace Timeline.Services.Api +{ + public class SearchResultItem + { + public SearchResultItem(TItem item, int score) + { + Item = item; + Score = score; + } + + public TItem Item { get; set; } = default!; + + /// + /// Bigger is better. + /// + public int Score { get; set; } + } + + public class SearchResult + { +#pragma warning disable CA2227 // Collection properties should be read only + public List> Items { get; set; } = new(); +#pragma warning restore CA2227 // Collection properties should be read only + } + + public interface ISearchService + { + /// + /// Search timelines whose name or title contains query string. + /// + /// String to contain. + /// Search results. + /// Thrown when is null. + /// Thrown when is empty. + /// + /// Implementation should promise high score is at first. + /// + Task> SearchTimeline(string query); + + /// + /// Search users whose username or nickname contains query string. + /// + /// String to contain. + /// Search results. + /// Thrown when is null. + /// Thrown when is empty. + /// + /// Implementation should promise high score is at first. + /// + Task> SearchUser(string query); + } + + public class SearchService : ISearchService + { + private readonly DatabaseContext _database; + + public SearchService(DatabaseContext database) + { + _database = database; + } + + public async Task> SearchTimeline(string query) + { + if (query is null) + throw new ArgumentNullException(nameof(query)); + if (query.Length == 0) + throw new ArgumentException("Query string can't be empty.", nameof(query)); + + var nameLikeTimelines = await _database.Timelines.Include(t => t.Owner).Where(t => t.Name == null ? t.Owner.Username.Contains(query) : t.Name.Contains(query)).ToListAsync(); + var titleLikeTimelines = await _database.Timelines.Where(t => t.Title != null && t.Title.Contains(query)).ToListAsync(); + + var searchResult = new SearchResult(); + searchResult.Items.AddRange(nameLikeTimelines.Select(t => new SearchResultItem(t, 2))); + searchResult.Items.AddRange(titleLikeTimelines.Select(t => new SearchResultItem(t, 1))); + + return searchResult; + } + + public async Task> SearchUser(string query) + { + if (query is null) + throw new ArgumentNullException(nameof(query)); + if (query.Length == 0) + throw new ArgumentException("Query string can't be empty.", nameof(query)); + + var usernameLikeUsers = await _database.Users.Where(u => u.Username.Contains(query)).ToListAsync(); + var nicknameLikeUsers = await _database.Users.Where(u => u.Nickname != null && u.Nickname.Contains(query)).ToListAsync(); + + var searchResult = new SearchResult(); + searchResult.Items.AddRange(usernameLikeUsers.Select(u => new SearchResultItem(u, 2))); + searchResult.Items.AddRange(nicknameLikeUsers.Select(u => new SearchResultItem(u, 1))); + + return searchResult; + + } + } +} -- cgit v1.2.3