using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; namespace Sozsoft.Platform.Data.Seeds; /// /// Component'in designer dokumanindaki (Props) Data sekmesi endpoint'lerini cozup /// CRUD endpoint katalogu ile eslestiren ortak mantik. /// /// Ayni cozum hem kaydetme sirasinda (CustomComponentAppService, katalog veritabanindan gelir) /// hem de seed sirasinda (CustomComponentDataSeeder, katalog crud/*.json dosyalarindan gelir) /// kullanilir; boylece DataSources sutunu iki yolda da ayni sekilde uretilir. /// /// public static class CustomComponentDataSourceResolver { private static readonly JsonSerializerOptions JsonReadOptions = new() { PropertyNameCaseInsensitive = true }; /// Eslestirmede kullanilan CRUD endpoint tanimi. public sealed class CrudEndpointReference { public string EntityName { get; set; } = string.Empty; public string Method { get; set; } = string.Empty; public string Path { get; set; } = string.Empty; public string OperationType { get; set; } = string.Empty; } /// /// Props icindeki visualDesigner.dataSources listesini okur ve her kaydi method + path /// ile icinde arar. Eslesmeyen (elle yazilmis ya da custom) /// endpoint'ler de listede kalir; yalnizca entity/seed dosyasi alanlari bos gelir. /// public static List Resolve( string? props, IReadOnlyCollection endpoints) { var documentSources = ParseDocumentDataSources(props); if (documentSources.Count == 0) { return []; } var resolved = new List(); foreach (var source in documentSources) { var method = (source.Method ?? string.Empty).Trim().ToUpperInvariant(); var url = (source.Url ?? string.Empty).Trim(); if (url.Length == 0) { continue; } // Ayni method + path birden fazla bilesene baglanmis olabilir; tekrarlari eleriz. if (resolved.Exists(x => x.Method == method && string.Equals(x.Url, url, StringComparison.OrdinalIgnoreCase))) { continue; } var endpoint = endpoints.FirstOrDefault(x => string.Equals(x.Method?.Trim(), method, StringComparison.OrdinalIgnoreCase) && string.Equals(x.Path?.Trim(), url, StringComparison.OrdinalIgnoreCase)); resolved.Add(new CustomComponentSeedDataSourceDto { Name = (source.Name ?? string.Empty).Trim(), Method = method, Url = url, ResponsePath = string.IsNullOrWhiteSpace(source.ResponsePath) ? null : source.ResponsePath.Trim(), EntityName = endpoint?.EntityName, OperationType = endpoint?.OperationType, SeedFile = endpoint == null ? null : $"{SeedPathResolver.CrudFolder}/{endpoint.EntityName}.json" }); } return resolved; } /// Props JSON'undaki designer dokumanindan yalnizca dataSources dizisini ayiklar. private static List ParseDocumentDataSources(string? props) { if (string.IsNullOrWhiteSpace(props)) { return []; } try { using var document = JsonDocument.Parse(props); if (!document.RootElement.TryGetProperty("visualDesigner", out var designer) || designer.ValueKind != JsonValueKind.Object || !designer.TryGetProperty("dataSources", out var dataSources) || dataSources.ValueKind != JsonValueKind.Array) { return []; } return JsonSerializer.Deserialize>(dataSources.GetRawText(), JsonReadOptions) ?? []; } catch (JsonException) { return []; } } /// Designer dokumanindaki tek bir data source kaydi. private sealed class DesignerDataSourceDto { public string? Name { get; set; } public string? Method { get; set; } public string? Url { get; set; } public string? ResponsePath { get; set; } } }