Compare commits

..

4 Commits

Author SHA1 Message Date
khwezi 466458e230 Merge pull request 'Implemented Product Data Seeder' (#45) from midrandshop into master
Reviewed-on: #45
2026-05-29 18:56:45 +02:00
Khwezi Mngoma 60fcc70e98 Implemented Product Data Seeder
continuous-integration/drone/pr Build is passing
2026-05-29 18:56:08 +02:00
khwezi 141d32f591 Merge pull request 'Refactored migrations' (#44) from midrandshop into master
Reviewed-on: #44
2026-05-29 09:03:27 +02:00
Khwezi Mngoma 38e765203d Refactored migrations
continuous-integration/drone/pr Build is passing
2026-05-29 09:02:47 +02:00
12 changed files with 417 additions and 134 deletions
@@ -0,0 +1,8 @@
namespace LiteCharms.Features.MidrandBooks.Seed.Configuration;
public class CdnSettings
{
public string? BaseCdn { get; set; }
public string[]? BookCovers { get; set; }
}
@@ -0,0 +1,158 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>5c3bc894-8654-4691-99e8-f90d3414843f</UserSecretsId>
</PropertyGroup>
<!-- Quartz Scheduler-->
<ItemGroup>
<PackageReference Include="Bogus" Version="35.6.5" />
<PackageReference Include="Meziantou.Analyzer" Version="3.0.96">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="OpenTelemetry" Version="1.15.3" />
<PackageReference Include="Quartz" Version="3.18.1" />
<PackageReference Include="Quartz.Plugins" Version="3.18.1" />
<PackageReference Include="Quartz.Plugins.TimeZoneConverter" Version="3.18.1" />
<PackageReference Include="Quartz.Serialization.SystemTextJson" Version="3.18.1" />
<PackageReference Include="Quartz.AspNetCore" Version="3.18.1" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.18.1" />
<!-- Global Usings -->
<Using Include="Quartz" />
</ItemGroup>
<!-- Configuration -->
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.8" />
<!-- Global Usings -->
<Using Include="Microsoft.Extensions.Configuration" />
</ItemGroup>
<!-- Health Checks -->
<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Data" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="10.0.8" />
<!-- Global Usings -->
<Using Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
<Using Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" />
</ItemGroup>
<!-- Open Telemetry -->
<ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.15.3" />
<!-- Global Usings -->
<Using Include="OpenTelemetry.Resources" />
<Using Include="OpenTelemetry.Exporter" />
<Using Include="OpenTelemetry.Logs" />
<Using Include="OpenTelemetry.Metrics" />
<Using Include="OpenTelemetry.Trace" />
</ItemGroup>
<!-- Database -->
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
<!-- Global Usings -->
<Using Include="Npgsql" />
<Using Include="Microsoft.EntityFrameworkCore" />
<Using Include="Microsoft.EntityFrameworkCore.Design" />
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
</ItemGroup>
<!-- Email -->
<ItemGroup>
<PackageReference Include="MailKit" Version="4.16.0" />
<PackageReference Include="MimeKit" Version="4.16.0" />
<!-- Global Usings-->
<Using Include="MimeKit" />
<Using Include="MailKit.Net.Smtp" />
</ItemGroup>
<!-- CQRS -->
<ItemGroup>
<PackageReference Include="FluentResults" Version="4.0.0" />
<PackageReference Include="Mediator.Abstractions" Version="3.0.2" />
<!-- Global Usings -->
<Using Include="FluentResults" />
<Using Include="Mediator" />
</ItemGroup>
<!-- Amazon S3 SDK -->
<ItemGroup>
<PackageReference Include="AWSSDK.Extensions.NetCore.Setup" Version="4.0.4.1" />
<PackageReference Include="AWSSDK.S3" Version="4.0.23.4" />
<ProjectReference Include="..\LiteCharms.Features\LiteCharms.Features.csproj" />
<!-- global Usings -->
<Using Include="Amazon.S3" />
<Using Include="Amazon.S3.Model" />
<Using Include="Amazon.Runtime" />
</ItemGroup>
<!-- Shared Usings -->
<ItemGroup>
<Using Include="Bogus" />
<Using Include="System.Globalization" />
<Using Include="System.Reflection" />
<Using Include="Microsoft.AspNetCore.Builder" />
<Using Include="Microsoft.Extensions.Hosting" />
<Using Include="System.Text" />
<Using Include="System.Text.Json" />
<Using Include="System.Threading.Channels" />
<Using Include="System.Collections.ObjectModel" />
<Using Include="System.Diagnostics" />
<Using Include="System.Diagnostics.Metrics" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<Using Include="System.Security.Cryptography" />
<Using Include="Microsoft.Extensions.Options" />
<Using Include="Microsoft.Extensions.Logging" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LiteCharms.Features.MidrandBooks\LiteCharms.Features.MidrandBooks.csproj" />
<ProjectReference Include="..\LiteCharms.Features\LiteCharms.Features.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,190 @@
using LiteCharms.Features.MidrandBooks.AuthorBooks;
using LiteCharms.Features.MidrandBooks.Authors;
using LiteCharms.Features.MidrandBooks.Products;
using LiteCharms.Features.MidrandBooks.Seed.Configuration;
namespace LiteCharms.Features.MidrandBooks.Seed;
public class ProductsSeederService(ProductService productService, AuthorService authorService, BooksService booksService,
IOptions<CdnSettings> options, ILogger<ProductsSeederService> logger) : BackgroundService
{
private readonly CdnSettings cdnSettings = options.Value;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
logger.LogInformation("Product Seeding started");
if (cdnSettings.BookCovers is null || cdnSettings.BookCovers.Length == 0)
{
logger.LogWarning("No book covers found in CDN settings. Seeding aborted.");
return;
}
// Initialize Bogus Faker engine
var faker = new Faker();
var culture = CultureInfo.InvariantCulture;
// Ensure repeatable data sets if run multiple times by anchoring the seed
Randomizer.Seed = new Random(42);
foreach (var bookCover in cdnSettings.BookCovers)
{
if (stoppingToken.IsCancellationRequested) break;
// Generate beautifully mixed eclectic topics on the fly
var bookTopic = faker.PickRandom(
// --- Tech & IT ---
"C# 12 & Modern .NET Architecture",
"PostgreSQL Database Optimization",
"Docker & Kubernetes in Production",
"Domain-Driven Design Paradigms",
"Artificial Intelligence with Python",
// --- Sci-Fi & Fantasy ---
"The Chronicles of the Quantum Nebula",
"Legends of the Lost Cybernetic Kingdom",
"Parallel Dimensions and Rogue Time Streams",
"The Last Android in Neo-Johannesburg",
// --- Thrillers, Mystery & Crime ---
"The Midnight Code Cryptograph",
"Shadows in the Highveld",
"The Silent Witness of Midrand",
"Deception on the 14th Floor",
// --- Business, Finance & Wealth ---
"Mastering the South African Tech Market",
"The Modern Entrepreneur's Blueprint",
"Generational Wealth and Venture Capital",
"Negotiation Tactics for High-Stakes Deals",
// --- Self-Help & Personal Growth ---
"The Art of Relentless Focus",
"Building High-Performance Habits",
"The Mindfulness Guide for Software Engineers",
"Unlocking Creative Flow Under Pressure"
);
// Defensive Length Processing to avoid Entity Framework / Postgres string truncation crashes
var rawTitle = $"{faker.Company.CatchPhrase()} with {bookTopic}";
var bookTitle = rawTitle.Length > 255 ? rawTitle[..252] + "..." : rawTitle;
var rawSummary = $"A comprehensive guide to mastering {bookTopic}. Learn modern implementation techniques through real-world software engineering paradigms.";
var bookSummary = rawSummary.Length > 512 ? rawSummary[..509] + "..." : rawSummary;
// Generating a single concise paragraph ensures a rich text description falling safely well under 1024
var rawDescription = faker.Lorem.Paragraph(3);
var bookDescription = rawDescription.Length > 1024 ? rawDescription[..1021] + "..." : rawDescription;
var authorFirstName = faker.Name.FirstName();
var authorLastName = faker.Name.LastName();
var publisherCompany = faker.Company.CompanyName();
// Step 1: Add Product
var productCreateResult = await productService.CreateProductAsync(new Products.Models.CreateProduct
{
Name = bookTitle,
Summary = bookSummary,
Description = bookDescription,
ImageUrl = $"{cdnSettings.BaseCdn}{bookCover}",
Type = ProductTypes.Book,
Metadata = new Models.ProductMetadata
{
CopyrightInfo = $"© {DateTime.UtcNow.Year} {publisherCompany}. All rights reserved.",
ManufactureDate = faker.Date.Past(3).ToString("yyyy-MM-dd", culture),
Manufacturer = $"{authorFirstName} {authorLastName} / {publisherCompany}",
SerialNumber = faker.Phone.PhoneNumber("978-##########")
},
Categories = ["Coding", "Computers", "IT"]
}, stoppingToken);
if (productCreateResult.IsFailed)
{
logger.LogError("Failed to create product: {Error}", productCreateResult.Errors[0].Message);
break;
}
// Step 2: Enable product so it can show on the shop
var enableProductResult = await productService.UpdateProductStatusAsync(productId: productCreateResult.Value, isEnabled: true, stoppingToken);
if (enableProductResult.IsFailed)
{
logger.LogError("Failed to enable created product: {Error}", enableProductResult.Errors[0].Message);
break;
}
// Step 3: Create Product Price
var productPriceCreateResult = await productService.CreateProductPriceAsync(productId: productCreateResult.Value, request: new Products.Models.CreateProductPrice
{
// Generates fair, dynamic prices in Rands between R150 and R650, snapped neatly to integers
Amount = Math.Round(faker.Random.Decimal(150m, 650m), 2),
Discount = 0.0m
}, stoppingToken);
if (productPriceCreateResult.IsFailed)
{
logger.LogError("Failed to create product price: {Error}", productPriceCreateResult.Errors[0].Message);
break;
}
// Step 4: Create Author
var authorCreateResult = await authorService.CreateAuthorAsync(request: new Authors.Models.CreateAuthor
{
Name = authorFirstName,
LastName = authorLastName,
Company = publisherCompany,
VatNumber = faker.Random.Bool() ? faker.Phone.PhoneNumber("4#########") : "",
PublisherType = faker.PickRandom<PublisherTypes>(),
Email = faker.Internet.Email(authorFirstName, authorLastName),
Website = faker.Internet.Url(),
ImageUrl = faker.Internet.Avatar(),
SocialMedia =
[
new Models.SocialMedia
{
Name = "LinkedIn",
ImageUrl = "https://cdn.example.com/icons/linkedin.png",
Type = SocialMediaTypes.LinkedIn,
Url = $"https://linkedin.com/in/{authorFirstName.ToLower(culture)}-{authorLastName.ToLower(culture)}"
},
new Models.SocialMedia
{
Name = "GitHub",
ImageUrl = "https://cdn.example.com/icons/github.png",
Type = SocialMediaTypes.GitHub,
Url = $"https://github.com/tech-{authorFirstName.ToLower(culture)}"
}
],
Biography = $"{authorFirstName} {authorLastName} is a veteran technologist and systems architect with over a decade of domain expertise. " + faker.Lorem.Paragraph(2),
ThumbnailImageUrl = null
}, stoppingToken);
if (authorCreateResult.IsFailed)
{
logger.LogError("Failed to create author: {Error}", authorCreateResult.Errors[0].Message);
break;
}
// Step 5: Create Author-Book link (product linkage)
var authorBookCreateResult = await booksService.CreateBookAsync(authorId: authorCreateResult.Value, productId: productCreateResult.Value, stoppingToken);
if (authorBookCreateResult.IsFailed)
{
logger.LogError("Failed to create author-book linkage: {Error}", authorBookCreateResult.Errors[0].Message);
break;
}
var enableAuthorBookResult = await booksService.UpdateBookStatusAsync(bookId: authorBookCreateResult.Value, isEnabled: true, stoppingToken);
if (enableAuthorBookResult.IsFailed)
{
logger.LogError("Failed to enable author-book link: {Error}", enableAuthorBookResult.Errors[0].Message);
break;
}
logger.LogInformation("Successfully seeded book product: {Title}", bookTitle);
}
logger.LogInformation("Product Seeding completed successfully.");
}
}
@@ -0,0 +1,21 @@
using LiteCharms.Features.MidrandBooks.Extensions;
using LiteCharms.Features.MidrandBooks.Seed;
using LiteCharms.Features.MidrandBooks.Seed.Configuration;
var builder = Host.CreateApplicationBuilder(args);
builder.Configuration
.AddJsonFile("appsettings.json")
.AddUserSecrets(typeof(Program).Assembly);
builder.Services
.AddLogging()
.AddShopServices()
.AddHostedService<ProductsSeederService>()
.AddMidrandShopDatabase(builder.Configuration);
builder.Services.Configure<CdnSettings>(options => builder.Configuration.GetSection(nameof(CdnSettings)).Bind(options));
using var host = builder.Build();
await host.RunAsync();
@@ -0,0 +1,28 @@
{
"CdnSettings": {
"BaseCdn": "https://bookshop.cdn.khongisa.co.za/design/",
"BookCovers": [
"144e0314-0bd8-4e2c-8814-2b34608c0600_1764780116467.webp",
"2bf1f9a2-7b25-4fcf-9aa7-08941ea21e6c_1764838499686.webp",
"3cd172b9-416e-4b3a-b613-7ff0a3aecc4c_1764780129459.webp",
"762947b6-63ac-436e-98fb-91dd94de1d82_1764780126141.webp",
"7b42f23f-666c-4dd9-82e1-9b928e1b4db7_1764780186376.webp",
"8e281eea-8910-473d-b650-43f539995d9e_1764780152316.webp",
"91d18e2c-6ee6-44b4-84a5-8692db5dbfe4_1764780114484.webp",
"94fdf403-4d10-4cb4-a537-fc914a1f5ba8_1764780198423.webp",
"9b881786-75e1-47f7-9bc9-27188d46d1ec_1764780122458.webp",
"c417236d-a628-45eb-82c2-ec1cb0326e4f_1765006317965.webp",
"clpqjsgi71jpr1i6392e449l2.webp",
"clps1mk9f0m1z1i32grvq17tg.webp",
"clq550xxy2dab1ywb6mdv4acv.webp",
"clq5535o52dj51yw557ml49c1.webp",
"clq55455w2dcm1yvd8d8258d8.webp",
"clq558fkh2djy1ywbghwcawnh.webp",
"clq55cvqh2dqi1yyratl123wq.webp",
"clrhnk94e115k1y00bg8h9ixb.webp",
"d44a3c04-f124-4f0b-8301-3841ae2fd439_1764780121224.webp",
"e6ba52f208914285bcdf1966cfb08f6f.jpg",
"fa9cbbe6-f947-4f83-8e98-61d2661f43e0_1764841636705.webp"
]
}
}
@@ -162,8 +162,5 @@
<Using Include="Microsoft.Extensions.Options" /> <Using Include="Microsoft.Extensions.Options" />
<Using Include="Microsoft.Extensions.Logging" /> <Using Include="Microsoft.Extensions.Logging" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Postgres\Migrations\" />
</ItemGroup>
</Project> </Project>
@@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
{ {
[DbContext(typeof(MidrandBooksDbContext))] [DbContext(typeof(MidrandBooksDbContext))]
[Migration("20260528052014_Init")] [Migration("20260529070104_Init")]
partial class Init partial class Init
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -649,40 +649,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b.ToTable("Prices", (string)null); b.ToTable("Prices", (string)null);
}); });
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<decimal>("Amount")
.HasColumnType("numeric");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("Discount")
.HasColumnType("numeric");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<long>("ProductId")
.HasColumnType("bigint");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("ProductId")
.IsUnique();
b.ToTable("ProductPrice");
});
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b => modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
{ {
b.HasOne("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", "Author") b.HasOne("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", "Author")
@@ -931,15 +897,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b.Navigation("Product"); b.Navigation("Product");
}); });
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", b =>
{
b.HasOne("LiteCharms.Features.MidrandBooks.Products.Entities.Product", null)
.WithOne("Price")
.HasForeignKey("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", "ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b => modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
{ {
b.Navigation("Pages"); b.Navigation("Pages");
@@ -973,8 +930,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Entities.Product", b => modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Entities.Product", b =>
{ {
b.Navigation("Price");
b.Navigation("Prices"); b.Navigation("Prices");
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
@@ -259,30 +259,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
onDelete: ReferentialAction.Restrict); onDelete: ReferentialAction.Restrict);
}); });
//migrationBuilder.CreateTable(
// name: "ProductPrice",
// columns: table => new
// {
// Id = table.Column<long>(type: "bigint", nullable: false)
// .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
// CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
// UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
// ProductId = table.Column<long>(type: "bigint", nullable: false),
// Amount = table.Column<decimal>(type: "numeric", nullable: false),
// Discount = table.Column<decimal>(type: "numeric", nullable: false),
// Enabled = table.Column<bool>(type: "boolean", nullable: false)
// },
// constraints: table =>
// {
// table.PrimaryKey("PK_ProductPrice", x => x.Id);
// table.ForeignKey(
// name: "FK_ProductPrice_Products_ProductId",
// column: x => x.ProductId,
// principalTable: "Products",
// principalColumn: "Id",
// onDelete: ReferentialAction.Cascade);
// });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Shippings", name: "Shippings",
columns: table => new columns: table => new
@@ -427,12 +403,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
table: "Prices", table: "Prices",
column: "ProductId"); column: "ProductId");
migrationBuilder.CreateIndex(
name: "IX_ProductPrice_ProductId",
table: "ProductPrice",
column: "ProductId",
unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Refunds_OrderId", name: "IX_Refunds_OrderId",
table: "Refunds", table: "Refunds",
@@ -467,9 +437,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "OrderItems"); name: "OrderItems");
migrationBuilder.DropTable(
name: "ProductPrice");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Refunds"); name: "Refunds");
@@ -57,7 +57,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b.HasIndex("ProductId"); b.HasIndex("ProductId");
b.ToTable("Books", (string)null); b.ToTable("Books");
}); });
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", b => modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", b =>
@@ -454,7 +454,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("ShippingProviders", (string)null); b.ToTable("ShippingProviders");
}); });
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Pages.Entities.BookPage", b => modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Pages.Entities.BookPage", b =>
@@ -646,40 +646,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b.ToTable("Prices", (string)null); b.ToTable("Prices", (string)null);
}); });
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<decimal>("Amount")
.HasColumnType("numeric");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("Discount")
.HasColumnType("numeric");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<long>("ProductId")
.HasColumnType("bigint");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("ProductId")
.IsUnique();
b.ToTable("ProductPrice", (string)null);
});
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b => modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
{ {
b.HasOne("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", "Author") b.HasOne("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", "Author")
@@ -718,7 +684,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b1.HasKey("AuthorId", "__synthesizedOrdinal"); b1.HasKey("AuthorId", "__synthesizedOrdinal");
b1.ToTable("Authors", (string)null); b1.ToTable("Authors");
b1 b1
.ToJson("SocialMedia") .ToJson("SocialMedia")
@@ -772,7 +738,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b1.HasKey("CustomerId", "__synthesizedOrdinal"); b1.HasKey("CustomerId", "__synthesizedOrdinal");
b1.ToTable("Customers", (string)null); b1.ToTable("Customers");
b1 b1
.ToJson("SocialMedia") .ToJson("SocialMedia")
@@ -862,7 +828,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b1.HasKey("BookPageId", "__synthesizedOrdinal"); b1.HasKey("BookPageId", "__synthesizedOrdinal");
b1.ToTable("BookPages", (string)null); b1.ToTable("BookPages");
b1 b1
.ToJson("References") .ToJson("References")
@@ -904,7 +870,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b1.HasKey("ProductId"); b1.HasKey("ProductId");
b1.ToTable("Products", (string)null); b1.ToTable("Products");
b1 b1
.ToJson("Metadata") .ToJson("Metadata")
@@ -928,15 +894,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
b.Navigation("Product"); b.Navigation("Product");
}); });
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", b =>
{
b.HasOne("LiteCharms.Features.MidrandBooks.Products.Entities.Product", null)
.WithOne("Price")
.HasForeignKey("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", "ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b => modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
{ {
b.Navigation("Pages"); b.Navigation("Pages");
@@ -970,8 +927,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Entities.Product", b => modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Entities.Product", b =>
{ {
b.Navigation("Price");
b.Navigation("Prices"); b.Navigation("Prices");
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
@@ -4,6 +4,8 @@ public sealed class ProductConfiguration : IEntityTypeConfiguration<Product>
{ {
public void Configure(EntityTypeBuilder<Product> builder) public void Configure(EntityTypeBuilder<Product> builder)
{ {
builder.Ignore(p => p.Price);
builder.ToTable("Products"); builder.ToTable("Products");
builder.HasKey(f => f.Id); builder.HasKey(f => f.Id);
+2 -1
View File
@@ -93,7 +93,8 @@ public enum SocialMediaTypes : int
YouTube = 5, YouTube = 5,
Pinterest = 6, Pinterest = 6,
Reddit = 7, Reddit = 7,
Tumblr = 8 Tumblr = 8,
GitHub = 9
} }
public enum EmailStatuses : int public enum EmailStatuses : int
+1
View File
@@ -9,6 +9,7 @@
<Project Path="LiteCharms.Features/LiteCharms.Features.csproj" /> <Project Path="LiteCharms.Features/LiteCharms.Features.csproj" />
</Folder> </Folder>
<Folder Name="/tests/"> <Folder Name="/tests/">
<Project Path="LiteCharms.Features.MidrandBooks.Seed/LiteCharms.Features.MidrandBooks.Seed.csproj" Id="aa80643a-28dc-431f-b163-053a94e5c77c" />
<Project Path="LiteCharms.Features.MidrandBooks.Tests/LiteCharms.Features.MidrandBooks.Tests.csproj" Id="cac2f738-dbb5-4538-8565-3c2bd6f65259" /> <Project Path="LiteCharms.Features.MidrandBooks.Tests/LiteCharms.Features.MidrandBooks.Tests.csproj" Id="cac2f738-dbb5-4538-8565-3c2bd6f65259" />
<Project Path="LiteCharms.Features.TechShop.Tests/LiteCharms.Features.TechShop.Tests.csproj" Id="0e0967c2-7f28-4668-a387-2fc437ab066f" /> <Project Path="LiteCharms.Features.TechShop.Tests/LiteCharms.Features.TechShop.Tests.csproj" Id="0e0967c2-7f28-4668-a387-2fc437ab066f" />
<Project Path="LiteCharms.Features.Tests/LiteCharms.Features.Tests.csproj" Id="0696323f-7148-4ab9-9145-68b7b5df5415" /> <Project Path="LiteCharms.Features.Tests/LiteCharms.Features.Tests.csproj" Id="0696323f-7148-4ab9-9145-68b7b5df5415" />