Commands/Search-EFPosh.ps1

Function Search-EFPosh{
    <#
    .SYNOPSIS
    Takes a PowerShell expression, converts to BinaryExpression, and then runs it against SQL
     
    .DESCRIPTION
    Will convert a PowerShell expression block to the Linq equivalent and then run it
     
    .PARAMETER Entity
    Entity from the DBContext - Has to have been created with New-EFPoshContext
     
    .PARAMETER Expression
    Expression to run against the entity
 
    .PARAMETER Arguments
    Arguments for the expression when $0 is used
     
    .PARAMETER AsNoTracking
    Should tracking be set up? If you don't want to edit the results, this could significantly reduce the query time
     
    .PARAMETER Include
    Should any navigation properties be included?
     
    .PARAMETER Take
    How many results should be returned
     
    .PARAMETER Skip
    Do we skip any results
     
    .PARAMETER OrderBy
    Order by what property
     
    .PARAMETER OrderByDescending
    Order by what property descending
     
    .PARAMETER Distinct
    Should results be distinct
     
    .PARAMETER Select
    Which properties do we return - default is all
     
    .PARAMETER FromSql
    Uses a SQL query as the base query instead of the entity
 
    .PARAMETER ToList
    Will return results in a List<T>
     
    .PARAMETER FirstOrDefault
    Will return only the first result or null if none are found
     
    .PARAMETER Any
    Will return bool true if results are found, false if nothing is found.
     
    .EXAMPLE
    Search-EFPosh -Entity $Context.TableOne -Expression { $_.Name -eq 'Test' }
 
    .EXAMPLE
    Search-EFPosh -Entity $Context.TableOne -Expression { $_.Name -contains $0 } -Arguments @($Example)
     
    .NOTES
    .Author: Ryan Ephgrave
    #>

    [CmdletBinding(DefaultParameterSetName="ToList")]
    Param(
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [object]$DbContext,
        [Parameter(Mandatory=$true, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$true, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$true, ParameterSetName = 'Any')]
        [ArgumentCompleter({
            param ( $commandName,$parameterName,$wordToComplete,$commandAst,$fakeBoundParameters)
            if($wordToComplete -like '$*'){
                return
            }
            if($fakeBoundParameters.ContainsKey('DbContext')){
                $EntityNames = $DbContext.GetEntities()
            }
            else{
                $LatestContext = (Get-Module EFPosh).Invoke({ $Script:LatestDBContext })
                if($null -eq $LatestContext) { return }
                $EntityNames = $LatestContext.GetEntities()
            }
            foreach($ename in $EntityNames){
                if($ename -like "*$($wordToComplete)*"){
                    $eName
                }
            }
        })]
        [string]$Entity,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [ScriptBlock]$Expression,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [object[]]$Arguments,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [switch]$AsNoTracking,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [string[]]$Include,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [string[]]$ThenInclude,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [int]$Take,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [int]$Skip,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [string]$OrderBy,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [string]$OrderByDescending,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [switch]$Distinct,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [string[]]$Select,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [Parameter(Mandatory=$false, ParameterSetName = 'FirstOrDefault')]
        [Parameter(Mandatory=$false, ParameterSetName = 'Any')]
        [string]$FromSql,
        [Parameter(Mandatory=$false, ParameterSetName = 'ToList')]
        [switch]$ToList,
        [Parameter(Mandatory=$true, ParameterSetName = 'FirstOrDefault')]
        [switch]$FirstOrDefault,
        [Parameter(Mandatory=$true, ParameterSetName = 'Any')]
        [switch]$Any
    )
    if(-not $PSBoundParameters.ContainsKey('DbContext')){
        $DbContext = $Script:LatestDBContext
    }
    if($null -eq $DbContext){
        throw "Null DbContext - Run New-EFPoshContext to get one and provide it."
        return
    }
    if($DbContext.GetEntities() -notcontains $Entity){
        throw "Entity not found in DbContext - If no DbContext was specified, the last created one was used."
        return
    }
    $EntityObj = $DbContext."$($Entity)"

    if(-not [string]::IsNullOrEmpty($FromSql)){
        $EntityObj.FromSql($FromSql)
    }

    if($Expression){
        try{
            #I'd love to break this out to it's own function, but below the PsCmdlet session state stuff needs to be run in here
            #so it has to stay in the function called by the user.
            $ExpressionValues = New-Object 'System.Collections.Generic.Dictionary[[string],[object]]'
            $VariableValues = @{}
            $varAsts = $Expression.Ast.FindAll({
                param( [System.Management.Automation.Language.Ast] $AstObject )
        
            return ( $AstObject -is [System.Management.Automation.Language.VariableExpressionAst] )
            }, $true)
            foreach($varAst in $varAsts){
                try{
                    $ExpressionBase = Get-EFPoshExpressionBase -Ast $varAst
                    #Why aren't we just getting the variable value?
                    #To account for weird instances, like: $var.PropertyName
                    #or $var."$propIwant"
                    if(-not [string]::IsNullOrEmpty($ExpressionBase)){
                        $VariableValues[$varAst.VariablePath.UserPath] = $PSCmdlet.SessionState.PSVariable.GetValue($varAst.VariablePath.UserPath)
                        $VariableValue = Invoke-Command -ScriptBlock {
                            Param([hashtable]$VariableValues, $ExpressionBase)
                            foreach($key in $VariableValues.Keys){
                                Set-Variable -Name $key -Value $VariableValues[$key]
                            }
                            return (Invoke-Expression $ExpressionBase)
                        } -ArgumentList @($VariableValues, $ExpressionBase) -ErrorAction SilentlyContinue
                        $ExpressionValues[$ExpressionBase.ToString()] = $VariableValue
                    }
                }
                catch{}
            }
            $EntityObj.ApplyExpression($Expression, $Arguments, $ExpressionValues)
        }
        catch{
            throw
            return
        }
    }
    if($PSCmdlet.ParameterSetName -eq 'ToList'){
        $ToList = $true
    }

    if($Include){
        $includeCount = 0
        foreach($instance in $Include){
            $thenInstance = $null
            if($ThenInclude){
                $thenInstance = @($ThenInclude)[$includeCount]
            }
            if(-not ( [string]::IsNullOrEmpty($instance))){
                $EntityObj.Include($instance, $thenInstance)
            }
            $includeCount++
        }
    }
    if($AsNoTracking){
        $EntityObj.AsNoTracking()
    }
    if($Take){
        $EntityObj.Take($Take)
    }
    if($Skip){
        $EntityObj.Skip($Skip)
    }
    if($OrderBy){
        $EntityObj.OrderBy($OrderBy)
    }
    if($OrderByDescending){
        $EntityObj.OrderBy($OrderByDescending)
    }
    if($Distinct){
        $EntityObj.Distinct()
    }
    if($Select){
        $EntityObj.Select($Select)
    }
    if($ToList){
        return $EntityObj.ToList()
    }
    if($FirstOrDefault){
        return $EntityObj.FirstOrDefault()
    }
    if($Any){
        return $EntityObj.Any()
    }
}