diff options
author | vitya-smirnov <vitya-smirnov@yandex-team.com> | 2025-06-26 16:37:42 +0300 |
---|---|---|
committer | vitya-smirnov <vitya-smirnov@yandex-team.com> | 2025-06-26 17:24:30 +0300 |
commit | 633c9e434ac33037ba01b36a8f2937034903fe9f (patch) | |
tree | e620cfd34faf4354d3d25d05b564def09445118a /yql/essentials/sql/v1/complete | |
parent | e99c3783c2970a70b35b1c67ba177fe940936aae (diff) | |
download | ydb-633c9e434ac33037ba01b36a8f2937034903fe9f.tar.gz |
YQL-19747: Refactor SQL completion engine
Some refactorings to compact the code:
- YQL-19747: Pass TParsedInput to visitor
- YQL-19747: Add TParsedInput
- YQL-19747: Cosmetics
- YQL-19747: Refactor configuration
- YQL-19747: Refactor name to candidate mapping
commit_hash:44dfe7dc7bcc627ef9c20696077f2d962a3014f6
Diffstat (limited to 'yql/essentials/sql/v1/complete')
24 files changed, 336 insertions, 297 deletions
diff --git a/yql/essentials/sql/v1/complete/analysis/global/column.cpp b/yql/essentials/sql/v1/complete/analysis/global/column.cpp index 9a9fd7f18a2..5cecb40fb13 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/column.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/column.cpp @@ -220,8 +220,8 @@ namespace NSQLComplete { class TVisitor: public TSQLv1NarrowingVisitor { public: - TVisitor(antlr4::TokenStream* tokens, size_t cursorPosition) - : TSQLv1NarrowingVisitor(tokens, cursorPosition) + TVisitor(const TParsedInput& input) + : TSQLv1NarrowingVisitor(input) { } @@ -247,12 +247,9 @@ namespace NSQLComplete { } // namespace - TMaybe<TColumnContext> InferColumnContext( - SQLv1::Sql_queryContext* ctx, - antlr4::TokenStream* tokens, - size_t cursorPosition) { + TMaybe<TColumnContext> InferColumnContext(TParsedInput input) { // TODO: add utility `auto ToMaybe<T>(std::any any) -> TMaybe<T>` - std::any result = TVisitor(tokens, cursorPosition).visit(ctx); + std::any result = TVisitor(input).visit(input.SqlQuery); if (!result.has_value()) { return Nothing(); } diff --git a/yql/essentials/sql/v1/complete/analysis/global/column.h b/yql/essentials/sql/v1/complete/analysis/global/column.h index 790dbee1d15..306626ba061 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/column.h +++ b/yql/essentials/sql/v1/complete/analysis/global/column.h @@ -1,13 +1,10 @@ #pragma once #include "global.h" -#include "parse_tree.h" +#include "input.h" namespace NSQLComplete { - TMaybe<TColumnContext> InferColumnContext( - SQLv1::Sql_queryContext* ctx, - antlr4::TokenStream* tokens, - size_t cursorPosition); + TMaybe<TColumnContext> InferColumnContext(TParsedInput input); } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/analysis/global/function.cpp b/yql/essentials/sql/v1/complete/analysis/global/function.cpp index 16140bc614e..0bd9740796a 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/function.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/function.cpp @@ -8,8 +8,8 @@ namespace NSQLComplete { class TVisitor: public TSQLv1NarrowingVisitor { public: - TVisitor(antlr4::TokenStream* tokens, size_t cursorPosition) - : TSQLv1NarrowingVisitor(tokens, cursorPosition) + TVisitor(const TParsedInput& input) + : TSQLv1NarrowingVisitor(input) { } @@ -37,11 +37,8 @@ namespace NSQLComplete { } // namespace - TMaybe<TString> EnclosingFunction( - SQLv1::Sql_queryContext* ctx, - antlr4::TokenStream* tokens, - size_t cursorPosition) { - std::any result = TVisitor(tokens, cursorPosition).visit(ctx); + TMaybe<TString> EnclosingFunction(TParsedInput input) { + std::any result = TVisitor(input).visit(input.SqlQuery); if (!result.has_value()) { return Nothing(); } diff --git a/yql/essentials/sql/v1/complete/analysis/global/function.h b/yql/essentials/sql/v1/complete/analysis/global/function.h index bb94e71318e..77f1478c5cc 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/function.h +++ b/yql/essentials/sql/v1/complete/analysis/global/function.h @@ -1,15 +1,12 @@ #pragma once -#include "parse_tree.h" +#include "input.h" #include <util/generic/maybe.h> #include <util/generic/string.h> namespace NSQLComplete { - TMaybe<TString> EnclosingFunction( - SQLv1::Sql_queryContext* ctx, - antlr4::TokenStream* tokens, - size_t cursorPosition); + TMaybe<TString> EnclosingFunction(TParsedInput input); } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/analysis/global/global.cpp b/yql/essentials/sql/v1/complete/analysis/global/global.cpp index f11447c1f12..5bdba0714b3 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/global.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/global.cpp @@ -2,6 +2,7 @@ #include "column.h" #include "function.h" +#include "input.h" #include "named_node.h" #include "parse_tree.h" #include "use.h" @@ -87,18 +88,10 @@ namespace NSQLComplete { template <bool IsAnsiLexer> class TSpecializedGlobalAnalysis: public IGlobalAnalysis { public: - using TDefaultYQLGrammar = TAntlrGrammar< - NALADefaultAntlr4::SQLv1Antlr4Lexer, - NALADefaultAntlr4::SQLv1Antlr4Parser>; - - using TAnsiYQLGrammar = TAntlrGrammar< - NALAAnsiAntlr4::SQLv1Antlr4Lexer, - NALAAnsiAntlr4::SQLv1Antlr4Parser>; - - using G = std::conditional_t< + using TLexer = std::conditional_t< IsAnsiLexer, - TAnsiYQLGrammar, - TDefaultYQLGrammar>; + NALAAnsiAntlr4::SQLv1Antlr4Lexer, + NALADefaultAntlr4::SQLv1Antlr4Lexer>; TSpecializedGlobalAnalysis() : Chars_() @@ -128,11 +121,17 @@ namespace NSQLComplete { TGlobalContext ctx; - // TODO(YQL-19747): Add ~ParseContext(Tokens, ParseTree, CursorPosition) - ctx.Use = FindUseStatement(sqlQuery, &Tokens_, input.CursorPosition, env); - ctx.Names = CollectNamedNodes(sqlQuery, &Tokens_, input.CursorPosition); - ctx.EnclosingFunction = EnclosingFunction(sqlQuery, &Tokens_, input.CursorPosition); - ctx.Column = InferColumnContext(sqlQuery, &Tokens_, input.CursorPosition); + TParsedInput parsed = { + .Original = input, + .Tokens = &Tokens_, + .Parser = &Parser_, + .SqlQuery = sqlQuery, + }; + + ctx.Use = FindUseStatement(parsed, env); + ctx.Names = CollectNamedNodes(parsed); + ctx.EnclosingFunction = EnclosingFunction(parsed); + ctx.Column = InferColumnContext(parsed); if (ctx.Use && ctx.Column) { EnrichTableClusters(*ctx.Column, *ctx.Use); @@ -176,9 +175,9 @@ namespace NSQLComplete { } antlr4::ANTLRInputStream Chars_; - G::TLexer Lexer_; + TLexer Lexer_; antlr4::CommonTokenStream Tokens_; - TDefaultYQLGrammar::TParser Parser_; + SQLv1 Parser_; }; class TGlobalAnalysis: public IGlobalAnalysis { diff --git a/yql/essentials/sql/v1/complete/analysis/global/input.cpp b/yql/essentials/sql/v1/complete/analysis/global/input.cpp new file mode 100644 index 00000000000..018d9c796f3 --- /dev/null +++ b/yql/essentials/sql/v1/complete/analysis/global/input.cpp @@ -0,0 +1 @@ +#include "input.h" diff --git a/yql/essentials/sql/v1/complete/analysis/global/input.h b/yql/essentials/sql/v1/complete/analysis/global/input.h new file mode 100644 index 00000000000..3f40ec1f31d --- /dev/null +++ b/yql/essentials/sql/v1/complete/analysis/global/input.h @@ -0,0 +1,16 @@ +#pragma once + +#include "parse_tree.h" + +#include <yql/essentials/sql/v1/complete/core/input.h> + +namespace NSQLComplete { + + struct TParsedInput { + TCompletionInput Original; + antlr4::CommonTokenStream* Tokens; + SQLv1* Parser; + SQLv1::Sql_queryContext* SqlQuery; + }; + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/analysis/global/named_node.cpp b/yql/essentials/sql/v1/complete/analysis/global/named_node.cpp index 0896b508432..57223e73405 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/named_node.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/named_node.cpp @@ -14,11 +14,8 @@ namespace NSQLComplete { class TVisitor: public TSQLv1NarrowingVisitor { public: - TVisitor( - antlr4::TokenStream* tokens, - size_t cursorPosition, - THashSet<TString>* names) - : TSQLv1NarrowingVisitor(tokens, cursorPosition) + TVisitor(const TParsedInput& input, THashSet<TString>* names) + : TSQLv1NarrowingVisitor(input) , Names_(names) { } @@ -110,12 +107,9 @@ namespace NSQLComplete { } // namespace - TVector<TString> CollectNamedNodes( - SQLv1::Sql_queryContext* ctx, - antlr4::TokenStream* tokens, - size_t cursorPosition) { + TVector<TString> CollectNamedNodes(TParsedInput input) { THashSet<TString> names; - TVisitor(tokens, cursorPosition, &names).visit(ctx); + TVisitor(input, &names).visit(input.SqlQuery); return TVector<TString>(begin(names), end(names)); } diff --git a/yql/essentials/sql/v1/complete/analysis/global/named_node.h b/yql/essentials/sql/v1/complete/analysis/global/named_node.h index 119fbc4d5f6..55466765013 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/named_node.h +++ b/yql/essentials/sql/v1/complete/analysis/global/named_node.h @@ -1,15 +1,12 @@ #pragma once -#include "parse_tree.h" +#include "input.h" #include <util/generic/string.h> #include <util/generic/vector.h> namespace NSQLComplete { - TVector<TString> CollectNamedNodes( - SQLv1::Sql_queryContext* ctx, - antlr4::TokenStream* tokens, - size_t cursorPosition); + TVector<TString> CollectNamedNodes(TParsedInput input); } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/analysis/global/narrowing_visitor.cpp b/yql/essentials/sql/v1/complete/analysis/global/narrowing_visitor.cpp index f1cd303062c..95f5e1c13bd 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/narrowing_visitor.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/narrowing_visitor.cpp @@ -2,9 +2,9 @@ namespace NSQLComplete { - TSQLv1NarrowingVisitor::TSQLv1NarrowingVisitor(antlr4::TokenStream* tokens, size_t cursorPosition) - : Tokens_(tokens) - , CursorPosition_(cursorPosition) + TSQLv1NarrowingVisitor::TSQLv1NarrowingVisitor(const TParsedInput& input) + : Tokens_(input.Tokens) + , CursorPosition_(input.Original.CursorPosition) { } diff --git a/yql/essentials/sql/v1/complete/analysis/global/narrowing_visitor.h b/yql/essentials/sql/v1/complete/analysis/global/narrowing_visitor.h index 1ad4bbe2274..759ad5bd37c 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/narrowing_visitor.h +++ b/yql/essentials/sql/v1/complete/analysis/global/narrowing_visitor.h @@ -1,13 +1,13 @@ #pragma once #include "base_visitor.h" -#include "parse_tree.h" +#include "input.h" namespace NSQLComplete { class TSQLv1NarrowingVisitor: public TSQLv1BaseVisitor { public: - TSQLv1NarrowingVisitor(antlr4::TokenStream* tokens, size_t cursorPosition); + TSQLv1NarrowingVisitor(const TParsedInput& input); protected: bool shouldVisitNextChild(antlr4::tree::ParseTree* node, const std::any& /*currentResult*/) override; diff --git a/yql/essentials/sql/v1/complete/analysis/global/use.cpp b/yql/essentials/sql/v1/complete/analysis/global/use.cpp index d9a430ec12b..ce592b724c3 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/use.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/use.cpp @@ -9,11 +9,8 @@ namespace NSQLComplete { class TVisitor: public TSQLv1NarrowingVisitor { public: - TVisitor( - antlr4::TokenStream* tokens, - size_t cursorPosition, - const TEnvironment* env) - : TSQLv1NarrowingVisitor(tokens, cursorPosition) + TVisitor(const TParsedInput& input, const TEnvironment* env) + : TSQLv1NarrowingVisitor(input) , Env_(env) { } @@ -78,12 +75,9 @@ namespace NSQLComplete { } // namespace - TMaybe<TUseContext> FindUseStatement( - SQLv1::Sql_queryContext* ctx, - antlr4::TokenStream* tokens, - size_t cursorPosition, - const TEnvironment& env) { - std::any result = TVisitor(tokens, cursorPosition, &env).visit(ctx); + // TODO(YQL-19747): Use any to maybe conversion function + TMaybe<TUseContext> FindUseStatement(TParsedInput input, const TEnvironment& env) { + std::any result = TVisitor(input, &env).visit(input.SqlQuery); if (!result.has_value()) { return Nothing(); } diff --git a/yql/essentials/sql/v1/complete/analysis/global/use.h b/yql/essentials/sql/v1/complete/analysis/global/use.h index 0cdb9b15469..964519e4e99 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/use.h +++ b/yql/essentials/sql/v1/complete/analysis/global/use.h @@ -1,7 +1,7 @@ #pragma once #include "global.h" -#include "parse_tree.h" +#include "input.h" #include <util/generic/ptr.h> #include <util/generic/maybe.h> @@ -9,10 +9,6 @@ namespace NSQLComplete { - TMaybe<TUseContext> FindUseStatement( - SQLv1::Sql_queryContext* ctx, - antlr4::TokenStream* tokens, - size_t cursorPosition, - const TEnvironment& env); + TMaybe<TUseContext> FindUseStatement(TParsedInput input, const TEnvironment& env); } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/analysis/global/ya.make b/yql/essentials/sql/v1/complete/analysis/global/ya.make index b67f290a3be..25c83108230 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/ya.make +++ b/yql/essentials/sql/v1/complete/analysis/global/ya.make @@ -6,6 +6,7 @@ SRCS( evaluate.cpp function.cpp global.cpp + input.cpp named_node.cpp narrowing_visitor.cpp parse_tree.cpp diff --git a/yql/essentials/sql/v1/complete/configuration.cpp b/yql/essentials/sql/v1/complete/configuration.cpp new file mode 100644 index 00000000000..9dbba885b2c --- /dev/null +++ b/yql/essentials/sql/v1/complete/configuration.cpp @@ -0,0 +1,62 @@ +#include "configuration.h" + +#include <yql/essentials/sql/v1/complete/syntax/grammar.h> + +namespace NSQLComplete { + + TConfiguration MakeConfiguration(THashSet<TString> allowedStmts) { + allowedStmts.emplace("sql_stmt"); + + TConfiguration config; + for (const std::string& name : GetSqlGrammar().GetAllRules()) { + if (name.ends_with("_stmt") && !allowedStmts.contains(name)) { + config.IgnoredRules_.emplace(name); + } + } + return config; + } + + TConfiguration MakeYDBConfiguration() { + TConfiguration config; + config.IgnoredRules_ = { + "use_stmt", + "import_stmt", + "export_stmt", + }; + return config; + } + + TConfiguration MakeYQLConfiguration() { + auto config = MakeConfiguration(/* allowedStmts = */ { + "lambda_stmt", + "pragma_stmt", + "select_stmt", + "named_nodes_stmt", + "drop_table_stmt", + "use_stmt", + "into_table_stmt", + "commit_stmt", + "declare_stmt", + "import_stmt", + "export_stmt", + "do_stmt", + "define_action_or_subquery_stmt", + "if_stmt", + "for_stmt", + "values_stmt", + }); + + config.DisabledPreviousByToken_ = {}; + + config.ForcedPreviousByToken_ = { + {"PARALLEL", {}}, + {"TABLESTORE", {}}, + {"FOR", {"EVALUATE"}}, + {"IF", {"EVALUATE"}}, + {"EXTERNAL", {"USING"}}, + }; + + return config; + } + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/configuration.h b/yql/essentials/sql/v1/complete/configuration.h new file mode 100644 index 00000000000..620207bfcf2 --- /dev/null +++ b/yql/essentials/sql/v1/complete/configuration.h @@ -0,0 +1,28 @@ +#pragma once + +#include <util/generic/string.h> +#include <util/generic/hash.h> +#include <util/generic/hash_set.h> + +namespace NSQLComplete { + + struct TConfiguration { + friend class TSqlCompletionEngine; + friend TConfiguration MakeYDBConfiguration(); + friend TConfiguration MakeYQLConfiguration(); + friend TConfiguration MakeConfiguration(THashSet<TString> allowedStmts); + + public: + size_t Limit = 256; + + private: + THashSet<TString> IgnoredRules_; + THashMap<TString, THashSet<TString>> DisabledPreviousByToken_; + THashMap<TString, THashSet<TString>> ForcedPreviousByToken_; + }; + + TConfiguration MakeYDBConfiguration(); + + TConfiguration MakeYQLConfiguration(); + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/name/service/name_service.h b/yql/essentials/sql/v1/complete/name/service/name_service.h index e4971b86250..a5d793835ee 100644 --- a/yql/essentials/sql/v1/complete/name/service/name_service.h +++ b/yql/essentials/sql/v1/complete/name/service/name_service.h @@ -78,7 +78,7 @@ namespace NSQLComplete { struct TBindingName: TIndentifier { }; - struct TUnkownName { + struct TUnknownName { TString Content; TString Type; }; @@ -94,7 +94,7 @@ namespace NSQLComplete { TClusterName, TColumnName, TBindingName, - TUnkownName>; + TUnknownName>; struct TNameConstraints { TMaybe<TPragmaName::TConstraints> Pragma; diff --git a/yql/essentials/sql/v1/complete/name/service/ranking/ranking.cpp b/yql/essentials/sql/v1/complete/name/service/ranking/ranking.cpp index d8e0e0ff1bb..09edce52123 100644 --- a/yql/essentials/sql/v1/complete/name/service/ranking/ranking.cpp +++ b/yql/essentials/sql/v1/complete/name/service/ranking/ranking.cpp @@ -118,7 +118,7 @@ namespace NSQLComplete { if constexpr (std::is_base_of_v<TIndentifier, T>) { return name.Indentifier; } - if constexpr (std::is_base_of_v<TUnkownName, T>) { + if constexpr (std::is_base_of_v<TUnknownName, T>) { return name.Content; } }, name); diff --git a/yql/essentials/sql/v1/complete/name/service/schema/name_service.cpp b/yql/essentials/sql/v1/complete/name/service/schema/name_service.cpp index 736f7c3090e..3b13ec93784 100644 --- a/yql/essentials/sql/v1/complete/name/service/schema/name_service.cpp +++ b/yql/essentials/sql/v1/complete/name/service/schema/name_service.cpp @@ -130,7 +130,7 @@ namespace NSQLComplete { local.Indentifier = std::move(entry.Name); name = std::move(local); } else { - TUnkownName local; + TUnknownName local; local.Content = std::move(entry.Name); local.Type = std::move(entry.Type); name = std::move(local); diff --git a/yql/essentials/sql/v1/complete/name_mapping.cpp b/yql/essentials/sql/v1/complete/name_mapping.cpp new file mode 100644 index 00000000000..541188ea8c8 --- /dev/null +++ b/yql/essentials/sql/v1/complete/name_mapping.cpp @@ -0,0 +1,147 @@ +#include "name_mapping.h" + +#include <yql/essentials/sql/v1/complete/syntax/format.h> + +namespace NSQLComplete { + + TCandidate ToCandidate(TKeyword name, TLocalSyntaxContext& context) { + TVector<TString>& seq = context.Keywords[name.Content]; + seq.insert(std::begin(seq), name.Content); + + TCandidate candidate = { + .Kind = ECandidateKind::Keyword, + .Content = FormatKeywords(seq), + }; + + if (candidate.Content.EndsWith('(')) { + candidate.Content += ')'; + candidate.CursorShift = 1; + } + + return candidate; + } + + TCandidate ToCandidate(TPragmaName name) { + return {ECandidateKind::PragmaName, std::move(name.Indentifier)}; + } + + TCandidate ToCandidate(TTypeName name) { + TCandidate candidate = { + .Kind = ECandidateKind::TypeName, + .Content = std::move(name.Indentifier), + }; + + switch (name.Kind) { + case TTypeName::EKind::Simple: { + } break; + case TTypeName::EKind::Container: { + candidate.Content += "<>"; + candidate.CursorShift = 1; + } break; + case TTypeName::EKind::Parameterized: { + candidate.Content += "()"; + candidate.CursorShift = 1; + } break; + } + + return candidate; + } + + TCandidate ToCandidate(TFunctionName name) { + TCandidate candidate = { + .Kind = ECandidateKind::FunctionName, + .Content = std::move(name.Indentifier), + }; + + candidate.Content += "()"; + candidate.CursorShift = 1; + + return candidate; + } + + TCandidate ToCandidate(THintName name) { + return {ECandidateKind::HintName, std::move(name.Indentifier)}; + } + + TCandidate ToCandidate(TFolderName name, TLocalSyntaxContext& context) { + TCandidate candidate = { + .Kind = ECandidateKind::FolderName, + .Content = std::move(name.Indentifier), + }; + + if (!context.IsQuoted.AtLhs) { + candidate.Content.prepend('`'); + } + + candidate.Content.append('/'); + + if (!context.IsQuoted.AtRhs) { + candidate.Content.append('`'); + candidate.CursorShift = 1; + } + + return candidate; + } + + TCandidate ToCandidate(TTableName name, TLocalSyntaxContext& context) { + if (!context.IsQuoted.AtLhs) { + name.Indentifier.prepend('`'); + } + if (!context.IsQuoted.AtRhs) { + name.Indentifier.append('`'); + } + return {ECandidateKind::TableName, std::move(name.Indentifier)}; + } + + TCandidate ToCandidate(TClusterName name) { + return {ECandidateKind::ClusterName, std::move(name.Indentifier)}; + } + + TCandidate ToCandidate(TColumnName name, TLocalSyntaxContext& context) { + if (context.Column->Table.empty() && !name.TableAlias.empty()) { + name.Indentifier.prepend('.'); + name.Indentifier.prepend(name.TableAlias); + } + + return {ECandidateKind::ColumnName, std::move(name.Indentifier)}; + } + + TCandidate ToCandidate(TBindingName name, TLocalSyntaxContext& context) { + if (!context.Binding) { + name.Indentifier.prepend('$'); + } + return {ECandidateKind::BindingName, std::move(name.Indentifier)}; + } + + TCandidate ToCandidate(TUnknownName name) { + return {ECandidateKind::UnknownName, std::move(name.Content)}; + } + + TCandidate ToCandidate(TGenericName generic, TLocalSyntaxContext& context) { + return std::visit([&](auto&& name) -> TCandidate { + using T = std::decay_t<decltype(name)>; + constexpr bool IsContextSensitive = + std::is_same_v<T, TKeyword> || + std::is_same_v<T, TFolderName> || + std::is_same_v<T, TTableName> || + std::is_same_v<T, TColumnName> || + std::is_same_v<T, TBindingName>; + + if constexpr (IsContextSensitive) { + return ToCandidate(std::move(name), context); + } else { + return ToCandidate(std::move(name)); + } + }, std::move(generic)); + } + + TVector<TCandidate> ToCandidate(TVector<TGenericName> names, TLocalSyntaxContext context) { + TVector<TCandidate> candidates; + candidates.reserve(names.size()); + for (auto& name : names) { + candidates.emplace_back(ToCandidate(std::move(name), context)); + } + return candidates; + } + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/name_mapping.h b/yql/essentials/sql/v1/complete/name_mapping.h new file mode 100644 index 00000000000..0bde9ffd6dc --- /dev/null +++ b/yql/essentials/sql/v1/complete/name_mapping.h @@ -0,0 +1,14 @@ +#pragma once + +#include "sql_complete.h" + +#include <yql/essentials/sql/v1/complete/analysis/local/local.h> +#include <yql/essentials/sql/v1/complete/name/service/name_service.h> + +namespace NSQLComplete { + + TCandidate ToCandidate(TGenericName name, TLocalSyntaxContext& context); + + TVector<TCandidate> ToCandidate(TVector<TGenericName> names, TLocalSyntaxContext context); + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/sql_complete.cpp b/yql/essentials/sql/v1/complete/sql_complete.cpp index 59cbeba1385..307bc432518 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete.cpp @@ -1,5 +1,7 @@ #include "sql_complete.h" +#include "name_mapping.h" + #include <yql/essentials/sql/v1/complete/syntax/grammar.h> #include <yql/essentials/sql/v1/complete/text/word.h> #include <yql/essentials/sql/v1/complete/name/object/simple/static/schema.h> @@ -23,7 +25,7 @@ namespace NSQLComplete { TSqlCompletionEngine( TLexerSupplier lexer, INameService::TPtr names, - ISqlCompletionEngine::TConfiguration configuration) + TConfiguration configuration) : Configuration_(std::move(configuration)) , SyntaxAnalysis_(MakeLocalSyntaxAnalysis( lexer, @@ -41,10 +43,9 @@ namespace NSQLComplete { } NThreading::TFuture<TCompletion> CompleteAsync(TCompletionInput input, TEnvironment env) override { - if ( - input.CursorPosition < input.Text.length() && - IsUTF8ContinuationByte(input.Text.at(input.CursorPosition)) || - input.Text.length() < input.CursorPosition) { + if ((input.CursorPosition < input.Text.length() && + IsUTF8ContinuationByte(input.Text.at(input.CursorPosition))) || + (input.Text.length() < input.CursorPosition)) { ythrow yexception() << "invalid cursor position " << input.CursorPosition << " for input size " << input.Text.size(); @@ -167,13 +168,10 @@ namespace NSQLComplete { return request; } - TCompletion ToCompletion( - TCompletionInput input, - TLocalSyntaxContext context, - TNameResponse response) const { + TCompletion ToCompletion(TCompletionInput input, TLocalSyntaxContext context, TNameResponse response) const { TCompletion completion = { .CompletedToken = GetCompletedToken(input, context.EditRange), - .Candidates = Convert(std::move(response.RankedNames), std::move(context)), + .Candidates = ToCandidate(std::move(response.RankedNames), std::move(context)), }; if (response.NameHintLength) { @@ -188,200 +186,16 @@ namespace NSQLComplete { return completion; } - static TVector<TCandidate> Convert(TVector<TGenericName> names, TLocalSyntaxContext context) { - TVector<TCandidate> candidates; - candidates.reserve(names.size()); - for (auto& name : names) { - candidates.emplace_back(Convert(std::move(name), context)); - } - return candidates; - } - - // TODO(YQL-19747): extract to a separate file - static TCandidate Convert(TGenericName name, TLocalSyntaxContext& context) { - return std::visit([&](auto&& name) -> TCandidate { - using T = std::decay_t<decltype(name)>; - - if constexpr (std::is_base_of_v<TKeyword, T>) { - TVector<TString>& seq = context.Keywords[name.Content]; - seq.insert(std::begin(seq), name.Content); - - TCandidate candidate = { - .Kind = ECandidateKind::Keyword, - .Content = FormatKeywords(seq), - }; - - if (candidate.Content.EndsWith('(')) { - candidate.Content += ')'; - candidate.CursorShift = 1; - } - - return candidate; - } - - if constexpr (std::is_base_of_v<TPragmaName, T>) { - return {ECandidateKind::PragmaName, std::move(name.Indentifier)}; - } - - if constexpr (std::is_base_of_v<TTypeName, T>) { - TCandidate candidate = { - .Kind = ECandidateKind::TypeName, - .Content = std::move(name.Indentifier), - }; - - switch (name.Kind) { - case TTypeName::EKind::Simple: { - } break; - case TTypeName::EKind::Container: { - candidate.Content += "<>"; - candidate.CursorShift = 1; - } break; - case TTypeName::EKind::Parameterized: { - candidate.Content += "()"; - candidate.CursorShift = 1; - } break; - } - - return candidate; - } - - if constexpr (std::is_base_of_v<TFunctionName, T>) { - TCandidate candidate = { - .Kind = ECandidateKind::FunctionName, - .Content = std::move(name.Indentifier), - }; - - candidate.Content += "()"; - candidate.CursorShift = 1; - - return candidate; - } - - if constexpr (std::is_base_of_v<THintName, T>) { - return {ECandidateKind::HintName, std::move(name.Indentifier)}; - } - - if constexpr (std::is_base_of_v<TFolderName, T>) { - TCandidate candidate = { - .Kind = ECandidateKind::FolderName, - .Content = std::move(name.Indentifier), - }; - - if (!context.IsQuoted.AtLhs) { - candidate.Content.prepend('`'); - } - - candidate.Content.append('/'); - - if (!context.IsQuoted.AtRhs) { - candidate.Content.append('`'); - candidate.CursorShift = 1; - } - - return candidate; - } - - if constexpr (std::is_base_of_v<TTableName, T>) { - if (!context.IsQuoted.AtLhs) { - name.Indentifier.prepend('`'); - } - if (!context.IsQuoted.AtRhs) { - name.Indentifier.append('`'); - } - return {ECandidateKind::TableName, std::move(name.Indentifier)}; - } - - if constexpr (std::is_base_of_v<TClusterName, T>) { - return {ECandidateKind::ClusterName, std::move(name.Indentifier)}; - } - - if constexpr (std::is_base_of_v<TColumnName, T>) { - if (context.Column->Table.empty() && !name.TableAlias.empty()) { - name.Indentifier.prepend('.'); - name.Indentifier.prepend(name.TableAlias); - } - - return {ECandidateKind::ColumnName, std::move(name.Indentifier)}; - } - - if constexpr (std::is_base_of_v<TBindingName, T>) { - if (!context.Binding) { - name.Indentifier.prepend('$'); - } - return {ECandidateKind::BindingName, std::move(name.Indentifier)}; - } - - if constexpr (std::is_base_of_v<TUnkownName, T>) { - return {ECandidateKind::UnknownName, std::move(name.Content)}; - } - }, std::move(name)); - } - TConfiguration Configuration_; ILocalSyntaxAnalysis::TPtr SyntaxAnalysis_; IGlobalAnalysis::TPtr GlobalAnalysis_; INameService::TPtr Names_; }; - ISqlCompletionEngine::TConfiguration MakeConfiguration(THashSet<TString> allowedStmts) { - allowedStmts.emplace("sql_stmt"); - - ISqlCompletionEngine::TConfiguration config; - for (const std::string& name : GetSqlGrammar().GetAllRules()) { - if (name.ends_with("_stmt") && !allowedStmts.contains(name)) { - config.IgnoredRules_.emplace(name); - } - } - return config; - } - - ISqlCompletionEngine::TConfiguration MakeYDBConfiguration() { - ISqlCompletionEngine::TConfiguration config; - config.IgnoredRules_ = { - "use_stmt", - "import_stmt", - "export_stmt", - }; - return config; - } - - ISqlCompletionEngine::TConfiguration MakeYQLConfiguration() { - auto config = MakeConfiguration(/* allowedStmts = */ { - "lambda_stmt", - "pragma_stmt", - "select_stmt", - "named_nodes_stmt", - "drop_table_stmt", - "use_stmt", - "into_table_stmt", - "commit_stmt", - "declare_stmt", - "import_stmt", - "export_stmt", - "do_stmt", - "define_action_or_subquery_stmt", - "if_stmt", - "for_stmt", - "values_stmt", - }); - - config.DisabledPreviousByToken_ = {}; - - config.ForcedPreviousByToken_ = { - {"PARALLEL", {}}, - {"TABLESTORE", {}}, - {"FOR", {"EVALUATE"}}, - {"IF", {"EVALUATE"}}, - {"EXTERNAL", {"USING"}}, - }; - - return config; - } - ISqlCompletionEngine::TPtr MakeSqlCompletionEngine( TLexerSupplier lexer, INameService::TPtr names, - ISqlCompletionEngine::TConfiguration configuration) { + TConfiguration configuration) { return MakeHolder<TSqlCompletionEngine>( lexer, std::move(names), std::move(configuration)); } diff --git a/yql/essentials/sql/v1/complete/sql_complete.h b/yql/essentials/sql/v1/complete/sql_complete.h index ce8a7c5296f..3387019e25f 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.h +++ b/yql/essentials/sql/v1/complete/sql_complete.h @@ -1,5 +1,7 @@ #pragma once +#include "configuration.h" + #include <yql/essentials/sql/v1/complete/core/input.h> #include <yql/essentials/sql/v1/complete/core/environment.h> #include <yql/essentials/sql/v1/complete/name/service/name_service.h> @@ -51,20 +53,8 @@ namespace NSQLComplete { public: using TPtr = THolder<ISqlCompletionEngine>; - struct TConfiguration { - friend class TSqlCompletionEngine; - friend ISqlCompletionEngine::TConfiguration MakeYDBConfiguration(); - friend ISqlCompletionEngine::TConfiguration MakeYQLConfiguration(); - friend ISqlCompletionEngine::TConfiguration MakeConfiguration(THashSet<TString> allowedStmts); - - public: - size_t Limit = 256; - - private: - THashSet<TString> IgnoredRules_; - THashMap<TString, THashSet<TString>> DisabledPreviousByToken_; - THashMap<TString, THashSet<TString>> ForcedPreviousByToken_; - }; + // TODO(YQL-19747): Deprecated, Migrate YDB CLI to `TConfiguration` + using TConfiguration = NSQLComplete::TConfiguration; virtual ~ISqlCompletionEngine() = default; @@ -77,13 +67,9 @@ namespace NSQLComplete { using TLexerSupplier = std::function<NSQLTranslation::ILexer::TPtr(bool ansi)>; - ISqlCompletionEngine::TConfiguration MakeYDBConfiguration(); - - ISqlCompletionEngine::TConfiguration MakeYQLConfiguration(); - ISqlCompletionEngine::TPtr MakeSqlCompletionEngine( TLexerSupplier lexer, INameService::TPtr names, - ISqlCompletionEngine::TConfiguration configuration = {}); + TConfiguration configuration = {}); } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/ya.make b/yql/essentials/sql/v1/complete/ya.make index e85ba90b524..b0b5ee4be21 100644 --- a/yql/essentials/sql/v1/complete/ya.make +++ b/yql/essentials/sql/v1/complete/ya.make @@ -1,6 +1,8 @@ LIBRARY() SRCS( + configuration.cpp + name_mapping.cpp sql_complete.cpp ) |