Reputation: 24685
Is it possible to delay pipeline execution, or to modify a previous pipeline? What I am looking for is the ability to interact with an ODATA endpoint. I want to use standard (or custom) powershell commands to filter the data, but I don't want to retrieve the whole list. For example
function Get-Records() {
Invoke-RestMethod -Method Get -Uri $endpoint.Uri.AbsoluteUri ...
}
Calling this could return 500+ records. Normally I would not want to retrieve all 500 records, sometimes I would. So I might just call Get-Records
if I need all 500. But if I only wanted specific ones I would want to do
Get-Records | Where {$_.Name -eq 'me'}
The above still receives all 500 records and then filters them down. I would somehow want the Where {$_.Name -eq 'me'}
to instead pass back to the previous pipeline a filter to the Invoke-RestMethod
and appending to the URI $filter=Name eq 'me'
Upvotes: 2
Views: 524
Reputation: 439257
You cannot modify a pipeline retroactively via a post-processing filter such as Where-Object
.
Instead, you must filter at the source, using the syntax of the data provider.
This is how PowerShell's built-in cmdlets such as Get-ChildItem
do it, via a [string]
-typed -Filter
parameter.
If you want to pass a PowerShell script block as the filter, you'll have to translate it to the provider's syntax yourself - if possible.
There will rarely be a one-to-one mapping of PowerShell expressions to a provider's filter capabilities, so perhaps the better approach is to require the user to use the provider's syntax directly:
function Get-Records() {
param(
[Parameter(Mandatory)]
[uri] $Uri
,
[string] $Filter # Optional filter in provider syntax; e.g. "Name eq 'me'"
)
if ($Filter) { $Uri += '?$filter=' + $Filter }
Invoke-RestMethod -Method Get -Uri $uri
}
# Invoke with a filter in the provider's syntax.
Get-Records "Name eq 'me'"
If you do want the user to be able to pass a script block, you'll have to do your own translation to the provider syntax and ensure that translation is possible.
To do this robustly, you'd have to process the script block's AST (abstract syntax tree), which is accessible via its .Ast
property, which is nontrivial.
If you're willing to make assumptions about the type of expressions a user is allowed to pass, you can get away with string parsing, such as in the following simplistic example:
function Get-Records {
param(
[Parameter(Mandatory)]
[uri] $Uri
,
[scriptblock] $FilterScriptBlock # Optional filter
)
if ($FilterScriptBlock) {
# Translate the script block' *string representation*
# into the provider-native filter syntax.
# Note: This is overly simplistic in that it simply removes '$_.'
# and '-' before '-eq'.
$Uri += '?$filter=' + $FilterScriptBlock -replace '\$_\.' -replace '-(?=[a-z]+\b)'
}
Invoke-RestMethod -Method Get -Uri $Uri
}
# Invoke with a filter specified as a PowerShell script block.
Get-Records { $_.Name -eq 'me' }
Upvotes: 2