app/BTCPayApp.Core/Data/AppDbContext.cs
2024-07-31 13:28:41 +02:00

207 lines
10 KiB
C#

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using BTCPayApp.CommonServer.Models;
using BTCPayApp.Core.JsonConverters;
using BTCPayApp.Core.LDK;
using BTCPayServer.Lightning;
using Laraue.EfCoreTriggers.Common.Extensions;
using Laraue.EfCoreTriggers.Common.TriggerBuilders.Actions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using NBitcoin;
namespace BTCPayApp.Core.Data;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Setting> Settings { get; set; }
public DbSet<Channel> LightningChannels { get; set; }
public DbSet<ChannelAlias> ChannelAliases { get; set; }
public DbSet<AppLightningPayment> LightningPayments { get; set; }
public DbSet<Outbox> OutboxItems { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Outbox>()
.HasKey(w => new {w.Entity, w.Key, w.ActionType, w.Version});
modelBuilder.Entity<Outbox>().Property(payment => payment.Timestamp).HasDefaultValueSql("datetime('now')");
modelBuilder.Entity<AppLightningPayment>().HasIndex(payment => payment.EntityKey).IsUnique();
modelBuilder.Entity<Setting>().HasIndex(payment => payment.EntityKey).IsUnique();
modelBuilder.Entity<Channel>().HasIndex(payment => payment.EntityKey).IsUnique();
modelBuilder.Entity<AppLightningPayment>().Property(payment => payment.PaymentRequest)
.HasConversion(
request => request.ToString(),
str => NetworkHelper.Try(network => BOLT11PaymentRequest.Parse(str, network)));
modelBuilder.Entity<AppLightningPayment>().Property(payment => payment.Secret)
.HasConversion(
request => request.ToString(),
str => uint256.Parse(str));
modelBuilder.Entity<AppLightningPayment>().Property(payment => payment.PaymentHash)
.HasConversion(
request => request.ToString(),
str => uint256.Parse(str));
modelBuilder.Entity<AppLightningPayment>().Property(payment => payment.Value)
.HasConversion(
request => request.MilliSatoshi,
str => new LightMoney(str));
modelBuilder.Entity<AppLightningPayment>().Property(payment => payment.AdditionalData).HasJsonConversion();
modelBuilder.Entity<AppLightningPayment>()
.HasKey(w => new {w.PaymentHash, w.Inbound, w.PaymentId});
//handling versioned data
//settings, channels, payments
//when creating, set the version to 0
//when updating, increment the version
// outbox creation
// when creating, insert an outbox item
// when updating, insert an outbox item
// when deleting, insert an outbox item
modelBuilder.Entity<Setting>()
.AfterInsert(trigger => trigger
.Action(group =>
{
group
.Condition(@ref => @ref.New.Backup)
.Insert(
// .InsertIfNotExists( (@ref, outbox) => outbox.Version == @ref.New.Version && outbox.ActionType == OutboxAction.Insert && outbox.Entity == "Setting" && outbox.Key == @ref.New.Key,
@ref => new Outbox()
{
Entity = "Setting",
Version = @ref.New.Version,
Key = @ref.New.EntityKey,
ActionType = OutboxAction.Insert
});
}))
.AfterDelete(trigger => trigger
.Action(group => group
.Condition(@ref => @ref.Old.Backup)
.Insert(
// .InsertIfNotExists( (@ref, outbox) => @ref.Old.Version == outbox.Version && outbox.ActionType == OutboxAction.Delete && outbox.Entity == "Setting" && outbox.Key == @ref.Old.Key,
@ref => new Outbox()
{
Entity = "Setting",
Version = @ref.Old.Version,
Key = @ref.Old.EntityKey,
ActionType = OutboxAction.Delete
})))
.AfterUpdate(trigger => trigger
.Action(group => group
.Condition(@ref => @ref.Old.Backup)
// .Condition(@ref => @ref.Old.Value != @ref.New.Value)
.Update<Setting>(
(tableRefs, setting) => tableRefs.Old.Key == setting.Key,
(tableRefs, setting) => new Setting() {Version = tableRefs.Old.Version + 1})
.Insert(
// .InsertIfNotExists( (@ref, outbox) => @ref.New.Version == outbox.Version && outbox.ActionType == OutboxAction.Update && outbox.Entity == "Setting" && outbox.Key == @ref.New.Key,
@ref => new Outbox()
{
Entity = "Setting",
Version = @ref.Old.Version + 1,
Key = @ref.New.EntityKey,
ActionType = OutboxAction.Update
})));
// .Action(group => group
// .Condition(@ref => @ref.Old.Backup && !@ref.New.Backup)
// .Insert(
// // .InsertIfNotExists( (@ref, outbox) => @ref.New.Version == outbox.Version && outbox.ActionType == OutboxAction.Update && outbox.Entity == "Setting" && outbox.Key == @ref.New.Key,
// @ref => new Outbox()
// {
// Entity = "Setting",
// Version = @ref.Old.Version +1,
// Key = @ref.New.Key,
// ActionType = OutboxAction.Delete
// })));
modelBuilder.Entity<Channel>()
.AfterInsert(trigger => trigger
.Action(group => group
.Insert(
// .InsertIfNotExists( (@ref, outbox) => outbox.Version == @ref.New.Version && outbox.ActionType == OutboxAction.Insert && outbox.Entity == "Channel" && outbox.Key == @ref.New.Id,
@ref => new Outbox()
{
Entity = "Channel",
Version = @ref.New.Version,
Key = @ref.New.EntityKey,
ActionType = OutboxAction.Insert
})))
.AfterDelete(trigger => trigger
.Action(group => group
.Insert(
// .InsertIfNotExists( (@ref, outbox) => @ref.Old.Version == outbox.Version && outbox.ActionType == OutboxAction.Delete && outbox.Entity == "Channel" && outbox.Key == @ref.Old.Id,
@ref => new Outbox()
{
Entity = "Channel",
Version = @ref.Old.Version,
Key = @ref.Old.EntityKey,
ActionType = OutboxAction.Delete
})))
.AfterUpdate(trigger => trigger
.Action(group => group.Update<Channel>(
(tableRefs, setting) => tableRefs.Old.Id == setting.Id,
(tableRefs, setting) => new Channel() {Version = tableRefs.Old.Version + 1}).Insert(
// .InsertIfNotExists( (@ref, outbox) => @ref.New.Version == outbox.Version && outbox.ActionType == OutboxAction.Update && outbox.Entity == "Channel" && outbox.Key == @ref.New.Id,
@ref => new Outbox()
{
Entity = "Channel",
Version = @ref.Old.Version +1,
Key = @ref.New.EntityKey,
ActionType = OutboxAction.Update
})));
modelBuilder.Entity<AppLightningPayment>()
.AfterInsert(trigger => trigger
.Action(group => group
.Insert(
// .InsertIfNotExists( (@ref, outbox) => outbox.Version == @ref.New.Version && outbox.ActionType == OutboxAction.Insert && outbox.Entity == "Payment" && outbox.Key == @ref.New.PaymentHash+ "_"+@ref.New.PaymentId+ "_"+@ref.New.Inbound,
@ref => new Outbox()
{
Entity = "Payment",
Version = @ref.New.Version,
Key = @ref.New.EntityKey,
ActionType = OutboxAction.Insert
})))
.AfterDelete(trigger => trigger
.Action(group => group
.Insert(
// .InsertIfNotExists( (@ref, outbox) => @ref.Old.Version == outbox.Version && outbox.ActionType == OutboxAction.Delete && outbox.Entity == "Payment" && outbox.Key == @ref.Old.PaymentHash+ "_"+@ref.Old.PaymentId+ "_"+@ref.Old.Inbound,
@ref => new Outbox()
{
Entity = "Payment",
Version = @ref.Old.Version,
Key = @ref.Old.EntityKey,
ActionType = OutboxAction.Delete
})))
.AfterUpdate(trigger => trigger
.Action(group =>
group.Update<AppLightningPayment>(
(tableRefs, setting) => tableRefs.Old.PaymentHash == setting.PaymentHash,
(tableRefs, setting) => new AppLightningPayment() {Version = tableRefs.Old.Version + 1}).Insert(
// .InsertIfNotExists( (@ref, outbox) =>
// outbox.Version != @ref.New.Version || outbox.ActionType != OutboxAction.Update || outbox.Entity != "Payment" || outbox.Key != @ref.New.PaymentHash+ "_"+@ref.New.PaymentId+ "_"+@ref.New.Inbound,
@ref => new Outbox()
{
Entity = "Payment",
Version = @ref.Old.Version +1,
Key = @ref.New.EntityKey,
ActionType = OutboxAction.Update
})));
base.OnModelCreating(modelBuilder);
}
}