From 4b6b3edc87723cf754bd57ae7294efa55de99c94 Mon Sep 17 00:00:00 2001 From: Thom Lamb Date: Wed, 27 May 2026 17:08:26 -0500 Subject: [PATCH] refactor(dedup): TryMatchTwoCharOperator helper in PG StatementReader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .../Statements/StatementReader.cs | 76 +++++++------------ 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/src/Strata.SqlTools.PostgreSql/Statements/StatementReader.cs b/src/Strata.SqlTools.PostgreSql/Statements/StatementReader.cs index 511f425..2320580 100644 --- a/src/Strata.SqlTools.PostgreSql/Statements/StatementReader.cs +++ b/src/Strata.SqlTools.PostgreSql/Statements/StatementReader.cs @@ -104,76 +104,39 @@ public class StatementReader : SqlServerStatementReader if (CurrentCharacter == '=') { - // Handle => operator (used in PostgreSQL for hstore and other operations) + // =, => (PostgreSQL hstore + other operations) MovePosition(); - if (CurrentCharacter == '>') - { - MovePosition(); - _currentToken = new Token(TokenType.Operator, "=>"); - return true; - } - // Single = is handled as regular operator + if (TryMatchTwoCharOperator('>', "=>")) return true; _currentToken = new Token(TokenType.Operator, "="); return true; } if (CurrentCharacter == '|') { - // Handle || concatenation operator + // |, || MovePosition(); - if (CurrentCharacter == '|') - { - MovePosition(); - _currentToken = new Token(TokenType.Operator, "||"); - return true; - } - // Single | is also an operator + if (TryMatchTwoCharOperator('|', "||")) return true; _currentToken = new Token(TokenType.Operator, "|"); return true; } if (CurrentCharacter == '<') { - // Handle <, <=, <>, << operators + // <, <=, <>, << MovePosition(); - if (CurrentCharacter == '=') - { - MovePosition(); - _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; - } + if (TryMatchTwoCharOperator('=', "<=")) return true; + if (TryMatchTwoCharOperator('>', "<>")) return true; + if (TryMatchTwoCharOperator('<', "<<")) return true; _currentToken = new Token(TokenType.Operator, "<"); return true; } if (CurrentCharacter == '>') { - // Handle >, >=, >> operators + // >, >=, >> MovePosition(); - if (CurrentCharacter == '=') - { - MovePosition(); - _currentToken = new Token(TokenType.Operator, ">="); - return true; - } - if (CurrentCharacter == '>') - { - MovePosition(); - _currentToken = new Token(TokenType.Operator, ">>"); - return true; - } + if (TryMatchTwoCharOperator('=', ">=")) return true; + if (TryMatchTwoCharOperator('>', ">>")) return true; _currentToken = new Token(TokenType.Operator, ">"); return true; } @@ -244,6 +207,23 @@ public class StatementReader : SqlServerStatementReader return stringValue.ToString(); } + + /// + /// If the position is currently sitting on , advances past it, + /// emits as the current Operator token, and returns + /// true. Otherwise leaves position untouched and returns false. Used by the + /// multi-character operator dispatch (e.g. </<=/<>/<<). + /// + private bool TryMatchTwoCharOperator(char nextChar, string twoCharOperator) + { + if (CurrentCharacter != nextChar) + { + return false; + } + MovePosition(); + _currentToken = new Token(TokenType.Operator, twoCharOperator); + return true; + } }