lib/TMQL.ps1


function Invoke-TMQLStatement {
    <#
    .SYNOPSIS
    Executes a statement against the TMQL endpoint
     
    .DESCRIPTION
    This function will execute a statement written in TM query language against the
    REST API endpoint on a TransitionManager instance
     
    .PARAMETER TMSession
    The name of the TM Session to use when executing a statement
     
    .PARAMETER Statement
    The TMQL staement to be executed
     
    .EXAMPLE
    "find Device by 'Name' ate '$Server1|$Server2' fetch 'id'" | Invoke-TMQLStatement -TMSession TMAD60
     
    .EXAMPLE
    $Statement = @"
        find Person by \
        'email' eq 'sowen@tdsi.com' \
        fetch 'id', 'email', 'firstName', 'lastName'
    "@
    Invoke-TMQLStatement -TMSession TMAD60 -Statement $Statement
 
    .OUTPUTS
    A PSCustomObject containing the results of the statement execution
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false, Position = 1)]
        [String]$TMSession = "Default",

        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
        [String]$Statement
    )

    begin {

        # Get the session configuration
        Write-Verbose "Checking for cached TMSession"
        $TMSessionConfig = $global:TMSessions[$TMSession]
        Write-Debug "TMSessionConfig:"
        Write-Debug ($TMSessionConfig | ConvertTo-Json -Depth 5)
        if (-not $TMSessionConfig) {
            throw "TMSession '$TMSession' not found. Use New-TMSession command before using features."
        }
        
        # Make sure we have a bearer token for the REST endpoint
        Write-Verbose "Checking for TMRestSession with bearer token"
        if (-not $TMSessionConfig.TMRestSession) {
            throw "TMSession '$TMSession' is not logged into the TransitionManager API. Use New-TMSession -Api `$true command to connect to a compatible server."
        }

        # Make sure the TM instance is v5.0.4 or greater
        Write-Verbose "Checking for compatible TransitionManager instance"
        Write-Debug "TM Version: $($TMSessionConfig.TMVersion)"
        if (([Int]$TMSessionConfig.TMVersion.Split('.')[0] -eq 5) -and ([Int]$TMSessionConfig.TMVersion.Split('.')[2] -lt 4)) {
            throw "The TMQL endpoint is not available on TransitionManager versions below 5.0.4"
        }

        # Form the URI
        Write-Verbose "Forming the web request URI"
        $Uri = "https://$($TMSessionConfig.TMServer)/tdstm/api/tmql/statement"
    }

    process {
        try {
            Write-Verbose "Forming web request parameters"
            ## Create the Field Settings body, differs for TM separate TM versions
            $TMVersion = [Version]::parse($TMSessionConfig.TMVersion)
            if ((($TMVersion.Major -eq 5) -and ($TMVersion -ge '5.0.4')) -or
                (($TMVersion.Major -eq 6 -and $TMVersion -ge '6.0.0.2'))) {
                
                $RestSplat = @{
                    Uri                = $Uri
                    Method             = 'GET'
                    WebSession         = $TMSessionConfig.TMRestSession
                    Body               = (@{
                            statement = $Statement
                            project   = $TMSessionConfig.userContext.project.id
                        } | ConvertTo-Json)
                    SkipHttpErrorCheck = $true
                    StatusCodeVariable = 'StatusCode'
                }
            }
            else {

                $RestSplat = @{
                    Uri                = $Uri
                    Method             = 'GET'
                    WebSession         = $TMSessionConfig.TMRestSession
                    Body               = (@{
                            statement = $Statement
                        } | ConvertTo-Json)
                    SkipHttpErrorCheck = $true
                    StatusCodeVariable = 'StatusCode'
                }
            }
            Write-Debug "Web Request Parameters:"
            Write-Debug ($RestSplat | ConvertTo-Json -Depth 10)
            Write-Verbose "Invoking web request"
            $Response = Invoke-RestMethod @RestSplat
            if ($StatusCode -in 200, 204) {
                $Response
            }
            elseif (-not [String]::IsNullOrWhiteSpace($Response)) {
                throw $Response
            }
            else {
                throw "The response status code $StatusCode does not indicate success."
            }
        }
        catch {
            throw "Could not execute statement: $($_.Exception.Message)"
        }
    }
}