Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

save data in redis as bytes #43

Merged
merged 1 commit into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.Globalization;
using System.Text.Json;
using Basket.API.Models;
using Google.Protobuf;
using Marten;
using Microsoft.Extensions.Caching.Distributed;

namespace Basket.API.IntegrationTests.Database.Redis;
Expand All @@ -8,20 +11,34 @@ public class RedisDataSeeder(IDistributedCache cache)
{
public async Task<bool> AddShoppingCartAsync(ShoppingCart shoppingCart, CancellationToken cancellationToken = default)
{
await cache.SetStringAsync(shoppingCart.Username, JsonSerializer.Serialize(shoppingCart), cancellationToken)
await cache.SetAsync(shoppingCart.Username, GetShoppingCartAsByteArray(shoppingCart), cancellationToken)
.ConfigureAwait(false);

return true;
}


public async Task<ShoppingCart?> GetShoppingCartAsync(string username, CancellationToken cancellationToken = default)
{
ShoppingCart? cachedBasketResult = null;
var cachedBasket = await cache.GetStringAsync(username, cancellationToken).ConfigureAwait(false);
if (!string.IsNullOrEmpty(cachedBasket))
cachedBasketResult = JsonSerializer.Deserialize<ShoppingCart>(cachedBasket);
var cachedBasket = await cache.GetAsync(username, cancellationToken).ConfigureAwait(false);
if (cachedBasket is not null)
{
var cachedShoppingCart = Proto.ShoppingCart.Parser.ParseFrom(cachedBasket);
cachedBasketResult = new ShoppingCart()
{
Username = cachedShoppingCart.Username,
Items = cachedShoppingCart.ShoppingCartItem.Select(x => new ShoppingCartItem()
{
Color = x.Color,
ProductName = x.ProductName,
Price = decimal.Parse(x.Price),
ProduceId = Guid.Parse(x.ProduceId),
Quantity = x.Quantity
}).ToList(),
Version = cachedShoppingCart.Version
};

}
return cachedBasketResult;
}

Expand All @@ -30,4 +47,24 @@ public async Task<bool> DeleteBasketAsync(string username, CancellationToken can
await cache.RemoveAsync(username, cancellationToken).ConfigureAwait(false);
return true;
}

private static byte[] GetShoppingCartAsByteArray(ShoppingCart basket)
{
var basketInDb = new Proto.ShoppingCart()
{
Username = basket.Username,
TotalPrice = basket.TotalPrice.ToString(CultureInfo.InvariantCulture),
Version = basket.Version
};
basketInDb.ShoppingCartItem.AddRange(basket.Items.Select(x => new Proto.ShoppingCartItem()
{
Color = x.Color,
Price = x.Price.ToString(CultureInfo.InvariantCulture),
ProduceId = x.ProduceId.ToString(),
ProductName = x.ProductName,
Quantity = x.Quantity
}));

return basketInDb.ToByteArray();
}
}
9 changes: 8 additions & 1 deletion src/Services/Basket/Basket.API/Basket.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="8.0.1" />
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
<PackageReference Include="Grpc.Core" Version="2.46.6" />
<PackageReference Include="Grpc.Tools" Version="2.54.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Marten" Version="7.26.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3"/>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.7" />
Expand All @@ -20,8 +26,9 @@
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\BuildingBlocks\BuildingBlocks.csproj" />
<ProjectReference Include="..\..\Shared\Shared.csproj" />
<Protobuf Include="Protos\basket.proto" GrpcServices="none" />
</ItemGroup>

<ItemGroup>
<Content Include="..\..\..\.dockerignore">
<Link>.dockerignore</Link>
Expand Down
95 changes: 84 additions & 11 deletions src/Services/Basket/Basket.API/Data/CachedBasketRepository.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Google.Protobuf;

namespace Basket.API.Data;

internal class CachedBasketRepository(IBasketRepository repository, IDistributedCache cache) : IBasketRepository
{
public async Task<ShoppingCart> GetBasketAsync(string username, CancellationToken cancellationToken = default)
{
var cachedBasket = await cache.GetStringAsync(username, cancellationToken).ConfigureAwait(false);
if (!string.IsNullOrEmpty(cachedBasket))
{
var cachedBasketResult = JsonSerializer.Deserialize<ShoppingCart>(cachedBasket);
return cachedBasketResult!;
}

var cachedBasket = await cache.GetAsync(username, cancellationToken).ConfigureAwait(false);
if (cachedBasket is not null && TryParseBasket(cachedBasket, out var shoppingCart))
return shoppingCart;

var basketInDb = await repository.GetBasketAsync(username, cancellationToken).ConfigureAwait(false);
await cache.SetStringAsync(username, JsonSerializer.Serialize(basketInDb), cancellationToken)
var basketByteArray = GetShoppingCartAsByteArray(basketInDb);
await cache.SetAsync(username, basketByteArray, cancellationToken)
.ConfigureAwait(false);

return basketInDb;
Expand All @@ -21,8 +23,8 @@ await cache.SetStringAsync(username, JsonSerializer.Serialize(basketInDb), cance
public async Task<ShoppingCart> StoreBasketAsync(ShoppingCart basket, CancellationToken cancellationToken = default)
{
await repository.StoreBasketAsync(basket, cancellationToken).ConfigureAwait(false);
await cache.SetStringAsync(basket.Username, JsonSerializer.Serialize(basket), cancellationToken)
.ConfigureAwait(false);
var basketByteArray = GetShoppingCartAsByteArray(basket);
await cache.SetAsync(basket.Username, basketByteArray, cancellationToken).ConfigureAwait(false);

return basket;
}
Expand All @@ -33,4 +35,75 @@ public async Task<bool> DeleteBasketAsync(string username, CancellationToken can
await cache.RemoveAsync(username, cancellationToken).ConfigureAwait(false);
return isSuccess;
}
}

private static bool TryParseBasket(byte[] basketByteArray, [NotNullWhen(true)] out ShoppingCart? shoppingCart)
{
var basket = Proto.ShoppingCart.Parser.ParseFrom(basketByteArray);

if (basket is null)
{
shoppingCart = null;
return false;
}

decimal? totalPrice = decimal.TryParse(basket.TotalPrice, out var totalPriceResult) ? totalPriceResult : null;

if (totalPrice is null)
{
shoppingCart = null;
return false;
}

var shoppingCartItems = new List<ShoppingCartItem>();

foreach (var item in basket.ShoppingCartItem)
{
decimal? price = decimal.TryParse(item.Price, out var parsedPrice) ? parsedPrice : null;
Guid? productId = Guid.TryParse(item.ProduceId, out var parsedProductId) ? parsedProductId : null;

if (price is null || productId is null)
{
shoppingCart = null;
return false;
}

shoppingCartItems.Add(new ShoppingCartItem()
{
Color = item.Color,
Price = price.Value,
ProduceId = productId.Value,
ProductName = item.ProductName,
Quantity = item.Quantity
});
}

shoppingCart = new ShoppingCart()
{
Username = basket.Username,
Items = shoppingCartItems,
Version = basket.Version
};

return true;
}

private static byte[] GetShoppingCartAsByteArray(ShoppingCart basket)
{
var basketInDb = new Proto.ShoppingCart()
{
Username = basket.Username,
TotalPrice = basket.TotalPrice.ToString(CultureInfo.InvariantCulture),
Version = basket.Version
};
basketInDb.ShoppingCartItem.AddRange(basket.Items.Select(x => new Proto.ShoppingCartItem()
{
Color = x.Color,
Price = x.Price.ToString(CultureInfo.InvariantCulture),
ProduceId = x.ProduceId.ToString(),
ProductName = x.ProductName,
Quantity = x.Quantity
}));

return basketInDb.ToByteArray();
}
}
20 changes: 20 additions & 0 deletions src/Services/Basket/Basket.API/Protos/basket.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
syntax = "proto3";

option csharp_namespace = "Basket.API.Proto";

package basket;

message ShoppingCart{
string username = 1;
repeated ShoppingCartItem shoppingCartItem = 2;
string totalPrice = 3;
int32 version = 4;
}

message ShoppingCartItem{
int32 quantity = 1;
string color = 2;
string price = 3;
string produceId = 4;
string productName = 5;
}
Loading