using System; using System.IO; using System.Linq; using Microsoft.Extensions.Configuration; namespace Sozsoft.Platform.Data.Seeds; /// /// Runtime'da duzenlenebilen seed dosyalarinin klasorunu cozer. /// /// Kod ile birlikte versiyonlanan sabit seed'ler (DbMigrator projesindeki *Data.json dosyalari) /// buraya dahil degildir; onlar kendi projelerinin ciktisinda kalir. /// /// /// Klasor bilincli olarak hicbir projenin icinde degildir: depoda configs/seeds altinda durur ve /// konteynere bind mount ile baglanir. Boylece bir seed dosyasi degistiginde ne api ne de migrator /// imaji yeniden derlenir; deploy sirasindaki git pull yeterlidir. Ayni klasor File Manager /// uzerinden de duzenlenebildigi icin yapilan degisiklik dogrudan host diskinde kalici olur. /// /// /// Klasor duzeni CDN ile ayni kapsam mantigini izler — once kapsam, sonra icerik turu: /// /// seeds/ /// host/ → host (varsayilan) veritabani kapsami /// crud/ /// wizard/ /// data/ /// sql/ → SQL Server saglayicisi /// object/ → nesne olusturulur/guncellenir /// execute/ → nesne olusturulur, ayrica tum migration'lar bitince calistirilir /// postgres/ → PostgreSQL saglayicisi /// object/ /// execute/ /// tenants/ /// {tenantId}/ → her tenant kendi klasorunde /// crud/ wizard/ data/ sql/{object,execute}/ postgres/{object,execute}/ /// /// /// /// Cozum sirasi: /// 1) App:SeedsPath ayari (konteynerde mount noktasi), /// 2) calisma dizininden yukari dogru configs/seeds aramasi (local gelistirme), /// 3) calisma dizininin altindaki Seeds klasoru (son care). /// /// public static class SeedPathResolver { public const string ConfigurationKey = "App:SeedsPath"; /// Host veritabani kapsamindaki seed'lerin kok klasoru. public const string HostFolder = "host"; /// Tenant kapsamindaki seed'lerin kok klasoru; altinda tenant Id'si ile klasorler bulunur. public const string TenantsFolder = "tenants"; /// SQL Server saglayicisinin script klasoru. public const string SqlFolder = "sql"; /// PostgreSQL saglayicisinin script klasoru. public const string PostgresFolder = "postgres"; /// Yalnizca olusturulan/guncellenen nesne scriptleri. public const string ObjectFolder = "object"; /// Olusturulan, ayrica tum migration'lar bittikten sonra calistirilan scriptler. public const string ExecuteFolder = "execute"; /// Wizard'in urettigi konfigurasyon dosyalari. public const string WizardFolder = "wizard"; /// Crud endpoint konfigurasyon dosyalari. public const string CrudFolder = "crud"; /// Liste verisinin aynalandigi seed dosyalari (data/{ListFormCode}.json). public const string DataFolder = "data"; /// Bir ListForm icin varsayilan veri seed dosyasinin kapsam klasorune gore goreli yolu. public static string GetDataFilePath(string listFormCode) { return $"{DataFolder}/{listFormCode}.json"; } private const string RepositorySeedsFolder = "seeds"; private const string RepositoryConfigsFolder = "configs"; private const string FallbackFolderName = "Seeds"; /// Seed kok klasorunun tam yolunu dondurur. Klasorun var olmasi garanti edilmez. public static string GetRootPath(IConfiguration? configuration) { var configuredPath = configuration?[ConfigurationKey]; if (!string.IsNullOrWhiteSpace(configuredPath)) { return Path.GetFullPath(configuredPath); } var repositoryPath = FindRepositorySeedsPath(); if (repositoryPath != null) { return repositoryPath; } return Path.Combine(Directory.GetCurrentDirectory(), FallbackFolderName); } /// Seed kok klasorunun altindaki bir alt yolu dondurur. public static string GetPath(IConfiguration? configuration, params string[] subPaths) { var path = GetRootPath(configuration); foreach (var subPath in subPaths) { path = Path.Combine(path, subPath); } return path; } /// /// Kapsam klasorunun (host ya da ilgili tenant) altindaki yolu dondurur. /// null ise host/, aksi halde tenants/{tenantId}/ kullanilir. /// public static string GetScopePath(IConfiguration? configuration, Guid? tenantId, params string[] subPaths) { return GetPath(configuration, BuildScopeSubPaths(tenantId, subPaths)); } /// Kapsam klasorunun seed koküne gore goreli adi (host ya da tenants/{tenantId}). public static string GetScopeFolderName(Guid? tenantId) { return tenantId == null ? HostFolder : $"{TenantsFolder}/{tenantId.Value}"; } /// Aktif veritabani saglayicisina karsilik gelen script klasorunun adi. public static string GetProviderFolderName(bool isPostgreSql) { return isPostgreSql ? PostgresFolder : SqlFolder; } private static string[] BuildScopeSubPaths(Guid? tenantId, string[] subPaths) { var scopeSegments = tenantId == null ? new[] { HostFolder } : new[] { TenantsFolder, tenantId.Value.ToString() }; return scopeSegments.Concat(subPaths ?? Array.Empty()).ToArray(); } /// Calisma dizininden yukari dogru cikarak depodaki configs/seeds klasorunu arar. private static string? FindRepositorySeedsPath() { var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); while (dir != null) { var candidate = Path.Combine(dir.FullName, RepositoryConfigsFolder, RepositorySeedsFolder); if (Directory.Exists(candidate)) { return candidate; } dir = dir.Parent; } return null; } }