refactor(dedup): TryMatchTwoCharOperator helper in PG StatementReader

The PostgreSql-specific operator dispatch in
`StatementReader.TryHandleAdditionalCharacter` had four similar 4-7
line blocks (each handling a single-char operator with one or more
two-char variants — \<, \>, \|, \=). Sonar flagged it as a
self-duplication.

Extract a small `TryMatchTwoCharOperator(char, string)` helper that
encapsulates the "if next char matches, advance and emit two-char
operator" pattern. Each operator handler now reads as a small list:

    if (CurrentCharacter == '<')
    {
        MovePosition();
        if (TryMatchTwoCharOperator('=', "<=")) return true;
        if (TryMatchTwoCharOperator('>', "<>")) return true;
        if (TryMatchTwoCharOperator('<', "<<")) return true;
        _currentToken = new Token(TokenType.Operator, "<");
        return true;
    }

Reverses my earlier "extracting would obscure intent" call after
re-reading — the helper-based form actually surfaces the intent
("two-char operator dispatch") more clearly than the original.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Thom Lamb
2026-05-27 17:08:26 -05:00
co-authored by Claude Opus 4.7
parent 85cc79d5a1
commit 4b6b3edc87
@@ -104,76 +104,39 @@ public class StatementReader : SqlServerStatementReader
if (CurrentCharacter == '=') if (CurrentCharacter == '=')
{ {
// Handle => operator (used in PostgreSQL for hstore and other operations) // =, => (PostgreSQL hstore + other operations)
MovePosition(); MovePosition();
if (CurrentCharacter == '>') if (TryMatchTwoCharOperator('>', "=>")) return true;
{
MovePosition();
_currentToken = new Token(TokenType.Operator, "=>");
return true;
}
// Single = is handled as regular operator
_currentToken = new Token(TokenType.Operator, "="); _currentToken = new Token(TokenType.Operator, "=");
return true; return true;
} }
if (CurrentCharacter == '|') if (CurrentCharacter == '|')
{ {
// Handle || concatenation operator // |, ||
MovePosition(); MovePosition();
if (CurrentCharacter == '|') if (TryMatchTwoCharOperator('|', "||")) return true;
{
MovePosition();
_currentToken = new Token(TokenType.Operator, "||");
return true;
}
// Single | is also an operator
_currentToken = new Token(TokenType.Operator, "|"); _currentToken = new Token(TokenType.Operator, "|");
return true; return true;
} }
if (CurrentCharacter == '<') if (CurrentCharacter == '<')
{ {
// Handle <, <=, <>, << operators // <, <=, <>, <<
MovePosition(); MovePosition();
if (CurrentCharacter == '=') if (TryMatchTwoCharOperator('=', "<=")) return true;
{ if (TryMatchTwoCharOperator('>', "<>")) return true;
MovePosition(); if (TryMatchTwoCharOperator('<', "<<")) return true;
_currentToken = new Token(TokenType.Operator, "<=");
return true;
}
if (CurrentCharacter == '>')
{
MovePosition();
_currentToken = new Token(TokenType.Operator, "<>");
return true;
}
if (CurrentCharacter == '<')
{
MovePosition();
_currentToken = new Token(TokenType.Operator, "<<");
return true;
}
_currentToken = new Token(TokenType.Operator, "<"); _currentToken = new Token(TokenType.Operator, "<");
return true; return true;
} }
if (CurrentCharacter == '>') if (CurrentCharacter == '>')
{ {
// Handle >, >=, >> operators // >, >=, >>
MovePosition(); MovePosition();
if (CurrentCharacter == '=') if (TryMatchTwoCharOperator('=', ">=")) return true;
{ if (TryMatchTwoCharOperator('>', ">>")) return true;
MovePosition();
_currentToken = new Token(TokenType.Operator, ">=");
return true;
}
if (CurrentCharacter == '>')
{
MovePosition();
_currentToken = new Token(TokenType.Operator, ">>");
return true;
}
_currentToken = new Token(TokenType.Operator, ">"); _currentToken = new Token(TokenType.Operator, ">");
return true; return true;
} }
@@ -244,6 +207,23 @@ public class StatementReader : SqlServerStatementReader
return stringValue.ToString(); return stringValue.ToString();
} }
/// <summary>
/// If the position is currently sitting on <paramref name="nextChar"/>, advances past it,
/// emits <paramref name="twoCharOperator"/> as the current Operator token, and returns
/// <c>true</c>. Otherwise leaves position untouched and returns <c>false</c>. Used by the
/// multi-character operator dispatch (e.g. <c>&lt;</c>/<c>&lt;=</c>/<c>&lt;&gt;</c>/<c>&lt;&lt;</c>).
/// </summary>
private bool TryMatchTwoCharOperator(char nextChar, string twoCharOperator)
{
if (CurrentCharacter != nextChar)
{
return false;
}
MovePosition();
_currentToken = new Token(TokenType.Operator, twoCharOperator);
return true;
}
} }