Refactor member updates to use a patch object

This commit is contained in:
Ske
2020-06-29 13:57:48 +02:00
parent 472e556ef0
commit 281b669391
10 changed files with 289 additions and 84 deletions

View File

@@ -0,0 +1,80 @@
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using Dapper;
using Newtonsoft.Json;
namespace PluralKit.Core
{
[JsonConverter(typeof(PartialConverter))]
public struct Partial<T>: IEnumerable<T>
{
public bool IsPresent { get; }
public T Value { get; }
private Partial(bool isPresent, T value)
{
IsPresent = isPresent;
Value = value;
}
public static Partial<T> Null() => new Partial<T>(true, default!);
public static Partial<T> Present(T obj) => new Partial<T>(true, obj);
public static Partial<T> Absent = new Partial<T>(false, default!);
public IEnumerable<T> ToArray() => IsPresent ? new[] {Value} : new T[0];
public IEnumerator<T> GetEnumerator() => ToArray().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ToArray().GetEnumerator();
}
public class PartialConverter: JsonConverter
{
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue,
JsonSerializer serializer)
{
var innerType = objectType.GenericTypeArguments[0];
var innerValue = serializer.Deserialize(reader, innerType);
return typeof(Partial<>)
.MakeGenericType(innerType)
.GetMethod(nameof(Partial<object>.Present))!
.Invoke(null, new[] {innerValue});
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) =>
throw new NotImplementedException();
public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => false;
}
public static class PartialExt
{
public static bool TryGet<T>(this Partial<T> pt, out T value)
{
value = pt.IsPresent ? pt.Value : default!;
return pt.IsPresent;
}
public static T Or<T>(this Partial<T> pt, T fallback) => pt.IsPresent ? pt.Value : fallback;
public static T Or<T>(this Partial<T> pt, Func<T> fallback) => pt.IsPresent ? pt.Value : fallback.Invoke();
public static Partial<TOut> Map<TIn, TOut>(this Partial<TIn> pt, Func<TIn, TOut> fn) =>
pt.IsPresent ? Partial<TOut>.Present(fn.Invoke(pt.Value)) : Partial<TOut>.Absent;
public static void Apply<T>(this Partial<T> pt, DynamicParameters bag, QueryBuilder qb, string fieldName)
{
if (!pt.IsPresent) return;
bag.Add(fieldName, pt.Value);
qb.Variable(fieldName, $"@{fieldName}");
}
}
}

View File

@@ -26,31 +26,31 @@ namespace PluralKit.Core
_ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}")
};
public static void SetPrivacy(this PKMember member, MemberPrivacySubject subject, PrivacyLevel level)
public static void SetPrivacy(this MemberPatch member, MemberPrivacySubject subject, PrivacyLevel level)
{
// what do you mean switch expressions can't be statements >.>
_ = subject switch
{
MemberPrivacySubject.Name => member.NamePrivacy = level,
MemberPrivacySubject.Description => member.DescriptionPrivacy = level,
MemberPrivacySubject.Avatar => member.AvatarPrivacy = level,
MemberPrivacySubject.Pronouns => member.PronounPrivacy = level,
MemberPrivacySubject.Birthday => member.BirthdayPrivacy= level,
MemberPrivacySubject.Metadata => member.MetadataPrivacy = level,
MemberPrivacySubject.Visibility => member.MemberVisibility = level,
MemberPrivacySubject.Name => member.NamePrivacy = Partial<PrivacyLevel>.Present(level),
MemberPrivacySubject.Description => member.DescriptionPrivacy = Partial<PrivacyLevel>.Present(level),
MemberPrivacySubject.Avatar => member.AvatarPrivacy = Partial<PrivacyLevel>.Present(level),
MemberPrivacySubject.Pronouns => member.PronounPrivacy = Partial<PrivacyLevel>.Present(level),
MemberPrivacySubject.Birthday => member.BirthdayPrivacy= Partial<PrivacyLevel>.Present(level),
MemberPrivacySubject.Metadata => member.MetadataPrivacy = Partial<PrivacyLevel>.Present(level),
MemberPrivacySubject.Visibility => member.Visibility = Partial<PrivacyLevel>.Present(level),
_ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}")
};
}
public static void SetAllPrivacy(this PKMember member, PrivacyLevel level)
public static void SetAllPrivacy(this MemberPatch member, PrivacyLevel level)
{
member.NamePrivacy = level;
member.DescriptionPrivacy = level;
member.AvatarPrivacy = level;
member.PronounPrivacy = level;
member.BirthdayPrivacy = level;
member.MetadataPrivacy = level;
member.MemberVisibility = level;
member.NamePrivacy = Partial<PrivacyLevel>.Present(level);
member.DescriptionPrivacy = Partial<PrivacyLevel>.Present(level);
member.AvatarPrivacy = Partial<PrivacyLevel>.Present(level);
member.PronounPrivacy = Partial<PrivacyLevel>.Present(level);
member.BirthdayPrivacy = Partial<PrivacyLevel>.Present(level);
member.MetadataPrivacy = Partial<PrivacyLevel>.Present(level);
member.Visibility = Partial<PrivacyLevel>.Present(level);
}
public static bool TryParseMemberPrivacy(string input, out MemberPrivacySubject subject)

View File

@@ -0,0 +1,51 @@
using System.Text;
using Dapper;
namespace PluralKit.Core
{
public class UpdateQueryBuilder
{
private readonly string _table;
private readonly string _condition;
private readonly DynamicParameters _params = new DynamicParameters();
private bool _hasFields = false;
private readonly StringBuilder _setClause = new StringBuilder();
public UpdateQueryBuilder(string table, string condition)
{
_table = table;
_condition = condition;
}
public UpdateQueryBuilder WithConstant<T>(string name, T value)
{
_params.Add(name, value);
return this;
}
public UpdateQueryBuilder With<T>(string columnName, T value)
{
_params.Add(columnName, value);
if (_hasFields)
_setClause.Append(", ");
else _hasFields = true;
_setClause.Append($"{columnName} = @{columnName}");
return this;
}
public UpdateQueryBuilder With<T>(string columnName, Partial<T> partialValue)
{
return partialValue.IsPresent ? With(columnName, partialValue.Value) : this;
}
public (string Query, DynamicParameters Parameters) Build(string append = "")
{
var query = $"update {_table} set {_setClause} where {_condition} {append}";
return (query, _params);
}
}
}