using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Sozsoft.Platform.Data.Seeds; using Sozsoft.Platform.DynamicData; using Sozsoft.Platform.Enums; using Volo.Abp.Domain.Services; namespace Sozsoft.Mcp.Services; /// /// Sorguyu istegin kapsamindaki veri kaynaginda kosturur ve satir tavanini uygular. /// Veri kaynagi cozumu tek yerde kalsin diye burada toplanmistir. /// public interface IMcpQueryExecutor { /// /// Sunucu kaydindaki kod. Bos ya da !Tenant ise veri kaynagi istegin kiracisindan /// cozulur; host baglaminda varsayilan kaynaga duser. /// Task ResolveDataSourceAsync(string? dataSourceCode); /// /// Sorguyu kosturur. Sonuc kumesi satirda kesilir; kesilme /// olduysa sonuc bunu bildirir. /// Task ExecuteAsync( McpDataSourceContext context, string sql, IReadOnlyDictionary parameters, int maxRows); } public class McpQueryExecutor(IDynamicDataManager dynamicDataManager) : DomainService, IMcpQueryExecutor { public async Task ResolveDataSourceAsync(string? dataSourceCode) { var useTenantScope = string.IsNullOrWhiteSpace(dataSourceCode) || dataSourceCode == McpConsts.TenantDataSourceMarker; var resolvedCode = useTenantScope ? SeedConsts.DataSources.DefaultCode : dataSourceCode!; var (repository, connectionString, dataSourceType) = await dynamicDataManager.GetAsync(useTenantScope, resolvedCode); return new McpDataSourceContext(repository, connectionString, dataSourceType); } public async Task ExecuteAsync( McpDataSourceContext context, string sql, IReadOnlyDictionary parameters, int maxRows) { var stopwatch = Stopwatch.StartNew(); var rows = await context.Repository.QueryAsync( sql, context.ConnectionString, parameters.ToDictionary(entry => entry.Key, entry => entry.Value)); stopwatch.Stop(); var columns = new List(); var materialized = new List>(); var truncated = false; foreach (var row in rows) { if (materialized.Count >= maxRows) { truncated = true; break; } if (row is not IDictionary values) { continue; } if (columns.Count == 0) { columns = [.. values.Keys]; } materialized.Add(values.ToDictionary(entry => entry.Key, entry => (object?)entry.Value)); } return new McpQueryRows(columns, materialized, truncated, stopwatch.ElapsedMilliseconds); } } /// Cozumlenmis veri kaynagi: hangi depo, hangi baglanti, hangi saglayici. public sealed record McpDataSourceContext( IDynamicDataRepository Repository, string ConnectionString, DataSourceTypeEnum DataSourceType); /// Sorgu sonucunun ham hali. public sealed record McpQueryRows( List Columns, List> Rows, bool Truncated, long ExecutionTimeMs);