src/SqlParameter.psm1

using namespace System.Collections.Generic
using namespace System.Data

<#
.SYNOPSIS
    Represents a parameter of a parameterized SQL statement.
#>

class SqlParameter {

    <#
    .SYNOPSIS
        The prefixes used for parameter placeholders.
    #>

    hidden static [string[]] $Prefixes = "?", "@", ":", "$"

    <#
    .SYNOPSIS
        The database type of this parameter.
    #>

    [Nullable[DbType]] $DbType

    <#
    .SYNOPSIS
        Value indicating whether this parameter is input-only, output-only, bidirectional, or a stored procedure return value parameter.
    #>

    [Nullable[ParameterDirection]] $Direction

    <#
    .SYNOPSIS
        The parameter name.
    #>

    [ValidateNotNullOrWhiteSpace()]
    [string] $Name

    <#
    .SYNOPSIS
        Indicates the precision of numeric parameters.
    #>

    [Nullable[byte]] $Precision

    <#
    .SYNOPSIS
        Indicates the scale of numeric parameters.
    #>

    [Nullable[byte]] $Scale

    <#
    .SYNOPSIS
        The maximum size of this parameter, in bytes.
    #>

    [Nullable[int]] $Size

    <#
    .SYNOPSIS
        The parameter value.
    #>

    [object] $Value

    <#
    .SYNOPSIS
        Creates a new parameter.
    #>

    SqlParameter() {
        $this.Name = "?"
        $this.Value = [DBNull]::Value
    }

    <#
    .SYNOPSIS
        Creates a new parameter.
    .PARAMETER Name
        The parameter name.
    #>

    SqlParameter([string] $Name) {
        $this.Name = [SqlParameter]::NormalizeName($Name)
        $this.Value = [DBNull]::Value
    }

    <#
    .SYNOPSIS
        Creates a new parameter.
    .PARAMETER Name
        The parameter name.
    .PARAMETER Value
        The parameter value.
    #>

    SqlParameter([string] $Name, [object] $Value) {
        $this.Name = [SqlParameter]::NormalizeName($Name)
        $this.Value = [SqlParameter]::NormalizeValue($Value)
    }

    <#
    .SYNOPSIS
        Creates a new parameter from the specified tuple.
    .PARAMETER Parameter
        The tuple providing the parameter name and value.
    .OUTPUTS
        The parameter corresponding to the specified tuple.
    #>

    static [SqlParameter] op_Implicit([object[]] $Parameter) {
        return [SqlParameter]::new($Parameter[0] ?? "?", $Parameter[1] ?? [DBNull]::Value)
    }

    <#
    .SYNOPSIS
        Creates a new parameter from the specified key/value pair.
    .PARAMETER Parameter
        The key/value pair providing the parameter name and value.
    .OUTPUTS
        The parameter corresponding to the specified key/value pair.
    #>

    static [SqlParameter] op_Implicit([KeyValuePair[string, object]] $Parameter) {
        return [SqlParameter]::new($Parameter.Key, $Parameter.Value)
    }

    <#
    .SYNOPSIS
        Converts this parameter into an `IDbDataParameter` object.
    .PARAMETER Command
        The command to associate with the created parameter.
    .OUTPUTS
        The `IDbDataParameter` object corresponding to this parameter.
    #>

    [IDbDataParameter] ToDbParameter([IDbCommand] $Command) {
        $parameter = $Command.CreateParameter()
        $parameter.ParameterName = [SqlParameter]::NormalizeName($this.Name)
        $parameter.Value = [SqlParameter]::NormalizeValue($this.Value)
        if ($null -ne $this.DbType) { $parameter.DbType = $this.DbType.Value }
        if ($null -ne $this.Direction) { $parameter.Direction = $this.Direction.Value }
        if ($null -ne $this.Precision) { $parameter.Precision = $this.Precision.Value }
        if ($null -ne $this.Scale) { $parameter.Scale = $this.Scale.Value }
        if ($null -ne $this.Size) { $parameter.Size = $this.Size.Value }
        return $parameter
    }

    <#
    .SYNOPSIS
        Normalizes the specified parameter name.
    .PARAMETER Name
        The parameter name.
    .OUTPUTS
        The normalized parameter name.
    #>

    hidden static [string] NormalizeName([string] $Name) {
        return $Name ? ($Name[0] -in [SqlParameter]::Prefixes ? $Name : "@$Name") : "?"
    }

    <#
    .SYNOPSIS
        Normalizes the specified parameter value.
    .PARAMETER Value
        The parameter value.
    .OUTPUTS
        The normalized parameter value.
    #>

    hidden static [object] NormalizeValue([object] $Value) {
        return $Value ?? [DBNull]::Value
    }
}