diff --git a/src/MissionControl.Data/EntityConfigurations/MissionLaunchConfiguration.cs b/src/MissionControl.Data/EntityConfigurations/MissionLaunchConfiguration.cs new file mode 100644 index 0000000..cf7dfaa --- /dev/null +++ b/src/MissionControl.Data/EntityConfigurations/MissionLaunchConfiguration.cs @@ -0,0 +1,13 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using MissionControl.Domain.Entities; + +namespace MissionControl.Data.EntityConfigurations; + +public class MissionLaunchConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.Property(m => m.Status).HasConversion().HasMaxLength(20); + } +} diff --git a/src/MissionControl.Data/Migrations/20260727193151_Add_MissionLaunches.Designer.cs b/src/MissionControl.Data/Migrations/20260727193151_Add_MissionLaunches.Designer.cs new file mode 100644 index 0000000..e63713d --- /dev/null +++ b/src/MissionControl.Data/Migrations/20260727193151_Add_MissionLaunches.Designer.cs @@ -0,0 +1,102 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MissionControl.Data; + +#nullable disable + +namespace MissionControl.Data.Migrations +{ + [DbContext(typeof(MissionControlContext))] + [Migration("20260727193151_Add_MissionLaunches")] + partial class Add_MissionLaunches + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("MissionControl.Domain.Entities.Mission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.ToTable("Missions"); + }); + + modelBuilder.Entity("MissionControl.Domain.Entities.MissionLaunch", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("MissionId") + .HasColumnType("uniqueidentifier"); + + b.Property("ScheduledFor") + .HasColumnType("datetimeoffset"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("MissionId") + .IsUnique(); + + b.ToTable("MissionLaunches"); + }); + + modelBuilder.Entity("MissionControl.Domain.Entities.MissionLaunch", b => + { + b.HasOne("MissionControl.Domain.Entities.Mission", "Mission") + .WithOne("MissionLaunch") + .HasForeignKey("MissionControl.Domain.Entities.MissionLaunch", "MissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Mission"); + }); + + modelBuilder.Entity("MissionControl.Domain.Entities.Mission", b => + { + b.Navigation("MissionLaunch"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MissionControl.Data/Migrations/20260727193151_Add_MissionLaunches.cs b/src/MissionControl.Data/Migrations/20260727193151_Add_MissionLaunches.cs new file mode 100644 index 0000000..da53e03 --- /dev/null +++ b/src/MissionControl.Data/Migrations/20260727193151_Add_MissionLaunches.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MissionControl.Data.Migrations +{ + /// + public partial class Add_MissionLaunches : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "MissionLaunches", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ScheduledFor = table.Column(type: "datetimeoffset", nullable: false), + Status = table.Column(type: "nvarchar(20)", maxLength: 20, nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + MissionId = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MissionLaunches", x => x.Id); + table.ForeignKey( + name: "FK_MissionLaunches_Missions_MissionId", + column: x => x.MissionId, + principalTable: "Missions", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_MissionLaunches_MissionId", + table: "MissionLaunches", + column: "MissionId", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "MissionLaunches"); + } + } +} diff --git a/src/MissionControl.Data/Migrations/MissionControlContextModelSnapshot.cs b/src/MissionControl.Data/Migrations/MissionControlContextModelSnapshot.cs index 05e6658..cc18c8c 100644 --- a/src/MissionControl.Data/Migrations/MissionControlContextModelSnapshot.cs +++ b/src/MissionControl.Data/Migrations/MissionControlContextModelSnapshot.cs @@ -49,6 +49,50 @@ namespace MissionControl.Data.Migrations b.ToTable("Missions"); }); + + modelBuilder.Entity("MissionControl.Domain.Entities.MissionLaunch", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("MissionId") + .HasColumnType("uniqueidentifier"); + + b.Property("ScheduledFor") + .HasColumnType("datetimeoffset"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("MissionId") + .IsUnique(); + + b.ToTable("MissionLaunches"); + }); + + modelBuilder.Entity("MissionControl.Domain.Entities.MissionLaunch", b => + { + b.HasOne("MissionControl.Domain.Entities.Mission", "Mission") + .WithOne("MissionLaunch") + .HasForeignKey("MissionControl.Domain.Entities.MissionLaunch", "MissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Mission"); + }); + + modelBuilder.Entity("MissionControl.Domain.Entities.Mission", b => + { + b.Navigation("MissionLaunch"); + }); #pragma warning restore 612, 618 } } diff --git a/src/MissionControl.Data/MissionControlContext.cs b/src/MissionControl.Data/MissionControlContext.cs index 83ec92c..4cf14d9 100644 --- a/src/MissionControl.Data/MissionControlContext.cs +++ b/src/MissionControl.Data/MissionControlContext.cs @@ -7,7 +7,15 @@ public class MissionControlContext(DbContextOptions optio : DbContext(options) { public DbSet Missions => Set(); + public DbSet MissionLaunches => Set(); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasOne(mission => mission.MissionLaunch) + .WithOne(missionLaunch => missionLaunch.Mission) + .HasForeignKey(missionLaunch => missionLaunch.MissionId); - protected override void OnModelCreating(ModelBuilder modelBuilder) => modelBuilder.ApplyConfigurationsFromAssembly(typeof(MissionControlContext).Assembly); + } } diff --git a/src/MissionControl.Domain/Entities/Mission.cs b/src/MissionControl.Domain/Entities/Mission.cs index 84c9949..2114f44 100644 --- a/src/MissionControl.Domain/Entities/Mission.cs +++ b/src/MissionControl.Domain/Entities/Mission.cs @@ -11,4 +11,6 @@ public class Mission public MissionStatus Status { get; set; } = MissionStatus.Planned; public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow; + + public MissionLaunch? MissionLaunch { get; set; } } diff --git a/src/MissionControl.Domain/Entities/MissionLaunch.cs b/src/MissionControl.Domain/Entities/MissionLaunch.cs new file mode 100644 index 0000000..b5c0a77 --- /dev/null +++ b/src/MissionControl.Domain/Entities/MissionLaunch.cs @@ -0,0 +1,16 @@ +namespace MissionControl.Domain.Entities; + +public class MissionLaunch +{ + public Guid Id { get; set; } = Guid.NewGuid(); + + public DateTimeOffset ScheduledFor { get; set; } + + public MissionLaunchStatus Status { get; set; } + + public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow; + + public Guid MissionId { get; set; } + + public Mission Mission { get; set; } = null!; +} diff --git a/src/MissionControl.Domain/Entities/MissionLaunchStatus.cs b/src/MissionControl.Domain/Entities/MissionLaunchStatus.cs new file mode 100644 index 0000000..b51dcbe --- /dev/null +++ b/src/MissionControl.Domain/Entities/MissionLaunchStatus.cs @@ -0,0 +1,10 @@ +namespace MissionControl.Domain.Entities; + +public enum MissionLaunchStatus +{ + Pending, + Delayed, + Launching, + Launched, + Cancelled, +}