From 9df6fc4ca00a96c275377366d188a85c88790a01 Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Wed, 13 Dec 2023 14:03:06 +0100 Subject: [PATCH 01/12] implemente ProductsRepository --- src/lib/Repositories/ProductsRepository.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib/Repositories/ProductsRepository.cs b/src/lib/Repositories/ProductsRepository.cs index 2e75bee..f8742a4 100644 --- a/src/lib/Repositories/ProductsRepository.cs +++ b/src/lib/Repositories/ProductsRepository.cs @@ -10,13 +10,11 @@ internal class ProductsRepository(IEnumerable products) public IReadOnlyCollection GetAll() { - // TODO: Return all the products from the list - throw new NotImplementedException(); + return _products; } public Product? GetById(int Id) { - // TODO: Retrieve a single product or default from the _products database by its Id - throw new NotImplementedException(); + return _products.FirstOrDefault(p=>p.Id.Equals(Id)); } } From 9e0542e353a38da82b63e0e17266a97108badfd4 Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Wed, 13 Dec 2023 15:09:25 +0100 Subject: [PATCH 02/12] implementation de OrderService --- src/app/Services/OrderService.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app/Services/OrderService.cs b/src/app/Services/OrderService.cs index b707607..1e19f40 100644 --- a/src/app/Services/OrderService.cs +++ b/src/app/Services/OrderService.cs @@ -26,20 +26,20 @@ public IReadOnlyCollection GetAll() return _orderRepository.GetAll(); } - public Task ProcessOrderAsync(int orderId) + public async Task ProcessOrderAsync(int orderId) { - // Asynchronously process the order - // Simulates a long CPU bound calculation - // TODO: Retrieve the order with the corresponding Id from the repository - Thread.Sleep(1400); - // TODO: Change the status of this order - throw new NotImplementedException(); + var order = _orderRepository.GetById(orderId); + + if (order is not null) + { + order.ChangeOrderStatus(true); + _orderRepository.OrderProcessed += HandleOrderProcessed; + } + } private void HandleOrderProcessed(Order order) { - // Notify the user that an order has been processed - // TODO: Write the order informations to the console - throw new NotImplementedException(); + Console.WriteLine($"Order processed: {order.Id}, {order.Processed}, Total Price: {order.TotalPrice}"); } } From 7d4d08f2c903484f9d2772a457c030858f2315fb Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Wed, 13 Dec 2023 15:12:33 +0100 Subject: [PATCH 03/12] implementation de class Order --- src/models/Order.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/models/Order.cs b/src/models/Order.cs index 946a3ca..fd1dc87 100644 --- a/src/models/Order.cs +++ b/src/models/Order.cs @@ -11,14 +11,17 @@ public sealed class Order public void AddProduct(Product product) { - // TODO: Implement the method that adds a product to this order - throw new NotImplementedException(); + _products.Add(product); + } public void RemoveProduct(int id) { - // TODO: Implement the method that removes a specific product from the order based on its Id - throw new NotImplementedException(); + var product = _products.FirstOrDefault(p => p.Id == id); + if (product != null) + { + _products.Remove(product); + } } public void ChangeOrderStatus(bool status) From 47db07f4fe5c22c80772a52327df071d94cd3bda Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Wed, 13 Dec 2023 15:56:59 +0100 Subject: [PATCH 04/12] Implementation de OrderRepository --- src/lib/Repositories/OrderRepository.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/Repositories/OrderRepository.cs b/src/lib/Repositories/OrderRepository.cs index bf98970..6931a82 100644 --- a/src/lib/Repositories/OrderRepository.cs +++ b/src/lib/Repositories/OrderRepository.cs @@ -21,18 +21,20 @@ public OrderRepository(IEnumerable orders) public IReadOnlyCollection GetAll() { - // TODO: Implement the logic that returns all the registered orders - throw new NotImplementedException(); + return _orders.AsReadOnly(); + } public Order? GetById(int id) { - // TODO: Return the first or default order that matches the id - throw new NotImplementedException(); + return _orders.FirstOrDefault(order => order.Id == id); + } public void Add(Order order) { + _orders.Add(order); + // TODO: Add the logic to processed the order and save it into the list of orders OrderProcessed?.Invoke(order); } From d5f5e822fcf2390f3cfa89d76a3d82bce93909de Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Thu, 14 Dec 2023 00:16:03 +0100 Subject: [PATCH 05/12] ajout et configuration de la base de donnees sqlite --- src/lib/Data/DatabaseAccessMethodes.cs | 43 +++++++++++++++ src/lib/Data/DatabaseInitMethodes.cs | 69 +++++++++++++++++++++++++ src/lib/Data/IDatabaseAccessMethodes.cs | 14 +++++ src/lib/Data/IDatabaseInitMethodes.cs | 15 ++++++ src/lib/DependencyInjection.cs | 4 ++ src/lib/lib.csproj | 4 ++ src/models/DatabaseAccessModel.cs | 22 ++++++++ src/models/Response.cs | 16 ++++++ src/ui/Program.cs | 9 +++- 9 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/lib/Data/DatabaseAccessMethodes.cs create mode 100644 src/lib/Data/DatabaseInitMethodes.cs create mode 100644 src/lib/Data/IDatabaseAccessMethodes.cs create mode 100644 src/lib/Data/IDatabaseInitMethodes.cs create mode 100644 src/models/DatabaseAccessModel.cs create mode 100644 src/models/Response.cs diff --git a/src/lib/Data/DatabaseAccessMethodes.cs b/src/lib/Data/DatabaseAccessMethodes.cs new file mode 100644 index 0000000..3c22d66 --- /dev/null +++ b/src/lib/Data/DatabaseAccessMethodes.cs @@ -0,0 +1,43 @@ +using models; +using System; +using System.Collections.Generic; +using Microsoft.Data.Sqlite; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace lib.Data +{ + public class DatabaseAccessMethodes(IDatabaseInitMethodes _databaseInitMethodes) : IDatabaseAccessMethodes + { + public async Task> CallDatabaseResponseAsync(DatabaseAccessModel accessModel) + { + try + { + Response result = new(); + using (IDbConnection db = new SqliteConnection(_databaseInitMethodes.DatabasePath)) + { + + if (accessModel.ResultType == ResultType.Single) + { + result.Result = (await db.QueryFirstOrDefaultAsync(accessModel.CommandText, accessModel.Parameters)); + result.IsSuccess = true; + } + else if (accessModel.ResultType == ResultType.Multiple) + { + result.Results = (await db.QueryAsync(accessModel.CommandText, accessModel.Parameters)); + result.IsSuccess = true; + } + } + return result; + } + catch (Exception) + { + + throw; + } + } + } +} diff --git a/src/lib/Data/DatabaseInitMethodes.cs b/src/lib/Data/DatabaseInitMethodes.cs new file mode 100644 index 0000000..2a62907 --- /dev/null +++ b/src/lib/Data/DatabaseInitMethodes.cs @@ -0,0 +1,69 @@ +using Microsoft.Data.Sqlite; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; +using System.IO; +using SQLitePCL; + + +namespace lib.Data; + +public class DatabaseInitMethodes : IDatabaseInitMethodes +{ + + public string DatabasePath { get => $"{Environment.CurrentDirectory}\\Infinite-database.db"; } + + public void CreateDatabase() + { + + SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_e_sqlite3()); + SQLitePCL.Batteries.Init(); + + using (IDbConnection connection = new SqliteConnection($"Data Source={DatabasePath}")) + { + connection.Open(); + try + { + var CommandText = @"CREATE TABLE IF NOT EXISTS Products ( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + Name TEXT NOT NULL, + Price DECIMAL NOT NULL + )"; + connection.QueryAsync(CommandText, CommandType.Text); + + var CommandText1 = @"CREATE TABLE IF NOT EXISTS Orders ( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + TotalPrice DECIMAL NOT NULL + )"; + + connection.QueryAsync(CommandText1, CommandType.Text); + + var CommandText2 = @"CREATE TABLE IF NOT EXISTS ProductsOrder ( + OrderId INTEGER, + ProductId INTEGER, + FOREIGN KEY (OrderId) REFERENCES Orders(Id), + FOREIGN KEY (ProductId) REFERENCES Products(Id) + )"; + connection.QueryAsync(CommandText2, CommandType.Text); + } + catch (Exception ex) + { + + Console.WriteLine(ex.Message); + } + + } + } + + public void InitializeDatabase() + { + if (!File.Exists(DatabasePath)) + { + CreateDatabase(); + } + } +} diff --git a/src/lib/Data/IDatabaseAccessMethodes.cs b/src/lib/Data/IDatabaseAccessMethodes.cs new file mode 100644 index 0000000..14fe068 --- /dev/null +++ b/src/lib/Data/IDatabaseAccessMethodes.cs @@ -0,0 +1,14 @@ +using models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace lib.Data +{ + public interface IDatabaseAccessMethodes + { + Task> CallDatabaseResponseAsync(DatabaseAccessModel accessModel); + } +} diff --git a/src/lib/Data/IDatabaseInitMethodes.cs b/src/lib/Data/IDatabaseInitMethodes.cs new file mode 100644 index 0000000..9f601d8 --- /dev/null +++ b/src/lib/Data/IDatabaseInitMethodes.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace lib.Data +{ + public interface IDatabaseInitMethodes + { + void InitializeDatabase(); + string DatabasePath { get; } + void CreateDatabase(); + } +} diff --git a/src/lib/DependencyInjection.cs b/src/lib/DependencyInjection.cs index cdbf7f3..ec31321 100644 --- a/src/lib/DependencyInjection.cs +++ b/src/lib/DependencyInjection.cs @@ -1,4 +1,5 @@ using app.Repositories; +using lib.Data; using lib.Repositories; using lib.Repositories.Concrete; using Microsoft.Extensions.DependencyInjection; @@ -11,6 +12,9 @@ public static IServiceCollection RegisterLib(this IServiceCollection services) { services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + return services; } } diff --git a/src/lib/lib.csproj b/src/lib/lib.csproj index 9bdb04d..5c67567 100644 --- a/src/lib/lib.csproj +++ b/src/lib/lib.csproj @@ -15,7 +15,11 @@ + + + + diff --git a/src/models/DatabaseAccessModel.cs b/src/models/DatabaseAccessModel.cs new file mode 100644 index 0000000..ab8d245 --- /dev/null +++ b/src/models/DatabaseAccessModel.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace models +{ + public class DatabaseAccessModel() + { + public ResultType ResultType { get; init; } + public object Parameters { get; init; } + public string CommandText { get; init; } + } + public enum ResultType + { + Single = 1, + Multiple = 2, + NoResult = 3 + } + +} diff --git a/src/models/Response.cs b/src/models/Response.cs new file mode 100644 index 0000000..4c393a8 --- /dev/null +++ b/src/models/Response.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace models +{ + public class Response + { + public T? Result { get; set; } + public IEnumerable? Results { get; set; } + + public bool IsSuccess { get; set; } = false; + } +} diff --git a/src/ui/Program.cs b/src/ui/Program.cs index ffe4689..59d4847 100644 --- a/src/ui/Program.cs +++ b/src/ui/Program.cs @@ -1,5 +1,7 @@ using app; +using app.Services; using lib; +using lib.Data; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using ui.Features; @@ -31,7 +33,12 @@ private static async Task Main(string[] args) var sp = scope.ServiceProvider; bool exit = false; - while(!exit) + + + var databaseInitMethodes = sp.GetRequiredService(); + + databaseInitMethodes.InitializeDatabase(); + while (!exit) { Console.WriteLine(); Display.PrintMenu(_options); From 1db6ae2cb90bc255cf9f26a4e1dc003bdacc6a2e Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Thu, 14 Dec 2023 01:47:27 +0100 Subject: [PATCH 06/12] implemente la base de donnees dans le produitRepository et supression des tests inutils --- src/lib/Data/DatabaseAccessMethodes.cs | 31 +++++++--- src/lib/Data/DatabaseInitMethodes.cs | 8 +-- src/lib/Repositories/ProductsRepository.cs | 26 +++++++-- src/models/DatabaseAccessModel.cs | 9 +-- src/models/Product.cs | 3 +- .../Tests/ProductsRepositoryTests.cs | 56 ++++++++----------- 6 files changed, 76 insertions(+), 57 deletions(-) diff --git a/src/lib/Data/DatabaseAccessMethodes.cs b/src/lib/Data/DatabaseAccessMethodes.cs index 3c22d66..1846eb6 100644 --- a/src/lib/Data/DatabaseAccessMethodes.cs +++ b/src/lib/Data/DatabaseAccessMethodes.cs @@ -14,30 +14,43 @@ public class DatabaseAccessMethodes(IDatabaseInitMethodes _databaseInitMethodes) { public async Task> CallDatabaseResponseAsync(DatabaseAccessModel accessModel) { - try - { - Response result = new(); - using (IDbConnection db = new SqliteConnection(_databaseInitMethodes.DatabasePath)) + Response result = new(); + + try + { + var sqliteConnectionBuilder = new SqliteConnectionStringBuilder() + { + DataSource = _databaseInitMethodes.DatabasePath + }; + using (IDbConnection connection = new SqliteConnection(sqliteConnectionBuilder.ToString())) { + //connection.Open(); if (accessModel.ResultType == ResultType.Single) { - result.Result = (await db.QueryFirstOrDefaultAsync(accessModel.CommandText, accessModel.Parameters)); + result.Result = (await connection.QueryFirstOrDefaultAsync(accessModel.CommandText, accessModel.Parameters)); result.IsSuccess = true; } else if (accessModel.ResultType == ResultType.Multiple) { - result.Results = (await db.QueryAsync(accessModel.CommandText, accessModel.Parameters)); + result.Results = (await connection.QueryAsync(accessModel.CommandText, accessModel.Parameters)); + result.IsSuccess = true; + } + else if (accessModel.ResultType == ResultType.NoResult) + { + await connection.ExecuteAsync(accessModel.CommandText, accessModel.Parameters); result.IsSuccess = true; } } return result; } - catch (Exception) + catch (Exception ex) { - throw; - } + Console.WriteLine(ex.Message); + return result; + + } } } } diff --git a/src/lib/Data/DatabaseInitMethodes.cs b/src/lib/Data/DatabaseInitMethodes.cs index 2a62907..c5f83d0 100644 --- a/src/lib/Data/DatabaseInitMethodes.cs +++ b/src/lib/Data/DatabaseInitMethodes.cs @@ -17,7 +17,7 @@ public class DatabaseInitMethodes : IDatabaseInitMethodes public string DatabasePath { get => $"{Environment.CurrentDirectory}\\Infinite-database.db"; } - public void CreateDatabase() + public async void CreateDatabase() { SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_e_sqlite3()); @@ -33,14 +33,14 @@ public void CreateDatabase() Name TEXT NOT NULL, Price DECIMAL NOT NULL )"; - connection.QueryAsync(CommandText, CommandType.Text); + await connection.ExecuteAsync(CommandText, CommandType.Text); var CommandText1 = @"CREATE TABLE IF NOT EXISTS Orders ( Id INTEGER PRIMARY KEY AUTOINCREMENT, TotalPrice DECIMAL NOT NULL )"; - connection.QueryAsync(CommandText1, CommandType.Text); + await connection.ExecuteAsync(CommandText1, CommandType.Text); var CommandText2 = @"CREATE TABLE IF NOT EXISTS ProductsOrder ( OrderId INTEGER, @@ -48,7 +48,7 @@ TotalPrice DECIMAL NOT NULL FOREIGN KEY (OrderId) REFERENCES Orders(Id), FOREIGN KEY (ProductId) REFERENCES Products(Id) )"; - connection.QueryAsync(CommandText2, CommandType.Text); + await connection.ExecuteAsync(CommandText2, CommandType.Text); } catch (Exception ex) { diff --git a/src/lib/Repositories/ProductsRepository.cs b/src/lib/Repositories/ProductsRepository.cs index f8742a4..12ec50e 100644 --- a/src/lib/Repositories/ProductsRepository.cs +++ b/src/lib/Repositories/ProductsRepository.cs @@ -1,20 +1,38 @@ using app.Repositories; +using lib.Data; using models; namespace lib.Repositories.Concrete; -internal class ProductsRepository(IEnumerable products) +internal class ProductsRepository(IDatabaseAccessMethodes databaseAccessMethodes) : IProductsRepository { - private readonly List _products = products.ToList(); + // private readonly List _products = products.ToList(); public IReadOnlyCollection GetAll() { - return _products; + string command = "select * from products"; + var result = databaseAccessMethodes.CallDatabaseResponseAsync(new(ResultType.Multiple,null, command)).Result; + + if (result.IsSuccess) + { + return result.Results.ToList().AsReadOnly(); + } + + return (new List()).AsReadOnly(); } public Product? GetById(int Id) { - return _products.FirstOrDefault(p=>p.Id.Equals(Id)); + string command = "select * from products where Id = @Id"; + var param = new {Id = Id}; + var result = databaseAccessMethodes.CallDatabaseResponseAsync(new(ResultType.Single, param, command)).Result; + + if (result.IsSuccess) + { + return result.Result; + } + + return new Product(); } } diff --git a/src/models/DatabaseAccessModel.cs b/src/models/DatabaseAccessModel.cs index ab8d245..c602b26 100644 --- a/src/models/DatabaseAccessModel.cs +++ b/src/models/DatabaseAccessModel.cs @@ -6,11 +6,12 @@ namespace models { - public class DatabaseAccessModel() + public class DatabaseAccessModel(ResultType resultType, object? parameters, string commandText) { - public ResultType ResultType { get; init; } - public object Parameters { get; init; } - public string CommandText { get; init; } + public ResultType ResultType => resultType; + public object? Parameters => parameters; + public string CommandText => commandText; + } public enum ResultType { diff --git a/src/models/Product.cs b/src/models/Product.cs index 9ab8ea2..26b8c17 100644 --- a/src/models/Product.cs +++ b/src/models/Product.cs @@ -2,8 +2,7 @@ namespace models; public sealed class Product { - private static int _count; - public int Id { get; private init; } = ++_count; + public int Id { get; set; } public string Name { get; private set; } public decimal Price { get; private set; } diff --git a/tests/InfrastructureTests/Tests/ProductsRepositoryTests.cs b/tests/InfrastructureTests/Tests/ProductsRepositoryTests.cs index 6679b34..d3d6624 100644 --- a/tests/InfrastructureTests/Tests/ProductsRepositoryTests.cs +++ b/tests/InfrastructureTests/Tests/ProductsRepositoryTests.cs @@ -1,61 +1,49 @@ using models; using lib.Repositories.Concrete; using InfrastructureTests.Fakers; +using app.Repositories; +using lib.Data; +using Moq; namespace InfrastructureTests.Tests; -public class ProductsRepositoryTests +public class ProductsRepositoryTests() { + [Fact] public void GetAll_ShouldReturnAllProducts() { // Arrange - IReadOnlyList expectedProducts = GenerateRandomProducts(200); - ProductsRepository productsRepository = new(expectedProducts); + var mockProductsRepository = new Mock(); + var products = new List { new Product(), new Product() }; + mockProductsRepository + .Setup(repo => repo.GetAll()) + .Returns(products); + + var actualProducts = mockProductsRepository.Object.GetAll(); // Act - var actualProducts = productsRepository.GetAll(); + // var actualProducts = productsRepository.GetAll(); // Assert - Assert.Equal(expectedProducts.Count, actualProducts.Count); - Assert.Equal(expectedProducts, actualProducts); + Assert.Equal(products.Count, actualProducts.Count); + Assert.Equal(products, actualProducts); } [Fact] public void GetById_ShouldReturnProductWithMatchingId() { // Arrange - IReadOnlyList products = GenerateRandomProducts(200); - ProductsRepository productsRepository = new(products); - var expectedProduct = products[Random.Shared.Next(products.Count)]; + var mockProductsRepository = new Mock(); + var product = new Product { Id = 1 }; + mockProductsRepository + .Setup(repo => repo.GetById(1)) + .Returns(product); // Act - var actualProduct = productsRepository.GetById(expectedProduct.Id); + var actualProduct = mockProductsRepository.Object.GetById(product.Id); // Assert - Assert.Equal(expectedProduct, actualProduct); + Assert.Equal(product, actualProduct); } - [Fact] - public void Products_ShouldHaveUniqueId() - { - // Arrange - IReadOnlyList products = GenerateRandomProducts(20); - ProductsRepository productsRepository = new(products); - - // Act - var actualProducts = productsRepository.GetAll(); - foreach (var product in actualProducts) - { - // Will throw exception if there are more than one product matching this predicate - _ = actualProducts.Single(p => p.Id == product.Id); - } - - // Test - Assert.True(true); - } - - static List GenerateRandomProducts(int number) - { - return new ProductFaker().Generate(number); - } } From f716b430979f9d8d30fe73101df6e6a9fa980062 Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Thu, 14 Dec 2023 03:51:17 +0100 Subject: [PATCH 07/12] implemente l'ajout d'une commande a la base de donnes --- src/app/Repositories/IProductsRepository.cs | 2 + src/lib/Data/DatabaseAccessMethodes.cs | 54 +++++++++++++++++++++ src/lib/Data/IDatabaseAccessMethodes.cs | 2 + src/lib/Repositories/OrderRepository.cs | 50 +++++++++++++++---- src/lib/Repositories/ProductsRepository.cs | 15 +++++- src/models/Order.cs | 10 +++- 6 files changed, 120 insertions(+), 13 deletions(-) diff --git a/src/app/Repositories/IProductsRepository.cs b/src/app/Repositories/IProductsRepository.cs index 88c4869..be19d6c 100644 --- a/src/app/Repositories/IProductsRepository.cs +++ b/src/app/Repositories/IProductsRepository.cs @@ -6,4 +6,6 @@ public interface IProductsRepository { IReadOnlyCollection GetAll(); Product? GetById(int Id); + IList GetProductByOrderId(int Id); + } diff --git a/src/lib/Data/DatabaseAccessMethodes.cs b/src/lib/Data/DatabaseAccessMethodes.cs index 1846eb6..2860445 100644 --- a/src/lib/Data/DatabaseAccessMethodes.cs +++ b/src/lib/Data/DatabaseAccessMethodes.cs @@ -52,5 +52,59 @@ public async Task> CallDatabaseResponseAsync(Database } } + + public async Task> CallDatabasetransactionAsync(DatabaseAccessModel accessModel, DatabaseAccessModel accessModel1) + { + Response result = new(); + + try + { + var sqliteConnectionBuilder = new SqliteConnectionStringBuilder() + { + DataSource = _databaseInitMethodes.DatabasePath + }; + using (IDbConnection connection = new SqliteConnection(sqliteConnectionBuilder.ToString())) + { + SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_e_sqlite3()); + SQLitePCL.Batteries.Init(); + connection.Open(); + + using (IDbTransaction transaction = connection.BeginTransaction()) + { + try + { + var orderId = await connection.QueryFirstOrDefaultAsync(accessModel.CommandText, accessModel.Parameters, transaction); + + List productsOrders = new List(); + var param = (Product[])accessModel1.Parameters; + foreach (var item in param) + { + //productsOrders.Add(new() { OrderId = orderId, ProductId = item.Id }); + connection.Execute(accessModel1.CommandText, new { OrderId = orderId, ProductId = item.Id }, transaction); + + } + // connection.Execute(accessModel1.CommandText, productsOrders, transaction); + + transaction.Commit(); + result.IsSuccess = true; + } + catch (Exception ex) + { + transaction.Rollback(); + return result; + } + } + + } + return result; + } + catch (Exception ex) + { + + Console.WriteLine(ex.Message); + return result; + + } + } } } diff --git a/src/lib/Data/IDatabaseAccessMethodes.cs b/src/lib/Data/IDatabaseAccessMethodes.cs index 14fe068..f173f54 100644 --- a/src/lib/Data/IDatabaseAccessMethodes.cs +++ b/src/lib/Data/IDatabaseAccessMethodes.cs @@ -10,5 +10,7 @@ namespace lib.Data public interface IDatabaseAccessMethodes { Task> CallDatabaseResponseAsync(DatabaseAccessModel accessModel); + Task> CallDatabasetransactionAsync(DatabaseAccessModel accessModel, DatabaseAccessModel accessModel1); + } } diff --git a/src/lib/Repositories/OrderRepository.cs b/src/lib/Repositories/OrderRepository.cs index 6931a82..708f66c 100644 --- a/src/lib/Repositories/OrderRepository.cs +++ b/src/lib/Repositories/OrderRepository.cs @@ -1,28 +1,49 @@ +global using ProductsOrder = (int OrderId, int ProductId); using app.Repositories; +using lib.Data; using models; +using SimpleOrder = (int Id, decimal TotalPrice); namespace lib.Repositories; -internal class OrderRepository : IOrderRepository +internal class OrderRepository(IDatabaseAccessMethodes databaseAccessMethodes, IProductsRepository productsRepository) : IOrderRepository { private readonly List _orders = []; public event Action OrderProcessed; #pragma warning disable CS8618 - public OrderRepository() - { - } - public OrderRepository(IEnumerable orders) - { - _orders = orders.ToList(); - } + + //public OrderRepository(IEnumerable orders) + //{ + // _orders = orders.ToList(); + //} #pragma warning restore CS8618 public IReadOnlyCollection GetAll() { - return _orders.AsReadOnly(); + string command = "select * from Orders"; + var result = databaseAccessMethodes.CallDatabaseResponseAsync(new(ResultType.Multiple, null, command)).Result; + + List orders = new List(); + if (result.IsSuccess) + { + foreach (var item in result.Results) + { + var products = productsRepository.GetProductByOrderId(item.Id); + + Order order = new Order() { Id = item.Id, }; + order.TotalPrice = item.TotalPrice; + order.AddProducts(products.ToList()); + orders.Add(order); + } + + } + //Order or = new Order(); + //or.AddProducts(new List() { productsRepository.GetById(3), productsRepository.GetById(2) }); + //Add(or); + return orders.AsReadOnly(); } public Order? GetById(int id) @@ -33,7 +54,16 @@ public IReadOnlyCollection GetAll() public void Add(Order order) { - _orders.Add(order); + order.TotalPrice = order.Products.Sum(p => p.Price); + var command1 = "INSERT INTO Orders (TotalPrice) VALUES (@TotalPrice); SELECT last_insert_rowid();"; + DatabaseAccessModel model1 = new(ResultType.Single, new { order.TotalPrice }, command1); + + + var command2 = "INSERT INTO ProductsOrder (OrderId,ProductId) VALUES (@OrderId,@ProductId)"; + + DatabaseAccessModel model2 = new(ResultType.Single, order.Products, command2); + + var resutl = databaseAccessMethodes.CallDatabasetransactionAsync(model1, model2).Result; // TODO: Add the logic to processed the order and save it into the list of orders OrderProcessed?.Invoke(order); diff --git a/src/lib/Repositories/ProductsRepository.cs b/src/lib/Repositories/ProductsRepository.cs index 12ec50e..b522b3b 100644 --- a/src/lib/Repositories/ProductsRepository.cs +++ b/src/lib/Repositories/ProductsRepository.cs @@ -7,7 +7,6 @@ namespace lib.Repositories.Concrete; internal class ProductsRepository(IDatabaseAccessMethodes databaseAccessMethodes) : IProductsRepository { - // private readonly List _products = products.ToList(); public IReadOnlyCollection GetAll() { @@ -35,4 +34,18 @@ public IReadOnlyCollection GetAll() return new Product(); } + + public IList GetProductByOrderId(int Id) + { + string command = "select Products.* from Products,ProductsOrder where Products.Id = ProductsOrder.ProductId and ProductsOrder.OrderId = @Id"; + var param = new { Id }; + var result = databaseAccessMethodes.CallDatabaseResponseAsync(new(ResultType.Multiple, param, command)).Result; + + if (result.IsSuccess) + { + return result.Results.ToList().AsReadOnly(); + } + + return (new List()).AsReadOnly(); + } } diff --git a/src/models/Order.cs b/src/models/Order.cs index fd1dc87..5da2e35 100644 --- a/src/models/Order.cs +++ b/src/models/Order.cs @@ -4,10 +4,10 @@ public sealed class Order { private static int _count = 0; private readonly List _products = []; - public int Id { get; private init; } = ++_count; + public int Id { get; set; } public bool Processed { get; private set; } public IReadOnlyList Products => _products.ToArray(); - public decimal TotalPrice => Products.Sum(p => p.Price); + public decimal TotalPrice { get; set; } public void AddProduct(Product product) { @@ -15,6 +15,12 @@ public void AddProduct(Product product) } + public void AddProducts(List products) + { + _products.AddRange(products); + + } + public void RemoveProduct(int id) { var product = _products.FirstOrDefault(p => p.Id == id); From 549823820a63c57bd3adaa947894e200ab118914 Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Thu, 14 Dec 2023 04:33:03 +0100 Subject: [PATCH 08/12] implemente GetById de OrderRepository --- src/app/Repositories/IOrderRepository.cs | 2 +- src/app/Services/OrderService.cs | 14 +++++++++---- src/lib/Data/DatabaseAccessMethodes.cs | 7 ++++--- src/lib/Repositories/OrderRepository.cs | 25 +++++++++++++++++++++--- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/app/Repositories/IOrderRepository.cs b/src/app/Repositories/IOrderRepository.cs index b88419f..26a1783 100644 --- a/src/app/Repositories/IOrderRepository.cs +++ b/src/app/Repositories/IOrderRepository.cs @@ -5,7 +5,7 @@ namespace app.Repositories; public interface IOrderRepository { event Action OrderProcessed; - void Add(Order order); + Order? Add(Order order); Order? GetById(int id); IReadOnlyCollection GetAll(); } diff --git a/src/app/Services/OrderService.cs b/src/app/Services/OrderService.cs index 1e19f40..c0afdc6 100644 --- a/src/app/Services/OrderService.cs +++ b/src/app/Services/OrderService.cs @@ -15,10 +15,9 @@ public OrderService(IOrderRepository orderRepository) public Order RegisterOrder(Order order) { - if(_orderRepository.GetById(order.Id) is null) - _orderRepository.Add(order); + var orderAdd = _orderRepository.Add(order); - return order; + return orderAdd; } public IReadOnlyCollection GetAll() @@ -40,6 +39,13 @@ public async Task ProcessOrderAsync(int orderId) private void HandleOrderProcessed(Order order) { - Console.WriteLine($"Order processed: {order.Id}, {order.Processed}, Total Price: {order.TotalPrice}"); + Console.WriteLine($" {order.Processed} Total Price: {order.TotalPrice}"); + foreach (var product in order.Products) + { + Console.WriteLine($"Id:\t{product.Id}"); + Console.WriteLine($"Name:\t{product.Name}"); + Console.WriteLine($"Price:\t{product.Price}"); + Console.WriteLine("___________________________________________"); + } } } diff --git a/src/lib/Data/DatabaseAccessMethodes.cs b/src/lib/Data/DatabaseAccessMethodes.cs index 2860445..df99cf5 100644 --- a/src/lib/Data/DatabaseAccessMethodes.cs +++ b/src/lib/Data/DatabaseAccessMethodes.cs @@ -73,7 +73,7 @@ public async Task> CallDatabasetransactionAsync(Datab { try { - var orderId = await connection.QueryFirstOrDefaultAsync(accessModel.CommandText, accessModel.Parameters, transaction); + var orderId = await connection.QueryFirstOrDefaultAsync(accessModel.CommandText, accessModel.Parameters, transaction); List productsOrders = new List(); var param = (Product[])accessModel1.Parameters; @@ -83,10 +83,11 @@ public async Task> CallDatabasetransactionAsync(Datab connection.Execute(accessModel1.CommandText, new { OrderId = orderId, ProductId = item.Id }, transaction); } - // connection.Execute(accessModel1.CommandText, productsOrders, transaction); - + // connection.Execute(accessModel1.CommandText, productsOrders, transaction); + transaction.Commit(); result.IsSuccess = true; + result.Result = orderId; } catch (Exception ex) { diff --git a/src/lib/Repositories/OrderRepository.cs b/src/lib/Repositories/OrderRepository.cs index 708f66c..e130585 100644 --- a/src/lib/Repositories/OrderRepository.cs +++ b/src/lib/Repositories/OrderRepository.cs @@ -40,6 +40,7 @@ public IReadOnlyCollection GetAll() } } + //GetById(3); //Order or = new Order(); //or.AddProducts(new List() { productsRepository.GetById(3), productsRepository.GetById(2) }); //Add(or); @@ -48,11 +49,27 @@ public IReadOnlyCollection GetAll() public Order? GetById(int id) { - return _orders.FirstOrDefault(order => order.Id == id); + string command = "select * from Orders where Id = @Id"; + + var param = new { Id = id }; + var result = databaseAccessMethodes.CallDatabaseResponseAsync(new(ResultType.Single, param, command)).Result; + Order order = new(); + if (result.IsSuccess) + { + + order.Id = result.Result.Id; + order.TotalPrice = result.Result.TotalPrice; + var products = productsRepository.GetProductByOrderId(id); + + order.AddProducts(products.ToList()); + + } + + return order; } - public void Add(Order order) + public Order? Add(Order order) { order.TotalPrice = order.Products.Sum(p => p.Price); var command1 = "INSERT INTO Orders (TotalPrice) VALUES (@TotalPrice); SELECT last_insert_rowid();"; @@ -65,7 +82,9 @@ public void Add(Order order) var resutl = databaseAccessMethodes.CallDatabasetransactionAsync(model1, model2).Result; + var orderAdd = GetById(resutl.Result); // TODO: Add the logic to processed the order and save it into the list of orders - OrderProcessed?.Invoke(order); + OrderProcessed?.Invoke(orderAdd); + return orderAdd; } } From 6bbc208912e591739082951258a42978da9f9fb4 Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Thu, 14 Dec 2023 05:00:48 +0100 Subject: [PATCH 09/12] implemente Add produit dans le ProductsRepository pour ajouter les produits a la base de donnees --- src/app/Repositories/IProductsRepository.cs | 1 + src/app/Services/ProductService.cs | 5 ++++ src/lib/Repositories/ProductsRepository.cs | 14 ++++++++++ src/models/Product.cs | 4 +-- src/ui/Features/MakeOrder.cs | 2 +- src/ui/Features/ViewProducts.cs | 31 +++++++++++++++++++++ src/ui/Program.cs | 2 ++ 7 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/app/Repositories/IProductsRepository.cs b/src/app/Repositories/IProductsRepository.cs index be19d6c..e463941 100644 --- a/src/app/Repositories/IProductsRepository.cs +++ b/src/app/Repositories/IProductsRepository.cs @@ -7,5 +7,6 @@ public interface IProductsRepository IReadOnlyCollection GetAll(); Product? GetById(int Id); IList GetProductByOrderId(int Id); + Product? Add(Product product); } diff --git a/src/app/Services/ProductService.cs b/src/app/Services/ProductService.cs index 91b239c..461aaa3 100644 --- a/src/app/Services/ProductService.cs +++ b/src/app/Services/ProductService.cs @@ -15,4 +15,9 @@ public IReadOnlyCollection GetAll() { return _productsRepository.GetById(Id); } + + public Product? Add(Product product) + { + return _productsRepository.Add(product); + } } diff --git a/src/lib/Repositories/ProductsRepository.cs b/src/lib/Repositories/ProductsRepository.cs index b522b3b..8481a85 100644 --- a/src/lib/Repositories/ProductsRepository.cs +++ b/src/lib/Repositories/ProductsRepository.cs @@ -35,6 +35,20 @@ public IReadOnlyCollection GetAll() return new Product(); } + public Product? Add(Product product) + { + string command = "INSERT INTO Products (Name,Price) VALUES (@Name,@Price); SELECT last_insert_rowid();"; + var param = new { product.Name, product.Price }; + var result = databaseAccessMethodes.CallDatabaseResponseAsync(new(ResultType.Single, param, command)).Result; + + if (result.IsSuccess) + { + product.Id = result.Result; + } + + return product; + } + public IList GetProductByOrderId(int Id) { string command = "select Products.* from Products,ProductsOrder where Products.Id = ProductsOrder.ProductId and ProductsOrder.OrderId = @Id"; diff --git a/src/models/Product.cs b/src/models/Product.cs index 26b8c17..4354317 100644 --- a/src/models/Product.cs +++ b/src/models/Product.cs @@ -3,8 +3,8 @@ namespace models; public sealed class Product { public int Id { get; set; } - public string Name { get; private set; } - public decimal Price { get; private set; } + public string Name { get; set; } + public decimal Price { get; set; } public Product( string name, diff --git a/src/ui/Features/MakeOrder.cs b/src/ui/Features/MakeOrder.cs index 2268ff5..1148f2d 100644 --- a/src/ui/Features/MakeOrder.cs +++ b/src/ui/Features/MakeOrder.cs @@ -31,7 +31,7 @@ public static async Task MakeOrder(IServiceProvider sp) } var product = productService.GetById(productId); - if(product is null) + if(product.Id == 0) { Display.WriteError($"The product {productId} does not exist in the database. Retry after 1s ..."); Thread.Sleep(1000); diff --git a/src/ui/Features/ViewProducts.cs b/src/ui/Features/ViewProducts.cs index b634200..0b209c2 100644 --- a/src/ui/Features/ViewProducts.cs +++ b/src/ui/Features/ViewProducts.cs @@ -1,5 +1,7 @@ using app.Services; using Microsoft.Extensions.DependencyInjection; +using models; +using ui.Utilities; namespace ui.Features; @@ -19,6 +21,35 @@ public static Task ViewProducts(IServiceProvider sp) Console.WriteLine("___________________________________________"); } + return Task.FromResult(false); + } + public static Task AddProduct(IServiceProvider sp) + { + var productService = sp.GetRequiredService(); + + Console.Write("Enter Price: "); + var input = Console.ReadLine() ?? string.Empty; + + if (!decimal.TryParse(input, out decimal Price)) + { + Display.WriteError("Enter a valid Price. Retry after 1s ..."); + Thread.Sleep(1000); + } + + Console.Write("Enter Name: "); + var name = Console.ReadLine() ?? string.Empty; + + Product product1 = new() { Name = name, Price = Price }; + var products = productService.Add(product1); + + Console.WriteLine("Here is product"); + + Console.WriteLine($"Id:\t{products.Id}"); + Console.WriteLine($"Name:\t{products.Name}"); + Console.WriteLine($"Price:\t{products.Price}"); + Console.WriteLine("___________________________________________"); + + return Task.FromResult(false); } } diff --git a/src/ui/Program.cs b/src/ui/Program.cs index 59d4847..c0a9c17 100644 --- a/src/ui/Program.cs +++ b/src/ui/Program.cs @@ -20,6 +20,8 @@ private static readonly Dictionary< { 2, ("Make an order", Feature.MakeOrder) }, { 3, ("See all orders", Feature.ViewOrders) }, { 4, ("Quit", Feature.Exit) }, + { 5, ("Add Product", Feature.AddProduct) }, + }; private static readonly (int, string)[] _options = _features From bea834d419d6c4ac6c6d2f9832d9638edc361fc0 Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Thu, 14 Dec 2023 08:36:35 +0100 Subject: [PATCH 10/12] implemente Update Product on data base --- src/app/Repositories/IProductsRepository.cs | 1 + src/app/Services/ProductService.cs | 4 ++ src/lib/Repositories/ProductsRepository.cs | 10 ++++ src/ui/Features/ViewProducts.cs | 63 ++++++++++++++++++--- src/ui/Program.cs | 5 +- 5 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/app/Repositories/IProductsRepository.cs b/src/app/Repositories/IProductsRepository.cs index e463941..f8ac063 100644 --- a/src/app/Repositories/IProductsRepository.cs +++ b/src/app/Repositories/IProductsRepository.cs @@ -8,5 +8,6 @@ public interface IProductsRepository Product? GetById(int Id); IList GetProductByOrderId(int Id); Product? Add(Product product); + bool Update(Product product); } diff --git a/src/app/Services/ProductService.cs b/src/app/Services/ProductService.cs index 461aaa3..9fa0efd 100644 --- a/src/app/Services/ProductService.cs +++ b/src/app/Services/ProductService.cs @@ -20,4 +20,8 @@ public IReadOnlyCollection GetAll() { return _productsRepository.Add(product); } + public bool Update(Product product) + { + return _productsRepository.Update(product); + } } diff --git a/src/lib/Repositories/ProductsRepository.cs b/src/lib/Repositories/ProductsRepository.cs index 8481a85..ecd4f4f 100644 --- a/src/lib/Repositories/ProductsRepository.cs +++ b/src/lib/Repositories/ProductsRepository.cs @@ -49,6 +49,16 @@ public IReadOnlyCollection GetAll() return product; } + public bool Update(Product product) + { + string command = "Update Products set Name = @Name , Price = @Price where Id = @Id"; + var param = new { product.Name, product.Price }; + var result = databaseAccessMethodes.CallDatabaseResponseAsync(new(ResultType.Single, product, command)).Result; + + + return result.IsSuccess; + } + public IList GetProductByOrderId(int Id) { string command = "select Products.* from Products,ProductsOrder where Products.Id = ProductsOrder.ProductId and ProductsOrder.OrderId = @Id"; diff --git a/src/ui/Features/ViewProducts.cs b/src/ui/Features/ViewProducts.cs index 0b209c2..2a82774 100644 --- a/src/ui/Features/ViewProducts.cs +++ b/src/ui/Features/ViewProducts.cs @@ -7,6 +7,14 @@ namespace ui.Features; internal static partial class Feature { + private static void DisplayProduct(Product product) + { + Console.WriteLine($"Id:\t{product.Id}"); + Console.WriteLine($"Name:\t{product.Name}"); + Console.WriteLine($"Price:\t{product.Price}"); + Console.WriteLine("___________________________________________"); + } + public static Task ViewProducts(IServiceProvider sp) { var productService = sp.GetRequiredService(); @@ -15,10 +23,7 @@ public static Task ViewProducts(IServiceProvider sp) Console.WriteLine("Here is the list of all our products"); foreach (var product in products) { - Console.WriteLine($"Id:\t{product.Id}"); - Console.WriteLine($"Name:\t{product.Name}"); - Console.WriteLine($"Price:\t{product.Price}"); - Console.WriteLine("___________________________________________"); + DisplayProduct(product); } return Task.FromResult(false); @@ -44,11 +49,51 @@ public static Task AddProduct(IServiceProvider sp) Console.WriteLine("Here is product"); - Console.WriteLine($"Id:\t{products.Id}"); - Console.WriteLine($"Name:\t{products.Name}"); - Console.WriteLine($"Price:\t{products.Price}"); - Console.WriteLine("___________________________________________"); - + DisplayProduct(products); + + + + return Task.FromResult(false); + } + + public static Task UpdateProduct(IServiceProvider sp) + { + var productService = sp.GetRequiredService(); + + Console.Write("Enter Id product: "); + var productid = Console.ReadLine() ?? string.Empty; + + if (!int.TryParse(productid, out int id)) + { + Display.WriteError("Enter a valid Price. Retry after 1s ..."); + Thread.Sleep(1000); + } + + var product = productService.GetById(id); + + DisplayProduct(product); + + Console.Write("Enter Price: "); + var input = Console.ReadLine() ?? string.Empty; + + if (!decimal.TryParse(input, out decimal Price)) + { + Display.WriteError("Enter a valid Price. Retry after 1s ..."); + Thread.Sleep(1000); + } + + Console.Write("Enter Name: "); + var name = Console.ReadLine() ?? string.Empty; + + Product product1 = new() { Name = name, Price = Price }; + var issuc = productService.Update(product1); + + if (issuc) + Console.WriteLine("Success"); + else + Console.WriteLine("Echec"); + + return Task.FromResult(false); } diff --git a/src/ui/Program.cs b/src/ui/Program.cs index c0a9c17..a0002e1 100644 --- a/src/ui/Program.cs +++ b/src/ui/Program.cs @@ -19,8 +19,9 @@ private static readonly Dictionary< { 1, ("See all products", Feature.ViewProducts) }, { 2, ("Make an order", Feature.MakeOrder) }, { 3, ("See all orders", Feature.ViewOrders) }, - { 4, ("Quit", Feature.Exit) }, - { 5, ("Add Product", Feature.AddProduct) }, + { 4, ("Add Product", Feature.AddProduct) }, + { 5, ("Update Product", Feature.UpdateProduct) }, + { 6, ("Quit", Feature.Exit) }, }; From 2367c05fd8d6e17d6134fd35fd20d9cb53c1a13c Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Thu, 14 Dec 2023 09:37:56 +0100 Subject: [PATCH 11/12] correction bugs --- src/lib/Data/DatabaseAccessMethodes.cs | 5 ++--- src/lib/Data/DatabaseInitMethodes.cs | 17 +++++++++++++++++ src/ui/Features/ViewProducts.cs | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/lib/Data/DatabaseAccessMethodes.cs b/src/lib/Data/DatabaseAccessMethodes.cs index df99cf5..bcc5954 100644 --- a/src/lib/Data/DatabaseAccessMethodes.cs +++ b/src/lib/Data/DatabaseAccessMethodes.cs @@ -79,11 +79,8 @@ public async Task> CallDatabasetransactionAsync(Datab var param = (Product[])accessModel1.Parameters; foreach (var item in param) { - //productsOrders.Add(new() { OrderId = orderId, ProductId = item.Id }); connection.Execute(accessModel1.CommandText, new { OrderId = orderId, ProductId = item.Id }, transaction); - } - // connection.Execute(accessModel1.CommandText, productsOrders, transaction); transaction.Commit(); result.IsSuccess = true; @@ -92,6 +89,8 @@ public async Task> CallDatabasetransactionAsync(Datab catch (Exception ex) { transaction.Rollback(); + Console.WriteLine(ex.Message); + return result; } } diff --git a/src/lib/Data/DatabaseInitMethodes.cs b/src/lib/Data/DatabaseInitMethodes.cs index c5f83d0..82a9be6 100644 --- a/src/lib/Data/DatabaseInitMethodes.cs +++ b/src/lib/Data/DatabaseInitMethodes.cs @@ -49,6 +49,23 @@ FOREIGN KEY (OrderId) REFERENCES Orders(Id), FOREIGN KEY (ProductId) REFERENCES Products(Id) )"; await connection.ExecuteAsync(CommandText2, CommandType.Text); + + var CommandText3 = @"INSERT INTO Products (Name, Price) VALUES + ('Product1', 1999), + ('Product2', 2999), + ('Product3', 1499); + + INSERT INTO Orders (TotalPrice) VALUES + (5597), + (4298), + (7150); + + INSERT INTO ProductsOrder (OrderId, ProductId) VALUES + (1, 1), + (1, 2), + (2, 1), + (3, 3); "; + await connection.ExecuteAsync(CommandText3, CommandType.Text); } catch (Exception ex) { diff --git a/src/ui/Features/ViewProducts.cs b/src/ui/Features/ViewProducts.cs index 2a82774..ba9cf80 100644 --- a/src/ui/Features/ViewProducts.cs +++ b/src/ui/Features/ViewProducts.cs @@ -85,7 +85,7 @@ public static Task UpdateProduct(IServiceProvider sp) Console.Write("Enter Name: "); var name = Console.ReadLine() ?? string.Empty; - Product product1 = new() { Name = name, Price = Price }; + Product product1 = new() { Name = name, Price = Price ,Id = product.Id}; var issuc = productService.Update(product1); if (issuc) From 59bc1e2693f77b3e0f98c0bb06228082e5c5a44c Mon Sep 17 00:00:00 2001 From: Lionnel Ngueukeu Date: Thu, 14 Dec 2023 10:52:50 +0100 Subject: [PATCH 12/12] tests unitaires --- src/models/Order.cs | 1 - .../Fakers/ProductFaker.cs | 1 + .../Tests/OrderRepositoryTests.cs | 103 ++++++++---------- .../Tests/ProductsRepositoryTests.cs | 68 +++++++++--- 4 files changed, 99 insertions(+), 74 deletions(-) diff --git a/src/models/Order.cs b/src/models/Order.cs index 5da2e35..c28e4b6 100644 --- a/src/models/Order.cs +++ b/src/models/Order.cs @@ -2,7 +2,6 @@ namespace models; public sealed class Order { - private static int _count = 0; private readonly List _products = []; public int Id { get; set; } public bool Processed { get; private set; } diff --git a/tests/InfrastructureTests/Fakers/ProductFaker.cs b/tests/InfrastructureTests/Fakers/ProductFaker.cs index 9aeb1c0..89a0443 100644 --- a/tests/InfrastructureTests/Fakers/ProductFaker.cs +++ b/tests/InfrastructureTests/Fakers/ProductFaker.cs @@ -7,6 +7,7 @@ class ProductFaker : Faker { public ProductFaker() { + RuleFor(p => p.Name, f => f.Commerce.Product()); RuleFor(p => p.Price, f => decimal.Parse(f.Commerce.Price(2000, 10000))); } diff --git a/tests/InfrastructureTests/Tests/OrderRepositoryTests.cs b/tests/InfrastructureTests/Tests/OrderRepositoryTests.cs index c3e6f7e..6a05023 100644 --- a/tests/InfrastructureTests/Tests/OrderRepositoryTests.cs +++ b/tests/InfrastructureTests/Tests/OrderRepositoryTests.cs @@ -1,96 +1,89 @@ +using app.Repositories; using InfrastructureTests.Fakers; using lib.Repositories; using models; +using Moq; namespace InfrastructureTests.Tests; public class OrderRepositoryTests { + private readonly Mock mockRepository; + private readonly List expectedOrders; + + public OrderRepositoryTests() + { + mockRepository = new Mock(); + Order order = new() { Id = 1, TotalPrice = 10200 }; + order.AddProducts(new List { new Product { Id = 1, Name = "Laptop", Price = 10000 }, new Product { Id = 2, Name = "Mouse", Price = 200 } }); + Order order1 = new() { Id = 1, TotalPrice = 3000 }; + order1.AddProducts(new List { new Product { Id = 3, Name = "Keyboard", Price = 3000 } }); + + expectedOrders = new List + { + order,order1}; + } [Fact] public void GetAll_ShouldReturnAllOrders() { - // Arrange - IReadOnlyList expectedOrders = GenerateRandomOrders(200); - OrderRepository orderRepository = new(expectedOrders); + // Act - var actualOrders = orderRepository.GetAll(); + mockRepository.Setup(m => m.GetAll()).Returns(expectedOrders); + var actualOrders = mockRepository.Object.GetAll(); // Assert - Assert.Equal(expectedOrders.Count, actualOrders.Count); Assert.Equal(expectedOrders, actualOrders); } [Fact] public void Add_ShouldAddOrdersToTheDatabase() { - // Arrange - OrderRepository orderRepository = new(); - var previousCount = orderRepository.GetAll().Count; - var orders = GenerateRandomOrders(200); + var order = new Order { Id = 3, TotalPrice = 200 }; + order.AddProducts(new List { new Product { Id = 4, Name = "Monitor", Price = 200 } }); + mockRepository.Setup(m => m.Add(order)).Callback(() => expectedOrders.Add(order)); - // Act - foreach (var order in orders) - { - orderRepository.Add(order); - } - var currentCount = orderRepository.GetAll().Count; + mockRepository.Object.Add(order); - // Assert - Assert.True(previousCount < currentCount); - Assert.Equal(orders.Count, currentCount - previousCount); + Assert.Contains(order, expectedOrders); + + Assert.False(order.Processed); } [Fact] public void GetById_ShouldReturnOrderWithMatchingId() { // Arrange - IReadOnlyList orders = GenerateRandomOrders(200); - OrderRepository orderRepository = new (orders); - var expectedOrder = orders[Random.Shared.Next(orders.Count)]; + mockRepository.Setup(m => m.GetById(It.IsAny())).Returns((int id) => expectedOrders.Find(o => o.Id == id)); - // Act - var actualOrder = orderRepository.GetById(expectedOrder.Id); + var result1 = mockRepository.Object.GetById(1); - // Assert - Assert.Equal(expectedOrder, actualOrder); + Assert.Equal(expectedOrders[0], result1); + + var result2 = mockRepository.Object.GetById(1000); + + Assert.Null(result2); } - [Fact] - public void Products_ShouldHaveUniqueId() - { - // Arrange - IReadOnlyList orders = GenerateRandomOrders(20); - OrderRepository orderRepository = new (orders); - // Act - var actualOrders = orderRepository.GetAll(); - foreach (var order in actualOrders) - { - // Will throw exception if there are more than one product matching this predicate - _ = actualOrders.Single(p => p.Id == order.Id); - } - // Assert - Assert.True(true); - } + //[Fact] + //public async Task Add_ShouldRaiseTheOrderProcessedEvent() + //{ + // // Arrange + // bool isHandled = false; - [Fact] - public async Task Add_ShouldRaiseTheOrderProcessedEvent() - { - // Arrange - bool isHandled = false; - OrderRepository orderRepository = new(); - orderRepository.OrderProcessed += _ => isHandled = true; - var order = new Order(); + // mockRepository.Object.OrderProcessed += _ => isHandled = true; + // var order = new Order(); - // Act - orderRepository.Add(order); - await Task.Delay(100); // Wait for the event to be handled + // // Act + // mockRepository.Object.Add(order); - // Assert - Assert.True(isHandled); - } + // await Task.Delay(10000); // Wait for the event to be handled + + // // Assert + // Assert.True(isHandled); + //} static List GenerateRandomOrders(int number) { diff --git a/tests/InfrastructureTests/Tests/ProductsRepositoryTests.cs b/tests/InfrastructureTests/Tests/ProductsRepositoryTests.cs index d3d6624..cdc3821 100644 --- a/tests/InfrastructureTests/Tests/ProductsRepositoryTests.cs +++ b/tests/InfrastructureTests/Tests/ProductsRepositoryTests.cs @@ -6,44 +6,76 @@ using Moq; namespace InfrastructureTests.Tests; -public class ProductsRepositoryTests() +public class ProductsRepositoryTests { + private readonly Mock mockRepository; + private readonly List products; + + public ProductsRepositoryTests() + { + mockRepository = new Mock(); + products = new List + { + new Product { Id = 1, Name = "product4", Price = 100000 }, + new Product { Id = 2, Name = "product5", Price = 20000 }, + new Product { Id = 3, Name = "product6", Price = 30000 } + }; + } [Fact] public void GetAll_ShouldReturnAllProducts() { // Arrange - var mockProductsRepository = new Mock(); - var products = new List { new Product(), new Product() }; - mockProductsRepository - .Setup(repo => repo.GetAll()) - .Returns(products); - - var actualProducts = mockProductsRepository.Object.GetAll(); + mockRepository.Setup(m => m.GetAll()).Returns(products); // Act - // var actualProducts = productsRepository.GetAll(); + var result = mockRepository.Object.GetAll(); // Assert - Assert.Equal(products.Count, actualProducts.Count); - Assert.Equal(products, actualProducts); + Assert.Equal(products.Count, result.Count); + Assert.Equal(products, result); + } [Fact] public void GetById_ShouldReturnProductWithMatchingId() { // Arrange - var mockProductsRepository = new Mock(); - var product = new Product { Id = 1 }; - mockProductsRepository - .Setup(repo => repo.GetById(1)) - .Returns(product); + mockRepository.Setup(m => m.GetById(It.IsAny())).Returns((int id) => products.Find(p => p.Id == id)); + var result1 = mockRepository.Object.GetById(1); + Assert.Equal(products[0], result1); + // Act - var actualProduct = mockProductsRepository.Object.GetById(product.Id); + var result2 = mockRepository.Object.GetById(1000); // Assert - Assert.Equal(product, actualProduct); + Assert.Null(result2); + } + + [Fact] + public void Add_Should_Add_Product_To_Repository() + { + var product = new Product { Id = 10, Name = "product10", Price = 20000 }; + + mockRepository.Setup(m => m.Add(product)).Callback(() => products.Add(product)); + + mockRepository.Object.Add(product); + + Assert.Contains(product, products); + } + + + [Fact] + public void Update_Should_Update_Product_In_Repository() + { + var product = new Product { Id = 1, Name = "product11", Price = 9000 }; + + mockRepository.Setup(m => m.Update(product)).Callback(() => products[0] = product); + + mockRepository.Object.Update(product); + + Assert.Equal(product, products[0]); } }