Patch-CDBDocument.psm1

$FunctionScriptName = "Patch-CDBDocument"
Write-Verbose "Import-Start| [$($FunctionScriptName)]"

#* Dependencies
# Create-CDBAuthHeader

#todo: check for conflict -> $_.Exception.Response.StatusCode = "Conflict" | $x.Exception.Response.Statuscode.value__ = 409
#todo: Add error handling
#todo: Add socket throttling check

function Patch-CDBDocument {
    <#
        .SYNOPSIS
            Patches part of an existing document in the database
         
        .DESCRIPTION
            Patches part of an existing document in the database
            Pkey value must match value in the entity/pipe!
             
            Only one operation at a time.
 
            Used by SQL/Core REST API
         
        .PARAMETER Config
            Config array
            Accepts the following values: DatabaseID / CollectionID / AuthKey / keyType / CosmosDBEndpoint / KeyType
            All required values can be set directly. Directly set values have precedent.
            Not all values may be required.
         
        .PARAMETER DatabaseID
            Can be set via -Config value
            Name of the CosmosDB Database
         
        .PARAMETER CollectionId
            Can be set via -Config value
            Name of the CosmosDB Collection
         
        .PARAMETER AuthKey
            Can be set via -Config value
            Key value to authenticate against cosmosDB
         
        .PARAMETER KeyType
            Can be set via -Config value
            Type of AuthKey provided.
            Default value: "master"
         
        .PARAMETER PartitionKey
            Value of the Partition. Not the Name of the Key itself!
            The PartitionKey itself is configured in the database collection.
         
        .PARAMETER DocumentID
            Value of the Document ID.
         
        .PARAMETER Operation
            Patch operation (default "add")
         
        .PARAMETER path
            Document path to patch
         
        .PARAMETER Entity
            The Document itself.
 
        .PARAMETER pipe
            Used automatically insted of "Entity" while using a Pipeline.
            Do not use Entity if a Pipeline is used!
         
        .EXAMPLE
            Patch-CDBDocument -Config $Config -PartitionKey $PKEY -DocumentID $ID -Entity $Document
         
        .NOTES
            AUTHOR: Ken Dobrunz // Ken.Dobrunz@Skaylink.com
            LASTEDIT: 08.08.2022 - Version: 1.0
        #>

    [cmdletbinding()]
    Param(
        #* Active data
        # Config or direct values needed
        [Parameter()]$Config,
        [Parameter()][string]$DatabaseID,
        [Parameter()][Alias('col')][string]$CollectionId,
        [Parameter()][Alias('key')][string]$AuthKey,
        [Parameter()][Alias('type')][string]$KeyType = "master",
        [Parameter()][Alias('uri')][string]$CosmosDBEndpoint,
        
        # Entity
        [parameter()]$Entity,
        [parameter(ValueFromPipeline = $True)]$pipe, #! Only for same ID - NO id in pipe/entity!
        [parameter()][Alias('pkey')][string]$PartitionKey,
        [parameter()][Alias('id')][string]$DocumentID,
        [parameter()][string]$path,  #! Only for same ID - NO id in pipe/entity!
        [parameter()][string]$Operation = "add",
        
        [parameter()][bool]$enablecrosspartition = $false,
        [parameter()][bool]$ReuseAuthHeader = $false
    )
    Begin {
        $SelfIdentifier = "Patch-CDBDocument"
        
        # Check Config / Set Variables
        $DatabaseID = if ($DatabaseID) { $DatabaseID }elseif ($Config.DatabaseID) { $Config.DatabaseID }else { Write-Error "[$($SelfIdentifier)] No DatabaseID provided" }
        $CollectionId = if ($CollectionId) { $CollectionId }elseif ($Config.CollectionId) { $Config.CollectionId }else { Write-Error "[$($SelfIdentifier)] No CollectionId provided" }
        $AuthKey = if ($AuthKey) { $AuthKey }elseif ($Config.AuthKey) { $Config.AuthKey }else { Write-Error "[$($SelfIdentifier)] No AuthKey provided" }
        $KeyType = if ($KeyType) { $KeyType }elseif ($Config.KeyType) { $Config.KeyType }else { Write-Error "[$($SelfIdentifier)] No KeyType provided" }
        $CosmosDBEndpoint = if ($CosmosDBEndpoint) { $CosmosDBEndpoint }elseif ($Config.CosmosDBEndpoint) { $Config.CosmosDBEndpoint }else { Write-Error "[$($SelfIdentifier)] No CosmosDBEndpoint provided" }
        
        $CosmosURI = "$CosmosDBEndPoint/dbs/$DatabaseId/colls/$CollectionId/docs/"
        
        if (!$PartitionKey) { throw "[$($SelfIdentifier)] No PartitionKey [$($PartitionKey)]" }
        if (!$DocumentID) { throw "[$($SelfIdentifier)] No DocumentID [$($DocumentID)]" }
        
        if ($ReuseAuthHeader) {
            $dateTime = [DateTime]::UtcNow.ToString("r")
            Write-Debug "[$($SelfIdentifier)] Reusing header for all requests - Datetime [$($dateTime)]"
            Write-Warning "[$($SelfIdentifier)] Static header may timeout before completion of all entities!"
            
            $header = Create-CDBAuthHeader -DatabaseID $DatabaseID -CollectionID $CollectionId -AuthKey $AuthKey -keytype $KeyType -HTTPverb "PATCH" -PartitionKey $PartitionKey -DocumentID $DocumentID
        }
        
        $functionverbosecount = 0
    }
    Process { 
        if ($Entity) { $pipe = $Entity }
        
        # Auth Header
        if (!$ReuseAuthHeader) {
            $header = Create-CDBAuthHeader -DatabaseID $DatabaseID -CollectionID $CollectionId -AuthKey $AuthKey -keytype $KeyType -HTTPverb "PATCH" -PartitionKey $PartitionKey -DocumentID $DocumentID
        }
        Write-Verbose "[$($SelfIdentifier)] Patching document for id [$($DocumentID)] @ [$($PartitionKey)]"
        
        # Creating body
        $OperationBody = @{operations = @(
            @{op=$Operation;path=$path;value=$pipe}
        )}        

        Invoke-RestMethod -Method PATCH -Uri ($CosmosURI + $DocumentID) -Headers $header -Body ($OperationBody | ConvertTo-Json -Depth 20) -ContentType application/json
        $functionverbosecount++
    
    }
    End {
        if ($functionverbosecount -gt 1) { Write-Verbose "[$($SelfIdentifier)] Updated $($functionverbosecount) entries" }
    }
} #v0.1

Export-ModuleMember -Function *
Write-Verbose "Import-END| [$($FunctionScriptName)]"