3
\$\begingroup\$

I've not played with SupportsPaging before, so wanted to knock up some demo code & get feedback on whether my implementation is OK, or if I've misunderstood something. I created the function 'Invoke-DummyRestMethod' to simulate calling Invoke-RestMethod with a URI for a web service which supported paging; only this Dummy version just spits out numbers, to keep things uncomplicated.

Function Invoke-DummyRestMethod {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)]
        [string]$Uri #= 'http://demo.com?start=20&limit=10' #example
    )
    begin {
        [string]$regex = '(?:[\?&]limit=(?<limit>\d+)|[\?&]start=(?<start>\d+))+'
        [long]$maxResults = 1000 #i.e. function will return 0 to 999 if no paging
    }
    Process {
        [long]$start = 0 #nb: these must be declared as int; otherwise (as the results later come from a regex match) they'll be treated as strings / will cause issues with the Math.Min function!
        [long]$limit = 0 #should 0 be a valid value / we use -1 for non valid?  Assuming 0 is invalid
        if ($Uri -match $regex) {
            if($matches.start){$start = $matches.start}
            if($matches.limit){$limit = $matches.limit}
        }
        write-verbose "Start: $start"
        write-verbose "Limit: $limit"
        if ($limit -le 0){$limit = $maxResults}
        $start..([Math]::Min(($start+$limit),$maxResults) - 1)
    }
}

Function Get-PagedData {
    [CmdletBinding(SupportsPaging = $True)]
    Param (
        [parameter(Mandatory = $true)]
        [uri]$Uri
    )
    Begin {
        Add-Type -AssemblyName 'System' #NameValueCollection (ok, we don't need to add this type; but I like to be explicit)
        Add-Type -AssemblyName 'System.Web'  #HttpUtility
        [long]$PagingSkip = [Math]::Max($PSCmdlet.PagingParameters.Skip,0)
        [long]$PagingFirst = [Math]::Max($PSCmdlet.PagingParameters.First, 0)
    }
    Process {
        [System.UriBuilder]$UriBuilder = New-Object -TypeName 'System.UriBuilder' -ArgumentList $Uri
        [System.Collections.Specialized.NameValueCollection]$Query = [System.Web.HttpUtility]::ParseQueryString($UriBuilder.Query)
        if ($PagingSkip -gt 0) {$Query['start'] = $PagingSkip}
        if ($PagingFirst -gt 0) {$Query['limit'] = $PagingFirst}
        $UriBuilder.Query = $Query.ToString()
        Invoke-DummyRestMethod -Uri $UriBuilder.ToString() | Tee-Object -Variable 'Results'
    }
    End{
        If ($PSCmdlet.PagingParameters.IncludeTotalCount){
            [bool]$knownCount = ($PagingFirst -eq 0) -or ($PagingFirst -gt $Results.Count) #if we got less results than our limit (or we've not applied a limit) then we've reached the end, so we know the number of result            
            #$PSCmdlet.PagingParameters.NewTotalCount($Results.Count + $PagingSkip, 1.0 * $knownCount) #use this if we want to avoid estimates; i.e. if we don't have all the results, we don't have a clue how many there are
            $PSCmdlet.PagingParameters.NewTotalCount($Results.Count + $PagingSkip, [Math]::Min(1.0, (1.0 * $knownCount + 0.5))) #use this if we want the number of results (plus any skipped) to be used as the estimated amount (i.e. there are at least this many results)
        }
    }
}


Get-PagedData 'http://demo.com' -Skip 10 -First 20 -IncludeTotalCount -Verbose 

I'm particularly interested in the rules for estimation; i.e. where you know the exact number of items clearly the accuracy should be 1.0; but where this figure's not known, is it OK to claim that because we have some results we can say that that's an estimate (since we know there are at least that many; so the total's not completely unknown); should we claim 0.0 as we don't know how far out this figure is, or is there some other guidance on this?

Related Gist: https://gist.github.com/JohnLBevan/70ee8247ae7c324f8710c8a8bedd2b96/

\$\endgroup\$
7
  • 1
    \$\begingroup\$ I haven't used paging before but it's very relevant to something I'm working on (particularly with REST APIs) so I'm very interested in this question. Nice job. \$\endgroup\$
    – briantist
    May 26, 2017 at 14:24
  • 1
    \$\begingroup\$ Thank-you @briantist. I was told about this feature by lipkau on GitHub. Hopefully I should be implementing something on this project over the weekend: github.com/brianbunke/ConfluencePS/issues/50, should that be of interest. \$\endgroup\$
    – JohnLBevan
    May 26, 2017 at 14:36
  • 2
    \$\begingroup\$ Ooooo a Confluence module, now I'm very intrigued. I'm a big fan of Confluence and have been using it for years. \$\endgroup\$
    – briantist
    May 26, 2017 at 14:38
  • \$\begingroup\$ While I have a few years of powershell programming, this is way over my head. Could anyone provide a brief overview of what this does. \$\endgroup\$
    – Nick W.
    Apr 27, 2018 at 16:06
  • \$\begingroup\$ Hey @NickW. Are you interested specifically in SupportsPaging; or is your question about some other part of the code? docs.microsoft.com/en-us/dotnet/api/… \$\endgroup\$
    – JohnLBevan
    Apr 27, 2018 at 16:16

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.