diff --git a/appsettings.Development.json b/appsettings.Development.json new file mode 100644 index 0000000..79e3d66 --- /dev/null +++ b/appsettings.Development.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + + "ConnectionStrings": { + + "DefaultConnectionString": "Host=localhost:5432; Database=postgres; Username=postgres; Password=123;" + + } +} diff --git a/appsettings.json b/appsettings.json new file mode 100644 index 0000000..21d4779 --- /dev/null +++ b/appsettings.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + + "ConnectionStrings": { + "DefaultConnectionString": "Host=127.0.0.1; Database=postgres; Username=postgres; Password=123;" + + } +} \ No newline at end of file diff --git a/exercise.pizzashopapi/DTO/CreateOrderDTO.cs b/exercise.pizzashopapi/DTO/CreateOrderDTO.cs new file mode 100644 index 0000000..96a17db --- /dev/null +++ b/exercise.pizzashopapi/DTO/CreateOrderDTO.cs @@ -0,0 +1,13 @@ +using exercise.pizzashopapi.Models; +using exercise.pizzashopapi.Repository; + +namespace exercise.pizzashopapi.DTO +{ + public class CreateOrderDTO + { + + public int CustomerId { get; set; } + public int PizzaID { get; set; } + public List Toppings { get; set; } + } +} diff --git a/exercise.pizzashopapi/DTO/CreateToppingDTO.cs b/exercise.pizzashopapi/DTO/CreateToppingDTO.cs new file mode 100644 index 0000000..d56bb82 --- /dev/null +++ b/exercise.pizzashopapi/DTO/CreateToppingDTO.cs @@ -0,0 +1,11 @@ +using exercise.pizzashopapi.Models; + +namespace exercise.pizzashopapi.DTO +{ + public class CreateToppingDTO + { + + public int ToppingId { get; set; } + public int amount { get; set; } + } +} diff --git a/exercise.pizzashopapi/DTO/OrderDTO.cs b/exercise.pizzashopapi/DTO/OrderDTO.cs new file mode 100644 index 0000000..05d8056 --- /dev/null +++ b/exercise.pizzashopapi/DTO/OrderDTO.cs @@ -0,0 +1,26 @@ +using System.Security.Policy; +using exercise.pizzashopapi.Models; +using exercise.pizzashopapi.Repository; + +namespace exercise.pizzashopapi.DTO +{ + public class OrderDTO + { + public OrderDTO(Order o) + { + this.OrderId = o.Id; + this.PizzaID = o.PizzaId; + this.PizzaName = o.Pizza.Name; + this.CustomerId = o.CustomerId; + + this.Toppings = o.OrderToppings.Select(x => new OrderToppingDTO(x)).ToList(); + this.orderedAt = o.startTime; + } + public int OrderId { get; set; } + public DateTime orderedAt { get; set; } + public int CustomerId { get; set; } + public int PizzaID { get; set; } + public string PizzaName { get; set; } + public List Toppings { get; set; } + } +} diff --git a/exercise.pizzashopapi/DTO/OrderToppingDTO.cs b/exercise.pizzashopapi/DTO/OrderToppingDTO.cs new file mode 100644 index 0000000..0280ab2 --- /dev/null +++ b/exercise.pizzashopapi/DTO/OrderToppingDTO.cs @@ -0,0 +1,17 @@ +using exercise.pizzashopapi.Models; +using exercise.pizzashopapi.Repository; + +namespace exercise.pizzashopapi.DTO +{ + public class OrderToppingDTO + { + public OrderToppingDTO(Models.OrderToppings orderTopping) { + ToppingId = orderTopping.ToppingId; + Name = orderTopping.Topping.Name; + Amount = orderTopping.Amount; + } + public int ToppingId { get; set; } + public string Name { get; set; } + public int Amount { get; set; } + } +} diff --git a/exercise.pizzashopapi/DTO/PizzaDTO.cs b/exercise.pizzashopapi/DTO/PizzaDTO.cs new file mode 100644 index 0000000..3475715 --- /dev/null +++ b/exercise.pizzashopapi/DTO/PizzaDTO.cs @@ -0,0 +1,17 @@ +using exercise.pizzashopapi.Models; + +namespace exercise.pizzashopapi.DTO +{ + public class PizzaDTO + { + public PizzaDTO(Pizza p) + { + this.Id = p.Id; + this.Name = p.Name; + this.Price = p.Price; + } + public int Id { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + } +} diff --git a/exercise.pizzashopapi/DTO/ToppingDTO.cs b/exercise.pizzashopapi/DTO/ToppingDTO.cs new file mode 100644 index 0000000..14ea0b3 --- /dev/null +++ b/exercise.pizzashopapi/DTO/ToppingDTO.cs @@ -0,0 +1,17 @@ +using exercise.pizzashopapi.Models; + +namespace exercise.pizzashopapi.DTO +{ + public class ToppingDTO + { + public ToppingDTO(Topping o) + { + Id = o.Id; + Name = o.Name; + Price = o.Price; + } + public int Id { get; set; } + public string Name { get; set; } + public Decimal Price { get; set; } + } +} diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 129199e..53ea91b 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -12,17 +12,47 @@ public DataContext() connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString"); } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + + modelBuilder.Entity(). + HasKey(p => new { p.Id }); + + modelBuilder.Entity(). + HasKey(p => new { p.Id }); + + modelBuilder.Entity(). + HasKey(p => new { p.Id}); + + modelBuilder.Entity(). + HasKey(p => new { p.Id }); + + modelBuilder.Entity(). + HasKey(p => new { p.Id }); + + + modelBuilder.Entity(). + HasOne(p => p.Topping). + WithMany(p => p.OrderToppings). + HasForeignKey(p => p.ToppingId); + + + modelBuilder.Entity(). + HasOne(p => p.Order). + WithMany(o => o.OrderToppings). + HasForeignKey(p => new { p.OrderId}); + + } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql(connectionString); - //set primary of order? - - //seed data? - } public DbSet Pizzas { get; set; } public DbSet Customers { get; set; } public DbSet Orders { get; set; } + public DbSet Toppings { get; set; } + public DbSet OrderToppings { get; set; } } } diff --git a/exercise.pizzashopapi/Data/Seeder.cs b/exercise.pizzashopapi/Data/Seeder.cs index f87fbef..bd77dc1 100644 --- a/exercise.pizzashopapi/Data/Seeder.cs +++ b/exercise.pizzashopapi/Data/Seeder.cs @@ -10,24 +10,51 @@ public async static void SeedPizzaShopApi(this WebApplication app) { if(!db.Customers.Any()) { - db.Add(new Customer() { Name="Nigel" }); + db.Add(new Customer() { Name="Nigel" }); db.Add(new Customer() { Name = "Dave" }); + db.Add(new Customer() { Name = "Lowe" }); await db.SaveChangesAsync(); } if(!db.Pizzas.Any()) { - db.Add(new Pizza() { Name = "Cheese & Pineapple" }); - db.Add(new Pizza() { Name = "Vegan Cheese Tastic" }); + db.Add(new Pizza() { Name = "Cheese & Pineapple" , Price = 8.5m }); + db.Add(new Pizza() { Name = "Vegan Cheese Tastic" , Price = 8.5m }); + db.Add(new Pizza() { Name = "Super Kebab" , Price = 8.5m }); await db.SaveChangesAsync(); } + // topping data + if(!db.Toppings.Any()) + { + + db.Add(new Topping() { Name = "Lettuce", Price = 0.25m }); + db.Add(new Topping() { Name = "Cucumber", Price = 0.25m}); + db.Add(new Topping() { Name = "Carrot", Price = 0.25m }); + await db.SaveChangesAsync(); + } + + //order data - if(1==1) + if(!db.Orders.Any()) { + + db.Add(new Order() { CustomerId = 1, PizzaId = 3, startTime = (DateTime.Now.AddMinutes(-2)).ToUniversalTime() }); + db.Add(new Order() { CustomerId = 2, PizzaId = 1, startTime = (DateTime.Now.AddMinutes(-3)).ToUniversalTime() }); + db.Add(new Order() { CustomerId = 3, PizzaId = 2, startTime = (DateTime.Now.AddMinutes(-14)).ToUniversalTime() }); + await db.SaveChangesAsync(); + } + // OrderToppings data + if (!db.OrderToppings.Any()) + { + db.Add(new OrderToppings() { OrderId=1, ToppingId = 1, Amount = 1 }); + db.Add(new OrderToppings() { OrderId=2, ToppingId = 2, Amount = 1 }); + db.Add(new OrderToppings() { OrderId=3, ToppingId = 3, Amount = 1 }); + db.Add(new OrderToppings() { OrderId=3, ToppingId = 2, Amount = 1 }); await db.SaveChangesAsync(); } + } } } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index f8be2b0..19a7dac 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,5 +1,9 @@ -using exercise.pizzashopapi.Repository; +using exercise.pizzashopapi.DTO; +using exercise.pizzashopapi.Models; +using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; namespace exercise.pizzashopapi.EndPoints { @@ -7,9 +11,112 @@ public static class PizzaShopApi { public static void ConfigurePizzaShopApi(this WebApplication app) { - + + var shop = app.MapGroup("shop"); + shop.MapGet("/orders", GetOrders); + shop.MapGet("/pizzas", GetPizzas); + shop.MapGet("/orderStatus", GetOrderStatus); + shop.MapPost("/orders", CreateOrder); + + } + + private static async Task CreateOrder(HttpContext context, IRepository o_repo, CreateOrderDTO dto) + { + try + { + Order order = new() + { + CustomerId = dto.CustomerId, + PizzaId = dto.PizzaID, + OrderToppings = dto.Toppings.Select( + x => new OrderToppings + { + Amount = x.amount, + ToppingId = x.ToppingId + }).ToList() + }; + var _order = await o_repo.CreateEntry(order); + if (_order == null) return TypedResults.BadRequest($"Not a valid DTO"); + + var retOrder = await o_repo.GetEntry(o => + o.Where( x => x.Id == _order.Id), + x => x.Include(x => x.Customer), + x => x.Include(x => x.Pizza), + x => x.Include(x => x.OrderToppings).ThenInclude(x=>x.Topping) + ); + + return TypedResults.Ok(new OrderDTO(retOrder)); + } + catch (Exception ex) + { + return TypedResults.BadRequest($"Something bad happened"); + } } + private static async Task GetOrders(HttpContext context, IRepository o_repo, int? customerId, int? orderID) + { + if (customerId == null && orderID == null) return await _GetOrders(context, o_repo); + if (customerId == null && orderID != null) return await _GetOrdersByOrderId(context, o_repo, orderID.Value); + else + return await _GetOrdersByCustomerId(context, o_repo, customerId.Value); + } + + + private static async Task GetOrderStatus(HttpContext context, IRepository o_rep, int orderId) + { + var l = await o_rep.GetEntry( + w => w.Where(x => x.Id == orderId), + x => x.Include(x => x.Pizza), + x => x.Include(x => x.Customer), + x => x.Include(x => x.OrderToppings).ThenInclude(x => x.Topping) + ); + + if (l == null) return TypedResults.NotFound(); - + var dur = DateTime.Now.ToUniversalTime() - l.startTime; + return TypedResults.Ok(new { + Status= dur.TotalMinutes <= 3 ? "Chef preparing your meal" : dur.TotalMinutes > 15 ? "Your meal should be delivered!" : "Your meal is on they way!" , + }); + } + + private static async Task GetPizzas(HttpContext context, IRepository p_rep) + { + var l = await p_rep.GetEntries(); + if (l.Count() == 0) return TypedResults.NotFound(); + return TypedResults.Ok(l.Select(x => new PizzaDTO(x)).ToList()); + } + private static async Task _GetOrdersByCustomerId(HttpContext context, IRepository o_repo, int customerId) + { + var l = await o_repo.GetEntries( + w => w.Where(x => x.CustomerId == customerId), + x => x.Include(x => x.Pizza), + x => x.Include(x => x.Customer), + x => x.Include(x => x.OrderToppings).ThenInclude(x =>x.Topping) + ); + if (l == null) return TypedResults.NotFound(); + return TypedResults.Ok(l.Select(x => new OrderDTO(x)).ToList()); + } + private static async Task _GetOrdersByOrderId(HttpContext context, IRepository o_repo, int orderID) + { + var l = await o_repo.GetEntry( + w => w.Where(x => x.Id == orderID), + x => x.Include(x => x.Pizza), + x => x.Include(x => x.Customer), + x => x.Include(x => x.OrderToppings).ThenInclude(x =>x.Topping) + ); + if (l == null) return TypedResults.NotFound(); + return TypedResults.Ok(new OrderDTO(l)); + } + + + private static async Task _GetOrders(HttpContext contextint, IRepository o_rep) + { + var l = await o_rep.GetEntries( + x => x.Include(x => x.Pizza), + x => x.Include(x => x.Customer), + x => x.Include(x => x.OrderToppings).ThenInclude(x => x.Topping) + ); + if (l.Count() == 0) return TypedResults.NotFound(); + return TypedResults.Ok(l.Select(x => new OrderDTO(x)).ToList()); + } } } diff --git a/exercise.pizzashopapi/Migrations/20250128114959_newmagratoin.Designer.cs b/exercise.pizzashopapi/Migrations/20250128114959_newmagratoin.Designer.cs new file mode 100644 index 0000000..51d0fd5 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128114959_newmagratoin.Designer.cs @@ -0,0 +1,197 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using exercise.pizzashopapi.Data; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20250128114959_newmagratoin")] + partial class newmagratoin + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.Property("startTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("integer"); + + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("ToppingId"); + + b.ToTable("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("Pizzas"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("Toppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.HasOne("exercise.pizzashopapi.Models.Customer", "Customer") + .WithMany("Orders") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Pizza", "Pizza") + .WithMany("Orders") + .HasForeignKey("PizzaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("Pizza"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.HasOne("exercise.pizzashopapi.Models.Order", "Order") + .WithMany("OrderToppings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany("OrderToppings") + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Navigation("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Navigation("OrderToppings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250128114959_newmagratoin.cs b/exercise.pizzashopapi/Migrations/20250128114959_newmagratoin.cs new file mode 100644 index 0000000..cbfc51f --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128114959_newmagratoin.cs @@ -0,0 +1,150 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class newmagratoin : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Customers", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Customers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Pizzas", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + Price = table.Column(type: "numeric", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Pizzas", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Toppings", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + Price = table.Column(type: "numeric", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Toppings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Orders", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CustomerId = table.Column(type: "integer", nullable: false), + PizzaId = table.Column(type: "integer", nullable: false), + startTime = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Orders", x => x.Id); + table.ForeignKey( + name: "FK_Orders_Customers_CustomerId", + column: x => x.CustomerId, + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Orders_Pizzas_PizzaId", + column: x => x.PizzaId, + principalTable: "Pizzas", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "OrderToppings", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Amount = table.Column(type: "integer", nullable: false), + ToppingId = table.Column(type: "integer", nullable: false), + OrderId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrderToppings", x => x.Id); + table.ForeignKey( + name: "FK_OrderToppings_Orders_OrderId", + column: x => x.OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_OrderToppings_Toppings_ToppingId", + column: x => x.ToppingId, + principalTable: "Toppings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Orders_CustomerId", + table: "Orders", + column: "CustomerId"); + + migrationBuilder.CreateIndex( + name: "IX_Orders_PizzaId", + table: "Orders", + column: "PizzaId"); + + migrationBuilder.CreateIndex( + name: "IX_OrderToppings_OrderId", + table: "OrderToppings", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_OrderToppings_ToppingId", + table: "OrderToppings", + column: "ToppingId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "OrderToppings"); + + migrationBuilder.DropTable( + name: "Orders"); + + migrationBuilder.DropTable( + name: "Toppings"); + + migrationBuilder.DropTable( + name: "Customers"); + + migrationBuilder.DropTable( + name: "Pizzas"); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 0000000..e7f86ae --- /dev/null +++ b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,194 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using exercise.pizzashopapi.Data; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + [DbContext(typeof(DataContext))] + partial class DataContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.Property("startTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("integer"); + + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("ToppingId"); + + b.ToTable("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("Pizzas"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("Toppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.HasOne("exercise.pizzashopapi.Models.Customer", "Customer") + .WithMany("Orders") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Pizza", "Pizza") + .WithMany("Orders") + .HasForeignKey("PizzaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("Pizza"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.HasOne("exercise.pizzashopapi.Models.Order", "Order") + .WithMany("OrderToppings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany("OrderToppings") + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Navigation("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Navigation("OrderToppings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Models/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index 2ca83bd..eed644f 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -6,5 +6,7 @@ public class Customer { public int Id { get; set; } public string Name { get; set; } + + public List Orders { get; set; } } } diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index fbe6113..ed5cafd 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -4,7 +4,13 @@ namespace exercise.pizzashopapi.Models { public class Order { - + public int Id { get; set; } + public int CustomerId { get; set; } + public int PizzaId { get; set; } + public DateTime startTime { get; set; } = DateTime.Now.ToUniversalTime(); + public Pizza Pizza { get; set; } + public Customer Customer { get; set; } + public List OrderToppings { get; set; } } } diff --git a/exercise.pizzashopapi/Models/OrderToppings.cs b/exercise.pizzashopapi/Models/OrderToppings.cs new file mode 100644 index 0000000..68b0c8d --- /dev/null +++ b/exercise.pizzashopapi/Models/OrderToppings.cs @@ -0,0 +1,16 @@ +namespace exercise.pizzashopapi.Models +{ + public class OrderToppings + { + public int Id { get; set; } + public int Amount { get; set; } + public int ToppingId { get; set; } + //public int CustomerId { get; set; } + //public int PizzaId { get; set; } + public int OrderId { get; set; } + + public Order Order { get; set; } + public Topping Topping { get; set; } + + } +} diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index 5c085ec..8c23fb0 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -8,5 +8,7 @@ public class Pizza public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } + + public List Orders { get; set; } } } \ No newline at end of file diff --git a/exercise.pizzashopapi/Models/Topping.cs b/exercise.pizzashopapi/Models/Topping.cs new file mode 100644 index 0000000..1802b0e --- /dev/null +++ b/exercise.pizzashopapi/Models/Topping.cs @@ -0,0 +1,10 @@ +namespace exercise.pizzashopapi.Models +{ + public class Topping + { + public int Id { get; set; } + public string Name { get; set; } + public Decimal Price { get; set; } + public List OrderToppings { get; set; } + } +} diff --git a/exercise.pizzashopapi/Program.cs b/exercise.pizzashopapi/Program.cs index c04a440..c51389f 100644 --- a/exercise.pizzashopapi/Program.cs +++ b/exercise.pizzashopapi/Program.cs @@ -1,5 +1,6 @@ using exercise.pizzashopapi.Data; using exercise.pizzashopapi.EndPoints; +using exercise.pizzashopapi.Models; using exercise.pizzashopapi.Repository; var builder = WebApplication.CreateBuilder(args); @@ -7,7 +8,9 @@ // Add services to the container. builder.Services.AddControllers(); -builder.Services.AddScoped(); +builder.Services.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); builder.Services.AddDbContext(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); diff --git a/exercise.pizzashopapi/Repository/IRepository.cs b/exercise.pizzashopapi/Repository/IRepository.cs index b114ea8..e5f4f0c 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -1,11 +1,18 @@ using exercise.pizzashopapi.Models; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Repository { - public interface IRepository + public interface IRepository where T : class { Task> GetOrdersByCustomer(int id); - + Task> GetEntries(); + Task> GetEntries(params Func, IQueryable>[] includes); + Task GetEntry(Func, IQueryable> id, params Func, IQueryable>[] expressions); + Task GetEntry(int id); + + Task CreateEntry(T entry); + } } diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index e109fce..984d732 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -1,14 +1,61 @@ using exercise.pizzashopapi.Data; using exercise.pizzashopapi.Models; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Repository { - public class Repository : IRepository + public class Repository : IRepository where T : class { private DataContext _db; + private DbSet _table = null!; + public Repository(DataContext db) + { + _db = db; + _table = db.Set(); + } public Task> GetOrdersByCustomer(int id) { throw new NotImplementedException(); } + + public async Task> GetEntries(params Func, IQueryable>[] includes) + { + IQueryable q = _table.AsQueryable(); + + foreach (var inc in includes) + q = inc.Invoke(q); + + return await q.ToArrayAsync(); + } + + public async Task GetEntry(Func, IQueryable> id, params Func, IQueryable>[] expressions) + { + IQueryable q = _table.AsQueryable(); + + q = id.Invoke(q); + foreach (var ex in expressions) + { + q = ex.Invoke(q); + } + + return await q.FirstOrDefaultAsync(); + } + public async Task CreateEntry(T entry) + { + var a = await _table.AddAsync(entry); + await _db.SaveChangesAsync(); + return entry; + + } + + public async Task> GetEntries() + { + return await _table.ToListAsync(); + } + + public async Task GetEntry(int id) + { + return await _table.FindAsync(id); + } } }