diff --git a/src/Carbunql/Analysis/AlterTableQueryParser.cs b/src/Carbunql/Analysis/AlterTableQueryParser.cs index 061bbd7a..0f35e1ee 100644 --- a/src/Carbunql/Analysis/AlterTableQueryParser.cs +++ b/src/Carbunql/Analysis/AlterTableQueryParser.cs @@ -3,23 +3,37 @@ namespace Carbunql.Analysis; +/// +/// Provides methods for parsing ALTER TABLE queries from SQL token streams. +/// public static class AlterTableQueryParser { + /// + /// Parses an ALTER TABLE query from SQL text. + /// + /// The SQL text to parse. + /// The parsed ALTER TABLE query. public static AlterTableQuery Parse(string text) { var r = new SqlTokenReader(text); - var q = Parse(r); + var query = Parse(r); + // If there are unparsed tokens remaining, it indicates an issue with parsing. if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } - return q; + return query; } + /// + /// Parses an ALTER TABLE query from a token reader. + /// + /// The token reader. + /// The parsed ALTER TABLE query. public static AlterTableQuery Parse(ITokenReader r) { return new AlterTableQuery(AlterTableClauseParser.Parse(r)); } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/BracketInnerTokenReader.cs b/src/Carbunql/Analysis/BracketInnerTokenReader.cs index 33d1122b..7ffecaf8 100644 --- a/src/Carbunql/Analysis/BracketInnerTokenReader.cs +++ b/src/Carbunql/Analysis/BracketInnerTokenReader.cs @@ -3,12 +3,27 @@ namespace Carbunql.Analysis; +/// +/// Token reader for reading tokens within brackets. +/// public class BracketInnerTokenReader : ITokenReader, IDisposable { + /// + /// Gets or sets the start symbol indicating the beginning of the bracket. + /// private string StartSymbol { get; init; } = "("; + /// + /// Gets or sets the end symbol indicating the end of the bracket. + /// private string EndSymbol { get; init; } = ")"; + /// + /// Initializes a new instance of the class with custom start and end symbols. + /// + /// The token reader to use. + /// The start symbol indicating the beginning of the bracket. + /// The end symbol indicating the end of the bracket. public BracketInnerTokenReader(ITokenReader r, string startSymbol, string endSymbol) { StartSymbol = startSymbol; @@ -20,6 +35,10 @@ public BracketInnerTokenReader(ITokenReader r, string startSymbol, string endSym RootBracketLevel = r.CurrentBracketLevel; } + /// + /// Initializes a new instance of the class with default start and end symbols. + /// + /// The token reader to use. public BracketInnerTokenReader(ITokenReader r) { r.Read(StartSymbol); @@ -28,14 +47,25 @@ public BracketInnerTokenReader(ITokenReader r) RootBracketLevel = r.CurrentBracketLevel; } + /// + /// Gets the token reader. + /// private ITokenReader Reader { get; set; } + /// + /// Gets the root bracket level. + /// private int RootBracketLevel { get; set; } + /// public int CurrentBracketLevel => Reader.CurrentBracketLevel; + /// + /// Gets or sets a value indicating whether the reading process is terminated. + /// private bool IsTerminated { get; set; } = false; + /// public string Peek() { if (IsTerminated) return string.Empty; @@ -43,6 +73,7 @@ public string Peek() return Reader.Peek(); } + /// public string Read() { if (IsTerminated) return string.Empty; @@ -55,16 +86,19 @@ public string Read() return token; } + /// public void Dispose() { Reader.Read(EndSymbol); } + /// public void RollBack() { throw new NotImplementedException(); } + /// public bool TryRead(string expect, [MaybeNullWhen(false)] out string token) { token = null; @@ -74,6 +108,6 @@ public bool TryRead(string expect, [MaybeNullWhen(false)] out string token) token = Read(); return true; } - return false; ; + return false; } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/CreateIndexQueryParser.cs b/src/Carbunql/Analysis/CreateIndexQueryParser.cs index c8d5de48..cd3c0ca6 100644 --- a/src/Carbunql/Analysis/CreateIndexQueryParser.cs +++ b/src/Carbunql/Analysis/CreateIndexQueryParser.cs @@ -4,8 +4,16 @@ namespace Carbunql.Analysis; +/// +/// Provides functionality to parse CREATE INDEX queries in SQL. +/// public static class CreateIndexQueryParser { + /// + /// Parses the specified CREATE INDEX query string. + /// + /// The CREATE INDEX query string. + /// The parsed CreateIndexQuery object. public static CreateIndexQuery Parse(string text) { var r = new SqlTokenReader(text); @@ -13,12 +21,17 @@ public static CreateIndexQuery Parse(string text) if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } return q; } + /// + /// Parses the CREATE INDEX query using the provided ITokenReader. + /// + /// The ITokenReader instance. + /// The parsed CreateIndexQuery object. public static CreateIndexQuery Parse(ITokenReader r) { var t = ParseAsCreateIndexCommand(r); @@ -30,6 +43,11 @@ public static CreateIndexQuery Parse(ITokenReader r) return t; } + /// + /// Parses the CREATE INDEX command. + /// + /// The ITokenReader instance. + /// The parsed CreateIndexQuery object. private static CreateIndexQuery ParseAsCreateIndexCommand(ITokenReader r) { var isUnique = false; @@ -44,7 +62,7 @@ private static CreateIndexQuery ParseAsCreateIndexCommand(ITokenReader r) } else { - throw new NotSupportedException($"Token:{token}"); + throw new NotSupportedException($"Invalid CREATE INDEX command. (Token: '{token}')"); } var indexName = string.Empty; @@ -61,6 +79,11 @@ private static CreateIndexQuery ParseAsCreateIndexCommand(ITokenReader r) }; } + /// + /// Parses the ON clause of the CREATE INDEX query. + /// + /// The ITokenReader instance. + /// The parsed IndexOnClause object. private static IndexOnClause ParseAsOnClause(ITokenReader r) { r.Read("on"); @@ -85,6 +108,11 @@ private static IndexOnClause ParseAsOnClause(ITokenReader r) return clause; } + /// + /// Parses the table name in the ON clause of the CREATE INDEX query. + /// + /// The ITokenReader instance. + /// The parsed table name and schema as a tuple. private static (string schema, string name) ParseAsTableName(ITokenReader r) { var token = r.Read(); @@ -104,4 +132,4 @@ private static (string schema, string name) ParseAsTableName(ITokenReader r) return (schema, name); } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/CreateTableQueryParser.cs b/src/Carbunql/Analysis/CreateTableQueryParser.cs index f8298248..69ce860f 100644 --- a/src/Carbunql/Analysis/CreateTableQueryParser.cs +++ b/src/Carbunql/Analysis/CreateTableQueryParser.cs @@ -3,8 +3,16 @@ namespace Carbunql.Analysis; +/// +/// Provides functionality to parse CREATE TABLE queries in SQL. +/// public static class CreateTableQueryParser { + /// + /// Parses the specified CREATE TABLE query string. + /// + /// The CREATE TABLE query string. + /// The parsed CreateTableQuery object. public static CreateTableQuery Parse(string text) { var r = new SqlTokenReader(text); @@ -12,14 +20,17 @@ public static CreateTableQuery Parse(string text) if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } return q; } - static IEnumerable ConstraintTokens => new[] { "primary key", "unique", "foreign key", "check", "not null", "constraint" }; - + /// + /// Parses the CREATE TABLE query using the provided ITokenReader. + /// + /// The ITokenReader instance. + /// The parsed CreateTableQuery object. public static CreateTableQuery Parse(ITokenReader r) { var t = ParseAsCreateTableCommand(r); @@ -56,6 +67,16 @@ public static CreateTableQuery Parse(ITokenReader r) return t; } + /// + /// The tokens representing constraints in CREATE TABLE queries. + /// + private static IEnumerable ConstraintTokens => new[] { "primary key", "unique", "foreign key", "check", "not null", "constraint" }; + + /// + /// Parses the CREATE TABLE command. + /// + /// The ITokenReader instance. + /// The parsed CreateTableQuery object. private static CreateTableQuery ParseAsCreateTableCommand(ITokenReader r) { var isTemporary = false; @@ -70,7 +91,7 @@ private static CreateTableQuery ParseAsCreateTableCommand(ITokenReader r) } else { - throw new NotSupportedException($"Token:{token}"); + throw new NotSupportedException($"Invalid CREATE TABLE command. (Token: '{token}')"); } token = r.Read(); @@ -89,4 +110,4 @@ private static CreateTableQuery ParseAsCreateTableCommand(ITokenReader r) return new CreateTableQuery(schema, table) { IsTemporary = isTemporary }; } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/DefinitionQuerySetParser.cs b/src/Carbunql/Analysis/DefinitionQuerySetParser.cs index 42c9e444..f95c99a6 100644 --- a/src/Carbunql/Analysis/DefinitionQuerySetParser.cs +++ b/src/Carbunql/Analysis/DefinitionQuerySetParser.cs @@ -4,8 +4,16 @@ namespace Carbunql.Analysis; +/// +/// Provides functionality to parse a set of definition queries in SQL. +/// public static class DefinitionQuerySetParser { + /// + /// Parses the specified definition query string and returns a list of DefinitionQuerySet objects. + /// + /// The definition query string. + /// A list of DefinitionQuerySet objects. public static DefinitionQuerySetList Parse(string text) { var r = new SqlTokenReader(text); @@ -15,7 +23,7 @@ public static DefinitionQuerySetList Parse(string text) { if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } if (!dic.ContainsKey(t.GetTableFullName())) @@ -38,7 +46,7 @@ public static DefinitionQuerySetList Parse(string text) } else { - throw new NotSupportedException(); + throw new NotSupportedException($"Unsupported query type: {t.GetType().Name}"); } } @@ -47,6 +55,12 @@ public static DefinitionQuerySetList Parse(string text) return lst; } + /// + /// Tries to parse the next query from the token reader. + /// + /// The SqlTokenReader instance. + /// The parsed table object. + /// True if parsing is successful, otherwise false. private static bool TryParse(SqlTokenReader r, [MaybeNullWhen(false)] out ITable t) { t = default; diff --git a/src/Carbunql/Analysis/ITokenReader.cs b/src/Carbunql/Analysis/ITokenReader.cs index e96a6730..8871254c 100644 --- a/src/Carbunql/Analysis/ITokenReader.cs +++ b/src/Carbunql/Analysis/ITokenReader.cs @@ -3,34 +3,71 @@ namespace Carbunql.Analysis; +/// +/// Represents a token reader interface for reading tokens. +/// public interface ITokenReader { + /// + /// Peeks the next token without consuming it. + /// + /// The next token. string Peek(); + /// + /// Reads the next token and consumes it. + /// + /// The read token. string Read(); + /// + /// Rolls back the last read token. + /// void RollBack(); + /// + /// Tries to read the next token and match it with the expected token. + /// + /// The expected token. + /// The actual token read. + /// True if the actual token matches the expected token, otherwise false. bool TryRead(string expect, [MaybeNullWhen(false)] out string token); + /// + /// Gets the current bracket level. + /// int CurrentBracketLevel { get; } } +/// +/// Provides extension methods for the ITokenReader interface. +/// public static class ITokenReaderExtension { + /// + /// Reads the next token and throws an exception if it does not match the expected token. + /// + /// The ITokenReader instance. + /// The expected token. + /// The read token. public static string Read(this ITokenReader source, string expect) { var s = source.Read(); - if (string.IsNullOrEmpty(s)) throw new SyntaxException($"expect '{expect}', actual is empty"); - if (!s.IsEqualNoCase(expect)) throw new SyntaxException($"expect '{expect}', actual '{s}'"); + if (string.IsNullOrEmpty(s)) throw new SyntaxException($"Expected '{expect}', but the actual token is empty."); + if (!s.IsEqualNoCase(expect)) throw new SyntaxException($"Expected '{expect}', but the actual token is '{s}'."); return s; } - // TODO TryRead + /// + /// Reads the next token if it matches the expected token, otherwise returns null. + /// + /// The ITokenReader instance. + /// The expected token. + /// The read token if it matches the expected token, otherwise null. public static string? ReadOrDefault(this ITokenReader source, string expect) { var s = source.Peek(); if (!s.IsEqualNoCase(expect)) return null; return source.Read(); } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/InsertQueryParser.cs b/src/Carbunql/Analysis/InsertQueryParser.cs index 8db7643d..b5f3e904 100644 --- a/src/Carbunql/Analysis/InsertQueryParser.cs +++ b/src/Carbunql/Analysis/InsertQueryParser.cs @@ -4,8 +4,16 @@ namespace Carbunql.Analysis; +/// +/// Provides functionality to parse INSERT queries in SQL. +/// public static class InsertQueryParser { + /// + /// Parses the specified INSERT query string. + /// + /// The INSERT query string. + /// The parsed InsertQuery object. public static InsertQuery Parse(string text) { var r = new SqlTokenReader(text); @@ -14,12 +22,17 @@ public static InsertQuery Parse(string text) if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } return iq; } + /// + /// Parses the INSERT query using the provided ITokenReader. + /// + /// The ITokenReader instance. + /// The parsed InsertQuery object. internal static InsertQuery Parse(ITokenReader r) { if (r.Peek().IsEqualNoCase("with")) @@ -44,9 +57,14 @@ internal static InsertQuery Parse(ITokenReader r) { return ParseMain(r); } - throw new NotSupportedException(); + throw new NotSupportedException("Unsupported INSERT query format."); } + /// + /// Parses the main part of the INSERT query. + /// + /// The ITokenReader instance. + /// The parsed InsertQuery object. internal static InsertQuery ParseMain(ITokenReader r) { var iq = new InsertQuery(); @@ -61,4 +79,4 @@ internal static InsertQuery ParseMain(ITokenReader r) return iq; } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/LexReader.cs b/src/Carbunql/Analysis/LexReader.cs index ac96019f..4d919dcb 100644 --- a/src/Carbunql/Analysis/LexReader.cs +++ b/src/Carbunql/Analysis/LexReader.cs @@ -25,8 +25,6 @@ public LexReader(string text) private int TextLength { get; init; } - //private bool IsEndOfText => TextLength <= Index; - public bool TryPeek(char expect) { if (TryPeekChar(0, out var c) && c == expect) diff --git a/src/Carbunql/Analysis/QueryCommandableParser.cs b/src/Carbunql/Analysis/QueryCommandableParser.cs index 827cc3d9..dfa0dae2 100644 --- a/src/Carbunql/Analysis/QueryCommandableParser.cs +++ b/src/Carbunql/Analysis/QueryCommandableParser.cs @@ -4,8 +4,16 @@ namespace Carbunql.Analysis; +/// +/// Provides functionality to parse various SQL query commands. +/// public static class QueryCommandableParser { + /// + /// Parses the specified SQL query string. + /// + /// The SQL query string. + /// The parsed QueryCommandable object. public static IQueryCommandable Parse(string text) { var r = new SqlTokenReader(text); @@ -13,12 +21,17 @@ public static IQueryCommandable Parse(string text) if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } return q; } + /// + /// Parses the SQL query using the provided ITokenReader. + /// + /// The ITokenReader instance. + /// The parsed QueryCommandable object. public static IQueryCommandable Parse(ITokenReader r) { var token = r.Peek(); @@ -52,7 +65,7 @@ public static IQueryCommandable Parse(ITokenReader r) return iq; } - throw new NotSupportedException(); + throw new NotSupportedException($"Unsupported query command: '{token}'"); } else { @@ -66,7 +79,7 @@ public static IQueryCommandable Parse(ITokenReader r) if (token.IsEqualNoCase("alter table")) return AlterTableQueryParser.Parse(r); - throw new NotSupportedException(); + throw new NotSupportedException($"Unsupported query command: '{token}'"); } } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/QueryParser.cs b/src/Carbunql/Analysis/QueryParser.cs index 99a7fe72..4a1296d9 100644 --- a/src/Carbunql/Analysis/QueryParser.cs +++ b/src/Carbunql/Analysis/QueryParser.cs @@ -3,8 +3,16 @@ namespace Carbunql.Analysis; +/// +/// Provides functionality to parse various SQL queries. +/// public static class QueryParser { + /// + /// Parses the specified SQL query string. + /// + /// The SQL query string. + /// The parsed ReadQuery object. public static IReadQuery Parse(string text) { var r = new SqlTokenReader(text); @@ -12,12 +20,17 @@ public static IReadQuery Parse(string text) if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } return q; } + /// + /// Parses the SQL query using the provided ITokenReader. + /// + /// The ITokenReader instance. + /// The parsed ReadQuery object. public static IReadQuery Parse(ITokenReader r) { var token = r.Peek(); @@ -25,6 +38,6 @@ public static IReadQuery Parse(ITokenReader r) if (token.IsEqualNoCase("select")) return SelectQueryParser.Parse(r); if (token.IsEqualNoCase("values")) return ValuesQueryParser.Parse(r); - throw new NotSupportedException($"Token:{r.Peek()}"); + throw new NotSupportedException($"Unsupported token: '{r.Peek()}'"); } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/ReadQueryParser.cs b/src/Carbunql/Analysis/ReadQueryParser.cs index 83319971..2fdfc470 100644 --- a/src/Carbunql/Analysis/ReadQueryParser.cs +++ b/src/Carbunql/Analysis/ReadQueryParser.cs @@ -2,19 +2,32 @@ namespace Carbunql.Analysis; +/// +/// Provides functionality to parse READ queries in SQL. +/// public static class ReadQueryParser { + /// + /// Parses the specified SQL query string. + /// + /// The SQL query string. + /// The parsed ReadQuery object. public static ReadQuery Parse(string text) { var r = new SqlTokenReader(text); return Parse(r); } + /// + /// Parses the READ query using the provided ITokenReader. + /// + /// The ITokenReader instance. + /// The parsed ReadQuery object. public static ReadQuery Parse(ITokenReader r) { if (r.Peek().IsEqualNoCase("select")) return SelectQueryParser.Parse(r); if (r.Peek().IsEqualNoCase("values")) return ValuesQueryParser.Parse(r); - throw new NotSupportedException(r.Peek()); + throw new NotSupportedException($"Unsupported token: '{r.Peek()}'"); } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/SelectQueryParser.cs b/src/Carbunql/Analysis/SelectQueryParser.cs index 5494acf4..b17265d2 100644 --- a/src/Carbunql/Analysis/SelectQueryParser.cs +++ b/src/Carbunql/Analysis/SelectQueryParser.cs @@ -4,8 +4,16 @@ namespace Carbunql.Analysis; +/// +/// Provides functionality to parse SELECT queries in SQL. +/// public static class SelectQueryParser { + /// + /// Parses the specified SQL query string as a SELECT query. + /// + /// The SQL query string. + /// The parsed SelectQuery object. public static SelectQuery Parse(string text) { var r = new SqlTokenReader(text); @@ -15,7 +23,7 @@ public static SelectQuery Parse(string text) if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } return sq; @@ -28,6 +36,11 @@ public static SelectQuery ParseAsInner(ITokenReader r) return v; } + /// + /// Parses the SELECT query using the provided ITokenReader. + /// + /// The ITokenReader instance. + /// The parsed SelectQuery object. internal static SelectQuery Parse(ITokenReader r) { var sq = ParseMain(r); @@ -44,6 +57,11 @@ internal static SelectQuery Parse(ITokenReader r) return sq; } + /// + /// Parses the main part of the SELECT query using the provided ITokenReader. + /// + /// The ITokenReader instance. + /// The parsed SelectQuery object. private static SelectQuery ParseMain(ITokenReader r) { var sq = new SelectQuery(); @@ -84,11 +102,13 @@ private static SelectQuery ParseMain(ITokenReader r) if (r.ReadOrDefault("having") == null) return null; return HavingClauseParser.Parse(r); } + private static WindowClause? ParseWindowOrDefault(ITokenReader r) { if (r.ReadOrDefault("window") == null) return null; return WindowClauseParser.Parse(r); } + private static OrderClause? ParseOrderOrDefault(ITokenReader r) { if (r.ReadOrDefault("order by") == null) return null; @@ -100,4 +120,4 @@ private static SelectQuery ParseMain(ITokenReader r) if (r.ReadOrDefault("limit") == null) return null; return LimitClauseParser.Parse(r); } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/Serializer.cs b/src/Carbunql/Analysis/Serializer.cs index d772fbdb..4dc3957f 100644 --- a/src/Carbunql/Analysis/Serializer.cs +++ b/src/Carbunql/Analysis/Serializer.cs @@ -2,18 +2,37 @@ namespace Carbunql.Analysis; +/// +/// Provides serialization and deserialization functionality for objects implementing the IReadQuery interface. +/// public static class Serializer { + /// + /// Serializes the specified IReadQuery object into a byte array. + /// + /// The IReadQuery object to serialize. + /// The serialized byte array. public static byte[] Serialize(IReadQuery query) { return MessagePackSerializer.Serialize(query); } + /// + /// Deserializes a byte array into an object implementing the IReadQuery interface. + /// + /// The byte array to deserialize. + /// The deserialized object. public static IReadQuery Deserialize(byte[] json) { return MessagePackSerializer.Deserialize(json); } + /// + /// Deserializes a byte array into an object of the specified type implementing the IReadQuery interface. + /// + /// The type of object to deserialize into, which must implement the IReadQuery interface. + /// The byte array to deserialize. + /// The deserialized object of the specified type. public static T Deserialize(byte[] json) where T : IReadQuery { return (T)MessagePackSerializer.Deserialize(json); diff --git a/src/Carbunql/Analysis/SqlLexReader.cs b/src/Carbunql/Analysis/SqlLexReader.cs index dec81e49..a89f408b 100644 --- a/src/Carbunql/Analysis/SqlLexReader.cs +++ b/src/Carbunql/Analysis/SqlLexReader.cs @@ -4,31 +4,42 @@ namespace Carbunql.Analysis; /// -/// LexReader class with SQL comment disabling. +/// LexReader class extended for parsing SQL with comment handling. /// public class SqlLexReader : LexReader { + /// + /// Constructor for the SqlLexReader class. + /// + /// The SQL text to be parsed. public SqlLexReader(string text) : base(text) { } + /// + /// Collection of tokens indicating SQL comments. + /// private static IEnumerable CommentTokens { get; set; } = new string[] { "--", "/*" }; + /// + /// Reads the next lexeme, skipping any SQL comments. + /// + /// The next lexeme after skipping any comments. protected override string ReadLex() { var lex = base.ReadLex(); - //skip comment block + // Skip comment blocks while (lex.IsEqualNoCase(CommentTokens)) { if (lex == "--") { - //line comment + // Line comment ReadUntilLineEnd(); } else { - //block comment + // Block comment ReadUntilCloseBlockComment(); } lex = base.ReadLex(); @@ -37,6 +48,10 @@ protected override string ReadLex() return lex; } + /// + /// Reads characters until the closing symbol of a block comment is found. + /// + /// The content of the block comment. private string ReadUntilCloseBlockComment() { var err = "Block comment is not closed"; diff --git a/src/Carbunql/Analysis/SqlTokenReader.cs b/src/Carbunql/Analysis/SqlTokenReader.cs index 37eb0da0..e7b62e20 100644 --- a/src/Carbunql/Analysis/SqlTokenReader.cs +++ b/src/Carbunql/Analysis/SqlTokenReader.cs @@ -4,14 +4,23 @@ namespace Carbunql.Analysis; /// -/// Class for reading tokens. Reading concludes when an SQL terminator is encountered. +/// Class for reading SQL tokens. Reading concludes when an SQL terminator is encountered. /// public class SqlTokenReader : TokenReader, ITokenReader { + /// + /// Constructor for the SqlTokenReader class. + /// + /// The SQL text to be read. public SqlTokenReader(string text) : base(text) { } + /// + /// Tries to read the next SQL query if the current token is an SQL terminator. + /// + /// The next token after peeking. + /// True if the next token is available, false otherwise. public bool TryReadNextQuery([MaybeNullWhen(false)] out string peekToken) { peekToken = null; @@ -28,18 +37,30 @@ public bool TryReadNextQuery([MaybeNullWhen(false)] out string peekToken) return true; } + /// + /// Indicates whether the reading process is terminated. + /// private bool IsTeminated { get; set; } = false; + /// + /// Cache for storing the current token. + /// private string Cache { get; set; } = string.Empty; + /// + /// Cache for storing the token for rollback. + /// private string RollBackCache { get; set; } = string.Empty; + /// + /// Cache for storing the previously read token. + /// private string ReadedCache { get; set; } = string.Empty; /// - /// Method to peek at a token. + /// Peeks at the next token. /// - /// The token. + /// The next token. public string Peek() { if (IsTeminated) return string.Empty; @@ -59,6 +80,9 @@ public string Peek() return Cache; } + /// + /// Commits the current token and marks it as read. + /// private void Commit() { if (!string.IsNullOrEmpty(Cache)) @@ -69,9 +93,9 @@ private void Commit() } /// - /// Method to read a token. + /// Reads the next token. /// - /// The token. + /// The next token. public override string Read() { if (IsTeminated) return string.Empty; @@ -87,6 +111,9 @@ public override string Read() return token; } + /// + /// Rolls back the read process to the last token. + /// public void RollBack() { if (string.IsNullOrEmpty(RollBackCache)) throw new Exception("fail"); @@ -96,6 +123,12 @@ public void RollBack() RollBackCache = string.Empty; } + /// + /// Attempts to read the specified token. + /// + /// The expected token. + /// The read token. + /// True if the expected token is read, false otherwise. public bool TryRead(string expect, [MaybeNullWhen(false)] out string token) { token = null; @@ -107,4 +140,4 @@ public bool TryRead(string expect, [MaybeNullWhen(false)] out string token) } return false; } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/SyntaxException.cs b/src/Carbunql/Analysis/SyntaxException.cs index 915c7f92..6e65bc71 100644 --- a/src/Carbunql/Analysis/SyntaxException.cs +++ b/src/Carbunql/Analysis/SyntaxException.cs @@ -1,6 +1,13 @@ namespace Carbunql.Analysis; +/// +/// Represents an exception that is thrown when a syntax error occurs. +/// public class SyntaxException : Exception { + /// + /// Initializes a new instance of the SyntaxException class with a specified error message. + /// + /// The message that describes the error. public SyntaxException(string message) : base(message) { } -} \ No newline at end of file +} diff --git a/src/Carbunql/Analysis/TokenReader.cs b/src/Carbunql/Analysis/TokenReader.cs index 2e531312..1053f1b4 100644 --- a/src/Carbunql/Analysis/TokenReader.cs +++ b/src/Carbunql/Analysis/TokenReader.cs @@ -3,8 +3,15 @@ namespace Carbunql.Analysis; +/// +/// Abstract class for reading tokens. +/// public abstract class TokenReader { + /// + /// Initializes a new instance of the TokenReader class with the specified text. + /// + /// The text to be read. public TokenReader(string text) { Reader = new SqlLexReader(text); @@ -22,8 +29,15 @@ public TokenReader(string text) private SqlLexReader Reader { get; set; } + /// + /// Gets or sets the current bracket level. + /// public int CurrentBracketLevel { get; private set; } = 0; + /// + /// Reads the next token. + /// + /// The next token. public virtual string Read() { var lex = Reader.Read(); diff --git a/src/Carbunql/Analysis/ValuesQueryParser.cs b/src/Carbunql/Analysis/ValuesQueryParser.cs index 170f530e..8e26431f 100644 --- a/src/Carbunql/Analysis/ValuesQueryParser.cs +++ b/src/Carbunql/Analysis/ValuesQueryParser.cs @@ -4,8 +4,16 @@ namespace Carbunql.Analysis; +/// +/// Static class for parsing VALUES queries. +/// public static class ValuesQueryParser { + /// + /// Parses a VALUES query from the specified text. + /// + /// The text containing the VALUES query. + /// The parsed VALUES query. public static ValuesQuery Parse(string text) { var r = new SqlTokenReader(text); @@ -13,12 +21,17 @@ public static ValuesQuery Parse(string text) if (!r.Peek().IsEndToken()) { - throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens.(token:'{r.Peek()}')"); + throw new NotSupportedException($"Parsing terminated despite the presence of unparsed tokens. (Token: '{r.Peek()}')"); } return q; } + /// + /// Parses a VALUES query from the specified token reader. + /// + /// The token reader. + /// The parsed VALUES query. internal static ValuesQuery Parse(ITokenReader r) { r.Read("values"); @@ -48,4 +61,4 @@ internal static ValuesQuery Parse(ITokenReader r) if (r.ReadOrDefault("limit") == null) return null; return LimitClauseParser.Parse(r); } -} \ No newline at end of file +} diff --git a/src/Carbunql/Clauses/IndexOnClause.cs b/src/Carbunql/Clauses/IndexOnClause.cs index 24eafeff..a77f1e54 100644 --- a/src/Carbunql/Clauses/IndexOnClause.cs +++ b/src/Carbunql/Clauses/IndexOnClause.cs @@ -7,6 +7,7 @@ public class IndexOnClause : QueryCommandCollection, ITable { public IndexOnClause(string table) { + Schema = string.Empty; Table = table; } @@ -22,7 +23,8 @@ public IndexOnClause(ITable t) Table = t.Table; } - public string Schema { get; init; } = null; + + public string Schema { get; init; } public string Table { get; init; } diff --git a/test/Carbunql.Analysis.Test/SelectQueryParserTest.cs b/test/Carbunql.Analysis.Test/SelectQueryParserTest.cs index def80529..100216a9 100644 --- a/test/Carbunql.Analysis.Test/SelectQueryParserTest.cs +++ b/test/Carbunql.Analysis.Test/SelectQueryParserTest.cs @@ -669,7 +669,7 @@ public void ParserError() var item = QueryParser.Parse(text) as SelectQuery; }); - Assert.Equal("Parsing terminated despite the presence of unparsed tokens.(token:'c')", e.Message); + Assert.Equal("Parsing terminated despite the presence of unparsed tokens. (Token: 'c')", e.Message); } [Fact] diff --git a/test/Carbunql.Annotation.Test/Book.cs b/test/Carbunql.Annotation.Test/Book.cs index 7a043146..43bc8f90 100644 --- a/test/Carbunql.Annotation.Test/Book.cs +++ b/test/Carbunql.Annotation.Test/Book.cs @@ -1,3 +1 @@ -using Carbunql.Annotations; - -namespace Carbunql.Annotation.Test; +namespace Carbunql.Annotation.Test;