diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index ccb218a0d..ada0fdfa9 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -3,10 +3,11 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers { using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; - using Microsoft.eShopOnContainers.Services.Catalog.API.Model; + using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using System; using System.Linq; using System.Threading.Tasks; + using ViewModel; [Route("api/v1/[controller]")] public class CatalogController : ControllerBase @@ -18,29 +19,71 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers _context = context; } - // GET api/v1/[controller]/all + // GET api/v1/[controller]/items/[?pageSize=3&pageIndex=10] [HttpGet] [Route("[action]")] - public async Task All() + public async Task Items(int pageSize = 10, int pageIndex = 0) { - var items = await _context.CatalogItems + var totalItems = await _context.CatalogItems + .LongCountAsync(); + + var itemsOnPage = await _context.CatalogItems + .Skip(pageSize * pageIndex) + .Take(pageSize) + .ToListAsync(); + + var model = new PaginatedItemsViewModel( + pageIndex, pageSize, totalItems, itemsOnPage); + + return Ok(model); + } + + // GET api/v1/[controller]/FindCatalogItemByName/samplename + + [HttpGet] + [Route("[action]/{name:minlength(1)}")] + public async Task Items(string name, int pageSize = 10, int pageIndex = 0) + { + + var totalItems = await _context.CatalogItems + .Where(c => c.Name.StartsWith(name)) + .LongCountAsync(); + + var itemsOnPage = await _context.CatalogItems + .Where(c => c.Name.StartsWith(name)) + .Skip(pageSize * pageIndex) + .Take(pageSize) + .ToListAsync(); + + var model = new PaginatedItemsViewModel( + pageIndex, pageSize, totalItems, itemsOnPage); + + return Ok(model); + } + + // GET api/v1/[controller]/CatalogTypes + + [HttpGet] + [Route("[action]")] + public async Task CatalogTypes() + { + var items = await _context.CatalogTypes .ToListAsync(); return Ok(items); } - // GET api/v1/[controller]/FindByName/samplename + // GET api/v1/[controller]/CatalogBrands [HttpGet] - [Route("FindByName/{name:minlength(1)}")] - public async Task Find(string name) + [Route("[action]")] + public async Task CatalogBrands() { - var items = await _context.CatalogItems - .Where(c => c.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase)) + var items = await _context.CatalogBrands .ToListAsync(); - return Ok(); + return Ok(items); } } } diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs new file mode 100644 index 000000000..a8b3cc642 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs @@ -0,0 +1,15 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + + public class CatalogBrand + { + public int Id { get; set; } + + public string Brand { get; set; } + } +} diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs new file mode 100644 index 000000000..cff069456 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs @@ -0,0 +1,86 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure +{ + using EntityFrameworkCore.Metadata.Builders; + using Microsoft.EntityFrameworkCore; + using Npgsql.EntityFrameworkCore.PostgreSQL; + + public class CatalogContext : DbContext + { + public CatalogContext(DbContextOptions options) : base(options) + { + } + + public DbSet CatalogItems { get; set; } + + public DbSet CatalogBrands { get; set; } + + public DbSet CatalogTypes { get; set; } + + protected override void OnModelCreating(ModelBuilder builder) + { + builder.HasSequence("idseqcatalog") + .StartsAt(1) + .IncrementsBy(1); + + builder.HasSequence("idseqcatalogbrand") + .StartsAt(1) + .IncrementsBy(1); + + builder.HasSequence("idseqcatalogtype") + .StartsAt(1) + .IncrementsBy(1); + + builder.Entity(ConfigureCatalogItem); + builder.Entity(ConfigureCatalogBrand); + builder.Entity(ConfigureCatalogType); + + builder.HasPostgresExtension("uuid-ossp"); + } + + void ConfigureCatalogItem(EntityTypeBuilder builder) + { + builder.ForNpgsqlToTable("catalog"); + + builder.Property(ci => ci.Id) + .HasDefaultValueSql("nextval('idseqcatalog')") + .IsRequired(); + + builder.Property(ci => ci.Name) + .IsRequired(true) + .HasMaxLength(50); + + builder.Property(ci => ci.Price) + .IsRequired(true); + + builder.Property(ci => ci.PictureUri) + .IsRequired(false); + + } + + void ConfigureCatalogBrand(EntityTypeBuilder builder) + { + builder.ForNpgsqlToTable("catalogbrand"); + + builder.Property(cb => cb.Id) + .HasDefaultValueSql("nextval('idseqcatalogbrand')") + .IsRequired(); + + builder.Property(cb => cb.Brand) + .IsRequired() + .HasMaxLength(100); + } + + void ConfigureCatalogType(EntityTypeBuilder builder) + { + builder.ForNpgsqlToTable("catalogtype"); + + builder.Property(cb => cb.Id) + .HasDefaultValueSql("nextval('idseqcatalogtype')") + .IsRequired(); + + builder.Property(cb => cb.Type) + .IsRequired() + .HasMaxLength(100); + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs new file mode 100644 index 000000000..76b1d1c53 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs @@ -0,0 +1,75 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure +{ + using Microsoft.AspNetCore.Builder; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + public class CatalogContextSeed + { + public static async Task SeedAsync(IApplicationBuilder applicationBuilder) + { + var context = (CatalogContext)applicationBuilder + .ApplicationServices.GetService(typeof(CatalogContext)); + + using (context) + { + context.Database.EnsureCreated(); + + if (!context.CatalogBrands.Any()) + { + context.CatalogBrands.AddRange( + GetPreconfiguredCatalogBrands()); + + await context.SaveChangesAsync(); + } + + if (!context.CatalogTypes.Any()) + { + context.CatalogTypes.AddRange( + GetPreconfiguredCatalogTypes()); + + await context.SaveChangesAsync(); + } + + if (!context.CatalogItems.Any()) + { + context.CatalogItems.AddRange( + GetPreconfiguredItems()); + + await context.SaveChangesAsync(); + } + } + } + + static IEnumerable GetPreconfiguredCatalogBrands() + { + return new List() + { + new CatalogBrand() { Brand="Azure"}, + new CatalogBrand() { Brand = "Visual Studio" } + }; + } + + static IEnumerable GetPreconfiguredCatalogTypes() + { + return new List() + { + new CatalogType() { Type="Mug"}, + new CatalogType() { Type = "T-Shirt" } + }; + } + + static IEnumerable GetPreconfiguredItems() + { + return new List() + { + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + }; + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogItem.cs similarity index 53% rename from src/Services/Catalog/Catalog.API/Model/CatalogItem.cs rename to src/Services/Catalog/Catalog.API/Infrastructure/CatalogItem.cs index b79f7bd1a..0c01486e1 100644 --- a/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogItem.cs @@ -1,4 +1,4 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure { using System; @@ -14,6 +14,14 @@ public string PictureUri { get; set; } + public int CatalogTypeId { get; set; } + + public CatalogType CatalogType { get; set; } + + public int CatalogBrandId { get; set; } + + public CatalogBrand CatalogBrand { get; set; } + public CatalogItem() { } } } diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs new file mode 100644 index 000000000..5577427fa --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs @@ -0,0 +1,14 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + public class CatalogType + { + public int Id { get; set; } + + public string Type { get; set; } + } +} diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs b/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs deleted file mode 100644 index dc78bce84..000000000 --- a/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model -{ - using EntityFrameworkCore.Metadata.Builders; - using Microsoft.EntityFrameworkCore; - using Npgsql.EntityFrameworkCore.PostgreSQL; - - public class CatalogContext : DbContext - { - public CatalogContext(DbContextOptions options) : base(options) - { - } - - public DbSet CatalogItems { get; set; } - - protected override void OnModelCreating(ModelBuilder builder) - { - builder.HasSequence("idseq") - .StartsAt(1) - .IncrementsBy(1); - - builder.Entity(ConfigureCatalogItem); - - builder.HasPostgresExtension("uuid-ossp"); - } - - void ConfigureCatalogItem(EntityTypeBuilder builder) - { - builder.ForNpgsqlToTable("catalog"); - - builder.Property(ci => ci.Id) - .HasDefaultValueSql("nextval('idseq')") - .IsRequired(); - - builder.Property(ci => ci.Name) - .IsRequired(true) - .HasMaxLength(50); - - builder.Property(ci => ci.Price) - .IsRequired(true); - - builder.Property(ci => ci.PictureUri) - .IsRequired(false); - - } - } -} diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs b/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs deleted file mode 100644 index a941dc165..000000000 --- a/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs +++ /dev/null @@ -1,67 +0,0 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model -{ - using Microsoft.AspNetCore.Builder; - using Model; - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - - public class CatalogContextSeed - { - public static async Task SeedAsync(IApplicationBuilder applicationBuilder) - { - var context = (CatalogContext)applicationBuilder - .ApplicationServices.GetService(typeof(CatalogContext)); - - using (context) - { - context.Database.EnsureCreated(); - - if (!context.CatalogItems.Any()) - { - context.CatalogItems.AddRange( - GetPreconfiguredItems()); - - await context.SaveChangesAsync(); - } - } - } - - static IEnumerable GetPreconfiguredItems() - { - return new List() - { - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" } - - }; - } - } -} diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 08a0baafb..9507678a2 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.eShopOnContainers.Services.Catalog.API.Model; +using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs b/src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs new file mode 100644 index 000000000..844f38e2b --- /dev/null +++ b/src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs @@ -0,0 +1,24 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel +{ + using System.Collections.Generic; + + + public class PaginatedItemsViewModel where TEntity : class + { + public int PageIndex { get; private set; } + + public int PageSize { get; private set; } + + public long Count { get; private set; } + + public IEnumerable Data { get; private set; } + + public PaginatedItemsViewModel(int pageIndex, int pageSize, long count, IEnumerable data) + { + this.PageIndex = pageIndex; + this.PageSize = pageSize; + this.Count = count; + this.Data = data; + } + } +}