add csfloat api usage
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
using BlueLaminate.EFCore.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace BlueLaminate.EFCore.Configurations;
|
||||
|
||||
public class ListingConfiguration : IEntityTypeConfiguration<Listing>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Listing> entity)
|
||||
{
|
||||
// CSFloat's listing id is the natural key; the incremental sweep upserts
|
||||
// against it and must never create duplicates.
|
||||
entity.HasIndex(e => e.CsFloatListingId).IsUnique();
|
||||
|
||||
entity.Property(e => e.Price).HasPrecision(18, 2);
|
||||
// Full precision to match SkinInstance for exact fingerprint joins.
|
||||
entity.Property(e => e.FloatValue).HasColumnType("numeric(20,18)");
|
||||
|
||||
// Store the enum as text so the DB is self-describing (matches the
|
||||
// project's readable-data leaning over opaque ints).
|
||||
entity.Property(e => e.Status).HasConversion<string>();
|
||||
|
||||
// The sweep filters/sorts by item identity and by what's still active.
|
||||
entity.HasIndex(e => new { e.DefIndex, e.PaintIndex });
|
||||
entity.HasIndex(e => e.Status);
|
||||
|
||||
// Best-effort catalogue link: a global sweep sees items we may not have,
|
||||
// so the FK is optional and set null if the skin is later removed.
|
||||
entity.HasOne(e => e.Skin)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.SkinId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
// Listings roll up to the physical item they represent.
|
||||
entity.HasOne(e => e.SkinInstance)
|
||||
.WithMany(i => i.Listings)
|
||||
.HasForeignKey(e => e.SkinInstanceId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
// Dupe analysis groups a fingerprint's listings by asset id.
|
||||
entity.HasIndex(e => e.AssetId);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,18 @@ public class SkinConfiguration : IEntityTypeConfiguration<Skin>
|
||||
// Slug is the natural key the sync upserts against.
|
||||
entity.HasIndex(e => e.Slug).IsUnique();
|
||||
|
||||
// Market listings join back to a skin by (def_index, paint_index). Unique
|
||||
// among populated rows; filtered so the many catalogue rows that predate
|
||||
// these columns (null) don't collide. Postgres treats nulls as distinct
|
||||
// anyway, but the filter makes the intent explicit and the index smaller.
|
||||
entity.HasIndex(e => new { e.DefIndex, e.PaintIndex })
|
||||
.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);
|
||||
|
||||
entity.HasOne(e => e.Weapon)
|
||||
.WithMany(w => w.Skins)
|
||||
.HasForeignKey(e => e.WeaponId);
|
||||
|
||||
@@ -8,19 +8,34 @@ public class SkinInstanceConfiguration : IEntityTypeConfiguration<SkinInstance>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SkinInstance> entity)
|
||||
{
|
||||
entity.Property(e => e.FloatValue).HasColumnType("numeric(10,9)");
|
||||
// Full precision so exact-match dupe detection isn't defeated by rounding.
|
||||
// CSFloat returns deterministic ~17-digit floats; numeric(20,18) holds them.
|
||||
entity.Property(e => e.FloatValue).HasColumnType("numeric(20,18)");
|
||||
|
||||
// Primary lookup key for trade fingerprinting.
|
||||
entity.HasIndex(e => e.FloatValue);
|
||||
entity.HasIndex(e => e.PaintSeed);
|
||||
// The fingerprint that identifies a physical item. NOT unique: duped items
|
||||
// legitimately share a fingerprint, and detecting that collision is the
|
||||
// point. Indexed for fast fingerprint resolution during the sweep.
|
||||
entity.HasIndex(e => new
|
||||
{
|
||||
e.SkinId,
|
||||
e.FloatValue,
|
||||
e.PaintSeed,
|
||||
e.StatTrak,
|
||||
e.Souvenir,
|
||||
});
|
||||
|
||||
// Surfacing fresh dupes is a hot query.
|
||||
entity.HasIndex(e => e.SuspectedDupe);
|
||||
|
||||
entity.HasOne(e => e.Skin)
|
||||
.WithMany(s => s.Instances)
|
||||
.HasForeignKey(e => e.SkinId);
|
||||
|
||||
// Condition is optional now (derived from float later); set null on delete
|
||||
// rather than restrict so condition rows can change without blocking.
|
||||
entity.HasOne(e => e.Condition)
|
||||
.WithMany(c => c.Instances)
|
||||
.HasForeignKey(e => e.ConditionId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user