Private/duckdb/Write-DuckDBAppender.ps1

function Write-DuckDBAppender {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [DuckDB.NET.Data.DuckDBConnection]$Connection,
        [Parameter(Mandatory)] [string]$TableName,
        [Parameter(Mandatory)] $Data,
        [Parameter(Mandatory=$false)]
        [switch]$SimpleTypesOnly = $false
    )

    $appender = $Connection.CreateAppender($TableName)
    $propNames = $null  # cached once from first row

    $i = 0
    foreach ($row in $Data) {
        $i++

        # Cache property names from first row only
        if ($null -eq $propNames) {
            $propNames = @($row.PSObject.Properties.Name)
        }

        $appenderRow = $appender.CreateRow()
        foreach ($name in $propNames) {
            $val = $row.$name
            # Normalize integer subtypes to Int64 before any other check,
            # because DuckDB.NET appender has no Int32 overload and PowerShell
            # would otherwise fall back to AppendValue(string).
            if ($val -is [int] -or $val -is [System.Int16] -or $val -is [byte] -or $val -is [uint16] -or $val -is [uint32]) {
                $val = [long]$val
            } elseif ($val -is [float]) {
                $val = [double]$val
            }
            # Inlined ConvertTo-DuckDBValue
            if ($null -eq $val) {
                [void]$appenderRow.AppendValue([DBNull]::Value)
            } elseif (-not $SimpleTypesOnly -and (
                      $val -is [System.Collections.IList] -or
                      $val -is [PSCustomObject] -or
                      $val -is [System.Collections.IDictionary])) {
                [void]$appenderRow.AppendValue((ConvertTo-Json -InputObject $val -Compress -Depth 10))
            } else {
                [void]$appenderRow.AppendValue($val)
            }
        }
        $appenderRow.EndRow()

        If ( $i % 10000 -eq 0 ) {
            Write-Verbose "[$TableName] Appender: Row $i written."
        }
    }

    $appender.Close()
    $appender.Dispose()
    Write-Verbose "[$TableName] Appender finished."
}