using System.Globalization;
using System.Runtime.CompilerServices;
using NpgsqlTypes;
namespace NpgsqlRest;
///
/// Pre-computed delegate array for type-specific parameter parsing.
/// Replaces sequential if-chain with O(1) delegate lookup.
///
public static class ParameterParsers
{
///
/// Delegate signature for type-specific parsing.
///
/// The string value to parse
/// The parsed result if successful
/// True if parsing succeeded, false otherwise
public delegate bool TryParseDelegate(string? value, out object? result);
private static readonly TryParseDelegate?[] _parsers;
static ParameterParsers()
{
_parsers = new TryParseDelegate?[128];
// Numeric types
_parsers[(int)NpgsqlDbType.Smallint] = TryParseSmallint;
_parsers[(int)NpgsqlDbType.Integer] = TryParseInteger;
_parsers[(int)NpgsqlDbType.Bigint] = TryParseBigint;
_parsers[(int)NpgsqlDbType.Double] = TryParseDouble;
_parsers[(int)NpgsqlDbType.Real] = TryParseReal;
_parsers[(int)NpgsqlDbType.Numeric] = TryParseDecimal;
_parsers[(int)NpgsqlDbType.Money] = TryParseDecimal;
// Boolean
_parsers[(int)NpgsqlDbType.Boolean] = TryParseBoolean;
// DateTime types
_parsers[(int)NpgsqlDbType.Timestamp] = TryParseTimestamp;
_parsers[(int)NpgsqlDbType.TimestampTz] = TryParseTimestampTz;
_parsers[(int)NpgsqlDbType.Date] = TryParseDate;
_parsers[(int)NpgsqlDbType.Time] = TryParseTime;
_parsers[(int)NpgsqlDbType.TimeTz] = TryParseTimeTz;
// UUID
_parsers[(int)NpgsqlDbType.Uuid] = TryParseUuid;
// Text types - handled separately (just return string as-is)
// Not added to lookup - will fall through to text handling
}
// NpgsqlDbType flags for Range and Multirange
private const int RangeFlag = 0x40000000; // NpgsqlDbType.Range
private const int MultirangeFlag = 0x20000000; // NpgsqlDbType.Multirange
///
/// Gets the parser delegate for the specified NpgsqlDbType.
/// Returns null if the type should be handled as text.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TryParseDelegate? GetParser(NpgsqlDbType dbType)
{
int rawValue = (int)dbType;
// Range and Multirange types are handled as text
if ((rawValue & (RangeFlag | MultirangeFlag)) != 0)
{
return null;
}
// Strip Array flag and look up in table
int index = rawValue & ~(int)NpgsqlDbType.Array;
return (uint)index < (uint)_parsers.Length ? _parsers[index] : null;
}
private static bool TryParseSmallint(string? value, out object? result)
{
if (short.TryParse(value, CultureInfo.InvariantCulture.NumberFormat, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseInteger(string? value, out object? result)
{
if (int.TryParse(value, CultureInfo.InvariantCulture.NumberFormat, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseBigint(string? value, out object? result)
{
if (long.TryParse(value, CultureInfo.InvariantCulture.NumberFormat, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseDouble(string? value, out object? result)
{
if (double.TryParse(value, CultureInfo.InvariantCulture.NumberFormat, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseReal(string? value, out object? result)
{
if (float.TryParse(value, CultureInfo.InvariantCulture.NumberFormat, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseDecimal(string? value, out object? result)
{
if (decimal.TryParse(value, CultureInfo.InvariantCulture.NumberFormat, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseBoolean(string? value, out object? result)
{
if (bool.TryParse(value, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseTimestamp(string? value, out object? result)
{
if (DateTime.TryParse(value, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseTimestampTz(string? value, out object? result)
{
if (DateTime.TryParse(value, out var v))
{
result = DateTime.SpecifyKind(v, DateTimeKind.Utc);
return true;
}
result = null;
return false;
}
private static bool TryParseDate(string? value, out object? result)
{
if (DateOnly.TryParse(value, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
private static bool TryParseTime(string? value, out object? result)
{
if (DateTime.TryParse(value, out var v))
{
result = TimeOnly.FromDateTime(v);
return true;
}
result = null;
return false;
}
private static bool TryParseTimeTz(string? value, out object? result)
{
if (DateTime.TryParse(value, out var v))
{
result = new DateTimeOffset(DateTime.SpecifyKind(v, DateTimeKind.Utc));
return true;
}
result = null;
return false;
}
private static bool TryParseUuid(string? value, out object? result)
{
if (Guid.TryParse(value, out var v))
{
result = v;
return true;
}
result = null;
return false;
}
}