fix: dapper doesn't play nice with List<T>

This commit is contained in:
sam 2024-10-27 23:43:07 +01:00
parent 64b4c26d93
commit da4dfae27c
Signed by: sam
GPG key ID: 5F3C3C1B3166639D
4 changed files with 31 additions and 6 deletions

View file

@ -50,7 +50,7 @@ public class KeyRoleCommands(
var guildRoles = roleCache.GuildRoles(guildId).ToList(); var guildRoles = roleCache.GuildRoles(guildId).ToList();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await db.GetGuildAsync(guildId);
if (guildConfig.KeyRoles.Count == 0) if (guildConfig.KeyRoles.Length == 0)
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
"There are no key roles to list. Add some with `/key-roles add`.", "There are no key roles to list. Add some with `/key-roles add`.",
isEphemeral: true isEphemeral: true
@ -92,7 +92,7 @@ public class KeyRoleCommands(
isEphemeral: true isEphemeral: true
); );
guildConfig.KeyRoles.Add(role.ID.Value); guildConfig.KeyRoles = guildConfig.KeyRoles.Append(role.ID.Value).ToArray();
db.Update(guildConfig); db.Update(guildConfig);
await db.SaveChangesAsync(); await db.SaveChangesAsync();
@ -117,7 +117,7 @@ public class KeyRoleCommands(
isEphemeral: true isEphemeral: true
); );
guildConfig.KeyRoles.Remove(role.ID.Value); guildConfig.KeyRoles = guildConfig.KeyRoles.Except([role.ID.Value]).ToArray();
db.Update(guildConfig); db.Update(guildConfig);
await db.SaveChangesAsync(); await db.SaveChangesAsync();

View file

@ -14,6 +14,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
using System.Data; using System.Data;
using System.Text.Json;
using System.Text.Json.Serialization;
using Catalogger.Backend.Database.Models;
using Dapper; using Dapper;
using NodaTime; using NodaTime;
using Npgsql; using Npgsql;
@ -113,6 +116,7 @@ public class DatabasePool
SqlMapper.AddTypeHandler(new UlongArrayHandler()); SqlMapper.AddTypeHandler(new UlongArrayHandler());
SqlMapper.AddTypeHandler(new PassthroughTypeHandler<Instant>()); SqlMapper.AddTypeHandler(new PassthroughTypeHandler<Instant>());
SqlMapper.AddTypeHandler(new JsonTypeHandler<Guild.ChannelConfig>());
} }
// Copied from PluralKit: // Copied from PluralKit:
@ -144,6 +148,21 @@ public class DatabasePool
public override ulong[] Parse(object value) => public override ulong[] Parse(object value) =>
Array.ConvertAll((long[])value, i => (ulong)i); Array.ConvertAll((long[])value, i => (ulong)i);
} }
public class JsonTypeHandler<T> : SqlMapper.TypeHandler<T>
{
public override T Parse(object value)
{
string json = (string)value;
return JsonSerializer.Deserialize<T>(json)
?? throw new CataloggerError("JsonTypeHandler<T> returned null");
}
public override void SetValue(IDbDataParameter parameter, T? value)
{
parameter.Value = JsonSerializer.Serialize(value);
}
}
} }
public static class ServiceCollectionDatabaseExtensions public static class ServiceCollectionDatabaseExtensions

View file

@ -74,12 +74,18 @@ public class DatabaseContext : DbContext
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())) c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode()))
); );
private static readonly ValueComparer<ulong[]> UlongArrayValueComparer =
new(
(c1, c2) => c1 != null && c2 != null && c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode()))
);
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
modelBuilder modelBuilder
.Entity<Guild>() .Entity<Guild>()
.Property(g => g.KeyRoles) .Property(g => g.KeyRoles)
.Metadata.SetValueComparer(UlongListValueComparer); .Metadata.SetValueComparer(UlongArrayValueComparer);
modelBuilder.Entity<Invite>().HasKey(i => i.Code); modelBuilder.Entity<Invite>().HasKey(i => i.Code);
modelBuilder.Entity<Invite>().HasIndex(i => i.GuildId); modelBuilder.Entity<Invite>().HasIndex(i => i.GuildId);

View file

@ -27,8 +27,8 @@ public class Guild
[Column(TypeName = "jsonb")] [Column(TypeName = "jsonb")]
public ChannelConfig Channels { get; init; } = new(); public ChannelConfig Channels { get; init; } = new();
public List<string> BannedSystems { get; init; } = []; public string[] BannedSystems { get; set; } = [];
public List<ulong> KeyRoles { get; init; } = []; public ulong[] KeyRoles { get; set; } = [];
public bool IsSystemBanned(PluralkitApiService.PkSystem system) => public bool IsSystemBanned(PluralkitApiService.PkSystem system) =>
BannedSystems.Contains(system.Id) || BannedSystems.Contains(system.Uuid.ToString()); BannedSystems.Contains(system.Id) || BannedSystems.Contains(system.Uuid.ToString());