using System.Collections.ObjectModel;
using FluentResults;
using Npgsql;
namespace pgLabII.PgUtils.ConnectionStrings;
///
/// Parser for converting a libpq style connection string into a dictionary of key value pairs
///
public ref struct PqConnectionStringParser
{
// Note possible keywords
// host
//hostaddr
//port
//dbname
//user
//password
//passfile
//channel_binding
//connect_timeout
//client_encoding
//options
//application_name
//fallback_application_name
//keepalives
//keepalives_idle
//keepalives_interval
//keepalives_count
//tcp_user_timeout
//replication
//gssencmode
//sslmode
//requiresll
//sslcompression
//sslcert
//sslkey
//sslpassword
//sslrootcert
//sslcrl
//sslcrldir
//sslsni
//requirepeer
//ssl_min_protocol_version
//ssl_max_protocol_version
//krbsrvname
//gsslib
//service
//target_session_attrs
public static Result> Parse(string input)
{
return new PqConnectionStringParser(
new PqConnectionStringTokenizer(input)
).Parse();
}
private readonly IPqConnectionStringTokenizer _tokenizer;
private readonly Dictionary _result = new();
public PqConnectionStringParser(IPqConnectionStringTokenizer tokenizer)
{
this._tokenizer = tokenizer;
}
public Result> Parse()
{
_result.Clear();
while (!_tokenizer.IsEof)
{
var result = ParsePair();
if (result.IsFailed)
return result;
}
return _result;
}
private Result ParsePair()
{
var kwResult = _tokenizer.GetKeyword();
if (kwResult.IsFailed)
return kwResult.ToResult();
var result = _tokenizer.ConsumeEquals();
if (result.IsFailed)
return result;
var valResult = _tokenizer.GetValue();
if (valResult.IsFailed)
return valResult.ToResult();
_result.Add(kwResult.Value, valResult.Value);
return Result.Ok();
}
private SslMode ToSslMode(ReadOnlySpan v)
=> v switch
{
"disable" => SslMode.Disable,
"allow" => SslMode.Allow,
"prefer" => SslMode.Prefer,
"require" => SslMode.Require,
"verify-ca" => SslMode.VerifyCA,
"verify-full" => SslMode.VerifyFull,
_ => throw new ArgumentException("Not a valid SSL mode"),
};
}