using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace Elwig.Models.Dtos { public class DataTable { public string Name { get; set; } public string FullName { get; set; } public IEnumerable Rows { get; private set; } public int RowNum => Rows.Count(); public int ColNum => ColumnNames.Count(); public IEnumerable<(string, Type?)> ColumnDefs => _map.Select(m => (m.Item1, m.Item2?.PropertyType ?? m.Item3?.FieldType)); public IEnumerable ColumnNames => ColumnDefs.Select(m => m.Item1); public IEnumerable ColumnTypes => ColumnDefs.Select(m => m.Item2); public IEnumerable ColumnFlatTypes { get; private set; } public IEnumerable ColumnSpans { get; private set; } public IEnumerable ColumnWidths { get; private set; } private readonly PropertyInfo[] _properties; private readonly FieldInfo[] _fields; private readonly (string, PropertyInfo?, FieldInfo?)[] _map; public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string, string, int?)>? colNames = null) { _fields = typeof(T).GetFields(); _properties = typeof(T).GetProperties(); colNames ??= _properties.Select(p => p.Name).Union(_fields.Select(f => f.Name)).Select(i => (i, i, (int?)null)).ToList(); _map = colNames.Select(n => (n.Item2, _properties.FirstOrDefault(p => p?.Name == n.Item1, null), _fields.FirstOrDefault(f => f?.Name == n.Item1, null))).ToArray(); Name = name; FullName = fullName; Rows = rows; ColumnFlatTypes = ColumnTypes.SelectMany(type => { var elType = type?.GetElementType(); return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Select(f => f.FieldType) : type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Select(f => f.FieldType) : new Type?[] { type }; }).ToList(); ColumnSpans = ColumnTypes.Select(type => { var elType = type?.GetElementType(); return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Length : type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length : 1; }).ToList(); ColumnWidths = colNames.Select(c => c.Item3).ToList(); } public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string, string)>? colNames = null) : this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, (int?)null))) { } public DataTable(string name, IEnumerable rows, IEnumerable<(string, string)>? colNames = null) : this(name, name, rows, colNames) { } public DataTable(string name, IEnumerable rows, IEnumerable<(string, string, int?)>? colNames = null) : this(name, name, rows, colNames) { } public DataTable(string name, IEnumerable rows, IEnumerable<(string, string, int)>? colNames = null) : this(name, name, rows, colNames) { } public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string, string, int)>? colNames = null) : this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, (int?)c.Item3))) { } protected IEnumerable<(string, object?)> GetNamedRowData(T row) { return _map.Select(i => (i.Item1, i.Item2?.GetValue(row) ?? i.Item3?.GetValue(row))); } protected IEnumerable GetRowData(T row) { return GetNamedRowData(row).Select(i => i.Item2); } public IEnumerable> GetData() { return Rows.Select(GetRowData); } public IEnumerable> GetNamedData() { return Rows.Select(GetNamedRowData); } } }