Skip to content

Commit

Permalink
use common base class for paginated results
Browse files Browse the repository at this point in the history
  • Loading branch information
Koenari committed Dec 23, 2024
1 parent d13e913 commit db791ac
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 801 deletions.
2 changes: 1 addition & 1 deletion NetStone/Definitions/DefinitionsContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public abstract class DefinitionsContainer : IDisposable
/// <summary>
/// Definitions for link shell members
/// </summary>
public LinkshellMemberDefinition LinkshellMember { get; protected set; }
public PagedDefinition<LinkshellMemberEntryDefinition> LinkshellMember { get; protected set; }

/// <summary>
/// Definitions for link-shell searches
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@

namespace NetStone.Definitions.Model.Linkshell;

/// <summary>
/// Definition for the list of linkshell members
/// </summary>
public class LinkshellMemberDefinition : PagedDefinition<LinkshellMemberEntryDefinition>
{

}

/// <summary>
/// Definition for one entry of the linkshell memebr list
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion NetStone/Definitions/Model/PagedDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class PagedDefinition<TEntry> : IDefinition where TEntry : PagedEntryDefi
/// DEfinition for node for empty results
/// </summary>
[JsonProperty("NO_RESULTS_FOUND")]
public DefinitionsPack NoResultsFound { get; set; }
public DefinitionsPack? NoResultsFound { get; set; }
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion NetStone/Definitions/XivApiDefinitionsContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public override async Task Reload()
this.CrossworldLinkshellSearch = await GetDefinition<PagedDefinition<CrossworldLinkshellSearchEntryDefinition>>("search/cwls.json");

this.Linkshell = await GetDefinition<LinkshellDefinition>("linkshell/ls.json");
this.LinkshellMember = await GetDefinition<LinkshellMemberDefinition>("linkshell/members.json");
this.LinkshellMember = await GetDefinition<PagedDefinition<LinkshellMemberEntryDefinition>>("linkshell/members.json");
this.LinkshellSearch = await GetDefinition<PagedDefinition<LinkshellSearchEntryDefinition>>("search/linkshell.json");
}

Expand Down
146 changes: 145 additions & 1 deletion NetStone/Model/IPaginatedResult.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using HtmlAgilityPack;
using NetStone.Definitions.Model;
using NetStone.Search;

namespace NetStone.Model;

Expand All @@ -23,4 +28,143 @@ public interface IPaginatedResult<T> where T : LodestoneParseable
/// </summary>
/// <returns>Task of retrieving next page</returns>
Task<T?> GetNextPage();
}

/// <summary>
/// Container class holding paginated information
/// </summary>
public abstract class PaginatedIdResult<TPage, TEntry, TEntryDef>
: PaginatedResult<TPage, TEntry, TEntryDef,string> where TPage : LodestoneParseable
where TEntry : LodestoneParseable
where TEntryDef : PagedEntryDefinition
{
///<inheritdoc />
protected PaginatedIdResult(HtmlNode rootNode, PagedDefinition<TEntryDef> pageDefinition,
Func<string, int, Task<TPage?>> nextPageFunc, string id)
: base(rootNode, pageDefinition, nextPageFunc, id)
{
}
}
/// <summary>
/// Container class holding paginated information
/// </summary>
public abstract class PaginatedSearchResult<TPage, TEntry, TEntryDef, TQuery>
: PaginatedResult<TPage, TEntry, TEntryDef,TQuery> where TPage : LodestoneParseable
where TEntry : LodestoneParseable
where TEntryDef : PagedEntryDefinition
where TQuery : ISearchQuery
{
///<inheritdoc />
protected PaginatedSearchResult(HtmlNode rootNode, PagedDefinition<TEntryDef> pageDefinition,
Func<TQuery, int, Task<TPage?>> nextPageFunc,
TQuery query)
: base(rootNode, pageDefinition, nextPageFunc, query)
{
}
}


/// <summary>
/// Container class holding paginated information
/// </summary>
public abstract class PaginatedResult<TPage, TEntry, TEntryDef,TRequest> : LodestoneParseable, IPaginatedResult<TPage> where TPage : LodestoneParseable where TEntry : LodestoneParseable where TEntryDef : PagedEntryDefinition
{
/// <summary>
/// Definition for the paginated type
/// </summary>
protected readonly PagedDefinition<TEntryDef> PageDefinition;

private readonly TRequest request;

private readonly Func<TRequest, int, Task<TPage?>> nextPageFunc;

/// <summary>
///
/// </summary>
/// <param name="rootNode">The root document node of the page</param>
/// <param name="pageDefinition">CSS definitions for the paginated type</param>
/// <param name="nextPageFunc">Function to retrieve a page of this type</param>
/// <param name="request">The input used to request further pages.</param>
protected PaginatedResult(HtmlNode rootNode, PagedDefinition<TEntryDef> pageDefinition,Func<TRequest, int, Task<TPage?>> nextPageFunc, TRequest request) : base(rootNode)
{
this.PageDefinition = pageDefinition;
this.request = request;
this.nextPageFunc = nextPageFunc;
}

/// <summary>
/// If there is any data
/// </summary>
public bool HasResults => this.PageDefinition.NoResultsFound is null || !HasNode(this.PageDefinition.NoResultsFound);

private TEntry[]? parsedResults;

/// <summary>
/// List of members
/// </summary>
protected IEnumerable<TEntry> Results
{
get
{
if (!this.HasResults) return Array.Empty<TEntry>();
this.parsedResults ??= ParseResults();
return this.parsedResults;
}
}

/// <summary>
/// Creates the array of all entries on this page>
/// </summary>
protected abstract TEntry[] ParseResults();

private int? currentPageVal;

///<inheritdoc />
public int CurrentPage
{
get
{
if (!this.HasResults)
return 0;
if (!this.currentPageVal.HasValue)
ParsePagesCount();

return this.currentPageVal!.Value;
}
}

private int? numPagesVal;

/// <inheritdoc/>
public int NumPages
{
get
{
if (!this.HasResults)
return 0;
if (!this.numPagesVal.HasValue)
ParsePagesCount();

return this.numPagesVal!.Value;
}
}
private void ParsePagesCount()
{
var results = ParseRegex(this.PageDefinition.PageInfo);

this.currentPageVal = int.Parse(results["CurrentPage"].Value);
this.numPagesVal = int.Parse(results["NumPages"].Value);
}

/// <inheritdoc />
public async Task<TPage?> GetNextPage()
{
if (!this.HasResults)
return null;

if (this.CurrentPage == this.NumPages)
return null;

return await this.nextPageFunc(this.request, this.CurrentPage + 1);
}
}
98 changes: 18 additions & 80 deletions NetStone/Model/Parseables/CWLS/LodestoneCrossworldLinkshell.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using HtmlAgilityPack;
using NetStone.Definitions;
using NetStone.Definitions.Model;
using NetStone.Definitions.Model.CWLS;
using NetStone.Model.Parseables.CWLS.Members;

Expand All @@ -11,14 +9,10 @@ namespace NetStone.Model.Parseables.CWLS;
/// <summary>
/// Container class holding information about a cross world linkshell and it's members.
/// </summary>
public class LodestoneCrossworldLinkshell : LodestoneParseable, IPaginatedResult<LodestoneCrossworldLinkshell>
public class LodestoneCrossworldLinkshell : PaginatedIdResult<LodestoneCrossworldLinkshell,CrossworldLinkshellMemberEntry, CrossworldLinkshellMemberEntryDefinition>
{
private readonly LodestoneClient client;

private readonly string cwlsId;

private readonly CrossworldLinkshellDefinition cwlsDefinition;
private readonly PagedDefinition<CrossworldLinkshellMemberEntryDefinition> pageDefinition;
private readonly CrossworldLinkshellDefinition definition;

/// <summary>
/// Container class for a parseable corss world linkshell page.
Expand All @@ -27,93 +21,37 @@ public class LodestoneCrossworldLinkshell : LodestoneParseable, IPaginatedResult
/// <param name="rootNode">The root document node of the page.</param>
/// <param name="container">The <see cref="DefinitionsContainer"/> holding definitions to be used to access data.</param>
/// <param name="id">The ID of the cross world linkshell.</param>
public LodestoneCrossworldLinkshell(LodestoneClient client, HtmlNode rootNode, DefinitionsContainer container, string id) : base(rootNode)
public LodestoneCrossworldLinkshell(LodestoneClient client, HtmlNode rootNode, DefinitionsContainer container, string id)
: base(rootNode,container.CrossworldLinkshellMember,client.GetCrossworldLinkshell,id)
{
this.client = client;
this.cwlsId = id;
this.cwlsDefinition = container.CrossworldLinkshell;
this.pageDefinition = container.CrossworldLinkshellMember;
this.definition = container.CrossworldLinkshell;
}

/// <summary>
/// Name
/// </summary>
public string Name => ParseDirectInnerText(this.cwlsDefinition.Name).Trim();

public string Name => ParseDirectInnerText(this.definition.Name).Trim();
/// <summary>
/// Datacenter
/// </summary>
public string DataCenter => Parse(this.cwlsDefinition.DataCenter);


private CrossworldLinkshellMemberEntry[]? parsedResults;

public string DataCenter => Parse(this.definition.DataCenter);

/// <summary>
/// Unlocked achievements for character
/// Members
/// </summary>
public IEnumerable<CrossworldLinkshellMemberEntry> Members
{
get
{
if (this.parsedResults == null)
ParseSearchResults();

return this.parsedResults!;
}
}

private void ParseSearchResults()
{
var nodes = QueryContainer(this.pageDefinition);

this.parsedResults = new CrossworldLinkshellMemberEntry[nodes.Length];
for (var i = 0; i < this.parsedResults.Length; i++)
{
this.parsedResults[i] = new CrossworldLinkshellMemberEntry(nodes[i], this.pageDefinition.Entry);
}
}

private int? currentPageVal;

public IEnumerable<CrossworldLinkshellMemberEntry> Members => this.Results;

///<inheritdoc />
public int CurrentPage
protected override CrossworldLinkshellMemberEntry[] ParseResults()
{
get
{
if (!this.currentPageVal.HasValue)
ParsePagesCount();
var nodes = QueryContainer(this.PageDefinition);

return this.currentPageVal!.Value;
}
}

private int? numPagesVal;

/// <inheritdoc/>
public int NumPages
{
get
var parsedResults = new CrossworldLinkshellMemberEntry[nodes.Length];
for (var i = 0; i < parsedResults.Length; i++)
{
if (!this.numPagesVal.HasValue)
ParsePagesCount();

return this.numPagesVal!.Value;
parsedResults[i] = new CrossworldLinkshellMemberEntry(nodes[i], this.PageDefinition.Entry);
}
}
private void ParsePagesCount()
{
var results = ParseRegex(this.pageDefinition.PageInfo);

this.currentPageVal = int.Parse(results["CurrentPage"].Value);
this.numPagesVal = int.Parse(results["NumPages"].Value);
}

/// <inheritdoc />
public async Task<LodestoneCrossworldLinkshell?> GetNextPage()
{
if (this.CurrentPage == this.NumPages)
return null;

return await this.client.GetCrossworldLinkshell(this.cwlsId, this.CurrentPage + 1);
return parsedResults;
}
}
Loading

0 comments on commit db791ac

Please sign in to comment.