Skip to content

Instantly share code, notes, and snippets.

@maximgorbatyuk
Created August 3, 2021 07:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maximgorbatyuk/fd765a64dc7a3c0555951c184822a771 to your computer and use it in GitHub Desktop.
Save maximgorbatyuk/fd765a64dc7a3c0555951c184822a771 to your computer and use it in GitHub Desktop.
public class Controller : ControllerBase {
[HttpPost("sql/read")]
public async Task<IActionResult> ExecuteReadSqlAsync([FromBody] SqlCommandRequest request)
{
request
.ThrowIfNull(nameof(request))
.ThrowIfInvalid();
var table = new DataTable();
try
{
await using var cmd = _context.Database.GetDbConnection().CreateCommand();
#pragma warning disable CA2100
cmd.CommandText = request.Query;
#pragma warning restore CA2100
if (cmd.Connection is not null)
{
await cmd.Connection?.OpenAsync();
table.Load(await cmd.ExecuteReaderAsync());
}
return Ok(new DataTableOutput(table).AsText());
}
catch (Exception e)
{
return Ok(new
{
Exception = new
{
Message = e.Message,
InnerExceptionMessage = e.InnerException?.Message
},
Query = request.Query
});
}
}
[HttpPost("sql/execute")]
[RoleAuthorize(Role.Administrator)]
public async Task<IActionResult> ExecuteSqlCommandAsync([FromBody] SqlCommandRequest request)
{
request
.ThrowIfNull(nameof(request))
.ThrowIfInvalid();
try
{
var result = await _context.Database.ExecuteSqlRawAsync(request.Query);
return Ok(new
{
Query = request.Query,
RowsAffected = result
});
}
catch (Exception e)
{
return Ok(new
{
Exception = new
{
Message = e.Message,
InnerExceptionMessage = e.InnerException?.Message
},
Query = request.Query
});
}
}
public class SqlCommandRequest
{
[Required]
public string Query { get; init; }
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
namespace Web.Infrastructure
{
public class DataTableOutput
{
private readonly DataTable _dataTable;
public DataTableOutput(DataTable dataTable)
{
_dataTable = dataTable;
}
public string AsText()
{
var rows = Rows();
var columns = Columns();
int[] maxColumnValues = rows
.Select(x => x.Values.Select(v => v.StringValue.Length))
.Union(new[] { columns.Select(c => c.ColumnName.Length) })
.Aggregate(new int[columns.Count + 1].AsEnumerable(), (accumulate, x) => accumulate.Zip(x, Math.Max))
.ToArray();
var headerLine = "| " + string.Join(" | ", columns.Select((n, i) => n.ColumnName.PadRight(maxColumnValues[i]))) + " |";
var headerDataDividerLine = "|-" + string.Join("+-", columns.Select((g, i) => new string('-', maxColumnValues[i] + 1))) + "|";
var lines = new List<string>()
{
headerLine,
headerDataDividerLine,
};
lines.AddRange(rows.Select(row => row.AsLine(maxColumnValues)));
return lines.Aggregate((p, c) => p + Environment.NewLine + c);
}
private IReadOnlyCollection<Column> Columns()
{
var list = new List<Column>();
foreach (DataColumn column in _dataTable.Columns)
{
list.Add(new Column(column));
}
return list;
}
private IReadOnlyCollection<Row> Rows()
{
var list = new List<Row>();
foreach (DataRow row in _dataTable.Rows)
{
list.Add(new Row(row));
}
return list;
}
public record Column
{
public Column(DataColumn column)
{
ColumnName = column.ColumnName;
ColumnType = column.DataType;
}
public string ColumnName { get; }
public Type ColumnType { get; }
}
public record Row
{
public Row(DataRow row)
{
Values = row.ItemArray.Select(x => new RowValue(x)).ToArray();
}
public IReadOnlyCollection<RowValue> Values { get; }
public string AsLine(int[] maxColumnValues)
{
return "| " + string.Join(" | ", Values.Select((s, i) => s.StringValue.PadRight(maxColumnValues[i]))) + " |";
}
}
public record RowValue
{
public RowValue(object value)
{
Value = value;
}
public object Value { get; }
public string StringValue => Value?.ToString() ?? string.Empty;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment