This commit is contained in:
2024-01-29 09:29:16 +08:00
parent 4f96b77e55
commit 083090c62b
63 changed files with 2479 additions and 1491 deletions

View File

@@ -0,0 +1,54 @@
using System.Data;
using MySqlConnector;
namespace ConsoleApp2.Helpers.Database;
public static class DatabaseHelper
{
public static async Task<DataSet> QueryTableAsync(string connStr, string sql)
{
await using var conn = new MySqlConnection(connStr);
if(conn.State is not ConnectionState.Open)
await conn.OpenAsync();
await using var cmd = conn.CreateCommand();
cmd.CommandText = sql;
var ds = new DataSet();
var adapter = new MySqlDataAdapter(cmd).Fill(ds);
return ds;
}
public static async Task<object?> QueryScalarAsync(string connStr, string sql)
{
await using var conn = new MySqlConnection(connStr);
if(conn.State is not ConnectionState.Open)
await conn.OpenAsync();
await using var cmd = conn.CreateCommand();
cmd.CommandText = sql;
return await cmd.ExecuteScalarAsync();
}
public static async Task<int> NonQueryAsync(string connStr, string sql)
{
await using var conn = new MySqlConnection(connStr);
if(conn.State is not ConnectionState.Open)
await conn.OpenAsync();
await using var cmd = conn.CreateCommand();
cmd.CommandText = sql;
return await cmd.ExecuteNonQueryAsync();
}
public static async Task<int> TransactionAsync(string connStr, string sql, params MySqlParameter[] parameters)
{
await using var conn = new MySqlConnection(connStr);
if(conn.State is not ConnectionState.Open)
await conn.OpenAsync();
await using var trans = await conn.BeginTransactionAsync();
await using var cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.Transaction = trans;
cmd.Parameters.AddRange(parameters);
var rows = await cmd.ExecuteNonQueryAsync();
await trans.CommitAsync();
return rows;
}
}

View File

@@ -1,6 +1,5 @@
using ConsoleApp2.Options;
using System.Text;
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
using ZstdSharp;
namespace ConsoleApp2.Helpers;
@@ -11,32 +10,41 @@ public static partial class DumpDataHelper
[GeneratedRegex(@"\([^)]*\)")]
private static partial Regex MatchBrackets();
public static async Task<string[]> GetCsvHeadersFromSqlFileAsync(string txt)
/// <summary>
/// 从MyDumper导出的SQL文件内容中读取表头
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static string[] GetCsvHeadersFromSqlFile(string content)
{
//var txt = await File.ReadAllTextAsync(filePath);
var match = MatchBrackets().Match(txt);
var match = MatchBrackets().Match(content);
if (!match.Success)
throw new ArgumentException("输入的SQL内容有误无法提取表头", nameof(content));
return ParseHeader(match.ValueSpan);
}
private static string[] ParseHeader(ReadOnlySpan<char> headerStr)
{
headerStr = headerStr[1..^1];
Span<Range> ranges = stackalloc Range[50];
var count = headerStr.Split(ranges, ',');
var arr = new string[count];
for (var i = 0; i < count; i++)
string[] ParseHeader(ReadOnlySpan<char> headerStr)
{
arr[i] = headerStr[ranges[i]].Trim("@`").ToString(); // 消除列名的反引号,如果是变量则消除@
}
headerStr = headerStr[1..^1];
Span<Range> ranges = stackalloc Range[50];
var count = headerStr.Split(ranges, ',');
var arr = new string[count];
return arr;
for (var i = 0; i < count; i++)
{
arr[i] = headerStr[ranges[i]].Trim("@`").ToString(); // 消除列名的反引号,如果是变量则消除@
}
return arr;
}
}
public static string GetTableName(ReadOnlySpan<char> filePath)
/// <summary>
/// 从MyDumper导出的Csv文件名解析出表名
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public static string GetTableNameFromCsvFileName(ReadOnlySpan<char> filePath)
{
filePath = filePath[(filePath.LastIndexOf('\\') + 1)..];
var firstDotIdx = -1;
@@ -60,13 +68,24 @@ public static partial class DumpDataHelper
return filePath[(firstDotIdx+1)..secondDotIdx].ToString();
}
public static async Task<string[]> GetCsvFileNamesFromSqlFileAsync(string txt,Regex regex)
/// <summary>
/// 从MyDumper导出的SQL文件内容中读取CSV文件名
/// </summary>
/// <param name="txt"></param>
/// <param name="regex"></param>
/// <returns></returns>
public static Task<string[]> GetCsvFileNamesFromSqlFileAsync(string txt, Regex regex)
{
//var txt = await File.ReadAllTextAsync(filePath);
var matches = regex.Matches(txt);
return matches.Select(match => match.ValueSpan[1..^1].ToString()).ToArray();
return Task.FromResult(matches.Select(match => match.ValueSpan[1..^1].ToString()).ToArray());
}
/// <summary>
/// 检查字符串是否为16进制
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static bool CheckHexField(string? str)
{
if (string.IsNullOrWhiteSpace(str))
@@ -90,9 +109,17 @@ public static partial class DumpDataHelper
return true;
}
/// <summary>
/// 将输入流以ZSTD标准解压为字符串
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public static async Task<string> DecompressZstAsStringAsync(Stream stream)
{
await using var ds = new DecompressionStream(stream);
var reader = new StreamReader(ds);
return await reader.ReadToEndAsync();
}
// public static string EliminateEscapeChars(ReadOnlySpan<char> str)
// {
// char[] escapeChars = ['0','\''];
// }
}

View File

@@ -0,0 +1,67 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
namespace ConsoleApp2.Helpers;
public static class EnumerableExtensions
{
public static string ToMarkdownTable<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]T>(this IEnumerable<T> source)
{
var properties = typeof(T).GetRuntimeProperties();
var fields = typeof(T)
.GetRuntimeFields()
.Where(f => f.IsPublic);
var gettables = Enumerable.Union(
properties.Select(p => new { p.Name, GetValue = (Func<object, object>)p.GetValue, Type = p.PropertyType }),
fields.Select(p => new { p.Name, GetValue = (Func<object, object>)p.GetValue, Type = p.FieldType }));
var maxColumnValues = source
.Select(x => gettables.Select(p => p.GetValue(x)?.ToString()?.Length ?? 0))
.Union(new[] { gettables.Select(p => p.Name.Length) }) // Include header in column sizes
.Aggregate(
new int[gettables.Count()].AsEnumerable(),
(accumulate, x) => accumulate.Zip(x, Math.Max))
.ToArray();
var columnNames = gettables.Select(p => p.Name);
var headerLine = "| " + string.Join(" | ", columnNames.Select((n, i) => n.PadRight(maxColumnValues[i]))) + " |";
var isNumeric = new Func<Type, bool>(type =>
type == typeof(Byte) ||
type == typeof(SByte) ||
type == typeof(UInt16) ||
type == typeof(UInt32) ||
type == typeof(UInt64) ||
type == typeof(Int16) ||
type == typeof(Int32) ||
type == typeof(Int64) ||
type == typeof(Decimal) ||
type == typeof(Double) ||
type == typeof(Single));
var rightAlign = new Func<Type, char>(type => isNumeric(type) ? ':' : ' ');
var headerDataDividerLine =
"| " +
string.Join(
"| ",
gettables.Select((g, i) => new string('-', maxColumnValues[i]) + rightAlign(g.Type))) +
"|";
var lines = new[]
{
headerLine,
headerDataDividerLine,
}.Union(
source
.Select(s =>
"| " + string.Join(" | ",
gettables.Select((n, i) => (n.GetValue(s)?.ToString() ?? "").PadRight(maxColumnValues[i]))) +
" |"));
return lines
.Aggregate((p, c) => p + Environment.NewLine + c);
}
}

View File

@@ -5,6 +5,12 @@ namespace ConsoleApp2.Helpers;
public static class StringExtensions
{
/// <summary>
/// 截断字符串
/// </summary>
/// <param name="this"></param>
/// <param name="maxLength">截断长度</param>
/// <returns></returns>
public static string Omit(this ReadOnlySpan<char> @this, int maxLength)
{
if (@this.Length > maxLength)
@@ -12,8 +18,20 @@ public static class StringExtensions
return @this.ToString();
}
/// <summary>
/// 截断字符串
/// </summary>
/// <param name="this"></param>
/// <param name="maxLength">截断长度</param>
/// <returns></returns>
public static string Omit(this string @this, int maxLength) => Omit(@this.AsSpan(), maxLength);
/// <summary>
/// 将16进制字符串转换为字符串
/// </summary>
/// <param name="hexString"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static string FromHex(ReadOnlySpan<char> hexString, Encoding? encoding = null)
{
encoding ??= Encoding.UTF8;
@@ -38,6 +56,11 @@ public static class StringExtensions
return encoding.GetString(bytes);
}
/// <summary>
/// 检查是否为JSON字符串
/// </summary>
/// <param name="hexStr"></param>
/// <returns></returns>
public static bool CheckJsonHex(ReadOnlySpan<char> hexStr)
{
if (hexStr.Length < 2)

View File

@@ -0,0 +1,19 @@
namespace ConsoleApp2.Helpers;
public static class TaskExtensions
{
public static async Task WaitUntil(Func<bool> condition, int pollDelay = 25, CancellationToken ct = default)
{
try
{
while (!condition())
{
await Task.Delay(pollDelay, ct);
}
}
catch(TaskCanceledException)
{
// CancellationToken激活时Task.Delay通过抛异常来结束停止等待不用管它
}
}
}

View File

@@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2.Helpers
{
public static class ValidateConsole
{
public static void ValidateInput<T>(Func<string,bool> converter,string message)
{
Console.Write(message);
string ? input = Console.ReadLine();
while (true)
{
if (!string.IsNullOrEmpty(input))
{
var result = converter(input);
if (result == false)
{
Console.WriteLine($"输入的内容不合法,请重新输入!");
input = Console.ReadLine();
}
else break;
}
break;
}
}
}
}