This commit is contained in:
Brandon Watson 2021-03-05 11:56:51 -05:00
parent 91d0a55d5e
commit b61ffde4c9
11 changed files with 234 additions and 140 deletions

View File

@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using Xunit;
using Aurora;
using Aurora.Services.Signal;
using Aurora.Cursor;
namespace AuroraSignal.test
@ -14,57 +13,30 @@ namespace AuroraSignal.test
[InlineData(SortDirection.Desc)]
public void CursorListSortOnStringValue(SortDirection direction)
{
CursorList<Party> cursor = new CursorList<Party>();
cursor.Add(new Party(){Name = "asdf", PartyId = "1111"});
cursor.Add(new Party(){Name = "bsdf", PartyId = "2222"});
cursor.Add(new Party(){Name = "csdf", PartyId = "3333"});
CursorList<Party> list = new CursorList<Party>();
list.Add(new Party() { Name = "asdf", Id = "1111" });
list.Add(new Party() { Name = "bsdf", Id = "2222" });
list.Add(new Party() { Name = "csdf", Id = "3333" });
List<Party> result = cursor.WithSort("Name", direction).Get();
CursorResult<Party> result = new Cursor<Party>(ref list)
.WithSort(item => item.Value.Name, direction)
.GetNextPage();
if(direction == SortDirection.Desc)
if (direction == SortDirection.Desc)
{
Assert.Collection<Party>(cursor,
item => item.Name.Equals("asdf"),
item => item.Name.Equals("bsdf"),
Assert.Collection<Party>(result.Result,
item => item.Name.Equals("asdf"),
item => item.Name.Equals("bsdf"),
item => item.Name.Equals("csdf"));
}
else
{
Assert.Collection<Party>(cursor,
item => item.Name.Equals("csdf"),
item => item.Name.Equals("bsdf"),
Assert.Collection<Party>(result.Result,
item => item.Name.Equals("csdf"),
item => item.Name.Equals("bsdf"),
item => item.Name.Equals("asdf"));
}
}
[Theory()]
[InlineData(SortDirection.Asc)]
[InlineData(SortDirection.Desc)]
public void CursorListSortOnIntValue(SortDirection direction)
{
CursorList<object> cursor = new CursorList<object>();
cursor.Add(new {Name = "asdf", PartyId = 1111});
cursor.Add(new {Name = "bsdf", PartyId = 2222});
cursor.Add(new {Name = "csdf", PartyId = 3333});
List<object> result = cursor.WithSort("PartyId", direction).Get();
if(direction == SortDirection.Desc)
{
Assert.Collection<object>(cursor,
item => item.Equals(new {Name = "asdf", PartyId = 1111}),
item => item.Equals(new {Name = "bsdf", PartyId = 2222}),
item => item.Equals(new {Name = "csdf", PartyId = 3333}));
}
else
{
Assert.Collection<object>(cursor,
item => item.Equals(new {Name = "csdf", PartyId = 3333}),
item => item.Equals(new {Name = "bsdf", PartyId = 2222}),
item => item.Equals(new {Name = "asdf", PartyId = 1111}));
}
}
}
}

View File

@ -0,0 +1,9 @@
using Aurora.Cursor;
namespace Aurora.Services.Signal
{
public partial class Party : ICursorObject
{
}
}

View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
#nullable enable
namespace Aurora.Cursor
{
public enum SortDirection
{
Asc,
Desc,
}
public class Cursor<T> where T : ICursorObject
{
private CursorList<T> _list;
private string? _previousPageToken;
private string? _nextPageToken;
private int _pageSize;
private Func<KeyValuePair<string, T>, string> _sortDelgate;
private SortDirection _direction;
public Cursor(ref CursorList<T> list)
{
this._list = list;
this._previousPageToken = string.Empty;
this._nextPageToken = string.Empty;
this._pageSize = 10;
this._sortDelgate = delegate (KeyValuePair<string, T> item)
{
return item.Value.Id;
};
}
public CursorResult<T> GetNextPage()
{
List<KeyValuePair<string, T>> tmpList;
// Sort reference list
if (this._direction == SortDirection.Desc)
{
tmpList = this._list.OrderByDescending(this._sortDelgate).ToList();
}
else
{
tmpList = this._list.OrderBy(this._sortDelgate).ToList();
}
if (tmpList == null)
{
throw new System.NullReferenceException();
}
int startIdx = 0;
if (!string.IsNullOrEmpty(this._nextPageToken))
{
// TODO find another way to index into the list that's not a regular array search
startIdx = tmpList.FindIndex(item => item.Key == this._nextPageToken);
}
int endIdx = startIdx + this._pageSize;
List<T> selection = new List<T>();
// Get page
for (int i = startIdx; i < tmpList.Count && i < endIdx; i++)
{
selection.Add(tmpList.ElementAt(i).Value);
}
return new CursorResult<T>
{
NextPageToken = selection[selection.Count - 1].Id,
PrevPageToken = selection[0].Id,
Count = this._list.Count,
Result = selection
};
}
public CursorResult<T> GetPreviousPage()
{
throw new NotImplementedException();
}
public Cursor<T> WithNextPage(string nextPageToken)
{
this._nextPageToken = nextPageToken;
return this;
}
public Cursor<T> WithPreviousPage(string prevPageToken)
{
this._previousPageToken = prevPageToken;
return this;
}
public Cursor<T> WithSort(Func<KeyValuePair<string, T>, string> sortDelegate, SortDirection direction)
{
this._sortDelgate = sortDelegate;
this._direction = direction;
return this;
}
public Cursor<T> WithSize(int size)
{
this._pageSize = size;
return this;
}
}
}

View File

@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Collections;
using System;
using System.Linq;
using Aurora.Utils;
#nullable enable
namespace Aurora.Cursor
{
public class CursorList<T> : SortedList<string, T> where T : ICursorObject
{
public CursorList()
{
}
public CursorList<T> Add(T item)
{
string itemHashId = HashUtil.GetHash(new string[] { item.Id, item.GetHashCode().ToString() }).ToString();
bool res = this.TryAdd(itemHashId, item);
if (res == false)
{
throw new System.Exception("Failed to add item to cursor list");
}
return this;
}
}
}

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Aurora.Cursor
{
public interface ICursorObject
{
string Id { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace Aurora.Cursor
{
public class CursorResult<T>
{
public CursorResult()
{
Result = new List<T>();
}
public CursorResult(CursorResult<T> cpy)
{
NextPageToken = cpy.NextPageToken;
PrevPageToken = cpy.PrevPageToken;
Result = cpy.Result;
Count = cpy.Count;
}
public string NextPageToken { get; set; }
public string PrevPageToken { get; set; }
public List<T> Result { get; set; }
public int Count { get; set; }
}
}

View File

@ -1,94 +0,0 @@
using System.Collections.Generic;
namespace Aurora
{
public enum SortDirection {
Asc,
Desc,
}
public class CursorList<T> : List<T>
{
private string _orderBy;
private SortDirection _direction;
private string _previousPageToken;
private string _nextPageToken;
private int _pageSize;
public CursorList(){
this._direction = SortDirection.Desc;
this._orderBy = string.Empty;
this._previousPageToken = string.Empty;
this._nextPageToken = string.Empty;
this._pageSize = 10;
}
public CursorList<T> WithNextPage(string nextPageToken){
this._nextPageToken = nextPageToken;
return this;
}
public CursorList<T> WithPreviousPage(string prevPageToken){
this._previousPageToken = prevPageToken;
return this;
}
public CursorList<T> WithSort(string orderBy, SortDirection direction ) {
this._orderBy = orderBy;
this._direction = direction;
return this;
}
public CursorList<T> WithSize(int size){
this._pageSize = size;
return this;
}
public List<T> Get(){
if(this._nextPageToken != string.Empty && this._previousPageToken != string.Empty){
throw new System.InvalidOperationException("Cannot specify both next and previous page tokens");
}
List<T> tmpList = new List<T>(this);
tmpList.Sort(delegate(T first, T second){
object firstVal = first.GetType().GetProperty(this._orderBy).GetValue(first, null);
object secondVal = first.GetType().GetProperty(this._orderBy).GetValue(second, null);
int compare = 0;
if(firstVal == null && secondVal == null)
{
compare = 0;
}
else if(firstVal == null)
{
compare = 1;
}
else if(secondVal == null)
{
compare = -1;
}
else
{
// Determine number or string types
if(firstVal is string)
{
string firstStr = firstVal as string;
string secondStr = secondVal as string;
compare = firstStr.CompareTo(secondStr);
} else if(firstVal is int)
{
int? firstInt = firstVal as int?;
int? secondInt = secondVal as int?;
compare = firstInt > secondInt ? 1 : -1;
}
}
return this._direction == SortDirection.Asc ? compare : compare * -1;
});
return tmpList.GetRange(0, this._pageSize > tmpList.Count ? tmpList.Count : this._pageSize);
}
}
}

View File

@ -54,7 +54,7 @@ service Signal {
message Party {
//The resource name of the party
string name = 1;
string party_id = 2;
string id = 2;
string display_name = 3;
string description = 4;
string host_ip = 5;
@ -63,7 +63,7 @@ message Party {
message PartyListItem {
string name = 1;
string party_id = 2;
string id = 2;
}
message ListPartiesRequest {

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Grpc.Core;
using Microsoft.Extensions.Logging;
using Aurora.Cursor;
namespace Aurora.Services.Signal
{

View File

@ -0,0 +1,25 @@
using System.Security.Cryptography;
using System.Text;
using System;
namespace Aurora.Utils
{
public class HashUtil
{
public static Guid GetHash(string[] inputs)
{
string input = "";
foreach (string str in inputs)
{
input += str;
}
byte[] stringbytes = Encoding.UTF8.GetBytes(input);
byte[] hashedBytes = new System.Security.Cryptography
.SHA1CryptoServiceProvider()
.ComputeHash(stringbytes);
Array.Resize(ref hashedBytes, 16);
return new Guid(hashedBytes);
}
}
}

View File

@ -7,6 +7,9 @@
"settings": {
"files.exclude": {
"**/obj": true
}
},
"dotnet-test-explorer.testProjectPath": "./AuroraSignal.test",
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-dotnettools.csharp"
}
}