diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ebc5af4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +x services: + postgres: + image: postgres:15 + container_name: postgres-db + environment: + POSTGRES_USER: jostein + POSTGRES_PASSWORD: password + POSTGRES_DB: pgdb + ports: + - 5432:5432 + volumes: + - postgres-data:/var/lib/postgresql/data +volumes: + postgres-data: + diff --git a/exercise.pizzashopapi/DTO/CustomerDTO.cs b/exercise.pizzashopapi/DTO/CustomerDTO.cs new file mode 100644 index 0000000..84337ac --- /dev/null +++ b/exercise.pizzashopapi/DTO/CustomerDTO.cs @@ -0,0 +1,8 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class CustomerDTO +{ + public string Name { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/CustomerPost.cs b/exercise.pizzashopapi/DTO/CustomerPost.cs new file mode 100644 index 0000000..0bb1f9c --- /dev/null +++ b/exercise.pizzashopapi/DTO/CustomerPost.cs @@ -0,0 +1,8 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class CustomerPost +{ + public string Name { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/OrderDTO.cs b/exercise.pizzashopapi/DTO/OrderDTO.cs new file mode 100644 index 0000000..6f840f5 --- /dev/null +++ b/exercise.pizzashopapi/DTO/OrderDTO.cs @@ -0,0 +1,14 @@ +using System; +using exercise.pizzashopapi.Enums; +using exercise.pizzashopapi.Models; + +namespace exercise.pizzashopapi.DTO; + +public class OrderDTO +{ + public CustomerDTO Customer { get; set; } + public PizzaDTO Pizza { get; set; } + public IEnumerable Toppings { get; set; } + public DateTime OrderDate { get; set; } + public OrderStage OrderStage { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/OrderPost.cs b/exercise.pizzashopapi/DTO/OrderPost.cs new file mode 100644 index 0000000..a114b84 --- /dev/null +++ b/exercise.pizzashopapi/DTO/OrderPost.cs @@ -0,0 +1,9 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class OrderPost +{ + public int CustomerId { get; set; } + public int PizzaId { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/OrderStatusDTO.cs b/exercise.pizzashopapi/DTO/OrderStatusDTO.cs new file mode 100644 index 0000000..f2e3a37 --- /dev/null +++ b/exercise.pizzashopapi/DTO/OrderStatusDTO.cs @@ -0,0 +1,8 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class OrderStatusDTO +{ + public string OrderStatus { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/OrderStatusPut.cs b/exercise.pizzashopapi/DTO/OrderStatusPut.cs new file mode 100644 index 0000000..ad3d0aa --- /dev/null +++ b/exercise.pizzashopapi/DTO/OrderStatusPut.cs @@ -0,0 +1,10 @@ +using System; +using exercise.pizzashopapi.Enums; + +namespace exercise.pizzashopapi.DTO; + +public class OrderStatusPut +{ + public int OrderId { get; set; } + public OrderStage OrderStage { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/PizzaDTO.cs b/exercise.pizzashopapi/DTO/PizzaDTO.cs new file mode 100644 index 0000000..944060d --- /dev/null +++ b/exercise.pizzashopapi/DTO/PizzaDTO.cs @@ -0,0 +1,9 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class PizzaDTO +{ + public string Name { get; set; } + public decimal Price { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/PizzaPost.cs b/exercise.pizzashopapi/DTO/PizzaPost.cs new file mode 100644 index 0000000..d48ffb1 --- /dev/null +++ b/exercise.pizzashopapi/DTO/PizzaPost.cs @@ -0,0 +1,9 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class PizzaPost +{ + 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..91d30a7 --- /dev/null +++ b/exercise.pizzashopapi/DTO/ToppingDTO.cs @@ -0,0 +1,9 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class ToppingDTO +{ + public string Name { get; set; } + public decimal Price { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/ToppingOrderPost.cs b/exercise.pizzashopapi/DTO/ToppingOrderPost.cs new file mode 100644 index 0000000..aefd449 --- /dev/null +++ b/exercise.pizzashopapi/DTO/ToppingOrderPost.cs @@ -0,0 +1,9 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class ToppingOrderPost +{ + public int ToppingId { get; set; } + public int OrderId { get; set; } +} diff --git a/exercise.pizzashopapi/DTO/ToppingPost.cs b/exercise.pizzashopapi/DTO/ToppingPost.cs new file mode 100644 index 0000000..06c2cc4 --- /dev/null +++ b/exercise.pizzashopapi/DTO/ToppingPost.cs @@ -0,0 +1,9 @@ +using System; + +namespace exercise.pizzashopapi.DTO; + +public class ToppingPost +{ + 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..3990d40 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -10,19 +10,35 @@ public DataContext() { var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString"); + this.Database.EnsureCreated(); + } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - optionsBuilder.UseNpgsql(connectionString); - //set primary of order? + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasKey(ot => new { ot.OrderId, ot.ToppingId }); + + modelBuilder.Entity() + .HasOne(ot => ot.Order) + .WithMany() + .HasForeignKey(ot => ot.OrderId); - //seed data? + modelBuilder.Entity() + .HasOne(ot => ot.Topping) + .WithMany() + .HasForeignKey(ot => ot.ToppingId); + } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseNpgsql(connectionString); } 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/PizzaShopContext.cs b/exercise.pizzashopapi/Data/PizzaShopContext.cs new file mode 100644 index 0000000..e69de29 diff --git a/exercise.pizzashopapi/Data/Seeder.cs b/exercise.pizzashopapi/Data/Seeder.cs index f87fbef..f1122d7 100644 --- a/exercise.pizzashopapi/Data/Seeder.cs +++ b/exercise.pizzashopapi/Data/Seeder.cs @@ -12,20 +12,34 @@ public async static void SeedPizzaShopApi(this WebApplication app) { db.Add(new Customer() { Name="Nigel" }); db.Add(new Customer() { Name = "Dave" }); + db.Add(new Customer() { Name = "Jostein" }); 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 = "Pepperoni & Ham" }); await db.SaveChangesAsync(); } //order data - if(1==1) + if(!db.Orders.Any()) { + db.Add(new Order() { CustomerId = 1, PizzaId = 1 }); + db.Add(new Order() { CustomerId = 2, PizzaId = 2 }); + db.Add(new Order() { CustomerId = 3, PizzaId = 3 }); + await db.SaveChangesAsync(); + } + if(!db.Toppings.Any()) + { + db.Add(new Topping() { Name = "Cheese" }); + db.Add(new Topping() { Name = "Pineapple" }); + db.Add(new Topping() { Name = "Vegan Cheese" }); + db.Add(new Topping() { Name = "Pepperoni" }); + db.Add(new Topping() { Name = "Ham" }); await db.SaveChangesAsync(); } } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index f8be2b0..70fe7bb 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,7 @@ -using exercise.pizzashopapi.Repository; +using AutoMapper; +using exercise.pizzashopapi.DTO; +using exercise.pizzashopapi.Models; +using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; namespace exercise.pizzashopapi.EndPoints @@ -7,9 +10,273 @@ public static class PizzaShopApi { public static void ConfigurePizzaShopApi(this WebApplication app) { - + var shop = app.MapGroup("shop"); + + shop.MapGet("/orders", GetAllOrders); + shop.MapGet("/orders/{id}", GetOrderById); + shop.MapPost("/orders", CreateOrder); + shop.MapGet("/orders/{id}/status", GetOrderStatusById); + shop.MapPost("/orders/{id}/status", UpdateOrderStatus); + shop.MapPost("/orders/{id}/toppings", AddToppingsToOrder); + + shop.MapGet("/customers", GetAllCustomers); + shop.MapGet("/customer/{id}", GetCustomerById); + shop.MapPost("/customers", CreateCustomer); + + shop.MapGet("/pizzas", GetAllPizzas); + shop.MapGet("/pizzas/{id}", GetPizzaById); + shop.MapPost("/pizzas", CreatePizza); + + shop.MapGet("/toppings", GetAllToppings); + shop.MapGet("/toppings/{id}", GetToppingById); + shop.MapPost("/toppings", CreateTopping); + } + + private static string baseUrl(HttpContext context) { + return $"{context.Request.Scheme}://{context.Request.Host}"; + } + + private static async Task CreateTopping(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, ToppingPost toppingPost) + { + try + { + Topping topping = mapper.Map(toppingPost); + topping = await repository.Create(topping); + + var response = mapper.Map(topping); + return TypedResults.Created($"{baseUrl(context)}/shop/toppings/{topping.Id}", response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } + + private static async Task GetToppingById(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, int id) + { + try + { + var topping = await repository.GetById(id); + if (topping == null) + { + return TypedResults.NotFound(); + } + + var response = mapper.Map(topping); + return TypedResults.Ok(response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } + + private static async Task GetAllToppings(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper) + { + var results = await repository.GetAll(); + var response = mapper.Map>(results); + + return TypedResults.Ok(response); + } + + private static async Task CreatePizza(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, PizzaPost pizzaPost) + { + try + { + Pizza pizza = mapper.Map(pizzaPost); + pizza = await repository.Create(pizza); + + var response = mapper.Map(pizza); + return TypedResults.Created($"{baseUrl(context)}/shop/pizzas/{pizza.Id}", response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } + + private static async Task GetPizzaById(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, int id) + { + try + { + var pizza = await repository.GetById(id); + if (pizza == null) + { + return TypedResults.NotFound(); + } + + var response = mapper.Map(pizza); + return TypedResults.Ok(response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } + + private static async Task GetAllPizzas(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper) + { + var results = await repository.GetAll(); + var response = mapper.Map>(results); + + return TypedResults.Ok(response); + } + + private static async Task CreateCustomer(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, CustomerPost customerPost) + { + try + { + Customer customer = mapper.Map(customerPost); + customer = await repository.Create(customer); + + var response = mapper.Map(customer); + return TypedResults.Created($"{baseUrl(context)}/shop/customers/{customer.Id}", response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } } - + private static async Task GetCustomerById(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, int id) + { + try + { + var customer = await repository.GetById(id); + if (customer == null) + { + return TypedResults.NotFound(); + } + + var response = mapper.Map(customer); + return TypedResults.Ok(response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } + + private static async Task GetAllCustomers(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper) + { + var results = await repository.GetAll(); + var response = mapper.Map>(results); + + return TypedResults.Ok(response); + } + + private static async Task CreateOrder(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, OrderPost orderPost) + { + try + { + Order order = mapper.Map(orderPost); + order = await repository.Create(order); + + var response = mapper.Map(order); + return TypedResults.Created($"{baseUrl(context)}/shop/orders/{order.Id}", response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } + + private static async Task GetOrderById(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, int id) + { + try + { + var order = await repository.GetById(id); + if (order == null) + { + return TypedResults.NotFound(); + } + + var response = mapper.Map(order); + return TypedResults.Ok(response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } + + private static async Task GetAllOrders(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper) + { + var results = await repository.GetWithIncludes(o => o.Customer, o => o.Pizza); + var response = mapper.Map>(results); + + return TypedResults.Ok(response); + } + + private static async Task GetOrderStatusById(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, int id) + { + try + { + var order = await repository.GetById(id); + if (order == null) + { + return TypedResults.NotFound(); + } + + var response = mapper.Map(order); + return TypedResults.Ok(response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } + + private static async Task AddToppingsToOrder(HttpContext context, [FromServices] IRepository repository, [FromServices] IRepository orderRepo, [FromServices] IRepository toppingRepo, [FromServices] IMapper mapper, ToppingOrderPost toppingPost) + { + try + { + var order = await orderRepo.GetById(toppingPost.OrderId); + if (order == null) + { + return TypedResults.NotFound("Order not found"); + } + + var topping = await toppingRepo.GetById(toppingPost.ToppingId); + if (topping == null) + { + return TypedResults.NotFound("Topping not found"); + } + + OrderToppings orderTopping = new() + { + OrderId = toppingPost.OrderId, + ToppingId = toppingPost.ToppingId, + Order = order, + Topping = topping + }; + + await repository.Create(orderTopping); + + var response = mapper.Map(order); + return TypedResults.Ok(response); + } + catch (Exception ex) + { + Console.WriteLine(ex.StackTrace); + return TypedResults.Problem(ex.Message); + } + } + + private static async Task UpdateOrderStatus(HttpContext context, [FromServices] IRepository repository, [FromServices] IMapper mapper, OrderStatusPut orderStatusPut) + { + try + { + Order order = mapper.Map(orderStatusPut); + order = await repository.Update(order); + + var response = mapper.Map(order); + return TypedResults.Ok(response); + } + catch (Exception ex) + { + return TypedResults.Problem(ex.Message); + } + } } } diff --git a/exercise.pizzashopapi/Enums/OrderStage.cs b/exercise.pizzashopapi/Enums/OrderStage.cs new file mode 100644 index 0000000..097451a --- /dev/null +++ b/exercise.pizzashopapi/Enums/OrderStage.cs @@ -0,0 +1,9 @@ +namespace exercise.pizzashopapi.Enums; + +public enum OrderStage +{ + Preparing, + Cooking, + Delivering, + Delivered +} diff --git a/exercise.pizzashopapi/Migrations/20250128083459_Initial.Designer.cs b/exercise.pizzashopapi/Migrations/20250128083459_Initial.Designer.cs new file mode 100644 index 0000000..c8c0e5f --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128083459_Initial.Designer.cs @@ -0,0 +1,199 @@ +// +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("20250128083459_Initial")] + partial class Initial + { + /// + 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("OrderTopping", b => + { + b.Property("OrdersId") + .HasColumnType("integer"); + + b.Property("ToppingsId") + .HasColumnType("integer"); + + b.HasKey("OrdersId", "ToppingsId"); + + b.HasIndex("ToppingsId"); + + b.ToTable("OrderTopping"); + }); + + 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("OrderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrderStage") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.HasKey("OrderId", "ToppingId"); + + 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("OrderTopping", b => + { + b.HasOne("exercise.pizzashopapi.Models.Order", null) + .WithMany() + .HasForeignKey("OrdersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", null) + .WithMany() + .HasForeignKey("ToppingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.HasOne("exercise.pizzashopapi.Models.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Pizza", "Pizza") + .WithMany() + .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() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany() + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250128083459_Initial.cs b/exercise.pizzashopapi/Migrations/20250128083459_Initial.cs new file mode 100644 index 0000000..60f7e44 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128083459_Initial.cs @@ -0,0 +1,175 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class Initial : 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), + OrderDate = table.Column(type: "timestamp with time zone", nullable: false), + OrderStage = table.Column(type: "integer", 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: "OrderTopping", + columns: table => new + { + OrdersId = table.Column(type: "integer", nullable: false), + ToppingsId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrderTopping", x => new { x.OrdersId, x.ToppingsId }); + table.ForeignKey( + name: "FK_OrderTopping_Orders_OrdersId", + column: x => x.OrdersId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_OrderTopping_Toppings_ToppingsId", + column: x => x.ToppingsId, + principalTable: "Toppings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "OrderToppings", + columns: table => new + { + OrderId = table.Column(type: "integer", nullable: false), + ToppingId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrderToppings", x => new { x.OrderId, x.ToppingId }); + 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_OrderTopping_ToppingsId", + table: "OrderTopping", + column: "ToppingsId"); + + migrationBuilder.CreateIndex( + name: "IX_OrderToppings_ToppingId", + table: "OrderToppings", + column: "ToppingId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "OrderTopping"); + + 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/20250128084332_Customertable.Designer.cs b/exercise.pizzashopapi/Migrations/20250128084332_Customertable.Designer.cs new file mode 100644 index 0000000..2c504ba --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128084332_Customertable.Designer.cs @@ -0,0 +1,169 @@ +// +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("20250128084332_Customertable")] + partial class Customertable + { + /// + 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("OrderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrderStage") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.HasKey("OrderId", "ToppingId"); + + 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() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Pizza", "Pizza") + .WithMany() + .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() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany() + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250128084332_Customertable.cs b/exercise.pizzashopapi/Migrations/20250128084332_Customertable.cs new file mode 100644 index 0000000..0051b5a --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128084332_Customertable.cs @@ -0,0 +1,50 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class Customertable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "OrderTopping"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "OrderTopping", + columns: table => new + { + OrdersId = table.Column(type: "integer", nullable: false), + ToppingsId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrderTopping", x => new { x.OrdersId, x.ToppingsId }); + table.ForeignKey( + name: "FK_OrderTopping_Orders_OrdersId", + column: x => x.OrdersId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_OrderTopping_Toppings_ToppingsId", + column: x => x.ToppingsId, + principalTable: "Toppings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_OrderTopping_ToppingsId", + table: "OrderTopping", + column: "ToppingsId"); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250128100022_TableNameUpdate.Designer.cs b/exercise.pizzashopapi/Migrations/20250128100022_TableNameUpdate.Designer.cs new file mode 100644 index 0000000..e52a382 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128100022_TableNameUpdate.Designer.cs @@ -0,0 +1,169 @@ +// +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("20250128100022_TableNameUpdate")] + partial class TableNameUpdate + { + /// + 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("OrderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrderStage") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.HasKey("OrderId", "ToppingId"); + + b.HasIndex("ToppingId"); + + b.ToTable("order_toppings"); + }); + + 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() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Pizza", "Pizza") + .WithMany() + .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() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany() + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250128100022_TableNameUpdate.cs b/exercise.pizzashopapi/Migrations/20250128100022_TableNameUpdate.cs new file mode 100644 index 0000000..98ef42f --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128100022_TableNameUpdate.cs @@ -0,0 +1,274 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class TableNameUpdate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Orders_Customers_CustomerId", + table: "Orders"); + + migrationBuilder.DropForeignKey( + name: "FK_Orders_Pizzas_PizzaId", + table: "Orders"); + + migrationBuilder.DropForeignKey( + name: "FK_OrderToppings_Orders_OrderId", + table: "OrderToppings"); + + migrationBuilder.DropForeignKey( + name: "FK_OrderToppings_Toppings_ToppingId", + table: "OrderToppings"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Toppings", + table: "Toppings"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Pizzas", + table: "Pizzas"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Orders", + table: "Orders"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Customers", + table: "Customers"); + + migrationBuilder.DropPrimaryKey( + name: "PK_OrderToppings", + table: "OrderToppings"); + + migrationBuilder.RenameTable( + name: "Toppings", + newName: "toppings"); + + migrationBuilder.RenameTable( + name: "Pizzas", + newName: "pizzas"); + + migrationBuilder.RenameTable( + name: "Orders", + newName: "orders"); + + migrationBuilder.RenameTable( + name: "Customers", + newName: "customers"); + + migrationBuilder.RenameTable( + name: "OrderToppings", + newName: "order_toppings"); + + migrationBuilder.RenameIndex( + name: "IX_Orders_PizzaId", + table: "orders", + newName: "IX_orders_PizzaId"); + + migrationBuilder.RenameIndex( + name: "IX_Orders_CustomerId", + table: "orders", + newName: "IX_orders_CustomerId"); + + migrationBuilder.RenameIndex( + name: "IX_OrderToppings_ToppingId", + table: "order_toppings", + newName: "IX_order_toppings_ToppingId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_toppings", + table: "toppings", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_pizzas", + table: "pizzas", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_orders", + table: "orders", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_customers", + table: "customers", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_order_toppings", + table: "order_toppings", + columns: new[] { "OrderId", "ToppingId" }); + + migrationBuilder.AddForeignKey( + name: "FK_order_toppings_orders_OrderId", + table: "order_toppings", + column: "OrderId", + principalTable: "orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_order_toppings_toppings_ToppingId", + table: "order_toppings", + column: "ToppingId", + principalTable: "toppings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_orders_customers_CustomerId", + table: "orders", + column: "CustomerId", + principalTable: "customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_orders_pizzas_PizzaId", + table: "orders", + column: "PizzaId", + principalTable: "pizzas", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_order_toppings_orders_OrderId", + table: "order_toppings"); + + migrationBuilder.DropForeignKey( + name: "FK_order_toppings_toppings_ToppingId", + table: "order_toppings"); + + migrationBuilder.DropForeignKey( + name: "FK_orders_customers_CustomerId", + table: "orders"); + + migrationBuilder.DropForeignKey( + name: "FK_orders_pizzas_PizzaId", + table: "orders"); + + migrationBuilder.DropPrimaryKey( + name: "PK_toppings", + table: "toppings"); + + migrationBuilder.DropPrimaryKey( + name: "PK_pizzas", + table: "pizzas"); + + migrationBuilder.DropPrimaryKey( + name: "PK_orders", + table: "orders"); + + migrationBuilder.DropPrimaryKey( + name: "PK_customers", + table: "customers"); + + migrationBuilder.DropPrimaryKey( + name: "PK_order_toppings", + table: "order_toppings"); + + migrationBuilder.RenameTable( + name: "toppings", + newName: "Toppings"); + + migrationBuilder.RenameTable( + name: "pizzas", + newName: "Pizzas"); + + migrationBuilder.RenameTable( + name: "orders", + newName: "Orders"); + + migrationBuilder.RenameTable( + name: "customers", + newName: "Customers"); + + migrationBuilder.RenameTable( + name: "order_toppings", + newName: "OrderToppings"); + + migrationBuilder.RenameIndex( + name: "IX_orders_PizzaId", + table: "Orders", + newName: "IX_Orders_PizzaId"); + + migrationBuilder.RenameIndex( + name: "IX_orders_CustomerId", + table: "Orders", + newName: "IX_Orders_CustomerId"); + + migrationBuilder.RenameIndex( + name: "IX_order_toppings_ToppingId", + table: "OrderToppings", + newName: "IX_OrderToppings_ToppingId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Toppings", + table: "Toppings", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Pizzas", + table: "Pizzas", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Orders", + table: "Orders", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Customers", + table: "Customers", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_OrderToppings", + table: "OrderToppings", + columns: new[] { "OrderId", "ToppingId" }); + + migrationBuilder.AddForeignKey( + name: "FK_Orders_Customers_CustomerId", + table: "Orders", + column: "CustomerId", + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Orders_Pizzas_PizzaId", + table: "Orders", + column: "PizzaId", + principalTable: "Pizzas", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_OrderToppings_Orders_OrderId", + table: "OrderToppings", + column: "OrderId", + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_OrderToppings_Toppings_ToppingId", + table: "OrderToppings", + column: "ToppingId", + principalTable: "Toppings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 0000000..f4a8ef6 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,166 @@ +// +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("OrderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrderStage") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.HasKey("OrderId", "ToppingId"); + + b.HasIndex("ToppingId"); + + b.ToTable("order_toppings"); + }); + + 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() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Pizza", "Pizza") + .WithMany() + .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() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany() + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Models/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index 2ca83bd..608fb8a 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -1,9 +1,12 @@ -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace exercise.pizzashopapi.Models { + [Table("customers")] public class Customer { + [Key] public int Id { get; set; } public string Name { get; set; } } diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index fbe6113..213c2c1 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -1,10 +1,22 @@ -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using exercise.pizzashopapi.Enums; namespace exercise.pizzashopapi.Models { + [Table("orders")] public class Order { - - + [Key] + public int Id { get; set; } + public int CustomerId { get; set; } + public int PizzaId { get; set; } + public Customer Customer { get; set; } + public Pizza Pizza { get; set; } + public ICollection OrderToppings { get; set; } // Add this line + [NotMapped] + public IEnumerable Toppings { get; set; } + public DateTime OrderDate { get; set; } + public OrderStage OrderStage { get; set; } } } diff --git a/exercise.pizzashopapi/Models/OrderToppings.cs b/exercise.pizzashopapi/Models/OrderToppings.cs new file mode 100644 index 0000000..f163d0b --- /dev/null +++ b/exercise.pizzashopapi/Models/OrderToppings.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace exercise.pizzashopapi.Models; + +[Table("order_toppings")] +public class OrderToppings +{ + [ForeignKey("order_id")] + public int OrderId { get; set; } + public Order Order { get; set; } + [ForeignKey("topping_id")] + public int ToppingId { get; set; } + public Topping Topping { get; set; } +} diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index 5c085ec..7f8c30b 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -1,10 +1,12 @@ -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace exercise.pizzashopapi.Models { - + [Table("pizzas")] public class Pizza { + [Key] public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } diff --git a/exercise.pizzashopapi/Models/Topping.cs b/exercise.pizzashopapi/Models/Topping.cs new file mode 100644 index 0000000..3e46d8f --- /dev/null +++ b/exercise.pizzashopapi/Models/Topping.cs @@ -0,0 +1,14 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace exercise.pizzashopapi.Models; + +[Table("toppings")] +public class Topping +{ + [Key] + public int Id { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } +} diff --git a/exercise.pizzashopapi/Program.cs b/exercise.pizzashopapi/Program.cs index c04a440..aa95416 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,12 +8,22 @@ // Add services to the container. builder.Services.AddControllers(); -builder.Services.AddScoped(); + builder.Services.AddDbContext(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +builder.Services.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); + + +builder.Services.AddAutoMapper(typeof(Program)); + + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -23,13 +34,8 @@ } app.UseHttpsRedirection(); - app.UseAuthorization(); - app.MapControllers(); - -app.ConfigurePizzaShopApi(); - +app.ConfigurePizzaShopApi(); // Ensure this line is present to register the endpoints app.SeedPizzaShopApi(); - app.Run(); diff --git a/exercise.pizzashopapi/Repository/IRepository.cs b/exercise.pizzashopapi/Repository/IRepository.cs index b114ea8..0cdd189 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -1,11 +1,16 @@ -using exercise.pizzashopapi.Models; +using System.Linq.Expressions; +using exercise.pizzashopapi.Models; namespace exercise.pizzashopapi.Repository { - public interface IRepository + public interface IRepository where T : class { - Task> GetOrdersByCustomer(int id); - - + Task> GetAll(); + Task GetById(int id); + Task Create(T entity); + Task Update(T entity); + Task Delete(int id); + Task> GetWithIncludes(params Expression>[] includes); + Task Save(); } } diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index e109fce..a2e3031 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -1,14 +1,66 @@ -using exercise.pizzashopapi.Data; +using System.Linq.Expressions; +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 DbSet _table = null; private DataContext _db; - public Task> GetOrdersByCustomer(int id) + public Repository(DataContext db) { - throw new NotImplementedException(); + _db = db; + _table = _db.Set(); + } + + public async Task> GetAll() + { + return _table.ToList(); + } + public async Task GetById(int id) + { + return await _table.FindAsync(id); + } + public async Task Create(T entity) + { + _table.Add(entity); + await _db.SaveChangesAsync(); + return entity; + } + public async Task Update(T entity) + { + _table.Update(entity); + _db.Entry(entity).State = EntityState.Modified; + await _db.SaveChangesAsync(); + return entity; + } + public async Task Delete(int id) + { + var entity = await _table.FindAsync(id); + if (entity == null) + { + return entity; + } + _table.Remove(entity); + await _db.SaveChangesAsync(); + return entity; + } + + public async Task> GetWithIncludes(params Expression>[] includes) + { + IQueryable query = _table; + foreach (var include in includes) + { + query = query.Include(include); + } + return await query.ToListAsync(); + } + + public async Task Save() + { + await _db.SaveChangesAsync(); } } } diff --git a/exercise.pizzashopapi/Tools/MappingProfile.cs b/exercise.pizzashopapi/Tools/MappingProfile.cs new file mode 100644 index 0000000..06d11da --- /dev/null +++ b/exercise.pizzashopapi/Tools/MappingProfile.cs @@ -0,0 +1,24 @@ +using System; +using AutoMapper; +using exercise.pizzashopapi.DTO; +using exercise.pizzashopapi.Models; + +namespace exercise.pizzashopapi.Tools; + +public class MappingProfile : Profile +{ + public MappingProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/exercise.pizzashopapi/exercise.pizzashopapi.csproj b/exercise.pizzashopapi/exercise.pizzashopapi.csproj index 624203b..e8e90cf 100644 --- a/exercise.pizzashopapi/exercise.pizzashopapi.csproj +++ b/exercise.pizzashopapi/exercise.pizzashopapi.csproj @@ -11,6 +11,7 @@ + all