almost ready
This commit is contained in:
@@ -8,7 +8,8 @@ public class InventoryItemConfiguration : IEntityTypeConfiguration<InventoryItem
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<InventoryItem> entity)
|
||||
{
|
||||
entity.HasIndex(e => e.AssetId);
|
||||
// A Steam asset id identifies one physical copy; never store it twice.
|
||||
entity.HasIndex(e => e.AssetId).IsUnique();
|
||||
|
||||
entity.HasOne(e => e.User)
|
||||
.WithMany(u => u.InventoryItems)
|
||||
|
||||
@@ -31,6 +31,14 @@ public class ListingConfiguration : IEntityTypeConfiguration<Listing>
|
||||
.HasForeignKey(e => e.SkinId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
// Wear band the sweep targeted (set directly from the sweep unit, not
|
||||
// best-effort). Set null on delete so a condition row can change without
|
||||
// blocking its listings — matching the cs.money/skin.land tables.
|
||||
entity.HasOne(e => e.Condition)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.ConditionId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
// Listings roll up to the physical item they represent.
|
||||
entity.HasOne(e => e.SkinInstance)
|
||||
.WithMany(i => i.Listings)
|
||||
|
||||
@@ -8,12 +8,11 @@ public class SkinConditionConfiguration : IEntityTypeConfiguration<SkinCondition
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SkinCondition> entity)
|
||||
{
|
||||
entity.Property(e => e.MinFloat).HasColumnType("numeric(10,9)");
|
||||
entity.Property(e => e.MaxFloat).HasColumnType("numeric(10,9)");
|
||||
entity.Property(e => e.FloatMin).HasColumnType("numeric(10,9)");
|
||||
entity.Property(e => e.FloatMax).HasColumnType("numeric(10,9)");
|
||||
|
||||
// The catalogue sweep orders bands by this (never-swept first, then stalest),
|
||||
// so index it like the equivalent column on skins.
|
||||
entity.HasIndex(e => e.ListingsSweptAt);
|
||||
// Per-site "last swept" checkpoints live in skin_condition_sweeps (one row per
|
||||
// site); see SkinConditionSweepConfiguration for the indexes that order them.
|
||||
|
||||
entity.HasOne(e => e.Skin)
|
||||
.WithMany(s => s.Conditions)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using BlueLaminate.EFCore.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace BlueLaminate.EFCore.Configurations;
|
||||
|
||||
public class SkinConditionSweepConfiguration : IEntityTypeConfiguration<SkinConditionSweep>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SkinConditionSweep> entity)
|
||||
{
|
||||
// One checkpoint per band per site: the natural key, and what the upsert
|
||||
// ("stamp") in SweepCheckpoints relies on.
|
||||
entity.HasIndex(e => new { e.SkinConditionId, e.Source }).IsUnique();
|
||||
|
||||
// Each site's sweep orders its bands never-swept-first then stalest; index the
|
||||
// ordering it scans (filter by source, sort by swept_at).
|
||||
entity.HasIndex(e => new { e.Source, e.SweptAt });
|
||||
|
||||
entity.HasOne(e => e.SkinCondition)
|
||||
.WithMany(c => c.Sweeps)
|
||||
.HasForeignKey(e => e.SkinConditionId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
@@ -29,9 +29,8 @@ public class SkinConfiguration : IEntityTypeConfiguration<Skin>
|
||||
.IsUnique()
|
||||
.HasFilter("def_index IS NOT NULL AND paint_index IS NOT NULL");
|
||||
|
||||
// The catalogue sweep orders skins by when they were last swept (nulls
|
||||
// first) to resume across capped runs; index that ordering.
|
||||
entity.HasIndex(e => e.ListingsSweptAt);
|
||||
// Per-site "last swept" checkpoints live in skin_sweeps (one row per site);
|
||||
// see SkinSweepConfiguration for the indexes that order them.
|
||||
|
||||
entity.HasOne(e => e.Weapon)
|
||||
.WithMany(w => w.Skins)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using BlueLaminate.EFCore.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace BlueLaminate.EFCore.Configurations;
|
||||
|
||||
public class SkinLandListingConfiguration : IEntityTypeConfiguration<SkinLandListing>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SkinLandListing> entity)
|
||||
{
|
||||
// skin.land's offer id is the natural key; ingest upserts against it and must
|
||||
// never create duplicates.
|
||||
entity.HasIndex(e => e.ListingId).IsUnique();
|
||||
|
||||
entity.Property(e => e.Price).HasPrecision(18, 2);
|
||||
// Full precision (matches SkinInstance/cs.money) even though skin.land offers
|
||||
// aren't fingerprinted — keep the float lossless for later analysis.
|
||||
entity.Property(e => e.FloatValue).HasColumnType("numeric(20,18)");
|
||||
|
||||
// Enum as text so the DB is self-describing (matches the project's leaning).
|
||||
entity.Property(e => e.Status).HasConversion<string>();
|
||||
|
||||
// Targeted scrape: results are filtered/sorted by skin+wear and by activity.
|
||||
entity.HasIndex(e => new { e.SkinId, e.ConditionId });
|
||||
entity.HasIndex(e => e.Status);
|
||||
|
||||
// Each job targets a known skin, so this link is required (Restrict: a skin with
|
||||
// live listings shouldn't be deleted out from under them).
|
||||
entity.HasOne(e => e.Skin)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.SkinId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
entity.HasOne(e => e.Condition)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.ConditionId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using BlueLaminate.EFCore.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace BlueLaminate.EFCore.Configurations;
|
||||
|
||||
public class SkinSweepConfiguration : IEntityTypeConfiguration<SkinSweep>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SkinSweep> entity)
|
||||
{
|
||||
// One checkpoint per skin per site: the natural key the upsert relies on.
|
||||
entity.HasIndex(e => new { e.SkinId, e.Source }).IsUnique();
|
||||
|
||||
// Mirror SkinConditionSweep: index the (source, swept_at) ordering each sweep scans.
|
||||
entity.HasIndex(e => new { e.Source, e.SweptAt });
|
||||
|
||||
entity.HasOne(e => e.Skin)
|
||||
.WithMany(s => s.Sweeps)
|
||||
.HasForeignKey(e => e.SkinId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,10 @@ public class TradeConfiguration : IEntityTypeConfiguration<Trade>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Trade> entity)
|
||||
{
|
||||
// Steam's trade id is the natural key for an observed trade. Nullable (some
|
||||
// trades are reconstructed without one); Postgres keeps multiple NULLs distinct.
|
||||
entity.HasIndex(e => e.SteamTradeId).IsUnique();
|
||||
|
||||
entity.HasOne(e => e.FromUser)
|
||||
.WithMany(u => u.TradesSent)
|
||||
.HasForeignKey(e => e.FromUserId)
|
||||
|
||||
Reference in New Issue
Block a user