diff --git a/sources/core/Crypto.Compare.Services/Handlers/Queries/Providers/GetProvidersQueryHandler.cs b/sources/core/Crypto.Compare.Services/Handlers/Queries/Providers/GetProvidersQueryHandler.cs index 245af34..58aeeef 100644 --- a/sources/core/Crypto.Compare.Services/Handlers/Queries/Providers/GetProvidersQueryHandler.cs +++ b/sources/core/Crypto.Compare.Services/Handlers/Queries/Providers/GetProvidersQueryHandler.cs @@ -1,7 +1,6 @@ using Crypto.Compare.DataAccess; using Crypto.Compare.Services.Queries.Symbols; using Crypto.Compare.Services.Results.Providers; -using Crypto.Compare.Services.Results.Symbols; using FluentResults; using MediatR; using Microsoft.EntityFrameworkCore; diff --git a/sources/core/Crypto.Compare.Services/Handlers/Queries/SymbolProviders/GetSymbolProvidersQueryHandler.cs b/sources/core/Crypto.Compare.Services/Handlers/Queries/SymbolProviders/GetSymbolProvidersQueryHandler.cs new file mode 100644 index 0000000..18c5958 --- /dev/null +++ b/sources/core/Crypto.Compare.Services/Handlers/Queries/SymbolProviders/GetSymbolProvidersQueryHandler.cs @@ -0,0 +1,55 @@ +using Crypto.Compare.DataAccess; +using Crypto.Compare.Services.Queries.SymbolProviders; +using Crypto.Compare.Services.Results.SymbolProviders; +using FluentResults; +using MediatR; +using Microsoft.EntityFrameworkCore; + +namespace Crypto.Compare.Services.Handlers.Queries.SymbolProviders; + +public class GetSymbolProvidersQueryHandler : IRequestHandler> +{ + private readonly CryptoCompareContext _cryptoCompareContext; + + public GetSymbolProvidersQueryHandler(CryptoCompareContext cryptoCompareContext) + { + _cryptoCompareContext = cryptoCompareContext; + } + + public async Task> Handle(GetSymbolProvidersQuery request, CancellationToken cancellationToken) + { + var query = _cryptoCompareContext + .SymbolProviders + .Include(x => x.Symbol) + .AsQueryable() + .AsNoTracking() + .Where(x => x.ProviderId == request.ProviderId); + + if (!string.IsNullOrEmpty(request.Ticker)) + { + query = query.Where(x => x.Symbol.Ticker == request.Ticker); + } + + + var symbols = await query + .Select(s => new SymbolProviderResult + { + Id = s.Symbol.Id, + Ticker = s.Ticker, + Symbol = $"{s.Symbol.BaseSymbol}/{s.Symbol.QuoteSymbol}", + ProviderId = s.ProviderId, + PriceSell = s.PriceSell, + PriceBuy = s.PriceBuy, + UpdatedAt = s.UpdatedAt + }) + .Skip((int)request.Skip) + .Take(request.Rows) + .ToListAsync(cancellationToken); + + + return new GetSymbolProviderResult + { + Symbols = symbols + }; + } +} diff --git a/sources/core/Crypto.Compare.Services/Handlers/Queries/Symbols/GetSymbolsQueryHandler.cs b/sources/core/Crypto.Compare.Services/Handlers/Queries/Symbols/GetSymbolsQueryHandler.cs index 577e0f6..4d54b67 100644 --- a/sources/core/Crypto.Compare.Services/Handlers/Queries/Symbols/GetSymbolsQueryHandler.cs +++ b/sources/core/Crypto.Compare.Services/Handlers/Queries/Symbols/GetSymbolsQueryHandler.cs @@ -19,7 +19,8 @@ public GetSymbolsQueryHandler(CryptoCompareContext cryptoCompareContext) public async Task> Handle(GetSymbolsQuery request, CancellationToken cancellationToken) { var query = _cryptoCompareContext - .SymbolProviders + .Symbols + .Include(x=>x.SymbolProviders) .AsQueryable() .AsNoTracking(); @@ -28,12 +29,30 @@ public async Task> Handle(GetSymbolsQuery request, Canc query = query.Where(x => x.Ticker == request.Ticker); } - if (request.ProviderId.HasValue) - { - query = query.Where(x => x.ProviderId == request.ProviderId); - } - var symbols = await query + .Select(symbol => new SymbolResult + { + Id = symbol.Id, + Ticker = symbol.Ticker, + Symbol = $"{symbol.BaseSymbol}/{symbol.QuoteSymbol}", + ProviderSellId = symbol.SymbolProviders + .OrderByDescending(sp => sp.PriceSell) + .Select(sp => sp.ProviderId) + .FirstOrDefault(), + PriceSell = symbol.SymbolProviders + .OrderByDescending(sp => sp.PriceSell) + .Select(sp => sp.PriceSell) + .FirstOrDefault(), + ProviderBuyId = symbol.SymbolProviders + .OrderBy(sp => sp.PriceBuy) + .Select(sp => sp.ProviderId) + .FirstOrDefault(), + PriceBuy = symbol.SymbolProviders + .OrderBy(sp => sp.PriceBuy) + .Select(sp => sp.PriceBuy) + .FirstOrDefault(), + UpdatedAt = symbol.UpdatedAt + }) .Skip((int)request.Skip) .Take(request.Rows) .ToListAsync(cancellationToken); diff --git a/sources/core/Crypto.Compare.Services/Queries/SymbolProviders/GetSymbolProvidersQuery.cs b/sources/core/Crypto.Compare.Services/Queries/SymbolProviders/GetSymbolProvidersQuery.cs new file mode 100644 index 0000000..7ecd095 --- /dev/null +++ b/sources/core/Crypto.Compare.Services/Queries/SymbolProviders/GetSymbolProvidersQuery.cs @@ -0,0 +1,37 @@ +using Crypto.Compare.Services.Results.SymbolProviders; +using FluentResults; +using MediatR; + +namespace Crypto.Compare.Services.Queries.SymbolProviders +{ + public class GetSymbolProvidersQuery : IRequest> + { + private const int MaxRows = 50; + private const int DefaultRows = 10; + + public GetSymbolProvidersQuery(int providerId, string? ticker = null, long? skip = 0, int? rows = DefaultRows) + { + Ticker = ticker?.ToLowerInvariant(); + ProviderId = providerId; + Skip = skip ?? 0; + Rows = rows is null or < 10 or > MaxRows ? DefaultRows : rows.Value; + } + + /// + /// Ticker symbol + /// + public string? Ticker { get; } + public int ProviderId { get; } + + + /// + /// Skip rows + /// + public long Skip { get; } + + /// + /// Get rows + /// + public int Rows { get; } + } +} diff --git a/sources/core/Crypto.Compare.Services/Queries/Symbols/GetSymbolsQuery.cs b/sources/core/Crypto.Compare.Services/Queries/Symbols/GetSymbolsQuery.cs index 8a2f34a..cfc3a9f 100644 --- a/sources/core/Crypto.Compare.Services/Queries/Symbols/GetSymbolsQuery.cs +++ b/sources/core/Crypto.Compare.Services/Queries/Symbols/GetSymbolsQuery.cs @@ -6,13 +6,12 @@ namespace Crypto.Compare.Services.Queries.Symbols; public class GetSymbolsQuery : IRequest> { - private const int MaxRows = 50; + private const int MaxRows = 30; private const int DefaultRows = 10; - public GetSymbolsQuery(string? ticker = null, int? providerId = null, long? skip = 0, int? rows = DefaultRows) + public GetSymbolsQuery(string? ticker = null, long? skip = 0, int? rows = DefaultRows) { Ticker = ticker?.ToLowerInvariant(); - ProviderId = providerId; Skip = skip ?? 0; Rows = rows is null or < 10 or > MaxRows ? DefaultRows : rows.Value; } @@ -22,11 +21,6 @@ public GetSymbolsQuery(string? ticker = null, int? providerId = null, long? skip /// public string? Ticker { get; } - /// - /// Provider for symbols - /// - public int? ProviderId { get; } - /// /// Skip rows /// diff --git a/sources/core/Crypto.Compare.Services/Results/SymbolProviders/GetSymbolProviderResult.cs b/sources/core/Crypto.Compare.Services/Results/SymbolProviders/GetSymbolProviderResult.cs new file mode 100644 index 0000000..20e1683 --- /dev/null +++ b/sources/core/Crypto.Compare.Services/Results/SymbolProviders/GetSymbolProviderResult.cs @@ -0,0 +1,8 @@ +using Crypto.Compare.Data; + +namespace Crypto.Compare.Services.Results.SymbolProviders; + +public class GetSymbolProviderResult : IHandlerResult +{ + public List Symbols { get; set; } +} \ No newline at end of file diff --git a/sources/core/Crypto.Compare.Services/Results/SymbolProviders/SymbolProviderResult.cs b/sources/core/Crypto.Compare.Services/Results/SymbolProviders/SymbolProviderResult.cs new file mode 100644 index 0000000..1553a56 --- /dev/null +++ b/sources/core/Crypto.Compare.Services/Results/SymbolProviders/SymbolProviderResult.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Crypto.Compare.Services.Results.SymbolProviders; + +public class SymbolProviderResult +{ + + /// + /// Uniq id + /// + public long Id { get; set; } + + /// + /// Ticker name + /// + public string Ticker { get; set; } + + /// + /// symbol or viewed name + /// + public string Symbol { get; set; } + + /// + /// Id provider the best sell price + /// + public int ProviderId { get; set; } + + /// + /// Price sell + /// + public decimal PriceSell { get; set; } + + /// + /// Current sell price + /// + public decimal PriceBuy { get; set; } + + /// + /// Last date get quotes + /// + public DateTime UpdatedAt { get; set; } + +} diff --git a/sources/core/Crypto.Compare.Services/Results/Symbols/GetSymbolsResult.cs b/sources/core/Crypto.Compare.Services/Results/Symbols/GetSymbolsResult.cs index 637bd57..fbe6741 100644 --- a/sources/core/Crypto.Compare.Services/Results/Symbols/GetSymbolsResult.cs +++ b/sources/core/Crypto.Compare.Services/Results/Symbols/GetSymbolsResult.cs @@ -1,8 +1,7 @@ using Crypto.Compare.Data; - namespace Crypto.Compare.Services.Results.Symbols; public class GetSymbolsResult : IHandlerResult { - public List Symbols { get; set; } + public List Symbols { get; set; } } \ No newline at end of file diff --git a/sources/core/Crypto.Compare.Services/Results/Symbols/SymbolResult.cs b/sources/core/Crypto.Compare.Services/Results/Symbols/SymbolResult.cs new file mode 100644 index 0000000..a0514a7 --- /dev/null +++ b/sources/core/Crypto.Compare.Services/Results/Symbols/SymbolResult.cs @@ -0,0 +1,44 @@ +namespace Crypto.Compare.Services.Results.Symbols; + +public class SymbolResult +{ + /// + /// Uniq id + /// + public long Id { get; set; } + + /// + /// Ticker name + /// + public string Ticker { get; set; } + + /// + /// symbol or viewed name + /// + public string Symbol { get; set; } + + /// + /// Id provider the best sell price + /// + public int ProviderSellId { get; set; } + + /// + /// Price sell + /// + public decimal PriceSell { get; set; } + + /// + /// Id provider the best buy price + /// + public int ProviderBuyId { get; set; } + + /// + /// Current sell price + /// + public decimal PriceBuy { get; set; } + + /// + /// Last date get quotes + /// + public DateTime UpdatedAt { get; set; } +} diff --git a/sources/infrastructure/Crypto.Compare.DataAccess/Mappers/SymbolProviderMap.cs b/sources/infrastructure/Crypto.Compare.DataAccess/Mappers/SymbolProviderMap.cs index 40ec3c1..c27df3b 100644 --- a/sources/infrastructure/Crypto.Compare.DataAccess/Mappers/SymbolProviderMap.cs +++ b/sources/infrastructure/Crypto.Compare.DataAccess/Mappers/SymbolProviderMap.cs @@ -38,6 +38,6 @@ public void Configure(EntityTypeBuilder builder) .HasForeignKey(p => p.SymbolId) .IsRequired(false); - builder.Ignore(p => p.Symbol); + //builder.Ignore(p => p.Symbol); } } diff --git a/sources/presentation/Crypto.Compare.PublicApi/Controllers/SymbolsController.cs b/sources/presentation/Crypto.Compare.PublicApi/Controllers/SymbolsController.cs index 5674a7f..46d6744 100644 --- a/sources/presentation/Crypto.Compare.PublicApi/Controllers/SymbolsController.cs +++ b/sources/presentation/Crypto.Compare.PublicApi/Controllers/SymbolsController.cs @@ -1,16 +1,19 @@ -using System.Net.Mime; -using Crypto.Compare.Data; +using Crypto.Compare.Data; using Crypto.Compare.PublicApi.Mapping; using Crypto.Compare.PublicApi.Responses; +using Crypto.Compare.PublicApi.Responses.v1.SymbolProvider; using Crypto.Compare.PublicApi.Responses.v1.Symbols; using Crypto.Compare.PublicApi.Swaggers.Responses; using Crypto.Compare.PublicApi.Swaggers.Responses.v1.Symbols; +using Crypto.Compare.Services.Queries.SymbolProviders; using Crypto.Compare.Services.Queries.Symbols; +using Crypto.Compare.Services.Results.SymbolProviders; using Crypto.Compare.Services.Results.Symbols; using MediatR; using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Filters; +using System.Net.Mime; namespace Crypto.Compare.PublicApi.Controllers; @@ -64,12 +67,12 @@ public async Task GetSymbols([FromQuery] int? skip, [FromQuery] i [SwaggerResponseExample(StatusCodes.Status200OK, typeof(GetSymbolsResponseExample))] public async Task GetSymbolsByProvider([FromRoute] int providerId, [FromQuery] int? skip, [FromQuery] int? rows, CancellationToken cancellationToken) { - var command = new GetSymbolsQuery(providerId: providerId, + var command = new GetSymbolProvidersQuery(providerId: providerId, skip: skip, rows: rows); var result = await _mediator.Send(command, cancellationToken); - return _responseMapper.ToCustomResponse(result); + return _responseMapper.ToCustomResponse(result); } /// diff --git a/sources/presentation/Crypto.Compare.PublicApi/Dtos/SymbolDto.cs b/sources/presentation/Crypto.Compare.PublicApi/Dtos/SymbolDto.cs index e135dd4..365b478 100644 --- a/sources/presentation/Crypto.Compare.PublicApi/Dtos/SymbolDto.cs +++ b/sources/presentation/Crypto.Compare.PublicApi/Dtos/SymbolDto.cs @@ -18,15 +18,20 @@ public class SymbolDto public string Symbol { get; set; } /// - /// Id provider + /// Id provider the best sell price /// - public int ProviderId { get; set; } + public int ProviderSellId { get; set; } /// /// Price sell /// public decimal PriceSell { get; set; } - + + /// + /// Id provider the best buy price + /// + public int ProviderBuyId { get; set; } + /// /// Current sell price /// diff --git a/sources/presentation/Crypto.Compare.PublicApi/Dtos/SymbolProviderDto.cs b/sources/presentation/Crypto.Compare.PublicApi/Dtos/SymbolProviderDto.cs new file mode 100644 index 0000000..e23a043 --- /dev/null +++ b/sources/presentation/Crypto.Compare.PublicApi/Dtos/SymbolProviderDto.cs @@ -0,0 +1,39 @@ +namespace Crypto.Compare.PublicApi.Dtos; + +public class SymbolProviderDto +{ + /// + /// Uniq id + /// + public long Id { get; set; } + + /// + /// Ticker name + /// + public string Ticker { get; set; } + + /// + /// symbol or viewed name + /// + public string Symbol { get; set; } + + /// + /// Id provider + /// + public int ProviderId { get; set; } + + /// + /// Price sell + /// + public decimal PriceSell { get; set; } + + /// + /// Current sell price + /// + public decimal PriceBuy { get; set; } + + /// + /// Last date get quotes + /// + public DateTime UpdatedAt { get; set; } +} diff --git a/sources/presentation/Crypto.Compare.PublicApi/Ioc/ServicesRegistry.cs b/sources/presentation/Crypto.Compare.PublicApi/Ioc/ServicesRegistry.cs index 8a90457..aff01e5 100644 --- a/sources/presentation/Crypto.Compare.PublicApi/Ioc/ServicesRegistry.cs +++ b/sources/presentation/Crypto.Compare.PublicApi/Ioc/ServicesRegistry.cs @@ -18,10 +18,13 @@ using Crypto.Compare.Services.Cache.Impl; using Crypto.Compare.Services.Configs; using Crypto.Compare.Services.Handlers.Queries.Providers; +using Crypto.Compare.Services.Handlers.Queries.SymbolProviders; using Crypto.Compare.Services.Handlers.Queries.Symbols; using Crypto.Compare.Services.Queries.Providers; +using Crypto.Compare.Services.Queries.SymbolProviders; using Crypto.Compare.Services.Queries.Symbols; using Crypto.Compare.Services.Results.Providers; +using Crypto.Compare.Services.Results.SymbolProviders; using Crypto.Compare.Services.Results.Symbols; using Crypto.Compare.Services.Subscribes; using Crypto.Compare.Services.WebSockets; @@ -249,6 +252,8 @@ private static IServiceCollection AddMediator(this IServiceCollection services) .AddScoped>, GetSymbolsQueryHandler>() .AddScoped>, GetProviderQueryHandler>() .AddScoped>, GetProvidersQueryHandler>() + .AddScoped>, GetSymbolProvidersQueryHandler>() + ; } } diff --git a/sources/presentation/Crypto.Compare.PublicApi/Mapping/AutoMapperProfile.cs b/sources/presentation/Crypto.Compare.PublicApi/Mapping/AutoMapperProfile.cs index a06a4a1..8acf1f4 100644 --- a/sources/presentation/Crypto.Compare.PublicApi/Mapping/AutoMapperProfile.cs +++ b/sources/presentation/Crypto.Compare.PublicApi/Mapping/AutoMapperProfile.cs @@ -2,8 +2,10 @@ using Crypto.Compare.Data; using Crypto.Compare.PublicApi.Dtos; using Crypto.Compare.PublicApi.Responses.v1.Providers; +using Crypto.Compare.PublicApi.Responses.v1.SymbolProvider; using Crypto.Compare.PublicApi.Responses.v1.Symbols; using Crypto.Compare.Services.Results.Providers; +using Crypto.Compare.Services.Results.SymbolProviders; using Crypto.Compare.Services.Results.Symbols; namespace Crypto.Compare.PublicApi.Mapping; @@ -15,9 +17,12 @@ public class AutoMapperProfile : Profile { public AutoMapperProfile() { - CreateMap(); + CreateMap(); + CreateMap(); CreateMap(); CreateMap(); + CreateMap(); + CreateMap(); CreateMap(); CreateMap(); diff --git a/sources/presentation/Crypto.Compare.PublicApi/Mapping/ResponseMapper.cs b/sources/presentation/Crypto.Compare.PublicApi/Mapping/ResponseMapper.cs index 13967de..7a9d7c1 100644 --- a/sources/presentation/Crypto.Compare.PublicApi/Mapping/ResponseMapper.cs +++ b/sources/presentation/Crypto.Compare.PublicApi/Mapping/ResponseMapper.cs @@ -18,9 +18,15 @@ public ResponseMapper(IMapper automapper) public IActionResult ToCustomResponse(Result? result) where TResponse : BaseApiResponse, new() { - if (result == null) return null; + if (result == null) + { + return null; + } - if (result.IsSuccess) return _automapper.Map(result.Value).ToObjectResult(); + if (result.IsSuccess) + { + return _automapper.Map(result.Value).ToObjectResult(); + } return result.ToApiErrorResult(); } diff --git a/sources/presentation/Crypto.Compare.PublicApi/Responses/v1/SymbolProvider/GetSymbolsProviderResponse.cs b/sources/presentation/Crypto.Compare.PublicApi/Responses/v1/SymbolProvider/GetSymbolsProviderResponse.cs new file mode 100644 index 0000000..fa7b7dd --- /dev/null +++ b/sources/presentation/Crypto.Compare.PublicApi/Responses/v1/SymbolProvider/GetSymbolsProviderResponse.cs @@ -0,0 +1,8 @@ +using Crypto.Compare.PublicApi.Dtos; + +namespace Crypto.Compare.PublicApi.Responses.v1.SymbolProvider; + +public class GetSymbolsProviderResponse : BaseApiResponse +{ + public List Symbols { get; set; } +} \ No newline at end of file diff --git a/sources/presentation/Crypto.Compare.PublicApi/Swaggers/Responses/v1/Symbols/GetSymbolsResponseExample.cs b/sources/presentation/Crypto.Compare.PublicApi/Swaggers/Responses/v1/Symbols/GetSymbolsResponseExample.cs index a465098..b0e620b 100644 --- a/sources/presentation/Crypto.Compare.PublicApi/Swaggers/Responses/v1/Symbols/GetSymbolsResponseExample.cs +++ b/sources/presentation/Crypto.Compare.PublicApi/Swaggers/Responses/v1/Symbols/GetSymbolsResponseExample.cs @@ -17,7 +17,7 @@ public GetSymbolsResponse GetExamples() Symbol = "BTCUSDT", PriceSell = 82000, PriceBuy = 79000, - ProviderId = 1, + ProviderSellId = 1, Ticker = "BTCUSDT" }, new() @@ -26,7 +26,7 @@ public GetSymbolsResponse GetExamples() Symbol = "ETHUSDT", PriceSell = 3200, PriceBuy = 3100, - ProviderId = 1, + ProviderSellId = 1, Ticker = "ETHUSDT" } }