Migrate to type-safe model ID structs
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using App.Metrics;
|
||||
@@ -36,13 +38,14 @@ namespace PluralKit.Core
|
||||
|
||||
public static void InitStatic()
|
||||
{
|
||||
DefaultTypeMap.MatchNamesWithUnderscores = true;
|
||||
|
||||
// Dapper by default tries to pass ulongs to Npgsql, which rejects them since PostgreSQL technically
|
||||
// doesn't support unsigned types on its own.
|
||||
// Instead we add a custom mapper to encode them as signed integers instead, converting them back and forth.
|
||||
SqlMapper.RemoveTypeMap(typeof(ulong));
|
||||
SqlMapper.AddTypeHandler(new UlongEncodeAsLongHandler());
|
||||
SqlMapper.AddTypeHandler(new UlongArrayHandler());
|
||||
DefaultTypeMap.MatchNamesWithUnderscores = true;
|
||||
|
||||
NpgsqlConnection.GlobalTypeMapper.UseNodaTime();
|
||||
// With the thing we add above, Npgsql already handles NodaTime integration
|
||||
@@ -51,6 +54,14 @@ namespace PluralKit.Core
|
||||
SqlMapper.AddTypeHandler(new PassthroughTypeHandler<Instant>());
|
||||
SqlMapper.AddTypeHandler(new PassthroughTypeHandler<LocalDate>());
|
||||
|
||||
// Add ID types to Dapper
|
||||
SqlMapper.AddTypeHandler(new NumericIdHandler<SystemId, int>(i => new SystemId(i)));
|
||||
SqlMapper.AddTypeHandler(new NumericIdHandler<MemberId, int>(i => new MemberId(i)));
|
||||
SqlMapper.AddTypeHandler(new NumericIdHandler<SwitchId, int>(i => new SwitchId(i)));
|
||||
SqlMapper.AddTypeHandler(new NumericIdArrayHandler<SystemId, int>(i => new SystemId(i)));
|
||||
SqlMapper.AddTypeHandler(new NumericIdArrayHandler<MemberId, int>(i => new MemberId(i)));
|
||||
SqlMapper.AddTypeHandler(new NumericIdArrayHandler<SwitchId, int>(i => new SwitchId(i)));
|
||||
|
||||
// Register our custom types to Npgsql
|
||||
// Without these it'll still *work* but break at the first launch + probably cause other small issues
|
||||
NpgsqlConnection.GlobalTypeMapper.MapComposite<ProxyTag>("proxy_tag");
|
||||
@@ -153,5 +164,37 @@ namespace PluralKit.Core
|
||||
|
||||
public override ulong[] Parse(object value) => Array.ConvertAll((long[]) value, i => (ulong) i);
|
||||
}
|
||||
|
||||
private class NumericIdHandler<T, TInner>: SqlMapper.TypeHandler<T>
|
||||
where T: INumericId<T, TInner>
|
||||
where TInner: IEquatable<TInner>, IComparable<TInner>
|
||||
{
|
||||
private readonly Func<TInner, T> _factory;
|
||||
|
||||
public NumericIdHandler(Func<TInner, T> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public override void SetValue(IDbDataParameter parameter, T value) => parameter.Value = value.Value;
|
||||
|
||||
public override T Parse(object value) => _factory((TInner) value);
|
||||
}
|
||||
|
||||
private class NumericIdArrayHandler<T, TInner>: SqlMapper.TypeHandler<T[]>
|
||||
where T: INumericId<T, TInner>
|
||||
where TInner: IEquatable<TInner>, IComparable<TInner>
|
||||
{
|
||||
private readonly Func<TInner, T> _factory;
|
||||
|
||||
public NumericIdArrayHandler(Func<TInner, T> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public override void SetValue(IDbDataParameter parameter, T[] value) => parameter.Value = Array.ConvertAll(value, v => v.Value);
|
||||
|
||||
public override T[] Parse(object value) => Array.ConvertAll((TInner[]) value, v => _factory(v));
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,18 +10,18 @@ namespace PluralKit.Core
|
||||
/// </summary>
|
||||
public class MessageContext
|
||||
{
|
||||
public int? SystemId { get; }
|
||||
public SystemId? SystemId { get; }
|
||||
public ulong? LogChannel { get; }
|
||||
public bool InBlacklist { get; }
|
||||
public bool InLogBlacklist { get; }
|
||||
public bool LogCleanupEnabled { get; }
|
||||
public bool ProxyEnabled { get; }
|
||||
public AutoproxyMode AutoproxyMode { get; }
|
||||
public int? AutoproxyMember { get; }
|
||||
public MemberId? AutoproxyMember { get; }
|
||||
public ulong? LastMessage { get; }
|
||||
public int? LastMessageMember { get; }
|
||||
public int LastSwitch { get; }
|
||||
public IReadOnlyList<int> LastSwitchMembers { get; } = new int[0];
|
||||
public MemberId? LastMessageMember { get; }
|
||||
public SwitchId LastSwitch { get; }
|
||||
public MemberId[] LastSwitchMembers { get; } = new MemberId[0];
|
||||
public Instant LastSwitchTimestamp { get; }
|
||||
public string? SystemTag { get; }
|
||||
public string? SystemAvatar { get; }
|
||||
|
@@ -8,7 +8,7 @@ namespace PluralKit.Core
|
||||
/// </summary>
|
||||
public class ProxyMember
|
||||
{
|
||||
public int Id { get; }
|
||||
public MemberId Id { get; }
|
||||
public IReadOnlyCollection<ProxyTag> ProxyTags { get; } = new ProxyTag[0];
|
||||
public bool KeepProxy { get; }
|
||||
|
||||
|
@@ -9,10 +9,10 @@ namespace PluralKit.Core
|
||||
{
|
||||
public static class DatabaseViewsExt
|
||||
{
|
||||
public static Task<IEnumerable<SystemFronter>> QueryCurrentFronters(this IPKConnection conn, int system) =>
|
||||
public static Task<IEnumerable<SystemFronter>> QueryCurrentFronters(this IPKConnection conn, SystemId system) =>
|
||||
conn.QueryAsync<SystemFronter>("select * from system_fronters where system = @system", new {system});
|
||||
|
||||
public static Task<IEnumerable<ListedMember>> QueryMemberList(this IPKConnection conn, int system, PrivacyLevel? privacyFilter = null, string? filter = null, bool includeDescriptionInNameFilter = false)
|
||||
public static Task<IEnumerable<ListedMember>> QueryMemberList(this IPKConnection conn, SystemId system, PrivacyLevel? privacyFilter = null, string? filter = null, bool includeDescriptionInNameFilter = false)
|
||||
{
|
||||
StringBuilder query = new StringBuilder("select * from member_list where system = @system");
|
||||
|
||||
|
@@ -4,10 +4,10 @@ namespace PluralKit.Core
|
||||
{
|
||||
public class SystemFronter
|
||||
{
|
||||
public int SystemId { get; }
|
||||
public int SwitchId { get; }
|
||||
public SystemId SystemId { get; }
|
||||
public SwitchId SwitchId { get; }
|
||||
public Instant SwitchTimestamp { get; }
|
||||
public int MemberId { get; }
|
||||
public MemberId MemberId { get; }
|
||||
public string MemberHid { get; }
|
||||
public string MemberName { get; }
|
||||
}
|
||||
|
Reference in New Issue
Block a user