using Microsoft.Data.Sqlite; namespace MoShiro.Backend.Storage.Sqlite; /// 手写的参数化 SQL 的小帮手:禁止字符串拼接值,所有值都经过参数。 internal static class Sql { public static SqliteCommand Cmd(this SqliteConnection connection, string sql, params (string Name, object? Value)[] parameters) { SqliteCommand command = connection.CreateCommand(); command.CommandText = sql; foreach ((string name, object? value) in parameters) { command.Parameters.AddWithValue(name, value ?? DBNull.Value); } return command; } public static int Exec(this SqliteConnection connection, string sql, params (string Name, object? Value)[] parameters) { using SqliteCommand command = connection.Cmd(sql, parameters); return command.ExecuteNonQuery(); } public static T? Scalar(this SqliteConnection connection, string sql, params (string Name, object? Value)[] parameters) { using SqliteCommand command = connection.Cmd(sql, parameters); object? value = command.ExecuteScalar(); return value is null or DBNull ? default : (T)Convert.ChangeType(value, Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), System.Globalization.CultureInfo.InvariantCulture); } public static List Query(this SqliteConnection connection, string sql, Func map, params (string Name, object? Value)[] parameters) { using SqliteCommand command = connection.Cmd(sql, parameters); using SqliteDataReader reader = command.ExecuteReader(); var rows = new List(); while (reader.Read()) { rows.Add(map(reader)); } return rows; } public static T? QueryOne(this SqliteConnection connection, string sql, Func map, params (string Name, object? Value)[] parameters) where T : class { using SqliteCommand command = connection.Cmd(sql, parameters); using SqliteDataReader reader = command.ExecuteReader(); return reader.Read() ? map(reader) : null; } public static long? NullableLong(this SqliteDataReader reader, int ordinal) => reader.IsDBNull(ordinal) ? null : reader.GetInt64(ordinal); public static string? NullableString(this SqliteDataReader reader, int ordinal) => reader.IsDBNull(ordinal) ? null : reader.GetString(ordinal); public static byte[] Bytes(this SqliteDataReader reader, int ordinal) => (byte[])reader.GetValue(ordinal); public static byte[]? NullableBytes(this SqliteDataReader reader, int ordinal) => reader.IsDBNull(ordinal) ? null : (byte[])reader.GetValue(ordinal); }