Private/Select-Note.ps1

function Select-Note {
    [cmdletbinding()]
    param(
        [object[]]$InputObject,
        [string[]]$ID,
        [string[]]$Query,
        [string[]]$Tags,
        [string[]]$Data,
        [validateset('and','or')]
        [string]$ComparisonOperator = 'and',
        [switch]$IncludeRelated = $IncludeRelated
    )
    $Notes = @( :note foreach($Note in $InputObject){
        Write-verbose "Checking ID [$($Note.ID)] with query [$Query] Tags [$Tags] IncludeRelated [$IncludeRelated]"
        $NoteAnd = [System.Collections.Generic.List[bool]]::new()
        if($PSBoundParameters.ContainsKey('ID')) {
            $And = [System.Collections.Generic.List[bool]]::new()
            foreach($IDstring in $ID){
                if($Note.ID -like $IDstring){
                    Write-Verbose "ID [$IDString] matched [$($Note.ID)]"
                    if($ComparisonOperator -eq 'And'){
                        $And.add($true)
                    }
                    else {
                        $Note
                        continue note
                    }
                }
                else {
                    $And.add($false)
                }
            }
            if($ComparisonOperator -eq 'and') {
                if($And -contains $false){
                    continue note
                }
                elseif($And -contains $true) {
                    $NoteAnd.add($True)
                }
            }
        }
        if($PSBoundParameters.ContainsKey('Tags')) {
            $And = [System.Collections.Generic.List[bool]]::new()
            foreach($Tag in $Tags){
                if(@($Note.Tags) -contains $Tag){
                    Write-Verbose "Tag [$Tag] found in [$($Note.Tags)]"
                    if($ComparisonOperator -eq 'And'){
                        $And.add($true)
                    }
                    else {
                        $Note
                        continue note
                    }
                }
                else {
                    $And.add($false)
                }
            }
            if($ComparisonOperator -eq 'and') {
                if($And -contains $false){
                    continue note
                }
                elseif($And -contains $true) {
                    $NoteAnd.add($True)
                }
            }
        }
        if($PSBoundParameters.ContainsKey('Data')){
            $And = [System.Collections.Generic.List[bool]]::new()
            foreach($DataString in $Data) {
                if($Note.Data -match $DataString){
                    $And.add($True)
                    Write-Verbose "Data [$DataString] matched Data [$($Note.Data)]"
                    if($ComparisonOperator -eq 'or') { $Note; continue note}
                }
                else{
                    # Okay, no matches, go to town and convert data to json... not too deep...
                    try {
                        $StringData = $null
                        $StringData = ConvertTo-Json -InputObject $Note.Data -Depth 3 -Compress -ErrorAction Stop
                        if($StringData -match $DataString) {
                            Write-Verbose "Data [$DataString] matched jsonified Data [$StringData]"
                            if($ComparisonOperator -eq 'and') {
                                $And.add($True)
                            } else {
                                $Note
                                continue note
                            }
                        }
                        else {
                            $NoteAnd.add($false)
                            $And.add($false)
                        }
                    }
                    catch {
                        Write-Warning $_
                        Write-Verbose "Could not jsonify note ID $($Note.ID), skipping."
                        $NoteAnd.add($false)
                        $And.add($false)
                        continue
                    }
                }
            }
            if($ComparisonOperator -eq 'and') {
                if($And -contains $false){
                    continue note
                }
                elseif($And -contains $true) {
                    $NoteAnd.add($True)
                }
            }
        }
        if($PSBoundParameters.ContainsKey('Query')){
            $And = [System.Collections.Generic.List[bool]]::new()
            foreach($QueryString in $Query){
                $ThisMatched = $False
                if($Note.ID -match $QueryString){
                    $And.add($true)
                    $ThisMatched = $true
                    Write-Verbose "Query [$QueryString] matched ID [$($Note.ID)]"
                    if($ComparisonOperator -eq 'or') { $Note; continue note}
                    continue
                }
                foreach($Tag in $Note.Tags){
                    if($Tag -match $QueryString){
                        $ThisMatched = $true
                        $And.add($true)
                        Write-Verbose "Query [$QueryString] matched tag [$Tag]"
                        if($ComparisonOperator -eq 'or') { $Note; continue note}
                        break
                    }
                }
                foreach($RelatedID in $Note.RelatedIDs){
                    if($RelatedID -match $QueryString){
                        $ThisMatched = $true
                        $And.add($true)
                        Write-Verbose "Query [$QueryString] matched RelatedID [$RelatedID]"
                        if($ComparisonOperator -eq 'or') { $Note; continue note}
                        break
                    }
                }
                if($Note.Data -match $QueryString){
                    $ThisMatched = $true
                    $And.add($true)
                    Write-Verbose "Query [$QueryString] matched Data [$($Note.Data)]"
                    if($ComparisonOperator -eq 'or') { $Note; continue note}
                    continue
                }
                if(-not $ThisMatched){
                    # Okay, no matches, go to town and convert data to json... not too deep...
                    try {
                        $StringData = $null
                        $StringData = ConvertTo-Json -InputObject $Note.Data -Depth 3 -Compress -ErrorAction Stop
                        if($StringData -match $QueryString) {
                            $And.add($True)
                            $ThisMatched = $true
                            Write-Verbose "Query [$QueryString] matched jsonified Data [$StringData]"
                            if($ComparisonOperator -eq 'or') {
                                $Note
                                continue note
                            }
                        }
                        else {
                            Write-Verbose "No query [$QueryString] match for [$($Note.Id)]"
                            $NoteAnd.add($false)
                            $And.add($false)
                        }
                    }
                    catch {
                        Write-Warning $_
                        Write-Verbose "Could not jsonify note ID $($Note.ID), skipping."
                        $NoteAnd.add($false)
                        $And.add($false)
                    }
                }
            }
            # We searched all the queries, did any switch output to true?
            if($ComparisonOperator -eq 'and') {
                if($And -contains $false -or -not $ThisMatched){
                    Write-Verbose "Skipping due to AND"
                    continue note
                }
                elseif($And -contains $true) {
                    Write-Verbose "Adding NoteAnd due to AND"
                    $NoteAnd.add($True)
                }
            }
        }
        # No query, return all data
        if($NoteAnd.Count -eq 0 -and
           -not $PSBoundParameters.ContainsKey('ID') -and
           -not $PSBoundParameters.ContainsKey('Query') -and
           -not $PSBoundParameters.ContainsKey('Tags') -and
           -not $PSBoundParameters.ContainsKey('Data')
        ) {
            $Note
            continue
        }
        if($ComparisonOperator -eq 'and' -and $NoteAnd -notcontains $false -and $NoteAnd -contains $true){
            $Note
        }
    })
    if($IncludeRelated){
        $ExistingIDs = @($Notes.ID)
        $RelatedIDs = @($Notes.RelatedIDs | Sort-Object -Unique)
        foreach($Note in $InputObject){
            if($ExistingIDs -notcontains $Note.ID -and $RelatedIDs -Contains $Note.ID){
                $ExistingIDs += $Note.ID
                $Notes += $Note
            }
        }
        $Notes
    }
    else {
        $Notes
    }
}