Expiriments with AvaloniaEdit and tracking document changes
This commit is contained in:
parent
29a141a971
commit
6325409d25
53 changed files with 643 additions and 627 deletions
|
|
@ -1,9 +1,11 @@
|
|||
namespace pgLabII.PgUtils.ConnectionStrings;
|
||||
using FluentResults;
|
||||
|
||||
namespace pgLabII.PgUtils.ConnectionStrings;
|
||||
|
||||
public interface IPqConnectionStringTokenizer
|
||||
{
|
||||
bool Eof { get; }
|
||||
string GetKeyword();
|
||||
void ConsumeEquals();
|
||||
string GetValue();
|
||||
bool IsEof { get; }
|
||||
Result<string> GetKeyword();
|
||||
Result ConsumeEquals();
|
||||
Result<string> GetValue();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace pgLabII.PgUtils.ConnectionStrings.Pq;
|
||||
|
||||
enum Keyword
|
||||
{
|
||||
Host,
|
||||
HostAddr,
|
||||
Port,
|
||||
DatabaseName,
|
||||
UserName,
|
||||
Password,
|
||||
}
|
||||
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using FluentResults;
|
||||
using Npgsql;
|
||||
|
||||
namespace pgLabII.PgUtils.ConnectionStrings;
|
||||
|
||||
/// <summary>
|
||||
/// Parser for converting a libpq style connection string into a dictionary of key value pairs
|
||||
/// </summary>
|
||||
public ref struct PqConnectionStringParser
|
||||
{
|
||||
// Note possible keywords
|
||||
|
|
@ -51,64 +55,38 @@ public ref struct PqConnectionStringParser
|
|||
).Parse();
|
||||
}
|
||||
|
||||
private readonly IPqConnectionStringTokenizer tokenizer;
|
||||
private readonly Dictionary<string, string> result = new();
|
||||
private readonly IPqConnectionStringTokenizer _tokenizer;
|
||||
private readonly Dictionary<string, string> _result = new();
|
||||
|
||||
public PqConnectionStringParser(IPqConnectionStringTokenizer tokenizer)
|
||||
{
|
||||
this.tokenizer = tokenizer;
|
||||
this._tokenizer = tokenizer;
|
||||
}
|
||||
|
||||
public IDictionary<string, string> Parse()
|
||||
{
|
||||
result.Clear();
|
||||
_result.Clear();
|
||||
|
||||
while (!tokenizer.Eof)
|
||||
while (!_tokenizer.IsEof)
|
||||
ParsePair();
|
||||
|
||||
return result;
|
||||
return _result;
|
||||
}
|
||||
|
||||
private void ParsePair()
|
||||
private Result ParsePair()
|
||||
{
|
||||
string kw = tokenizer.GetKeyword();
|
||||
tokenizer.ConsumeEquals();
|
||||
string v = tokenizer.GetValue();
|
||||
result.Add(kw, v);
|
||||
//switch (kw)
|
||||
//{
|
||||
// case "host":
|
||||
// case "hostaddr":
|
||||
// result.Host = v.ToString();
|
||||
// break;
|
||||
// case "port":
|
||||
// result.Port = int.Parse(v);
|
||||
// break;
|
||||
// case "dbname":
|
||||
// result.Database = v.ToString();
|
||||
// break;
|
||||
// case "user":
|
||||
// result.Username = v.ToString();
|
||||
// break;
|
||||
// case "password":
|
||||
// result.Password = v.ToString();
|
||||
// break;
|
||||
// case "connect_timeout":
|
||||
// result.Timeout = int.Parse(v);
|
||||
// break;
|
||||
// case "application_name":
|
||||
// result.ApplicationName = v.ToString();
|
||||
// break;
|
||||
// case "options":
|
||||
// result.Options = v.ToString();
|
||||
// break;
|
||||
// case "sslmode":
|
||||
// result.SslMode = ToSslMode(v);
|
||||
// break;
|
||||
// default:
|
||||
// // Todo what do we do with values we do not support/recognize?
|
||||
// break;
|
||||
//}
|
||||
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<char> v)
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
namespace pgLabII.PgUtils.ConnectionStrings;
|
||||
|
||||
public class PqConnectionStringParserException : Exception
|
||||
{
|
||||
public PqConnectionStringParserException()
|
||||
{
|
||||
}
|
||||
|
||||
public PqConnectionStringParserException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PqConnectionStringParserException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Text;
|
||||
using FluentResults;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace pgLabII.PgUtils.ConnectionStrings;
|
||||
|
|
@ -8,7 +9,7 @@ public class PqConnectionStringTokenizer : IPqConnectionStringTokenizer
|
|||
private readonly string input;
|
||||
private int position = 0;
|
||||
|
||||
public bool Eof
|
||||
public bool IsEof
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
@ -23,37 +24,38 @@ public class PqConnectionStringTokenizer : IPqConnectionStringTokenizer
|
|||
position = 0;
|
||||
}
|
||||
|
||||
public string GetKeyword()
|
||||
public Result<string> GetKeyword()
|
||||
{
|
||||
if (Eof)
|
||||
throw new PqConnectionStringParserException($"Unexpected end of file was expecting a keyword at position {position}");
|
||||
if (IsEof)
|
||||
return Result.Fail($"Unexpected end of file was expecting a keyword at position {position}");
|
||||
|
||||
return GetString(forKeyword: true);
|
||||
}
|
||||
|
||||
public void ConsumeEquals()
|
||||
public Result ConsumeEquals()
|
||||
{
|
||||
ConsumeWhitespace();
|
||||
if (position < input.Length && input[position] == '=')
|
||||
{
|
||||
position++;
|
||||
return Result.Ok();
|
||||
}
|
||||
else
|
||||
throw new PqConnectionStringParserException($"Was expecting '=' after keyword at position {position}");
|
||||
return Result.Fail($"Was expecting '=' after keyword at position {position}");
|
||||
}
|
||||
|
||||
public string GetValue()
|
||||
public Result<string> GetValue()
|
||||
{
|
||||
if (Eof)
|
||||
throw new PqConnectionStringParserException($"Unexpected end of file was expecting a keyword at position {position}");
|
||||
if (IsEof)
|
||||
return Result.Fail($"Unexpected end of file was expecting a keyword at position {position}");
|
||||
|
||||
return GetString(forKeyword: false);
|
||||
}
|
||||
|
||||
private string GetString(bool forKeyword)
|
||||
private Result<string> GetString(bool forKeyword)
|
||||
{
|
||||
if (forKeyword && input[position] == '=')
|
||||
throw new PqConnectionStringParserException($"Unexpected '=' was expecting keyword at position {position}");
|
||||
return Result.Fail($"Unexpected '=' was expecting keyword at position {position}");
|
||||
|
||||
if (input[position] == '\'')
|
||||
return ParseQuotedText();
|
||||
|
|
@ -75,7 +77,7 @@ public class PqConnectionStringTokenizer : IPqConnectionStringTokenizer
|
|||
return input.Substring(start, position - start);
|
||||
}
|
||||
|
||||
private string ParseQuotedText()
|
||||
private Result<string> ParseQuotedText()
|
||||
{
|
||||
bool escape = false;
|
||||
StringBuilder sb = new();
|
||||
|
|
@ -93,7 +95,7 @@ public class PqConnectionStringTokenizer : IPqConnectionStringTokenizer
|
|||
escape = false;
|
||||
break;
|
||||
default:
|
||||
throw new PqConnectionStringParserException($"Invalid escape sequence at position {position}");
|
||||
return Result.Fail($"Invalid escape sequence at position {position}");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -113,6 +115,6 @@ public class PqConnectionStringTokenizer : IPqConnectionStringTokenizer
|
|||
}
|
||||
}
|
||||
}
|
||||
throw new PqConnectionStringParserException($"Missing end quote on value starting at {start}");
|
||||
return Result.Fail($"Missing end quote on value starting at {start}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentResults" />
|
||||
<PackageReference Include="Npgsql" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue