wip: doctor/cli/docs/api to vector db consolidation; api hardening for descriptions, tenant, and scopes; migrations and conversions of all DALs to EF v10
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
// Placeholder for compiled model generated by `dotnet ef dbcontext optimize`.
|
||||
// This file should be regenerated when DbContext configuration changes.
|
||||
// Command:
|
||||
// dotnet ef dbcontext optimize \
|
||||
// --project src/Plugin/StellaOps.Plugin.Registry/ \
|
||||
// --output-dir EfCore/CompiledModels \
|
||||
// --namespace StellaOps.Plugin.Registry.EfCore.CompiledModels
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using StellaOps.Plugin.Registry.EfCore.Context;
|
||||
|
||||
#pragma warning disable 219, 612, 618, EF1001
|
||||
#nullable disable
|
||||
|
||||
namespace StellaOps.Plugin.Registry.EfCore.CompiledModels
|
||||
{
|
||||
[DbContext(typeof(PluginRegistryDbContext))]
|
||||
public partial class PluginRegistryDbContextModel : RuntimeModel
|
||||
{
|
||||
private static readonly bool _useOldBehavior31751 =
|
||||
System.AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31751", out var enabled31751) && enabled31751;
|
||||
|
||||
static PluginRegistryDbContextModel()
|
||||
{
|
||||
var model = new PluginRegistryDbContextModel();
|
||||
|
||||
if (_useOldBehavior31751)
|
||||
{
|
||||
model.Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
var thread = new System.Threading.Thread(RunInitialization, 10 * 1024 * 1024);
|
||||
thread.Start();
|
||||
thread.Join();
|
||||
|
||||
void RunInitialization()
|
||||
{
|
||||
model.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
model.Customize();
|
||||
_instance = (PluginRegistryDbContextModel)model.FinalizeModel();
|
||||
}
|
||||
|
||||
private static PluginRegistryDbContextModel _instance;
|
||||
public static IModel Instance => _instance;
|
||||
|
||||
partial void Initialize();
|
||||
|
||||
partial void Customize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Context;
|
||||
|
||||
/// <summary>
|
||||
/// Relationship overlays for PluginRegistryDbContext.
|
||||
/// </summary>
|
||||
public partial class PluginRegistryDbContext
|
||||
{
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
|
||||
{
|
||||
// Plugin -> PluginCapabilities (one-to-many, cascade delete)
|
||||
modelBuilder.Entity<PluginCapabilityEntity>(entity =>
|
||||
{
|
||||
entity.HasOne(e => e.Plugin)
|
||||
.WithMany(p => p.PluginCapabilities)
|
||||
.HasForeignKey(e => e.PluginId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
// Plugin -> PluginInstances (one-to-many, cascade delete)
|
||||
modelBuilder.Entity<PluginInstanceEntity>(entity =>
|
||||
{
|
||||
entity.HasOne(e => e.Plugin)
|
||||
.WithMany(p => p.PluginInstances)
|
||||
.HasForeignKey(e => e.PluginId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
// Plugin -> PluginHealthHistory (one-to-many, cascade delete)
|
||||
modelBuilder.Entity<PluginHealthHistoryEntity>(entity =>
|
||||
{
|
||||
entity.HasOne(e => e.Plugin)
|
||||
.WithMany(p => p.HealthHistory)
|
||||
.HasForeignKey(e => e.PluginId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Context;
|
||||
|
||||
/// <summary>
|
||||
/// EF Core DbContext for the Plugin Registry schema.
|
||||
/// </summary>
|
||||
public partial class PluginRegistryDbContext : DbContext
|
||||
{
|
||||
private readonly string _schemaName;
|
||||
|
||||
public PluginRegistryDbContext(DbContextOptions<PluginRegistryDbContext> options, string? schemaName = null)
|
||||
: base(options)
|
||||
{
|
||||
_schemaName = string.IsNullOrWhiteSpace(schemaName)
|
||||
? "platform"
|
||||
: schemaName.Trim();
|
||||
}
|
||||
|
||||
public virtual DbSet<PluginEntity> Plugins { get; set; }
|
||||
public virtual DbSet<PluginCapabilityEntity> PluginCapabilities { get; set; }
|
||||
public virtual DbSet<PluginInstanceEntity> PluginInstances { get; set; }
|
||||
public virtual DbSet<PluginHealthHistoryEntity> PluginHealthHistory { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
var schemaName = _schemaName;
|
||||
|
||||
modelBuilder.Entity<PluginEntity>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("plugins_pkey");
|
||||
|
||||
entity.ToTable("plugins", schemaName);
|
||||
|
||||
// Unique constraint
|
||||
entity.HasIndex(e => new { e.PluginId, e.Version }).IsUnique();
|
||||
|
||||
// Indexes matching SQL migration
|
||||
entity.HasIndex(e => e.PluginId, "idx_plugins_plugin_id");
|
||||
entity.HasIndex(e => e.Status, "idx_plugins_status")
|
||||
.HasFilter("status != 'active'");
|
||||
entity.HasIndex(e => e.TrustLevel, "idx_plugins_trust_level");
|
||||
entity.HasIndex(e => e.HealthStatus, "idx_plugins_health")
|
||||
.HasFilter("health_status != 'healthy'");
|
||||
|
||||
// Column mappings
|
||||
entity.Property(e => e.Id)
|
||||
.HasDefaultValueSql("gen_random_uuid()")
|
||||
.HasColumnName("id");
|
||||
entity.Property(e => e.PluginId)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("plugin_id");
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("name");
|
||||
entity.Property(e => e.Version)
|
||||
.HasMaxLength(50)
|
||||
.HasColumnName("version");
|
||||
entity.Property(e => e.Vendor)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("vendor");
|
||||
entity.Property(e => e.Description)
|
||||
.HasColumnName("description");
|
||||
entity.Property(e => e.LicenseId)
|
||||
.HasMaxLength(50)
|
||||
.HasColumnName("license_id");
|
||||
entity.Property(e => e.TrustLevel)
|
||||
.HasMaxLength(50)
|
||||
.HasColumnName("trust_level");
|
||||
entity.Property(e => e.Signature)
|
||||
.HasColumnName("signature");
|
||||
entity.Property(e => e.SigningKeyId)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("signing_key_id");
|
||||
entity.Property(e => e.Capabilities)
|
||||
.HasColumnName("capabilities")
|
||||
.HasDefaultValueSql("'{}'::text[]");
|
||||
entity.Property(e => e.CapabilityDetails)
|
||||
.HasColumnType("jsonb")
|
||||
.HasDefaultValueSql("'{}'::jsonb")
|
||||
.HasColumnName("capability_details");
|
||||
entity.Property(e => e.Source)
|
||||
.HasMaxLength(50)
|
||||
.HasColumnName("source");
|
||||
entity.Property(e => e.AssemblyPath)
|
||||
.HasMaxLength(500)
|
||||
.HasColumnName("assembly_path");
|
||||
entity.Property(e => e.EntryPoint)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("entry_point");
|
||||
entity.Property(e => e.Status)
|
||||
.HasMaxLength(50)
|
||||
.HasDefaultValue("discovered")
|
||||
.HasColumnName("status");
|
||||
entity.Property(e => e.StatusMessage)
|
||||
.HasColumnName("status_message");
|
||||
entity.Property(e => e.HealthStatus)
|
||||
.HasMaxLength(50)
|
||||
.HasDefaultValue("unknown")
|
||||
.HasColumnName("health_status");
|
||||
entity.Property(e => e.LastHealthCheck)
|
||||
.HasColumnName("last_health_check");
|
||||
entity.Property(e => e.HealthCheckFailures)
|
||||
.HasDefaultValue(0)
|
||||
.HasColumnName("health_check_failures");
|
||||
entity.Property(e => e.Manifest)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("manifest");
|
||||
entity.Property(e => e.RuntimeInfo)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("runtime_info");
|
||||
entity.Property(e => e.CreatedAt)
|
||||
.HasDefaultValueSql("now()")
|
||||
.HasColumnName("created_at");
|
||||
entity.Property(e => e.UpdatedAt)
|
||||
.HasDefaultValueSql("now()")
|
||||
.HasColumnName("updated_at");
|
||||
entity.Property(e => e.LoadedAt)
|
||||
.HasColumnName("loaded_at");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PluginCapabilityEntity>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("plugin_capabilities_pkey");
|
||||
|
||||
entity.ToTable("plugin_capabilities", schemaName);
|
||||
|
||||
// Unique constraint
|
||||
entity.HasIndex(e => new { e.PluginId, e.CapabilityType, e.CapabilityId }).IsUnique();
|
||||
|
||||
// Indexes matching SQL migration
|
||||
entity.HasIndex(e => e.CapabilityType, "idx_plugin_capabilities_type");
|
||||
entity.HasIndex(e => new { e.CapabilityType, e.CapabilityId }, "idx_plugin_capabilities_lookup");
|
||||
entity.HasIndex(e => e.PluginId, "idx_plugin_capabilities_plugin");
|
||||
|
||||
// Column mappings
|
||||
entity.Property(e => e.Id)
|
||||
.HasDefaultValueSql("gen_random_uuid()")
|
||||
.HasColumnName("id");
|
||||
entity.Property(e => e.PluginId)
|
||||
.HasColumnName("plugin_id");
|
||||
entity.Property(e => e.CapabilityType)
|
||||
.HasMaxLength(100)
|
||||
.HasColumnName("capability_type");
|
||||
entity.Property(e => e.CapabilityId)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("capability_id");
|
||||
entity.Property(e => e.ConfigSchema)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("config_schema");
|
||||
entity.Property(e => e.InputSchema)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("input_schema");
|
||||
entity.Property(e => e.OutputSchema)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("output_schema");
|
||||
entity.Property(e => e.DisplayName)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("display_name");
|
||||
entity.Property(e => e.Description)
|
||||
.HasColumnName("description");
|
||||
entity.Property(e => e.DocumentationUrl)
|
||||
.HasMaxLength(500)
|
||||
.HasColumnName("documentation_url");
|
||||
entity.Property(e => e.Metadata)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("metadata");
|
||||
entity.Property(e => e.IsEnabled)
|
||||
.HasDefaultValue(true)
|
||||
.HasColumnName("is_enabled");
|
||||
entity.Property(e => e.CreatedAt)
|
||||
.HasDefaultValueSql("now()")
|
||||
.HasColumnName("created_at");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PluginInstanceEntity>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("plugin_instances_pkey");
|
||||
|
||||
entity.ToTable("plugin_instances", schemaName);
|
||||
|
||||
// Indexes matching SQL migration
|
||||
entity.HasIndex(e => e.TenantId, "idx_plugin_instances_tenant")
|
||||
.HasFilter("tenant_id IS NOT NULL");
|
||||
entity.HasIndex(e => e.PluginId, "idx_plugin_instances_plugin");
|
||||
entity.HasIndex(e => new { e.PluginId, e.Enabled }, "idx_plugin_instances_enabled")
|
||||
.HasFilter("enabled = TRUE");
|
||||
|
||||
// Column mappings
|
||||
entity.Property(e => e.Id)
|
||||
.HasDefaultValueSql("gen_random_uuid()")
|
||||
.HasColumnName("id");
|
||||
entity.Property(e => e.PluginId)
|
||||
.HasColumnName("plugin_id");
|
||||
entity.Property(e => e.TenantId)
|
||||
.HasColumnName("tenant_id");
|
||||
entity.Property(e => e.InstanceName)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("instance_name");
|
||||
entity.Property(e => e.Config)
|
||||
.HasColumnType("jsonb")
|
||||
.HasDefaultValueSql("'{}'::jsonb")
|
||||
.HasColumnName("config");
|
||||
entity.Property(e => e.SecretsPath)
|
||||
.HasMaxLength(500)
|
||||
.HasColumnName("secrets_path");
|
||||
entity.Property(e => e.Enabled)
|
||||
.HasDefaultValue(true)
|
||||
.HasColumnName("enabled");
|
||||
entity.Property(e => e.Status)
|
||||
.HasMaxLength(50)
|
||||
.HasDefaultValue("pending")
|
||||
.HasColumnName("status");
|
||||
entity.Property(e => e.ResourceLimits)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("resource_limits");
|
||||
entity.Property(e => e.LastUsedAt)
|
||||
.HasColumnName("last_used_at");
|
||||
entity.Property(e => e.InvocationCount)
|
||||
.HasDefaultValue(0L)
|
||||
.HasColumnName("invocation_count");
|
||||
entity.Property(e => e.ErrorCount)
|
||||
.HasDefaultValue(0L)
|
||||
.HasColumnName("error_count");
|
||||
entity.Property(e => e.CreatedAt)
|
||||
.HasDefaultValueSql("now()")
|
||||
.HasColumnName("created_at");
|
||||
entity.Property(e => e.UpdatedAt)
|
||||
.HasDefaultValueSql("now()")
|
||||
.HasColumnName("updated_at");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PluginHealthHistoryEntity>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("plugin_health_history_pkey");
|
||||
|
||||
entity.ToTable("plugin_health_history", schemaName);
|
||||
|
||||
// Indexes matching SQL migration
|
||||
entity.HasIndex(e => new { e.PluginId, e.CheckedAt }, "idx_plugin_health_history_plugin")
|
||||
.IsDescending(false, true);
|
||||
entity.HasIndex(e => e.CheckedAt, "idx_plugin_health_history_checked")
|
||||
.IsDescending(true);
|
||||
|
||||
// Column mappings
|
||||
entity.Property(e => e.Id)
|
||||
.HasDefaultValueSql("gen_random_uuid()")
|
||||
.HasColumnName("id");
|
||||
entity.Property(e => e.PluginId)
|
||||
.HasColumnName("plugin_id");
|
||||
entity.Property(e => e.CheckedAt)
|
||||
.HasDefaultValueSql("now()")
|
||||
.HasColumnName("checked_at");
|
||||
entity.Property(e => e.Status)
|
||||
.HasMaxLength(50)
|
||||
.HasColumnName("status");
|
||||
entity.Property(e => e.ResponseTimeMs)
|
||||
.HasColumnName("response_time_ms");
|
||||
entity.Property(e => e.Details)
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("details");
|
||||
entity.Property(e => e.ErrorMessage)
|
||||
.HasColumnName("error_message");
|
||||
entity.Property(e => e.CreatedAt)
|
||||
.HasDefaultValueSql("now()")
|
||||
.HasColumnName("created_at");
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Context;
|
||||
|
||||
/// <summary>
|
||||
/// Design-time DbContext factory for dotnet ef CLI tooling.
|
||||
/// </summary>
|
||||
public sealed class PluginRegistryDesignTimeDbContextFactory
|
||||
: IDesignTimeDbContextFactory<PluginRegistryDbContext>
|
||||
{
|
||||
private const string DefaultConnectionString =
|
||||
"Host=localhost;Port=55433;Database=postgres;Username=postgres;Password=postgres;Search Path=platform,public";
|
||||
private const string ConnectionStringEnvironmentVariable =
|
||||
"STELLAOPS_PLUGINREGISTRY_EF_CONNECTION";
|
||||
|
||||
public PluginRegistryDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
var connectionString = ResolveConnectionString();
|
||||
var options = new DbContextOptionsBuilder<PluginRegistryDbContext>()
|
||||
.UseNpgsql(connectionString)
|
||||
.Options;
|
||||
|
||||
return new PluginRegistryDbContext(options);
|
||||
}
|
||||
|
||||
private static string ResolveConnectionString()
|
||||
{
|
||||
var fromEnvironment = Environment.GetEnvironmentVariable(ConnectionStringEnvironmentVariable);
|
||||
return string.IsNullOrWhiteSpace(fromEnvironment)
|
||||
? DefaultConnectionString
|
||||
: fromEnvironment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Navigation properties for PluginCapabilityEntity.
|
||||
/// </summary>
|
||||
public partial class PluginCapabilityEntity
|
||||
{
|
||||
public virtual PluginEntity Plugin { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
/// <summary>
|
||||
/// EF Core entity for the platform.plugin_capabilities table.
|
||||
/// </summary>
|
||||
public partial class PluginCapabilityEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid PluginId { get; set; }
|
||||
public string CapabilityType { get; set; } = null!;
|
||||
public string CapabilityId { get; set; } = null!;
|
||||
public string? ConfigSchema { get; set; }
|
||||
public string? InputSchema { get; set; }
|
||||
public string? OutputSchema { get; set; }
|
||||
public string? DisplayName { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? DocumentationUrl { get; set; }
|
||||
public string? Metadata { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Navigation properties and collection initializers for PluginEntity.
|
||||
/// </summary>
|
||||
public partial class PluginEntity
|
||||
{
|
||||
public virtual ICollection<PluginCapabilityEntity> PluginCapabilities { get; set; } = new List<PluginCapabilityEntity>();
|
||||
public virtual ICollection<PluginInstanceEntity> PluginInstances { get; set; } = new List<PluginInstanceEntity>();
|
||||
public virtual ICollection<PluginHealthHistoryEntity> HealthHistory { get; set; } = new List<PluginHealthHistoryEntity>();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
/// <summary>
|
||||
/// EF Core entity for the platform.plugins table.
|
||||
/// </summary>
|
||||
public partial class PluginEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string PluginId { get; set; } = null!;
|
||||
public string Name { get; set; } = null!;
|
||||
public string Version { get; set; } = null!;
|
||||
public string Vendor { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public string? LicenseId { get; set; }
|
||||
public string TrustLevel { get; set; } = null!;
|
||||
public byte[]? Signature { get; set; }
|
||||
public string? SigningKeyId { get; set; }
|
||||
public string[] Capabilities { get; set; } = [];
|
||||
public string CapabilityDetails { get; set; } = "{}";
|
||||
public string Source { get; set; } = null!;
|
||||
public string? AssemblyPath { get; set; }
|
||||
public string? EntryPoint { get; set; }
|
||||
public string Status { get; set; } = null!;
|
||||
public string? StatusMessage { get; set; }
|
||||
public string? HealthStatus { get; set; }
|
||||
public DateTimeOffset? LastHealthCheck { get; set; }
|
||||
public int HealthCheckFailures { get; set; }
|
||||
public string? Manifest { get; set; }
|
||||
public string? RuntimeInfo { get; set; }
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
public DateTimeOffset UpdatedAt { get; set; }
|
||||
public DateTimeOffset? LoadedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Navigation properties for PluginHealthHistoryEntity.
|
||||
/// </summary>
|
||||
public partial class PluginHealthHistoryEntity
|
||||
{
|
||||
public virtual PluginEntity Plugin { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
/// <summary>
|
||||
/// EF Core entity for the platform.plugin_health_history table.
|
||||
/// </summary>
|
||||
public partial class PluginHealthHistoryEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid PluginId { get; set; }
|
||||
public DateTimeOffset CheckedAt { get; set; }
|
||||
public string Status { get; set; } = null!;
|
||||
public int? ResponseTimeMs { get; set; }
|
||||
public string? Details { get; set; }
|
||||
public string? ErrorMessage { get; set; }
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Navigation properties for PluginInstanceEntity.
|
||||
/// </summary>
|
||||
public partial class PluginInstanceEntity
|
||||
{
|
||||
public virtual PluginEntity Plugin { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace StellaOps.Plugin.Registry.EfCore.Models;
|
||||
|
||||
/// <summary>
|
||||
/// EF Core entity for the platform.plugin_instances table.
|
||||
/// </summary>
|
||||
public partial class PluginInstanceEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid PluginId { get; set; }
|
||||
public Guid? TenantId { get; set; }
|
||||
public string? InstanceName { get; set; }
|
||||
public string Config { get; set; } = "{}";
|
||||
public string? SecretsPath { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public string Status { get; set; } = null!;
|
||||
public string? ResourceLimits { get; set; }
|
||||
public DateTimeOffset? LastUsedAt { get; set; }
|
||||
public long InvocationCount { get; set; }
|
||||
public long ErrorCount { get; set; }
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
public DateTimeOffset UpdatedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Npgsql;
|
||||
using StellaOps.Plugin.Registry.EfCore.CompiledModels;
|
||||
using StellaOps.Plugin.Registry.EfCore.Context;
|
||||
|
||||
namespace StellaOps.Plugin.Registry.Postgres;
|
||||
|
||||
/// <summary>
|
||||
/// Runtime factory for PluginRegistryDbContext with compiled model support.
|
||||
/// </summary>
|
||||
internal static class PluginRegistryDbContextFactory
|
||||
{
|
||||
public const string DefaultSchemaName = "platform";
|
||||
|
||||
public static PluginRegistryDbContext Create(
|
||||
NpgsqlConnection connection,
|
||||
int commandTimeoutSeconds,
|
||||
string schemaName)
|
||||
{
|
||||
var normalizedSchema = string.IsNullOrWhiteSpace(schemaName)
|
||||
? DefaultSchemaName
|
||||
: schemaName.Trim();
|
||||
|
||||
var optionsBuilder = new DbContextOptionsBuilder<PluginRegistryDbContext>()
|
||||
.UseNpgsql(connection, npgsql => npgsql.CommandTimeout(commandTimeoutSeconds));
|
||||
|
||||
// Use static compiled model ONLY for default schema path
|
||||
if (string.Equals(normalizedSchema, DefaultSchemaName, StringComparison.Ordinal))
|
||||
{
|
||||
optionsBuilder.UseModel(PluginRegistryDbContextModel.Instance);
|
||||
}
|
||||
|
||||
return new PluginRegistryDbContext(optionsBuilder.Options, normalizedSchema);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,17 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Migrations\**\*.sql" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Prevent automatic compiled-model binding so non-default schemas can build runtime models. -->
|
||||
<Compile Remove="EfCore\CompiledModels\PluginRegistryDbContextAssemblyAttributes.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
|
||||
@@ -19,14 +30,11 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Options" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||
<PackageReference Include="Npgsql" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StellaOps.Plugin.Abstractions\StellaOps.Plugin.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Migrations\*.sql" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user