This commit is contained in:
Rui Sousa 2021-12-10 00:04:48 +00:00
parent 6437336228
commit 1469b03c16
28 changed files with 425 additions and 230 deletions

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
namespace BlueWest.Collections namespace BlueWest.Collections
{ {
@ -131,6 +132,15 @@ namespace BlueWest.Collections
return false; return false;
} }
/// <summary>
/// Converts To a generic List
/// </summary>
/// <param name="item">Item.</param>
public System.Collections.Immutable.ImmutableArray<T> ToList()
{
return Buffer.ToImmutableArray();
}
/// <summary> /// <summary>
/// if the buffer is at its max more space will be allocated to fit additionalItemCount /// if the buffer is at its max more space will be allocated to fit additionalItemCount

View File

@ -1,9 +1,8 @@
#nullable enable using System;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
namespace BlueWest.WebApi.Tools namespace BlueWest.Collections
{ {
public static class IEnumerableExtensions public static class IEnumerableExtensions
{ {

View File

@ -0,0 +1 @@


View File

@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MapTo" Version="0.9.1" /> <PackageReference Include="MapTo" Version="0.9.3" />
<PackageReference Include="MessagePack" Version="2.3.85" /> <PackageReference Include="MessagePack" Version="2.3.85" />
<PackageReference Include="Newtonsoft.Json" Version="6.0.4" /> <PackageReference Include="Newtonsoft.Json" Version="6.0.4" />
</ItemGroup> </ItemGroup>

View File

@ -1,25 +0,0 @@
using System;
namespace BlueWest.Data
{
/// <summary>
/// Specifies that the annotated class can be mapped from the provided <see cref="SourceType"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public sealed class AAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="MapFromAttribute"/> class with the specified <paramref name="sourceType"/>.
/// </summary>
/// <param name="sourceType">The type of to map from.</param>
public AAttribute(Type sourceType)
{
SourceType = sourceType;
}
/// <summary>
/// Gets the type to map from.
/// </summary>
public Type SourceType { get; }
}
}

View File

@ -1,46 +0,0 @@

using System.Collections.Generic;
using BlueWest.Collections;
using MapTo;
using MessagePack;
using Newtonsoft.Json;
namespace BlueWest.Data
{
[MessagePackObject]
[MapFrom(typeof(UserUpdateDto))]
public partial struct User
{
[Key(1)]public int Id { get; }
[Key(2)]public string Name { get; set; }
[Key(3)]public string Address { get; set; }
[Key(4)]public string BTCAddress { get; set; }
[Key(5)]public string LTCAddress { get; set; }
[Key(6)]public double BTCAmount { get; set; }
[Key(7)]public double LTCAmount { get; set; }
[Key(8)] public List<FinanceTransaction> FinanceTransactions { get; set; }
public User(int id, string name, string address, string btcAddress, string ltcAddress, double btcAmount, double ltcAmount, List<FinanceTransaction> financeTransactions)
{
Id = id;
Name = name;
Address = address;
BTCAddress = btcAddress;
LTCAddress = ltcAddress;
BTCAmount = btcAmount;
LTCAmount = ltcAmount;
FinanceTransactions = financeTransactions;
}
public void AddTransaction(FinanceTransaction financeTransaction)
{
FinanceTransactions.Add(financeTransaction);
}
}
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using BlueWest.Collections;
using MessagePack;
namespace BlueWest.Data
{
[MessagePackObject]
public class UserList: DataObject
{
[Key(9)] public List<User> Users;
public UserList(List<User> users)
{
Users = users;
}
[IgnoreMember]
public int Length => Users.Count;
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BlueWest.Data
{
class DataQueryResult { }
internal sealed class PositiveResult<T> : DataQueryResult
{
public readonly T Value;
public PositiveResult(T value)
{
Value = value;
}
}
internal sealed class NegativeResult : DataQueryResult
{
public readonly string UserMessage;
public NegativeResult(string userMessage)
{
UserMessage = userMessage;
}
}
}

View File

@ -22,6 +22,7 @@ namespace BlueWest.Data
} }
[MessagePackObject] [MessagePackObject]
[MapFrom(typeof(FinanceTransactionInsertDto))]
public partial struct FinanceTransaction public partial struct FinanceTransaction
{ {
[Key(1)] public int Id { get; set; } [Key(1)] public int Id { get; set; }

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Text;
using MapTo;
namespace BlueWest.Data
{
[MapFrom(typeof(FinanceTransaction))]
public partial struct FinanceTransactionInsertDto
{
public int UserId { get; }
public FinanceTransactionType FinanceTransactionType { get; }
public FinanceSymbol FinanceSymbol { get; }
public double Amount { get; } // To Buy
public double Quantity { get; } // Bought
public double Fee { get; }
public DateTime DateTime { get; }
public FinanceTransactionInsertDto(
int userId,
FinanceTransactionType financeTransactionType,
FinanceSymbol financeSymbol,
double amount ,
double quantity,
double fee,
DateTime dateTime)
{
UserId = userId;
FinanceTransactionType = financeTransactionType;
FinanceSymbol = financeSymbol;
Amount = amount;
Quantity = quantity;
Fee = fee;
DateTime = dateTime;
}
}
}

View File

@ -0,0 +1,63 @@

using System;
using System.Collections.Generic;
using System.Transactions;
using BlueWest.Collections;
using MapTo;
using MessagePack;
using Newtonsoft.Json;
using BlueWest.Collections;
namespace BlueWest.Data
{
[MessagePackObject]
[UseUpdate]
[MapFrom(typeof(UserUpdateDto))]
public partial class User
{
[Key(1)] public int Id { get; }
[Key(2)] public string Name { get; set; }
[Key(3)] public string Address { get; set; }
[Key(4)] public string BTCAddress { get; set; }
[Key(5)] public string LTCAddress { get; set; }
[Key(6)] public double BTCAmount { get; set; }
[Key(7)] public double LTCAmount { get; set; }
[Key(8)] public FastDictionary<FinanceTransaction> FinanceTransactions { get; set; }
public User(int id, string name, string address, string btcAddress, string ltcAddress, double btcAmount, double ltcAmount, FastList<FinanceTransaction> financeTransactions)
{
Id = id;
Name = name;
Address = address;
BTCAddress = btcAddress;
LTCAddress = ltcAddress;
BTCAmount = btcAmount;
LTCAmount = ltcAmount;
FinanceTransactions = financeTransactions;
}
public void AddTransaction(FinanceTransaction financeTransaction)
{
FinanceTransactions.Add(financeTransaction);
}
public void AddTransaction(FinanceTransactionInsertDto financeTransaction)
{
FinanceTransactions.Add(new FinanceTransaction(financeTransaction));
}
internal bool HasTransaction(int transactionId)
{
return FinanceTransactions.Contains(transactionId);
}
internal Transaction GetTransactionById(int transactionId)
{
return FinanceTransactions(transactionId);
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BlueWest.Data
{
public static class UserExtensions
{
public static bool UserHasTransaction(this User user, int transactionId)
{
return user.FinanceTransactions.Contains(transactionId);
}
}
}

119
BlueWest.Data/UserList.cs Normal file
View File

@ -0,0 +1,119 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Transactions;
using BlueWest.Collections;
using MessagePack;
namespace BlueWest.Data
{
[MessagePackObject]
public class UserList: DataObject
{
[Key(9)] public readonly FastDictionary<int, User> Users;
public int Length = 0;
public UserList(FastDictionary<int, User> users)
{
Users = users;
}
private int GetIndexById(int userId)
{
var keys = Users.Keys;
foreach (var key in keys)
{
if (key == userId) return key;
}
return -1;
}
internal DataQueryResult GetUserById(int id)
{
if (Users.ContainsKey(id)) return new PositiveResult<User>(Users[id]);
return new NegativeResult("Can't find a user with the provided id.");
}
internal bool RemoveUser(int userId)
{
if (Users.ContainsKey(userId))
{
Users.Remove(userId);
return true;
}
return false;
}
internal bool HasUser(int userId)
{
return Users.Contains(userId);
}
internal DataQueryResult UpdateUser(int userId, UserUpdateDto userUpdate)
{
Users[userId].Update(userUpdate);
return Users[userId];
}
internal bool UserHasTransaction(int userId, int transactionId) => HasUser(userId) && Users[userId].FinanceTransactions.Contains(transactionId);
internal DataQueryResult GetTransactionById(int userId, int transactionId)
{
if(!HasUser(userId)) return new NegativeResult("Can't find a user with the provided id.");
if (UserHasTransaction(userId, transactionId)) return new PositiveResult<Transaction>(Users[userId].FinanceTransactions[transactionId]);
return new NegativeResult("No transaction was found with the specified id");
}
internal User AddUser(int userId, UserUpdateDto userUpdateDto)
{
if (Users.ContainsKey(userId))
{
Users[userId].Update(userUpdateDto);
return Users[userId];
}
var id = userId != -1 ? userId : Length + 1;
var newUser = new User(userUpdateDto, id, new FastList<FinanceTransaction>());
Users.Add(Length, newUser);
Length++;
return newUser;
}
const string NoIdError = "No transaction was found with the specified id";
static NegativeResult NoIdResult = new NegativeResult(NoIdError);
internal DataQueryResult AddFinanceTransaction(int userId, FinanceTransactionInsertDto financeTransactionDto)
{
if (Users.ContainsKey(userId))
{
var financeTransaction = new FinanceTransaction(financeTransactionDto);
Users[userId].AddTransaction(financeTransaction);
return new PositiveResult<BlueWest.Data.FinanceTransaction>(financeTransaction);
}
return NoIdResult;
}
internal FastList<FinanceTransaction> GetUserTransactions(int userId)
{
if (Users.ContainsKey(userId))
{
return Users[userId].FinanceTransactions;
}
return new FastList<FinanceTransaction>();
}
}
}

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Grpc.Net.Client" Version="2.41.0" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\greet.proto">
<GrpcServices>Both</GrpcServices>
<Access>Public</Access>
<ProtoCompile>True</ProtoCompile>
<CompileOutputs>True</CompileOutputs>
<OutputDir>obj\Release\net5.0-windows\</OutputDir>
<Generator>MSBuild:Compile</Generator>
</Protobuf>
</ItemGroup>
</Project>

View File

@ -0,0 +1,16 @@
using System;
using Grpc.Net.Client;
namespace BlueWest.GrpcClient
{
class Program
{
static void Main()
{
var channel = GrpcChannel.ForAddress("https://localhost:5001");
//var client = new Greet.GreeterClient(channel);
Console.WriteLine("Hello, World!");
}
}
}

View File

@ -0,0 +1,13 @@
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}

View File

@ -1,18 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net5.0-windows</TargetFramework>
<LangVersion>9</LangVersion> <LangVersion>10</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" /> <PackageReference Include="Grpc.AspNetCore" Version="2.41.0" />
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.41.0" />
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.41.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.12" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.2.3" /> <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.2.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\BlueWest\BlueWest.csproj" /> <ProjectReference Include="..\BlueWest\BlueWest.csproj" />
<Protobuf Include="Protos\greet.proto" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,5 @@
using BlueWest.Data; using BlueWest.Core.Tests;
using BlueWest.WebApi.Tools; using BlueWest.Data;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using PerformanceSolution.Data; using PerformanceSolution.Data;
@ -10,14 +10,15 @@ namespace BlueWest.WebApi.Controllers
[Route("[controller]")] [Route("[controller]")]
public class UserController : ControllerBase public class UserController : ControllerBase
{ {
private UserList _userList => MemoryData.UserList;
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[HttpGet] [HttpGet]
public ActionResult Get() public ActionResult Get()
{ {
if (MemoryData.UserList != null) if (_userList != null)
{ {
return Ok(MemoryData.UserList); return Ok(_userList);
} }
@ -30,11 +31,11 @@ namespace BlueWest.WebApi.Controllers
[HttpGet("{userId}", Name = nameof(GetUserById))] [HttpGet("{userId}", Name = nameof(GetUserById))]
public ActionResult GetUserById(int userId) public ActionResult GetUserById(int userId)
{ {
User user = MemoryData.GetUserById(userId); User? user = MemoryData.GetUserById(userId);
if (user != null) if (user != null)
{ {
return Ok(user); return Ok(user.Value);
} }
@ -47,14 +48,8 @@ namespace BlueWest.WebApi.Controllers
[HttpGet("{userId}/transactions")] [HttpGet("{userId}/transactions")]
public ActionResult GetTransactions(int userId) public ActionResult GetTransactions(int userId)
{ {
var user = MemoryData.GetUserById(userId); var transactions = MemoryData.GetUserTransactions(userId);
var transactions = user.FinanceTransactions; return OK(transactions.ToDictionary());
if (transactions != null)
{
return Ok(transactions);
}
return new NotFoundResult();
} }
@ -63,7 +58,7 @@ namespace BlueWest.WebApi.Controllers
[HttpGet("{userId}/transactions/{transactionId}")] [HttpGet("{userId}/transactions/{transactionId}")]
public ActionResult GetTransactionsById(int userId, int transactionId) public ActionResult GetTransactionsById(int userId, int transactionId)
{ {
var user = MemoryData.GetUserById(userId); var user = MemoryData.UserList.GetUserById(userId);
var transactions = user?.FinanceTransactions; var transactions = user?.FinanceTransactions;
@ -91,7 +86,7 @@ namespace BlueWest.WebApi.Controllers
[HttpPut("{userId}")] [HttpPut("{userId}")]
public ActionResult UpdateUser(int userId, UserUpdateDto userUpdate) public ActionResult UpdateUser(int userId, UserUpdateDto userUpdate)
{ {
var result = MemoryData.UpdateUser(userId, userUpdate); var result = MemoryData.UserList.UpdateUser(userId, userUpdate);
if (result != null) return Ok(result); if (result != null) return Ok(result);
@ -103,8 +98,7 @@ namespace BlueWest.WebApi.Controllers
[HttpDelete("{id}")] [HttpDelete("{id}")]
public ActionResult DeleteUser(int id) public ActionResult DeleteUser(int id)
{ {
bool result = MemoryData.UserList.RemoveUser(id);
bool result = MemoryData.RemoveUser(id);
if (result) if (result)
{ {
@ -117,9 +111,9 @@ namespace BlueWest.WebApi.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]
[HttpPost("{userId}/transactions")] [HttpPost("{userId}/transactions")]
public ActionResult PostTransaction(int userId, FinanceTransaction financeTransaction) public ActionResult PostTransaction(int userId, FinanceTransactionInsertDto financeTransaction)
{ {
FinanceTransaction? result = MemoryData.AddFinanceTransaction(userId, financeTransaction); FinanceTransaction? result = MemoryData.UserList.AddFinanceTransaction(userId, financeTransaction);
if(result != null) return Ok(result); if(result != null) return Ok(result);

View File

@ -0,0 +1,13 @@
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}

View File

@ -0,0 +1,11 @@
using Microsoft.Extensions.Logging;
namespace BlueWest.WebApi.Service
{
public class GreeterService : Greeter.GreeterBase
{
public GreeterService(ILogger<GreeterService> logger)
{
}
}
}

View File

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BlueWest.WebApi.Service;
using BlueWest.WebApi.Tools; using BlueWest.WebApi.Tools;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -56,6 +57,8 @@ namespace BlueWest.WebApi
Version = "v1" Version = "v1"
}); });
}); });
services.AddGrpc();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -79,6 +82,8 @@ namespace BlueWest.WebApi
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>
{ {
endpoints.MapControllers(); endpoints.MapControllers();
endpoints.MapGrpcService<GreeterService>();
}); });
} }
} }

View File

@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlueWest.WebApi", "BlueWest
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlueWest.Collections", "BlueWest.Collections\BlueWest.Collections.csproj", "{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlueWest.Collections", "BlueWest.Collections\BlueWest.Collections.csproj", "{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.GrpcClient", "BlueWest.GrpcClient\BlueWest.GrpcClient.csproj", "{65A6A17A-EFFB-4750-8B80-3B0690CCA59F}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -33,6 +35,10 @@ Global
{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Debug|Any CPU.Build.0 = Debug|Any CPU {F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Release|Any CPU.ActiveCfg = Release|Any CPU {F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Release|Any CPU.Build.0 = Release|Any CPU {F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Release|Any CPU.Build.0 = Release|Any CPU
{65A6A17A-EFFB-4750-8B80-3B0690CCA59F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65A6A17A-EFFB-4750-8B80-3B0690CCA59F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65A6A17A-EFFB-4750-8B80-3B0690CCA59F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65A6A17A-EFFB-4750-8B80-3B0690CCA59F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -37,13 +37,16 @@ namespace BlueWest.Core
return eoDynamic; return eoDynamic;
} }
/*
private static T DictionaryToObject<T>(IDictionary<String, Object> dictionary) where T : class private static T DictionaryToObject<T>(IDictionary<String, Object> dictionary) where T : class
{ {
var dicToObj = DictionaryToObject(dictionary); var dicToObj = DictionaryToObject(dictionary);
return dicToObj as T; return dicToObj as T;
} }
*/
/*
public static T ToDto<T>(this object obj) where T: class public static T ToDto<T>(this object obj) where T: class
{ {
var objDic = obj.ToDictionary(); var objDic = obj.ToDictionary();
@ -61,6 +64,6 @@ namespace BlueWest.Core
} }
return dataInstance; return dataInstance;
} }*/
} }
} }

View File

@ -13,9 +13,9 @@ namespace BlueWest.Core.Tests
private static readonly ConcurrentDictionary<Type, Func<object, IDictionary<string, object>>> Converters = new ConcurrentDictionary<Type, Func<object, IDictionary<string, object>>>(); private static readonly ConcurrentDictionary<Type, Func<object, IDictionary<string, object>>> Converters = new ConcurrentDictionary<Type, Func<object, IDictionary<string, object>>>();
private static readonly ConstructorInfo DictionaryConstructor = typeof(Dictionary<string, object>).GetConstructors().FirstOrDefault(c => c.IsPublic && !c.GetParameters().Any()); private static readonly ConstructorInfo DictionaryConstructor = typeof(Dictionary<string, object>).GetConstructors().FirstOrDefault(c => c.IsPublic && !c.GetParameters().Any());
public static IDictionary<string, object> ToDictionary(this object obj) => obj == null ? null : Converters.GetOrAdd(obj.GetType(), o => public static IDictionary<int, object> ToDictionary(this object obj) => obj == null ? null : Converters.GetOrAdd(obj.GetType(), o =>
{ {
var outputType = typeof(IDictionary<string, object>); var outputType = typeof(IDictionary<int, object>);
var inputType = obj.GetType(); var inputType = obj.GetType();
var inputExpression = Expression.Parameter(typeof(object), "input"); var inputExpression = Expression.Parameter(typeof(object), "input");
var typedInputExpression = Expression.Convert(inputExpression, inputType); var typedInputExpression = Expression.Convert(inputExpression, inputType);
@ -27,14 +27,14 @@ namespace BlueWest.Core.Tests
}; };
body.AddRange( body.AddRange(
from prop in inputType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy) from prop in inputType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)
where prop.CanRead && (prop.PropertyType.IsPrimitive || prop.PropertyType == typeof(string)) where prop.CanRead && (prop.PropertyType.IsPrimitive || prop.PropertyType == typeof(int))
let getExpression = Expression.Property(typedInputExpression, prop.GetMethod) let getExpression = Expression.Property(typedInputExpression, prop.GetMethod)
let convertExpression = Expression.Convert(getExpression, typeof(object)) let convertExpression = Expression.Convert(getExpression, typeof(object))
select Expression.Call(outputVariable, AddToDicitonaryMethod, Expression.Constant(prop.Name), convertExpression)); select Expression.Call(outputVariable, AddToDicitonaryMethod, Expression.Constant(prop.Name), convertExpression));
body.Add(Expression.Return(returnTarget, outputVariable)); body.Add(Expression.Return(returnTarget, outputVariable));
body.Add(Expression.Label(returnTarget, Expression.Constant(null, outputType))); body.Add(Expression.Label(returnTarget, Expression.Constant(null, outputType)));
var lambdaExpression = Expression.Lambda<Func<object, IDictionary<string, object>>>( var lambdaExpression = Expression.Lambda<Func<object, IDictionary<int, object>>>(
Expression.Block(new[] { outputVariable }, body), Expression.Block(new[] { outputVariable }, body),
inputExpression); inputExpression);

View File

@ -1,9 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Transactions;
using System.Threading.Tasks;
using BlueWest.Collections; using BlueWest.Collections;
using BlueWest.Core;
using BlueWest.Data; using BlueWest.Data;
using PerformanceSolution.Tools; using PerformanceSolution.Tools;
@ -11,7 +9,7 @@ namespace PerformanceSolution.Data
{ {
public static class MemoryData public static class MemoryData
{ {
public static UserList UserList = new UserList(new List<User>()); public static UserList UserList = new UserList(new FastDictionary<int, User>());
private const string SavePathName = "userData"; private const string SavePathName = "userData";
@ -37,119 +35,44 @@ namespace PerformanceSolution.Data
public static void LoadUsers() public static void LoadUsers()
{ {
UserList = SaveLoadManager.Load<UserList>(SavePathName); UserList = SaveLoadManager.Load<UserList>(SavePathName);
UserList ??= new UserList(new List<User>()); UserList ??= new UserList(new FastDictionary<int, User>());
} }
public static User? GetUserById(int id) public static Transaction GetTransactionById(int userId, int transactionId) => UserList.GetTransactionById(userId, transactionId);
{
var user = UserList.Users.FirstOrDefault(user => user.Id == id);
//var d = new UserUpdateDto(user);
return user;
}
public static bool RemoveUser(int userId)
{
int index = GetIndexById(userId);
if (index == -1) return false;
UserList.Users.RemoveAt(index);
SaveUserList();
return true;
}
public static async Task AddUserAsync(User user) => await Task.Run(() => { AddOrModifyUser(user); });
private static int GetIndexById(int userId) => UserList.Users.FindIndex(row => row.Id == userId);
private static void SaveUserList() => SaveUserList(UserList); private static void SaveUserList() => SaveUserList(UserList);
public static void AddOrModifyUser(User user) public static User AddOrModifyUser(UserUpdateDto userUpdateDto, int userId = -1)
{ {
var index = GetIndexById(user.Id); return UserList.AddUser(userId, userUpdateDto);
if (index != -1)
{
UserList.Users[index] = user;
SaveUserList();
}
else
{
UserList.Users.Add(user);
SaveUserList();
}
}
public static User? AddOrModifyUser(UserUpdateDto userUpdateDto, int userId = -1)
{
var id = userId != -1 ? userId : UserList.Length + 1;
var index = GetIndexById(userId);
User? user;
if (index != -1)
{
user = GetUserById(id);
if (user == null) return user;
UserList.Users[index] = user;
SaveUserList();
}
else
{
user = new User(userUpdateDto);
UserList.Users.Add(user);
SaveUserList();
}
return user;
}
public static User? UpdateUser(int userId, UserUpdateDto userUpdate)
{
var index = GetIndexById(userId);
if (index == -1) return null;
var actualUser = GetUserById(userId);
if (actualUser == null) return null;
actualUser.Update(userUpdate);
UserList.Users[index] = actualUser;
SaveUserList();
return actualUser;
}
public static FinanceTransaction? AddFinanceTransaction(int userId, FinanceTransaction financeTransaction)
{
var user = GetUserById(userId);
if (user == null) return null;
user.AddTransaction(financeTransaction);
SaveUserList();
return financeTransaction;
} }
private static UserList GenerateMockData() private static UserList GenerateMockData()
{ {
var u = new User(1, "Rui Sousa", "Sagres", "NOADD", "NOADD", 0 , 0, new List<FinanceTransaction>()
{
new FinanceTransaction(0, 1, FinanceTransactionType.Buy, FinanceSymbol.BTC_EUR, 0, 0, 0.1, DateTime.Now) var transactions = new FastList<FinanceTransaction>();
}); var financeTransaction = new FinanceTransaction(0, 1, FinanceTransactionType.Buy, FinanceSymbol.BTC_EUR, 0,
var list = new List<User>(10); 0, 0.1, DateTime.Now);
list.Add(u); transactions.Add(financeTransaction);
var u = new User(1, "Rui Sousa", "Sagres", "NOADD", "NOADD", 0, 0, transactions);
var list = new FastDictionary<int, User>(10);
list.Add(0, u);
return new UserList(list); return new UserList(list);
} }
public static User? GetUserById(int userId)
{
return UserList.GetUserById(userId);
}
public static FastList<FinanceTransaction> GetUserTransactions(int userId)
{
return UserList.GetUserTransactions(userId);
}
} }
} }

2
MapTo

@ -1 +1 @@
Subproject commit 63b2bcb3593440fb332917bed7d6c78827195dbe Subproject commit 9470afb737d873f2fbbc631813eadf10032c5c6b