diff --git a/src/FiscalOS.Infra/Data/AppDbContext.cs b/src/FiscalOS.Infra/Data/AppDbContext.cs index 50856cd..72a267c 100644 --- a/src/FiscalOS.Infra/Data/AppDbContext.cs +++ b/src/FiscalOS.Infra/Data/AppDbContext.cs @@ -124,6 +124,11 @@ public sealed class AppDbContext( .WithOne() .HasForeignKey(static m => m.AccountId) .OnDelete(DeleteBehavior.Cascade); + + eb.HasMany(static a => a.Balances) + .WithOne() + .HasForeignKey(static b => b.AccountId) + .OnDelete(DeleteBehavior.Cascade); }); modelBuilder.Entity(static eb => @@ -142,5 +147,12 @@ public sealed class AppDbContext( eb.Property(static m => m.PlaidId); eb.Property(static m => m.PlaidName); }); + + modelBuilder.Entity(static eb => + { + eb.Property(static b => b.AccountId); + eb.Property(static b => b.Current); + eb.Property(static b => b.Available); + }); } } \ No newline at end of file diff --git a/src/FiscalOS.Infra/Migrations/20260214112234_AddBalancesWithConnectionToAccounts.Designer.cs b/src/FiscalOS.Infra/Migrations/20260214112234_AddBalancesWithConnectionToAccounts.Designer.cs new file mode 100644 index 0000000..3f00522 --- /dev/null +++ b/src/FiscalOS.Infra/Migrations/20260214112234_AddBalancesWithConnectionToAccounts.Designer.cs @@ -0,0 +1,364 @@ +// +using System; +using FiscalOS.Infra.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace FiscalOS.Infra.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260214112234_AddBalancesWithConnectionToAccounts")] + partial class AddBalancesWithConnectionToAccounts + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.2"); + + modelBuilder.Entity("FiscalOS.Core.Accounts.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("InstitutionId") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstitutionId"); + + b.HasIndex("UserId"); + + b.ToTable("Account"); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.AccountMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AccountId") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("AccountMetadata"); + + b.HasDiscriminator("Type").HasValue("AccountMetadata"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.Balance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AccountId") + .HasColumnType("TEXT"); + + b.Property("Available") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Current") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("Balance"); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.Institution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Institution"); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.InstitutionMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("InstitutionId") + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstitutionId") + .IsUnique(); + + b.ToTable("InstitutionMetadata"); + + b.HasDiscriminator("Type").HasValue("InstitutionMetadata"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("FiscalOS.Core.Identity.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("ExpiresAt") + .HasColumnType("TEXT"); + + b.Property("Revoked") + .HasColumnType("INTEGER"); + + b.Property("Token") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("FiscalOS.Core.Identity.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("EncryptedDataKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("EncryptionKeyId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("HashedPassword") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("FiscalOS.Infra.Accounts.Plaid.PlaidAccountMetadata", b => + { + b.HasBaseType("FiscalOS.Core.Accounts.AccountMetadata"); + + b.Property("PlaidId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PlaidName") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasDiscriminator().HasValue("Plaid"); + }); + + modelBuilder.Entity("FiscalOS.Infra.Accounts.Plaid.PlaidMetadata", b => + { + b.HasBaseType("FiscalOS.Core.Accounts.InstitutionMetadata"); + + b.Property("EncryptedAccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PlaidId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PlaidName") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasDiscriminator().HasValue("Plaid"); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.Account", b => + { + b.HasOne("FiscalOS.Core.Accounts.Institution", "Institution") + .WithMany() + .HasForeignKey("InstitutionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FiscalOS.Core.Identity.User", null) + .WithMany("Accounts") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Institution"); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.AccountMetadata", b => + { + b.HasOne("FiscalOS.Core.Accounts.Account", null) + .WithOne("Metadata") + .HasForeignKey("FiscalOS.Core.Accounts.AccountMetadata", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.Balance", b => + { + b.HasOne("FiscalOS.Core.Accounts.Account", null) + .WithMany("Balances") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.Institution", b => + { + b.HasOne("FiscalOS.Core.Identity.User", null) + .WithMany("Institutions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.InstitutionMetadata", b => + { + b.HasOne("FiscalOS.Core.Accounts.Institution", null) + .WithOne("Metadata") + .HasForeignKey("FiscalOS.Core.Accounts.InstitutionMetadata", "InstitutionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FiscalOS.Core.Identity.RefreshToken", b => + { + b.HasOne("FiscalOS.Core.Identity.User", "User") + .WithMany("RefreshTokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.Account", b => + { + b.Navigation("Balances"); + + b.Navigation("Metadata"); + }); + + modelBuilder.Entity("FiscalOS.Core.Accounts.Institution", b => + { + b.Navigation("Metadata"); + }); + + modelBuilder.Entity("FiscalOS.Core.Identity.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Institutions"); + + b.Navigation("RefreshTokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/FiscalOS.Infra/Migrations/20260214112234_AddBalancesWithConnectionToAccounts.cs b/src/FiscalOS.Infra/Migrations/20260214112234_AddBalancesWithConnectionToAccounts.cs new file mode 100644 index 0000000..997b64a --- /dev/null +++ b/src/FiscalOS.Infra/Migrations/20260214112234_AddBalancesWithConnectionToAccounts.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FiscalOS.Infra.Migrations +{ + /// + public partial class AddBalancesWithConnectionToAccounts : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Balance", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + AccountId = table.Column(type: "TEXT", nullable: false), + Current = table.Column(type: "TEXT", nullable: false), + Available = table.Column(type: "TEXT", nullable: false), + CreatedAt = table.Column(type: "TEXT", nullable: false), + UpdatedAt = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Balance", x => x.Id); + table.ForeignKey( + name: "FK_Balance_Account_AccountId", + column: x => x.AccountId, + principalTable: "Account", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Balance_AccountId", + table: "Balance", + column: "AccountId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Balance"); + } + } +} diff --git a/src/FiscalOS.Infra/Migrations/AppDbContextModelSnapshot.cs b/src/FiscalOS.Infra/Migrations/AppDbContextModelSnapshot.cs index 14f45ae..12159f1 100644 --- a/src/FiscalOS.Infra/Migrations/AppDbContextModelSnapshot.cs +++ b/src/FiscalOS.Infra/Migrations/AppDbContextModelSnapshot.cs @@ -80,6 +80,34 @@ namespace FiscalOS.Infra.Migrations b.UseTphMappingStrategy(); }); + modelBuilder.Entity("FiscalOS.Core.Accounts.Balance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AccountId") + .HasColumnType("TEXT"); + + b.Property("Available") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Current") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("Balance"); + }); + modelBuilder.Entity("FiscalOS.Core.Accounts.Institution", b => { b.Property("Id") @@ -269,6 +297,15 @@ namespace FiscalOS.Infra.Migrations .IsRequired(); }); + modelBuilder.Entity("FiscalOS.Core.Accounts.Balance", b => + { + b.HasOne("FiscalOS.Core.Accounts.Account", null) + .WithMany("Balances") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("FiscalOS.Core.Accounts.Institution", b => { b.HasOne("FiscalOS.Core.Identity.User", null) @@ -300,14 +337,14 @@ namespace FiscalOS.Infra.Migrations modelBuilder.Entity("FiscalOS.Core.Accounts.Account", b => { - b.Navigation("Metadata") - .IsRequired(); + b.Navigation("Balances"); + + b.Navigation("Metadata"); }); modelBuilder.Entity("FiscalOS.Core.Accounts.Institution", b => { - b.Navigation("Metadata") - .IsRequired(); + b.Navigation("Metadata"); }); modelBuilder.Entity("FiscalOS.Core.Identity.User", b =>