using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using BirdsiteLive.DAL.Contracts; using BirdsiteLive.DAL.Models; using BirdsiteLive.DAL.Postgres.DataAccessLayers.Base; using BirdsiteLive.DAL.Postgres.Settings; using Dapper; using Newtonsoft.Json; namespace BirdsiteLive.DAL.Postgres.DataAccessLayers { public class FollowersPostgresDal : PostgresBase, IFollowersDal { #region Ctor public FollowersPostgresDal(PostgresSettings settings) : base(settings) { } #endregion public async Task CreateFollowerAsync(string acct, string host, string inboxRoute, string sharedInboxRoute, string actorId, int[] followings = null, Dictionary followingSyncStatus = null) { if(followings == null) followings = new int[0]; if(followingSyncStatus == null) followingSyncStatus = new Dictionary(); var serializedDic = JsonConvert.SerializeObject(followingSyncStatus); acct = acct.ToLowerInvariant(); host = host.ToLowerInvariant(); using (var dbConnection = Connection) { dbConnection.Open(); await dbConnection.ExecuteAsync( $"INSERT INTO {_settings.FollowersTableName} (acct,host,inboxRoute,sharedInboxRoute,followings,followingsSyncStatus,actorId) VALUES(@acct,@host,@inboxRoute,@sharedInboxRoute,@followings,CAST(@followingsSyncStatus as json),@actorId)", new { acct, host, inboxRoute, sharedInboxRoute, followings, followingsSyncStatus = serializedDic, actorId }); } } public async Task GetFollowersCountAsync() { var query = $"SELECT COUNT(*) FROM {_settings.FollowersTableName}"; using (var dbConnection = Connection) { dbConnection.Open(); var result = (await dbConnection.QueryAsync(query)).FirstOrDefault(); return result; } } public async Task GetFailingFollowersCountAsync() { var query = $"SELECT COUNT(*) FROM {_settings.FollowersTableName} WHERE postingErrorCount > 0"; using (var dbConnection = Connection) { dbConnection.Open(); var result = (await dbConnection.QueryAsync(query)).FirstOrDefault(); return result; } } public async Task GetFollowerAsync(string acct, string host) { var query = $"SELECT * FROM {_settings.FollowersTableName} WHERE acct = @acct AND host = @host"; acct = acct.ToLowerInvariant(); host = host.ToLowerInvariant(); using (var dbConnection = Connection) { dbConnection.Open(); var result = (await dbConnection.QueryAsync(query, new { acct, host })).FirstOrDefault(); return Convert(result); } } public async Task GetFollowersAsync(int followedUserId) { if (followedUserId == default) throw new ArgumentException("followedUserId"); var query = $"SELECT * FROM {_settings.FollowersTableName} WHERE @id=ANY(followings)"; using (var dbConnection = Connection) { dbConnection.Open(); var result = await dbConnection.QueryAsync(query, new { id = followedUserId}); return result.Select(Convert).ToArray(); } } public async Task GetAllFollowersAsync() { var query = $"SELECT * FROM {_settings.FollowersTableName}"; using (var dbConnection = Connection) { dbConnection.Open(); var result = await dbConnection.QueryAsync(query); return result.Select(Convert).ToArray(); } } public async Task UpdateFollowerAsync(Follower follower) { if (follower == default) throw new ArgumentException("follower"); if (follower.Id == default) throw new ArgumentException("id"); var serializedDic = JsonConvert.SerializeObject(follower.FollowingsSyncStatus); var query = $"UPDATE {_settings.FollowersTableName} SET followings = @followings, followingsSyncStatus = CAST(@followingsSyncStatus as json), postingErrorCount = @postingErrorCount WHERE id = @id"; using (var dbConnection = Connection) { dbConnection.Open(); await dbConnection.QueryAsync(query, new { follower.Id, follower.Followings, followingsSyncStatus = serializedDic, postingErrorCount = follower.PostingErrorCount }); } } public async Task DeleteFollowerAsync(int id) { if (id == default) throw new ArgumentException("id"); var query = $"DELETE FROM {_settings.FollowersTableName} WHERE id = @id"; using (var dbConnection = Connection) { dbConnection.Open(); await dbConnection.QueryAsync(query, new { id }); } } public async Task DeleteFollowerAsync(string acct, string host) { if (string.IsNullOrWhiteSpace(acct)) throw new ArgumentException("acct"); if (string.IsNullOrWhiteSpace(host)) throw new ArgumentException("host"); acct = acct.ToLowerInvariant(); host = host.ToLowerInvariant(); var query = $"DELETE FROM {_settings.FollowersTableName} WHERE acct = @acct AND host = @host"; using (var dbConnection = Connection) { dbConnection.Open(); await dbConnection.QueryAsync(query, new { acct, host }); } } private Follower Convert(SerializedFollower follower) { if (follower == null) return null; return new Follower() { Id = follower.Id, Acct = follower.Acct, Host = follower.Host, InboxRoute = follower.InboxRoute, ActorId = follower.ActorId, SharedInboxRoute = follower.SharedInboxRoute, Followings = follower.Followings.ToList(), FollowingsSyncStatus = JsonConvert.DeserializeObject>(follower.FollowingsSyncStatus), PostingErrorCount = follower.PostingErrorCount }; } } internal class SerializedFollower { public int Id { get; set; } public int[] Followings { get; set; } public string FollowingsSyncStatus { get; set; } public string Acct { get; set; } public string Host { get; set; } public string InboxRoute { get; set; } public string SharedInboxRoute { get; set; } public string ActorId { get; set; } public int PostingErrorCount { get; set; } } }