diff --git a/Masa.BuildingBlocks.sln b/Masa.BuildingBlocks.sln index 45adff2..75c76b7 100644 --- a/Masa.BuildingBlocks.sln +++ b/Masa.BuildingBlocks.sln @@ -68,6 +68,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Storage", "Storage", "{4CC7 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.Storage.ObjectStorage", "src\Storage\Masa.BuildingBlocks.Storage.ObjectStorage\Masa.BuildingBlocks.Storage.ObjectStorage.csproj", "{D52E223F-F406-47A7-BF3E-924DC2D74981}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests", "test\Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests\Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests.csproj", "{F8681808-45F3-4C2D-8A37-D24C0A3414A5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -134,6 +136,10 @@ Global {D52E223F-F406-47A7-BF3E-924DC2D74981}.Debug|Any CPU.Build.0 = Debug|Any CPU {D52E223F-F406-47A7-BF3E-924DC2D74981}.Release|Any CPU.ActiveCfg = Release|Any CPU {D52E223F-F406-47A7-BF3E-924DC2D74981}.Release|Any CPU.Build.0 = Release|Any CPU + {F8681808-45F3-4C2D-8A37-D24C0A3414A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8681808-45F3-4C2D-8A37-D24C0A3414A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8681808-45F3-4C2D-8A37-D24C0A3414A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8681808-45F3-4C2D-8A37-D24C0A3414A5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -167,6 +173,7 @@ Global {5E3CAD7F-B036-4CA0-9473-4CCA4F5AC5A8} = {022D6FF5-4B65-4213-9A97-C69E2B2F99E1} {4CC735F3-DB32-4D9D-863D-BB6E1BA362B9} = {77D17E30-CB7C-4DD7-8CF1-9D5350FF2304} {D52E223F-F406-47A7-BF3E-924DC2D74981} = {4CC735F3-DB32-4D9D-863D-BB6E1BA362B9} + {F8681808-45F3-4C2D-8A37-D24C0A3414A5} = {6ED365E6-4A1A-499F-85FB-F22E865CA4BA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03} diff --git a/README.md b/README.md index ae4c21e..96c9d32 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [中](README.zh-CN.md) | EN -# Masa.BuildingBlocks +# MASA.BuildingBlocks Building blocks of the MASA Stack, provides a unified interface standard for [MASA Contrib](https://github.com/masastack/MASA.Contrib/blob/main/README.md) implementation specifications and process connector. diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/AutoCompleteDocument.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/AutoCompleteDocument.cs index 0d68968..ce863fc 100644 --- a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/AutoCompleteDocument.cs +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/AutoCompleteDocument.cs @@ -1,7 +1,25 @@ namespace Masa.BuildingBlocks.SearchEngine.AutoComplete; -public class AutoCompleteDocument +public class AutoCompleteDocument where TValue : notnull { - public string Id => IdGenerator(); + private string _id; + + public string Id + { + get + { + if (string.IsNullOrEmpty(_id)) + return Value?.ToString() ?? throw new ArgumentException("{Id} cannot be empty", nameof(Id)); + + return _id; + } + init + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentException("{Id} cannot be empty", nameof(Id)); + + _id = value; + } + } public string Text { get; set; } @@ -11,11 +29,15 @@ public AutoCompleteDocument() { } - public AutoCompleteDocument(string text, TValue value) : this() + public AutoCompleteDocument(string text, TValue value) + : this(value?.ToString() ?? throw new ArgumentException($"{value} cannot be empty", nameof(value)), text, value) { + } + + public AutoCompleteDocument(string id, string text, TValue value) : this() + { + Id = id; Text = text; Value = value; } - - protected virtual string IdGenerator() => $"[{Value}]{Text}"; } diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/BaseAutoCompleteClient.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/BaseAutoCompleteClient.cs new file mode 100644 index 0000000..c11bdf9 --- /dev/null +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/BaseAutoCompleteClient.cs @@ -0,0 +1,56 @@ +namespace Masa.BuildingBlocks.SearchEngine.AutoComplete; +public abstract class BaseAutoCompleteClient : IAutoCompleteClient +{ + public virtual Task, Guid>> GetAsync(string keyword, AutoCompleteOptions? options = null, + CancellationToken cancellationToken = default) + => GetAsync(keyword, options, cancellationToken); + + public virtual Task, TValue>> GetAsync(string keyword, + AutoCompleteOptions? options = null, + CancellationToken cancellationToken = default) where TValue : notnull + => GetAsync, TValue>(keyword, options, cancellationToken); + + public abstract Task> GetAsync(string keyword, + AutoCompleteOptions? options = null, + CancellationToken cancellationToken = default) where TAudoCompleteDocument : AutoCompleteDocument where TValue : notnull; + + public virtual Task SetAsync(AutoCompleteDocument document, SetOptions? options = null, + CancellationToken cancellationToken = default) + => SetAsync, Guid>(document, options, cancellationToken); + + public virtual Task SetAsync(IEnumerable> documents, SetOptions? options = null, + CancellationToken cancellationToken = default) + => SetAsync, Guid>(documents, options, cancellationToken); + + public virtual Task SetAsync(AutoCompleteDocument document, SetOptions? options = null, + CancellationToken cancellationToken = default) where TValue : notnull + => SetAsync, TValue>(document, options, cancellationToken); + + public virtual Task SetAsync(IEnumerable> documents, SetOptions? options = null, + CancellationToken cancellationToken = default) where TValue : notnull + => SetAsync, TValue>(documents, options, cancellationToken); + + public virtual Task SetAsync(TAudoCompleteDocument document, SetOptions? options = null, + CancellationToken cancellationToken = default) where TAudoCompleteDocument : AutoCompleteDocument where TValue : notnull + => SetAsync(new List { document }, options, cancellationToken); + + public abstract Task SetAsync(IEnumerable documents, + SetOptions? options = null, + CancellationToken cancellationToken = default) where TAudoCompleteDocument : AutoCompleteDocument where TValue : notnull; + + public abstract Task DeleteAsync(string id, CancellationToken cancellationToken = default); + + public virtual Task DeleteAsync(T id, CancellationToken cancellationToken = default) where T : IComparable + => DeleteAsync(id!.ToString() ?? throw new ArgumentNullException($"{id} is not null", nameof(id)), cancellationToken); + + public abstract Task DeleteAsync(IEnumerable ids, CancellationToken cancellationToken = default); + + public virtual Task DeleteAsync(IEnumerable ids, CancellationToken cancellationToken = default) where T : IComparable + { + var type = typeof(T); + if (!type.IsPrimitive && type != typeof(Guid) && type != typeof(string)) + throw new NotSupportedException("Unsupported types, id only supports simple types or guid, string"); + + return DeleteAsync(ids.Select(id => id.ToString() ?? throw new ArgumentNullException($"{id} is not null", nameof(id))), cancellationToken); + } +} diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/IAutoCompleteClient.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/IAutoCompleteClient.cs index 8c5c24b..e03ecee 100644 --- a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/IAutoCompleteClient.cs +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/IAutoCompleteClient.cs @@ -1,24 +1,58 @@ namespace Masa.BuildingBlocks.SearchEngine.AutoComplete; + public interface IAutoCompleteClient { - Task, TValue>> GetAsync( + Task, Guid>> GetAsync( string keyword, AutoCompleteOptions? options = null, CancellationToken cancellationToken = default); + Task, TValue>> GetAsync( + string keyword, + AutoCompleteOptions? options = null, + CancellationToken cancellationToken = default) where TValue : notnull; + Task> GetAsync( string keyword, AutoCompleteOptions? options = null, CancellationToken cancellationToken = default) - where TAudoCompleteDocument : AutoCompleteDocument; + where TAudoCompleteDocument : AutoCompleteDocument where TValue : notnull; - Task SetAsync( - AutoCompleteDocument[] results, + Task SetAsync( + AutoCompleteDocument document, + SetOptions? options = null, + CancellationToken cancellationToken = default); + + Task SetAsync( + IEnumerable> documents, SetOptions? options = null, CancellationToken cancellationToken = default); + Task SetAsync( + AutoCompleteDocument document, + SetOptions? options = null, + CancellationToken cancellationToken = default) where TValue : notnull; + + Task SetAsync( + IEnumerable> documents, + SetOptions? options = null, + CancellationToken cancellationToken = default) where TValue : notnull; + Task SetAsync( - TAudoCompleteDocument[] documents, + TAudoCompleteDocument document, SetOptions? options = null, - CancellationToken cancellationToken = default) where TAudoCompleteDocument : AutoCompleteDocument ; + CancellationToken cancellationToken = default) where TAudoCompleteDocument : AutoCompleteDocument where TValue : notnull; + + Task SetAsync( + IEnumerable documents, + SetOptions? options = null, + CancellationToken cancellationToken = default) where TAudoCompleteDocument : AutoCompleteDocument where TValue : notnull; + + Task DeleteAsync(string id, CancellationToken cancellationToken = default); + + Task DeleteAsync(T id, CancellationToken cancellationToken = default) where T : IComparable; + + Task DeleteAsync(IEnumerable ids, CancellationToken cancellationToken = default); + + Task DeleteAsync(IEnumerable ids, CancellationToken cancellationToken = default) where T : IComparable; } diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Options/AutoCompleteOptions.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Options/AutoCompleteOptions.cs index 0b16135..8d6858d 100644 --- a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Options/AutoCompleteOptions.cs +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Options/AutoCompleteOptions.cs @@ -31,11 +31,11 @@ public int PageSize } } - public SearchType SearchType { get; } + public SearchType? SearchType { get; } - public AutoCompleteOptions(SearchType searchType = SearchType.Fuzzy) + public AutoCompleteOptions(SearchType? searchType = null) { - this.Field = "id"; + this.Field = "text"; this.Page = 1; this.PageSize = 10; this.SearchType = searchType; diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteMultiResponse.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteMultiResponse.cs new file mode 100644 index 0000000..25f0138 --- /dev/null +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteMultiResponse.cs @@ -0,0 +1,16 @@ +namespace Masa.BuildingBlocks.SearchEngine.AutoComplete.Response; +public class DeleteMultiResponse : ResponseBase +{ + public List Data { get; set; } + + public DeleteMultiResponse(bool isValid, string message) : base(isValid, message) + { + } + + public DeleteMultiResponse(bool isValid, string message, IEnumerable? data) : this(isValid, message) + { + ArgumentNullException.ThrowIfNull(data, nameof(data)); + + Data = data.ToList(); + } +} diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteRangeResponseItems.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteRangeResponseItems.cs new file mode 100644 index 0000000..57d3807 --- /dev/null +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteRangeResponseItems.cs @@ -0,0 +1,16 @@ +namespace Masa.BuildingBlocks.SearchEngine.AutoComplete.Response; +public class DeleteRangeResponseItems +{ + public string Id { get; } + + public bool IsValid { get; } + + public string Message { get; } + + public DeleteRangeResponseItems(string id, bool isValid, string message) + { + this.Id = id; + this.IsValid = isValid; + this.Message = message; + } +} diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteResponse.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteResponse.cs new file mode 100644 index 0000000..ec3d492 --- /dev/null +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/DeleteResponse.cs @@ -0,0 +1,7 @@ +namespace Masa.BuildingBlocks.SearchEngine.AutoComplete.Response; +public class DeleteResponse : ResponseBase +{ + public DeleteResponse(bool isValid, string message) : base(isValid, message) + { + } +} diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/GetResponse.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/GetResponse.cs index 80fa5bc..a14124c 100644 --- a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/GetResponse.cs +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/GetResponse.cs @@ -1,6 +1,6 @@ namespace Masa.BuildingBlocks.SearchEngine.AutoComplete.Response; public class GetResponse : ResponseBase - where TDropdownBox : AutoCompleteDocument + where TDropdownBox : AutoCompleteDocument where TValue : notnull { public long Total { get; set; } @@ -11,4 +11,11 @@ public class GetResponse : ResponseBase public GetResponse(bool isValid, string message) : base(isValid, message) { } + + public GetResponse(bool isValid, string message, IEnumerable data) : this(isValid, message) + { + ArgumentNullException.ThrowIfNull(data,nameof(data)); + + Data = data.ToList(); + } } diff --git a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/SetResponse.cs b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/SetResponse.cs index 924f495..b951c70 100644 --- a/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/SetResponse.cs +++ b/src/SearchEngine/Masa.BuildingBlocks.SearchEngine.AutoComplete/Response/SetResponse.cs @@ -1,5 +1,4 @@ namespace Masa.BuildingBlocks.SearchEngine.AutoComplete.Response; - public class SetResponse : ResponseBase { public List Items { get; set; } diff --git a/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/CustomAutoCompleteClient.cs b/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/CustomAutoCompleteClient.cs new file mode 100644 index 0000000..d4c2bc4 --- /dev/null +++ b/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/CustomAutoCompleteClient.cs @@ -0,0 +1,25 @@ +namespace Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests; +public class CustomAutoCompleteClient : BaseAutoCompleteClient +{ + public override Task> GetAsync(string keyword, + AutoCompleteOptions? options = null, + CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public override Task SetMultiAsync(IEnumerable documents, + SetOptions? options = null, + CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public override Task DeleteAsync(string id) + { + throw new NotImplementedException(); + } + + public override Task DeleteMultiAsync(IEnumerable ids) + => Task.FromResult(new DeleteMultiResponse(true, "")); +} diff --git a/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests.csproj b/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests.csproj new file mode 100644 index 0000000..101023b --- /dev/null +++ b/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests.csproj @@ -0,0 +1,21 @@ + + + + net6.0 + enable + enable + false + + + + + + + + + + + + + + diff --git a/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/TestAutoCompleteClient.cs b/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/TestAutoCompleteClient.cs new file mode 100644 index 0000000..ff02b98 --- /dev/null +++ b/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/TestAutoCompleteClient.cs @@ -0,0 +1,36 @@ +namespace Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests; + +[TestClass] +public class TestAutoCompleteClient +{ + [TestMethod] + public async Task TestDeleteMultiAsyncReturnThrowNotSupportedException() + { + var client = new CustomAutoCompleteClient(); + await Assert.ThrowsExceptionAsync(() => client.DeleteMultiAsync(new List>() + { + new("2", 2), + new("1", 1), + })); + } + + [TestMethod] + public async Task TestDeleteMultiAsyncReturnSuccess() + { + var client = new CustomAutoCompleteClient(); + var response = await client.DeleteMultiAsync(new[] { 1, 2 }); + Assert.IsTrue(response.IsValid); + + response = await client.DeleteMultiAsync(new[] { "1", "2" }); + Assert.IsTrue(response.IsValid); + + response = await client.DeleteMultiAsync(new[] { 1d, 2d }); + Assert.IsTrue(response.IsValid); + + response = await client.DeleteMultiAsync(new[] { 1l, 2l }); + Assert.IsTrue(response.IsValid); + + response = await client.DeleteMultiAsync(new[] { Guid.NewGuid(), Guid.NewGuid() }); + Assert.IsTrue(response.IsValid); + } +} diff --git a/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/_Imports.cs b/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/_Imports.cs new file mode 100644 index 0000000..3dee731 --- /dev/null +++ b/test/Masa.BuildingBlocks.SearchEngine.AutoComplete.Tests/_Imports.cs @@ -0,0 +1,4 @@ +global using Masa.BuildingBlocks.SearchEngine.AutoComplete.Options; +global using Masa.BuildingBlocks.SearchEngine.AutoComplete.Response; +global using Microsoft.VisualStudio.TestTools.UnitTesting; +