implementation followers DAL + Tests
This commit is contained in:
parent
d846756a7f
commit
490c68ccc5
4 changed files with 369 additions and 9 deletions
|
@ -1,9 +1,142 @@
|
||||||
using BirdsiteLive.DAL.Contracts;
|
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
|
namespace BirdsiteLive.DAL.Postgres.DataAccessLayers
|
||||||
{
|
{
|
||||||
public class FollowersPostgresDal : IFollowersDal
|
public class FollowersPostgresDal : PostgresBase, IFollowersDal
|
||||||
|
{
|
||||||
|
#region Ctor
|
||||||
|
public FollowersPostgresDal(PostgresSettings settings) : base(settings)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public async Task CreateFollowerAsync(string acct, string host, int[] followings, Dictionary<int, long> followingSyncStatus)
|
||||||
|
{
|
||||||
|
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,followings,followingsSyncStatus) VALUES(@acct,@host,@followings, CAST(@followingsSyncStatus as json))",
|
||||||
|
new { acct, host, followings, followingsSyncStatus = serializedDic });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Follower> 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<SerializedFollower>(query, new { acct, host })).FirstOrDefault();
|
||||||
|
return Convert(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Follower[]> 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<SerializedFollower>(query, new { id = followedUserId});
|
||||||
|
return result.Select(Convert).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateFollowerAsync(int id, int[] followings, Dictionary<int, long> followingsSyncStatus)
|
||||||
|
{
|
||||||
|
if (id == default) throw new ArgumentException("id");
|
||||||
|
|
||||||
|
var serializedDic = JsonConvert.SerializeObject(followingsSyncStatus);
|
||||||
|
var query = $"UPDATE {_settings.FollowersTableName} SET followings = @followings, followingsSyncStatus = CAST(@followingsSyncStatus as json) WHERE id = @id";
|
||||||
|
|
||||||
|
using (var dbConnection = Connection)
|
||||||
|
{
|
||||||
|
dbConnection.Open();
|
||||||
|
|
||||||
|
await dbConnection.QueryAsync(query, new { id, followings, followingsSyncStatus = serializedDic });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (acct == default) throw new ArgumentException("acct");
|
||||||
|
if (host == default) 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,
|
||||||
|
Followings = follower.Followings,
|
||||||
|
FollowingsSyncStatus = JsonConvert.DeserializeObject<Dictionary<int,long>>(follower.FollowingsSyncStatus)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,16 @@
|
||||||
namespace BirdsiteLive.DAL.Contracts
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BirdsiteLive.DAL.Models;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.DAL.Contracts
|
||||||
{
|
{
|
||||||
public interface IFollowersDal
|
public interface IFollowersDal
|
||||||
{
|
{
|
||||||
|
Task<Follower> GetFollowerAsync(string acct, string host);
|
||||||
|
Task CreateFollowerAsync(string acct, string host, int[] followings, Dictionary<int, long> followingSyncStatus);
|
||||||
|
Task<Follower[]> GetFollowersAsync(int followedUserId);
|
||||||
|
Task UpdateFollowerAsync(int id, int[] followings, Dictionary<int, long> followingSyncStatus);
|
||||||
|
Task DeleteFollowerAsync(int id);
|
||||||
|
Task DeleteFollowerAsync(string acct, string host);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,13 +1,15 @@
|
||||||
namespace BirdsiteLive.DAL.Models
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.DAL.Models
|
||||||
{
|
{
|
||||||
public class Follower
|
public class Follower
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int FollowingAccountId { get; set; }
|
|
||||||
|
public int[] Followings { get; set; }
|
||||||
|
public Dictionary<int, long> FollowingsSyncStatus { get; set; }
|
||||||
|
|
||||||
public string Acct { get; set; }
|
public string Acct { get; set; }
|
||||||
public string Host { get; set; }
|
public string Host { get; set; }
|
||||||
|
|
||||||
public long LastTweetSynchronizedId { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,216 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BirdsiteLive.DAL.Postgres.DataAccessLayers;
|
||||||
|
using BirdsiteLive.DAL.Postgres.Tests.DataAccessLayers.Base;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.DAL.Postgres.Tests.DataAccessLayers
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class FollowersPostgresDalTests : PostgresTestingBase
|
||||||
|
{
|
||||||
|
[TestInitialize]
|
||||||
|
public async Task TestInit()
|
||||||
|
{
|
||||||
|
var dal = new DbInitializerPostgresDal(_settings, _tools);
|
||||||
|
await dal.InitDbAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCleanup]
|
||||||
|
public async Task CleanUp()
|
||||||
|
{
|
||||||
|
var dal = new DbInitializerPostgresDal(_settings, _tools);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await dal.DeleteAllAsync();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task CreateAndGetFollower()
|
||||||
|
{
|
||||||
|
var acct = "myhandle";
|
||||||
|
var host = "domain.ext";
|
||||||
|
var following = new[] {12, 19, 23};
|
||||||
|
var followingSync = new Dictionary<int, long>()
|
||||||
|
{
|
||||||
|
{12, 165L},
|
||||||
|
{19, 166L},
|
||||||
|
{23, 167L}
|
||||||
|
};
|
||||||
|
|
||||||
|
var dal = new FollowersPostgresDal(_settings);
|
||||||
|
await dal.CreateFollowerAsync(acct, host, following, followingSync);
|
||||||
|
|
||||||
|
var result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
|
||||||
|
Assert.IsNotNull(result);
|
||||||
|
Assert.AreEqual(acct, result.Acct);
|
||||||
|
Assert.AreEqual(host, result.Host);
|
||||||
|
Assert.AreEqual(following.Length, result.Followings.Length);
|
||||||
|
Assert.AreEqual(following[0], result.Followings[0]);
|
||||||
|
Assert.AreEqual(followingSync.Count, result.FollowingsSyncStatus.Count);
|
||||||
|
Assert.AreEqual(followingSync.First().Key, result.FollowingsSyncStatus.First().Key);
|
||||||
|
Assert.AreEqual(followingSync.First().Value, result.FollowingsSyncStatus.First().Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task GetFollowersAsync()
|
||||||
|
{
|
||||||
|
var dal = new FollowersPostgresDal(_settings);
|
||||||
|
|
||||||
|
//User 1
|
||||||
|
var acct = "myhandle1";
|
||||||
|
var host = "domain.ext";
|
||||||
|
var following = new[] { 1,2,3 };
|
||||||
|
var followingSync = new Dictionary<int, long>();
|
||||||
|
await dal.CreateFollowerAsync(acct, host, following, followingSync);
|
||||||
|
|
||||||
|
//User 2
|
||||||
|
acct = "myhandle2";
|
||||||
|
host = "domain.ext";
|
||||||
|
following = new[] { 2, 4, 5 };
|
||||||
|
await dal.CreateFollowerAsync(acct, host, following, followingSync);
|
||||||
|
|
||||||
|
//User 2
|
||||||
|
acct = "myhandle3";
|
||||||
|
host = "domain.ext";
|
||||||
|
following = new[] { 1 };
|
||||||
|
await dal.CreateFollowerAsync(acct, host, following, followingSync);
|
||||||
|
|
||||||
|
var result = await dal.GetFollowersAsync(2);
|
||||||
|
Assert.AreEqual(2, result.Length);
|
||||||
|
|
||||||
|
result = await dal.GetFollowersAsync(5);
|
||||||
|
Assert.AreEqual(1, result.Length);
|
||||||
|
|
||||||
|
result = await dal.GetFollowersAsync(24);
|
||||||
|
Assert.AreEqual(0, result.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task CreateUpdateAndGetFollower_Add()
|
||||||
|
{
|
||||||
|
var acct = "myhandle";
|
||||||
|
var host = "domain.ext";
|
||||||
|
var following = new[] { 12, 19, 23 };
|
||||||
|
var followingSync = new Dictionary<int, long>()
|
||||||
|
{
|
||||||
|
{12, 165L},
|
||||||
|
{19, 166L},
|
||||||
|
{23, 167L}
|
||||||
|
};
|
||||||
|
|
||||||
|
var dal = new FollowersPostgresDal(_settings);
|
||||||
|
await dal.CreateFollowerAsync(acct, host, following, followingSync);
|
||||||
|
var result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
|
||||||
|
var updatedFollowing = new[] { 12, 19, 23, 24 };
|
||||||
|
var updatedFollowingSync = new Dictionary<int, long>()
|
||||||
|
{
|
||||||
|
{12, 170L},
|
||||||
|
{19, 171L},
|
||||||
|
{23, 172L},
|
||||||
|
{24, 173L}
|
||||||
|
};
|
||||||
|
|
||||||
|
await dal.UpdateFollowerAsync(result.Id, updatedFollowing, updatedFollowingSync);
|
||||||
|
result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
|
||||||
|
Assert.AreEqual(updatedFollowing.Length, result.Followings.Length);
|
||||||
|
Assert.AreEqual(updatedFollowing[0], result.Followings[0]);
|
||||||
|
Assert.AreEqual(updatedFollowingSync.Count, result.FollowingsSyncStatus.Count);
|
||||||
|
Assert.AreEqual(updatedFollowingSync.First().Key, result.FollowingsSyncStatus.First().Key);
|
||||||
|
Assert.AreEqual(updatedFollowingSync.First().Value, result.FollowingsSyncStatus.First().Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task CreateUpdateAndGetFollower_Remove()
|
||||||
|
{
|
||||||
|
var acct = "myhandle";
|
||||||
|
var host = "domain.ext";
|
||||||
|
var following = new[] { 12, 19, 23 };
|
||||||
|
var followingSync = new Dictionary<int, long>()
|
||||||
|
{
|
||||||
|
{12, 165L},
|
||||||
|
{19, 166L},
|
||||||
|
{23, 167L}
|
||||||
|
};
|
||||||
|
|
||||||
|
var dal = new FollowersPostgresDal(_settings);
|
||||||
|
await dal.CreateFollowerAsync(acct, host, following, followingSync);
|
||||||
|
var result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
|
||||||
|
var updatedFollowing = new[] { 12, 19 };
|
||||||
|
var updatedFollowingSync = new Dictionary<int, long>()
|
||||||
|
{
|
||||||
|
{12, 170L},
|
||||||
|
{19, 171L}
|
||||||
|
};
|
||||||
|
|
||||||
|
await dal.UpdateFollowerAsync(result.Id, updatedFollowing, updatedFollowingSync);
|
||||||
|
result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
|
||||||
|
Assert.AreEqual(updatedFollowing.Length, result.Followings.Length);
|
||||||
|
Assert.AreEqual(updatedFollowing[0], result.Followings[0]);
|
||||||
|
Assert.AreEqual(updatedFollowingSync.Count, result.FollowingsSyncStatus.Count);
|
||||||
|
Assert.AreEqual(updatedFollowingSync.First().Key, result.FollowingsSyncStatus.First().Key);
|
||||||
|
Assert.AreEqual(updatedFollowingSync.First().Value, result.FollowingsSyncStatus.First().Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task CreateAndDeleteFollower_ById()
|
||||||
|
{
|
||||||
|
var acct = "myhandle";
|
||||||
|
var host = "domain.ext";
|
||||||
|
var following = new[] { 12, 19, 23 };
|
||||||
|
var followingSync = new Dictionary<int, long>()
|
||||||
|
{
|
||||||
|
{12, 165L},
|
||||||
|
{19, 166L},
|
||||||
|
{23, 167L}
|
||||||
|
};
|
||||||
|
|
||||||
|
var dal = new FollowersPostgresDal(_settings);
|
||||||
|
await dal.CreateFollowerAsync(acct, host, following, followingSync);
|
||||||
|
var result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
Assert.IsNotNull(result);
|
||||||
|
|
||||||
|
await dal.DeleteFollowerAsync(result.Id);
|
||||||
|
|
||||||
|
result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
Assert.IsNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task CreateAndDeleteFollower_ByHandle()
|
||||||
|
{
|
||||||
|
var acct = "myhandle";
|
||||||
|
var host = "domain.ext";
|
||||||
|
var following = new[] { 12, 19, 23 };
|
||||||
|
var followingSync = new Dictionary<int, long>()
|
||||||
|
{
|
||||||
|
{12, 165L},
|
||||||
|
{19, 166L},
|
||||||
|
{23, 167L}
|
||||||
|
};
|
||||||
|
|
||||||
|
var dal = new FollowersPostgresDal(_settings);
|
||||||
|
await dal.CreateFollowerAsync(acct, host, following, followingSync);
|
||||||
|
var result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
Assert.IsNotNull(result);
|
||||||
|
|
||||||
|
await dal.DeleteFollowerAsync(acct, host);
|
||||||
|
|
||||||
|
result = await dal.GetFollowerAsync(acct, host);
|
||||||
|
Assert.IsNull(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue