Classes/Public/TMReference.ps1

#region Classes

class TMReference {
    [Int32]$Id = 0
    [String]$Name

    #region Constructors

    TMReference() {}

    TMReference([Int32]$id, [String]$name) {
        $this.Id = $id
        $this.Name = $name
    }

    TMReference([String]$name, [Int32]$id) {
        $this.Id = $id
        $this.Name = $name
    }

    TMReference([Int32]$id) {
        $this.Id = $id
    }

    TMReference([String]$name) {
        $this.Name = $name
    }

    TMReference([String]$nameOrId1, [String]$nameOrId2) {
        if ($nameOrId1 -match '^\d+$') {
            $this.Id = [Int32]$nameOrId1
            $this.Name = $nameOrId2
        } elseif ($nameOrId2 -match '^\d+$') {
            $this.Id = [Int32]$nameOrId2
            $this.Name = $nameOrId1
        }
    }

    TMReference([Object]$object) {
        $this.Id = $object.id
        $this.Name = $object.name
    }

    #endregion Constructors

    #region Non-Static Methods

    [String]ToString() {
        return "{Id = $($this.Id), Name = $($this.Name)}"
    }

    #endregion Non-Static Methods

    #region Static Methods

    <#
        Summary:
            Resolves the passed objects of the specified reference type into TMReference objects with a valid name and ID
        Params:
            References - One or more Names, IDs or objects representing a Name/ID reference to an object in TransitionManager
            Type - The type of reference(s) to lookup. Defined by the enum TMReferenceType
            TMSessionName - The name of the TMSession to use when resolving references
        Outputs:
            An array of TMReference objects with both the Name and ID resolved
    #>

    static [TMReference[]]Resolve([Object[]]$References, [TMReferenceType]$Type, [PSObject]$TMSessionName) {
        # Get Session Configuration
        $TMSession = $global:TMSessions[$TMSessionName]
        if (-not $TMSession) {
            throw "TMSession '$TMSession' not found. Check name or use New-TMSession"
        }

        $ResolvedReferences = @()
        if ($References) {
            $ReferencesToLookup = @{IDs = @(); Names = @() }
            Write-Verbose "Formatting $($Type) References"

            # Iterate over the passed references and sort them into already resolved
            # references and references that need to be looked up
            foreach ($Reference in $References) {
                Write-Debug "Reference: $Reference)"
                Write-Debug "Reference Type: $($Reference.GetType().FullName)"
                switch ($Reference.GetType()) {
                    ([String]) {
                        if ($Reference -match '^\d+$') {
                            # String is a number, probably an ID. The Name will need to be looked up
                            $ReferencesToLookup.IDs += [Int32]$Reference

                            # It's unlikely, but the number-only string could be the reference's Name, so the ID will need to be looked up
                            $ReferencesToLookup.Names += $Reference
                        } else {
                            # String is probably a Name. The ID will need to be looked up
                            $ReferencesToLookup.Names += $Reference
                        }
                    }

                    ([Int32]) {
                        # Number is probably an ID. The Name will need to be looked up
                        $ReferencesToLookup.IDs += $Reference
                    }

                    ([Hashtable]) {
                        # Convert to a Hashtable with case-insensitive keys
                        $Reference = [Hashtable]::new($Reference, [System.StringComparer]::OrdinalIgnoreCase)

                        # Make sure it has at least an ID or a Name
                        if (([Int32]$Reference.Id -gt 0) -and ([String]::IsNullOrWhiteSpace($Reference.Name))) {
                            # Hashtable has an ID but not a Name. The Name will need to be looked up
                            $ReferencesToLookup.IDs += [Int32]$Reference.Id
                        } elseif (([Int32]$Reference.Id -le 0) -and (-not [String]::IsNullOrWhiteSpace($Reference.Name))) {
                            # Hashtable has a Name but not an ID. The ID will need to be looked up
                            $ReferencesToLookup.Names += $Reference.Name
                        } elseif (([Int32]$Reference.Id -gt 0) -and (-not [String]::IsNullOrWhiteSpace($Reference.Name))) {
                            # Hashtable has both an ID and a Name. Convert to a TMReference object
                            $ResolvedReferences += [TMReference]::new($Reference)
                        }
                    }

                    default {
                        try {
                            # Reference is some other object. Make sure it has at least an ID or a Name property with a value
                            if (([Int32]$Reference.Id -gt 0) -and ([String]::IsNullOrWhiteSpace($Reference.Name))) {
                                # Object has an ID but not a Name. The Name will need to be looked up
                                $ReferencesToLookup.IDs += [Int32]$Reference.Id
                            } elseif (([Int32]$Reference.Id -le 0) -and (-not [String]::IsNullOrWhiteSpace($Reference.Name))) {
                                # Object has a Name but not an ID. The ID will need to be looked up
                                $ReferencesToLookup.Names += $Reference.Name
                            } elseif (([Int32]$Reference.Id -gt 0) -and (-not [String]::IsNullOrWhiteSpace($Reference.Name))) {
                                # Object has both an ID and a Name. Convert to a TMReference object
                                $ResolvedReferences += [TMReference]::new($Reference)
                            }
                        } catch {
                            Write-Warning "The value '$Reference' of type '$($Reference.GetType().FullName)' could not be resolved to a TMReference: $($_.Exception.Message)"
                        }
                    }
                }
            }

            # Assets' name field is capitalized
            $NameField = $Type -eq [TMReferenceType]::Asset ? 'Name' : 'name'

            # Use the IDs to lookup the Names
            if ($ReferencesToLookup.IDs.Count -gt 0) {
                Write-Verbose "Querying TM for Reference Names"
                try {
                    if ($Type -eq [TMReferenceType]::Tag) {
                        # Currently, TMQL can't be used for Tags
                        Get-TMTag -TMSession $TMSession.Name -Id $ReferencesToLookup.IDs | ForEach-Object {
                            $ResolvedReferences += [TMReference]::new($_)
                        }
                    } else {
                        # Use TMQL to get the Names
                        $Query = "find $($Type.ToString()) by 'id' inList([$($ReferencesToLookup.IDs -join ', ')]) fetch 'id', '$NameField'"
                        Invoke-TMQLStatement -TMSession $TMSession.Name -Statement $Query | ForEach-Object {
                            $ResolvedReferences += [TMReference]::new($_)
                        }
                    }
                } catch {
                    throw "Could not gather reference Names from TransitionManager: $($_.Exception.Message)"
                }
            }

            # Use the Names to lookup the IDs
            if ($ReferencesToLookup.Names.Count -gt 0) {
                Write-Verbose "Querying TM for Reference Names"
                try {
                    if ($Type -eq [TMReferenceType]::Tag) {
                        # Currently, TMQL can't be used for Tags
                        Get-TMTag -TMSession $TMSession.Name -Name $ReferencesToLookup.Names | ForEach-Object {
                            $ResolvedReferences += [TMReference]::new($_)
                        }
                    } else {
                        # Use TMQL to get the IDs
                        $Query = "find $($Type.ToString()) by '$NameField' ate '$($ReferencesToLookup.Names -join '|')' fetch 'id', '$NameField'"
                        Invoke-TMQLStatement -TMSession $TMSession.Name -Statement $Query | ForEach-Object {
                            $ResolvedReferences += [TMReference]::new($_)
                        }
                    }
                } catch {
                    throw "Could not gather reference IDs from TransitionManager: $($_.Exception.Message)"
                }
            }
        }

        return $ResolvedReferences
    }

    <#
        Summary:
            Resolves the passed objects of the specified reference type into TMReference objects with a valid name and ID using the Default TMSession
        Params:
            References - One or more Names, IDs or objects representing a Name/ID reference to an object in TransitionManager
            Type - The type of reference(s) to lookup. Defined by the enum TMReferenceType
        Outputs:
            An array of TMReference objects with both the Name and ID resolved
    #>

    static [TMReference[]]Resolve([Object[]]$References, [TMReferenceType]$Type) {
        return [TMReference]::Resolve($References, $Type, 'Default')
    }

    #endregion Static Methods
}

#endregion Classes


#region Enumerations

enum TMReferenceType {
    ApiAction
    Asset
    Bundle
    DataScript
    Event
    Manufacturer
    Model
    Person
    Project
    Recipe
    Tag
}

#endregion Enumerations