mirror of
https://github.com/NoiTheCat/BirthdayBot.git
synced 2024-11-21 21:54:36 +00:00
Rewrite GuildUserConfiguration
Corresponding to GuildConfiguration, no longer assumes it is cached.
This commit is contained in:
parent
7ac15e21a1
commit
488685bc79
1 changed files with 85 additions and 103 deletions
|
@ -8,161 +8,143 @@ using System.Threading.Tasks;
|
||||||
namespace BirthdayBot.Data
|
namespace BirthdayBot.Data
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Representation of a user's birthday settings within a guild.
|
/// Represents configuration for a guild user.
|
||||||
/// Instances are held and managed by <see cref="="GuildStateInformation"/>.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class GuildUserSettings
|
class GuildUserConfiguration
|
||||||
{
|
{
|
||||||
private int _month;
|
|
||||||
private int _day;
|
|
||||||
private string _tz;
|
|
||||||
|
|
||||||
public ulong GuildId { get; }
|
public ulong GuildId { get; }
|
||||||
public ulong UserId { get; }
|
public ulong UserId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Month of birth as a numeric value. Range 1-12.
|
/// Month of birth as a numeric value. Range 1-12.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int BirthMonth { get { return _month; } }
|
public int BirthMonth { get; private set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Day of birth as a numeric value. Ranges between 1-31 or lower based on month value.
|
/// Day of birth as a numeric value. Ranges between 1-31 or lower based on month value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int BirthDay { get { return _day; } }
|
public int BirthDay { get; private set; }
|
||||||
|
|
||||||
public string TimeZone { get { return _tz; } }
|
public string TimeZone { get; private set; }
|
||||||
public bool IsKnown { get { return _month != 0 && _day != 0; } }
|
public bool IsKnown { get { return BirthMonth != 0 && BirthDay != 0; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a data-less instance without any useful information.
|
/// Creates a new, data-less instance without a corresponding database entry.
|
||||||
/// Calling <see cref="UpdateAsync(int, int, int)"/> will create a real database enty
|
/// Calling <see cref="UpdateAsync(int, int, int)"/> will create a real database enty
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GuildUserSettings(ulong guildId, ulong userId)
|
private GuildUserConfiguration(ulong guildId, ulong userId)
|
||||||
{
|
{
|
||||||
GuildId = guildId;
|
GuildId = guildId;
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by GetGuildUsersAsync. Double-check ordinals when changes are made.
|
// Called by GetGuildUsersAsync. Double-check ordinals when changes are made.
|
||||||
private GuildUserSettings(DbDataReader reader)
|
private GuildUserConfiguration(DbDataReader reader)
|
||||||
{
|
{
|
||||||
GuildId = (ulong)reader.GetInt64(0);
|
GuildId = (ulong)reader.GetInt64(0);
|
||||||
UserId = (ulong)reader.GetInt64(1);
|
UserId = (ulong)reader.GetInt64(1);
|
||||||
_month = reader.GetInt32(2);
|
BirthMonth = reader.GetInt32(2);
|
||||||
_day = reader.GetInt32(3);
|
BirthDay = reader.GetInt32(3);
|
||||||
if (!reader.IsDBNull(4)) _tz = reader.GetString(4);
|
if (!reader.IsDBNull(4)) TimeZone = reader.GetString(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates user with given information.
|
/// Updates user with given information.
|
||||||
/// NOTE: If there exists a tz value and the update contains none, the old tz value is retained.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task UpdateAsync(int month, int day, string newtz, Database dbconfig)
|
public async Task UpdateAsync(int month, int day, string newtz)
|
||||||
{
|
{
|
||||||
// TODO note from rewrite: huh? why are we doing this here?
|
using (var db = await Database.OpenConnectionAsync())
|
||||||
var inserttz = newtz ?? TimeZone;
|
|
||||||
|
|
||||||
using (var db = await dbconfig.OpenConnectionAsync())
|
|
||||||
{
|
{
|
||||||
// Will do a delete/insert instead of insert...on conflict update. Because lazy.
|
using var c = db.CreateCommand();
|
||||||
using (var t = db.BeginTransaction())
|
c.CommandText = $"insert into {BackingTable} "
|
||||||
{
|
+ "(guild_id, user_id, birth_month, birth_day, time_zone) values "
|
||||||
await DoDeleteAsync(db);
|
+ "(@Gid, @Uid, @Month, @Day, @Tz) "
|
||||||
using (var c = db.CreateCommand())
|
+ "on conflict (guild_id, user_id) do update "
|
||||||
{
|
+ "set birth_month = EXCLUDED.birth_month, birth_day = EXCLUDED.birth_day, time_zone = EXCLUDED.time_zone";
|
||||||
c.CommandText = $"insert into {BackingTable} "
|
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = (long)GuildId;
|
||||||
+ "(guild_id, user_id, birth_month, birth_day, time_zone) values "
|
c.Parameters.Add("@Uid", NpgsqlDbType.Bigint).Value = (long)UserId;
|
||||||
+ "(@Gid, @Uid, @Month, @Day, @Tz)";
|
c.Parameters.Add("@Month", NpgsqlDbType.Numeric).Value = month;
|
||||||
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = (long)GuildId;
|
c.Parameters.Add("@Day", NpgsqlDbType.Numeric).Value = day;
|
||||||
c.Parameters.Add("@Uid", NpgsqlDbType.Bigint).Value = (long)UserId;
|
var tzp = c.Parameters.Add("@Tz", NpgsqlDbType.Text);
|
||||||
c.Parameters.Add("@Month", NpgsqlDbType.Numeric).Value = month;
|
if (newtz != null) tzp.Value = newtz;
|
||||||
c.Parameters.Add("@Day", NpgsqlDbType.Numeric).Value = day;
|
else tzp.Value = DBNull.Value;
|
||||||
var p = c.Parameters.Add("@Tz", NpgsqlDbType.Text);
|
c.Prepare();
|
||||||
if (inserttz != null) p.Value = inserttz;
|
await c.ExecuteNonQueryAsync();
|
||||||
else p.Value = DBNull.Value;
|
|
||||||
c.Prepare();
|
|
||||||
await c.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
await t.CommitAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We didn't crash! Get the new values stored locally.
|
// Database update succeeded; update instance values
|
||||||
_month = month;
|
BirthMonth = month;
|
||||||
_day = day;
|
BirthDay = day;
|
||||||
_tz = inserttz;
|
TimeZone = newtz;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes information of this user from the backing database.
|
/// Deletes information of this user from the backing database.
|
||||||
/// The corresponding object reference should ideally be discarded after calling this.
|
/// The corresponding object reference should ideally be discarded after calling this.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task DeleteAsync(Database dbconfig)
|
public async Task DeleteAsync()
|
||||||
{
|
{
|
||||||
using (var db = await dbconfig.OpenConnectionAsync())
|
using var db = await Database.OpenConnectionAsync();
|
||||||
{
|
using var c = db.CreateCommand();
|
||||||
await DoDeleteAsync(db);
|
c.CommandText = $"delete from {BackingTable} "
|
||||||
}
|
+ "where guild_id = @Gid and user_id = @Uid";
|
||||||
}
|
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = (long)GuildId;
|
||||||
|
c.Parameters.Add("@Uid", NpgsqlDbType.Bigint).Value = (long)UserId;
|
||||||
// Shared between UpdateAsync and DeleteAsync
|
c.Prepare();
|
||||||
private async Task DoDeleteAsync(NpgsqlConnection dbconn)
|
await c.ExecuteNonQueryAsync();
|
||||||
{
|
|
||||||
using (var c = dbconn.CreateCommand())
|
|
||||||
{
|
|
||||||
c.CommandText = $"delete from {BackingTable} "
|
|
||||||
+ "where guild_id = @Gid and user_id = @Uid";
|
|
||||||
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = (long)GuildId;
|
|
||||||
c.Parameters.Add("@Uid", NpgsqlDbType.Bigint).Value = (long)UserId;
|
|
||||||
c.Prepare();
|
|
||||||
await c.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Database
|
#region Database
|
||||||
public const string BackingTable = "user_birthdays";
|
public const string BackingTable = "user_birthdays";
|
||||||
|
// Take note of ordinals for use in the constructor
|
||||||
|
private const string SelectFields = "guild_id, user_id, birth_month, birth_day, time_zone";
|
||||||
|
|
||||||
internal static void SetUpDatabaseTable(NpgsqlConnection db)
|
internal static async Task DatabaseSetupAsync(NpgsqlConnection db)
|
||||||
{
|
{
|
||||||
using (var c = db.CreateCommand())
|
using var c = db.CreateCommand();
|
||||||
{
|
c.CommandText = $"create table if not exists {BackingTable} ("
|
||||||
c.CommandText = $"create table if not exists {BackingTable} ("
|
+ $"guild_id bigint not null references {GuildConfiguration.BackingTable} ON DELETE CASCADE, "
|
||||||
+ $"guild_id bigint not null references {GuildStateInformation.BackingTable} ON DELETE CASCADE, "
|
+ "user_id bigint not null, "
|
||||||
+ "user_id bigint not null, "
|
+ "birth_month integer not null, "
|
||||||
+ "birth_month integer not null, "
|
+ "birth_day integer not null, "
|
||||||
+ "birth_day integer not null, "
|
+ "time_zone text null, "
|
||||||
+ "time_zone text null, "
|
+ "last_seen timestamptz not null default NOW(), "
|
||||||
+ "last_seen timestamptz not null default NOW(), "
|
+ "PRIMARY KEY (guild_id, user_id)" // index automatically created with this
|
||||||
+ "PRIMARY KEY (guild_id, user_id)"
|
+ ")";
|
||||||
+ ")";
|
await c.ExecuteNonQueryAsync();
|
||||||
c.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all known birthday records from the specified guild. No further filtering is done here.
|
/// Attempts to retrieve a user's configuration. Returns a new, updateable instance if none is found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static IEnumerable<GuildUserSettings> GetGuildUsersAsync(Database dbsettings, ulong guildId)
|
public static async Task<GuildUserConfiguration> LoadAsync(ulong guildId, ulong userId)
|
||||||
{
|
{
|
||||||
using (var db = dbsettings.OpenConnectionAsync().GetAwaiter().GetResult())
|
using var db = await Database.OpenConnectionAsync();
|
||||||
{
|
using var c = db.CreateCommand();
|
||||||
using (var c = db.CreateCommand())
|
c.CommandText = $"select {SelectFields} from {BackingTable} where guild_id = @Gid and user_id = @Uid";
|
||||||
{
|
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = (long)guildId;
|
||||||
// Take note of ordinals for use in the constructor
|
c.Parameters.Add("@Uid", NpgsqlDbType.Bigint).Value = (long)userId;
|
||||||
c.CommandText = "select guild_id, user_id, birth_month, birth_day, time_zone "
|
c.Prepare();
|
||||||
+ $"from {BackingTable} where guild_id = @Gid";
|
|
||||||
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = (long)guildId;
|
using var r = c.ExecuteReader();
|
||||||
c.Prepare();
|
if (await r.ReadAsync()) return new GuildUserConfiguration(r);
|
||||||
using (var r = c.ExecuteReader())
|
else return new GuildUserConfiguration(guildId, userId);
|
||||||
{
|
}
|
||||||
var result = new List<GuildUserSettings>();
|
|
||||||
while (r.Read())
|
/// <summary>
|
||||||
{
|
/// Gets all known user configuration records associated with the specified guild.
|
||||||
result.Add(new GuildUserSettings(r));
|
/// </summary>
|
||||||
}
|
public static async Task<IEnumerable<GuildUserConfiguration>> LoadAllAsync(ulong guildId)
|
||||||
return result;
|
{
|
||||||
}
|
using var db = await Database.OpenConnectionAsync();
|
||||||
}
|
using var c = db.CreateCommand();
|
||||||
}
|
c.CommandText = $"select {SelectFields} from {BackingTable} where guild_id = @Gid";
|
||||||
|
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = (long)guildId;
|
||||||
|
c.Prepare();
|
||||||
|
|
||||||
|
using var r = await c.ExecuteReaderAsync();
|
||||||
|
var result = new List<GuildUserConfiguration>();
|
||||||
|
while (await r.ReadAsync()) result.Add(new GuildUserConfiguration(r));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue