aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/sql/v1/complete
diff options
context:
space:
mode:
authorvitya-smirnov <vitya-smirnov@yandex-team.com>2025-07-10 16:18:41 +0300
committervitya-smirnov <vitya-smirnov@yandex-team.com>2025-07-10 16:49:06 +0300
commitab4a6f4beadc1b478f8c208d07226687821b5fc2 (patch)
treee19e74f48361d1aa73d139c23ae514ea8ab4453f /yql/essentials/sql/v1/complete
parentea2073d5c0897338da46444473d7649ceac2289b (diff)
downloadydb-ab4a6f4beadc1b478f8c208d07226687821b5fc2.tar.gz
YQL-19747: Complete table functions
- Added table functions completion. - Also fixed a bug when USEd cluster was not added to table context at table function argument. - Complete folder names at `prefix` of `LIKE`, `RANGE`, etc. commit_hash:26be383be728796e8431f906e2815acd77645ad4
Diffstat (limited to 'yql/essentials/sql/v1/complete')
-rw-r--r--yql/essentials/sql/v1/complete/analysis/global/function.cpp22
-rw-r--r--yql/essentials/sql/v1/complete/analysis/global/function.h3
-rw-r--r--yql/essentials/sql/v1/complete/analysis/global/global.cpp8
-rw-r--r--yql/essentials/sql/v1/complete/analysis/global/global.h9
-rw-r--r--yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp12
-rw-r--r--yql/essentials/sql/v1/complete/analysis/local/local.cpp16
-rw-r--r--yql/essentials/sql/v1/complete/analysis/local/local.h5
-rw-r--r--yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.cpp8
-rw-r--r--yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.h4
-rw-r--r--yql/essentials/sql/v1/complete/core/name.h5
-rw-r--r--yql/essentials/sql/v1/complete/name/service/name_service.h4
-rw-r--r--yql/essentials/sql/v1/complete/name/service/static/name_service.cpp26
-rw-r--r--yql/essentials/sql/v1/complete/sql_complete.cpp36
-rw-r--r--yql/essentials/sql/v1/complete/sql_complete_ut.cpp87
14 files changed, 200 insertions, 45 deletions
diff --git a/yql/essentials/sql/v1/complete/analysis/global/function.cpp b/yql/essentials/sql/v1/complete/analysis/global/function.cpp
index 0bd9740796a..30072f4a69c 100644
--- a/yql/essentials/sql/v1/complete/analysis/global/function.cpp
+++ b/yql/essentials/sql/v1/complete/analysis/global/function.cpp
@@ -2,6 +2,8 @@
#include "narrowing_visitor.h"
+#include <library/cpp/iterator/enumerate.h>
+
namespace NSQLComplete {
namespace {
@@ -26,23 +28,35 @@ namespace NSQLComplete {
if (function == nullptr || lparen == nullptr) {
return {};
}
-
if (CursorPosition() <= TextInterval(lparen).b) {
return {};
}
- return function->getText();
+ return TFunctionContext{
+ .Name = function->getText(),
+ .ArgumentNumber = ArgumentNumber(ctx).GetOrElse(0),
+ };
+ }
+
+ private:
+ TMaybe<size_t> ArgumentNumber(SQLv1::Table_refContext* ctx) {
+ for (auto [i, arg] : Enumerate(ctx->table_arg())) {
+ if (IsEnclosing(arg)) {
+ return i;
+ }
+ }
+ return Nothing();
}
};
} // namespace
- TMaybe<TString> EnclosingFunction(TParsedInput input) {
+ TMaybe<TFunctionContext> EnclosingFunction(TParsedInput input) {
std::any result = TVisitor(input).visit(input.SqlQuery);
if (!result.has_value()) {
return Nothing();
}
- return std::any_cast<std::string>(result);
+ return std::any_cast<TFunctionContext>(result);
}
} // namespace NSQLComplete
diff --git a/yql/essentials/sql/v1/complete/analysis/global/function.h b/yql/essentials/sql/v1/complete/analysis/global/function.h
index 77f1478c5cc..52aa7090b7b 100644
--- a/yql/essentials/sql/v1/complete/analysis/global/function.h
+++ b/yql/essentials/sql/v1/complete/analysis/global/function.h
@@ -1,5 +1,6 @@
#pragma once
+#include "global.h"
#include "input.h"
#include <util/generic/maybe.h>
@@ -7,6 +8,6 @@
namespace NSQLComplete {
- TMaybe<TString> EnclosingFunction(TParsedInput input);
+ TMaybe<TFunctionContext> 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 be80531ad86..130338e03de 100644
--- a/yql/essentials/sql/v1/complete/analysis/global/global.cpp
+++ b/yql/essentials/sql/v1/complete/analysis/global/global.cpp
@@ -242,6 +242,14 @@ namespace NSQLComplete {
} // namespace NSQLComplete
template <>
+void Out<NSQLComplete::TFunctionContext>(IOutputStream& out, const NSQLComplete::TFunctionContext& value) {
+ out << "TFunctionContext { ";
+ out << "Name: " << value.Name;
+ out << ", Args: " << value.ArgumentNumber;
+ out << " }";
+}
+
+template <>
void Out<NSQLComplete::TColumnContext>(IOutputStream& out, const NSQLComplete::TColumnContext& value) {
out << "TColumnContext { ";
out << "Tables: " << JoinSeq(", ", value.Tables);
diff --git a/yql/essentials/sql/v1/complete/analysis/global/global.h b/yql/essentials/sql/v1/complete/analysis/global/global.h
index 17f8ffeb056..9a18f45f7c8 100644
--- a/yql/essentials/sql/v1/complete/analysis/global/global.h
+++ b/yql/essentials/sql/v1/complete/analysis/global/global.h
@@ -18,6 +18,13 @@ namespace NSQLComplete {
TString Cluster;
};
+ struct TFunctionContext {
+ TString Name;
+ size_t ArgumentNumber = 0;
+
+ friend bool operator==(const TFunctionContext& lhs, const TFunctionContext& rhs) = default;
+ };
+
// TODO(YQL-19747): Try to refactor to use Map/Set data structures
struct TColumnContext {
TVector<TAliased<TTableId>> Tables;
@@ -37,7 +44,7 @@ namespace NSQLComplete {
struct TGlobalContext {
TMaybe<TUseContext> Use;
TVector<TString> Names;
- TMaybe<TString> EnclosingFunction;
+ TMaybe<TFunctionContext> EnclosingFunction;
TMaybe<TColumnContext> Column;
};
diff --git a/yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp b/yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp
index 217c2fe8ff6..522628bb5d5 100644
--- a/yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp
+++ b/yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp
@@ -86,22 +86,26 @@ Y_UNIT_TEST_SUITE(GlobalAnalysisTests) {
{
TString query = "SELECT * FROM Concat(#)";
TGlobalContext ctx = global->Analyze(SharpedInput(query), {});
- UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, "Concat");
+ TFunctionContext expected = {"Concat", 0};
+ UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, expected);
}
{
TString query = "SELECT * FROM Concat(a, #)";
TGlobalContext ctx = global->Analyze(SharpedInput(query), {});
- UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, "Concat");
+ TFunctionContext expected = {"Concat", 1};
+ UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, expected);
}
{
TString query = "SELECT * FROM Concat(a#)";
TGlobalContext ctx = global->Analyze(SharpedInput(query), {});
- UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, "Concat");
+ TFunctionContext expected = {"Concat", 0};
+ UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, expected);
}
{
TString query = "SELECT * FROM Concat(#";
TGlobalContext ctx = global->Analyze(SharpedInput(query), {});
- UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, "Concat");
+ TFunctionContext expected = {"Concat", 0};
+ UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, expected);
}
{
TString query = "SELECT * FROM (#)";
diff --git a/yql/essentials/sql/v1/complete/analysis/local/local.cpp b/yql/essentials/sql/v1/complete/analysis/local/local.cpp
index 3841f7276f8..9db61777db7 100644
--- a/yql/essentials/sql/v1/complete/analysis/local/local.cpp
+++ b/yql/essentials/sql/v1/complete/analysis/local/local.cpp
@@ -224,16 +224,25 @@ namespace NSQLComplete {
TMaybe<TLocalSyntaxContext::TFunction> FunctionMatch(
const TCursorTokenContext& context, const TC3Candidates& candidates) const {
- if (!AnyOf(candidates.Rules, RuleAdapted(IsLikelyFunctionStack))) {
+ const bool isAnyFunction = AnyOf(candidates.Rules, RuleAdapted(IsLikelyFunctionStack));
+ const bool isTableFunction = AnyOf(candidates.Rules, RuleAdapted(IsLikelyTableFunctionStack));
+ if (!isAnyFunction && !isTableFunction) {
return Nothing();
}
TLocalSyntaxContext::TFunction function;
+
if (TMaybe<TRichParsedToken> begin;
(begin = context.MatchCursorPrefix({"ID_PLAIN", "NAMESPACE"})) ||
(begin = context.MatchCursorPrefix({"ID_PLAIN", "NAMESPACE", ""}))) {
function.Namespace = begin->Base->Content;
}
+
+ function.ReturnType = ENodeKind::Any;
+ if (isTableFunction) {
+ function.ReturnType = ENodeKind::Table;
+ }
+
return function;
}
@@ -267,7 +276,7 @@ namespace NSQLComplete {
object.Kinds.emplace(EObjectKind::Table);
}
- if (object.Kinds.empty()) {
+ if (object.Kinds.empty() && !AnyOf(candidates.Rules, RuleAdapted(IsLikelyTableArgStack))) {
return Nothing();
}
@@ -360,7 +369,8 @@ namespace NSQLComplete {
TEditRange EditRange(const TRichParsedToken& token, const TCursor& cursor) const {
size_t begin = token.Position;
- if (token.Base->Name == "NOT_EQUALS2") {
+ if (token.Base->Name == "NOT_EQUALS2" ||
+ token.Base->Name == "ID_QUOTED") {
begin += 1;
}
diff --git a/yql/essentials/sql/v1/complete/analysis/local/local.h b/yql/essentials/sql/v1/complete/analysis/local/local.h
index df708901cf9..3086c0663fa 100644
--- a/yql/essentials/sql/v1/complete/analysis/local/local.h
+++ b/yql/essentials/sql/v1/complete/analysis/local/local.h
@@ -26,6 +26,7 @@ namespace NSQLComplete {
struct TFunction {
TString Namespace;
+ ENodeKind ReturnType = ENodeKind::Any;
};
struct THint {
@@ -45,6 +46,10 @@ namespace NSQLComplete {
bool HasCluster() const {
return !Cluster.empty();
}
+
+ bool IsDeferred() const {
+ return Kinds.empty();
+ }
};
struct TColumn {
diff --git a/yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.cpp b/yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.cpp
index 7b30d2a20d7..9f0501f1968 100644
--- a/yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.cpp
+++ b/yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.cpp
@@ -98,6 +98,10 @@ namespace NSQLComplete {
EndsWith({RULE(Value_constructor)}, stack);
}
+ bool IsLikelyTableFunctionStack(const TParserCallStack& stack) {
+ return EndsWith({RULE(Table_ref), RULE(An_id_expr), RULE(Id_expr)}, stack);
+ }
+
bool IsLikelyHintStack(const TParserCallStack& stack) {
return ContainsRule(RULE(Id_hint), stack) ||
Contains({RULE(External_call_param), RULE(An_id)}, stack);
@@ -119,6 +123,10 @@ namespace NSQLComplete {
RULE(Id_table_or_type)}, stack));
}
+ bool IsLikelyTableArgStack(const TParserCallStack& stack) {
+ return Contains({RULE(Table_arg)}, stack);
+ }
+
bool IsLikelyClusterStack(const TParserCallStack& stack) {
return Contains({RULE(Cluster_expr)}, stack);
}
diff --git a/yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.h b/yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.h
index a0c479a8be0..66c87ebf17e 100644
--- a/yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.h
+++ b/yql/essentials/sql/v1/complete/analysis/local/parser_call_stack.h
@@ -13,12 +13,16 @@ namespace NSQLComplete {
bool IsLikelyFunctionStack(const TParserCallStack& stack);
+ bool IsLikelyTableFunctionStack(const TParserCallStack& stack);
+
bool IsLikelyHintStack(const TParserCallStack& stack);
bool IsLikelyObjectRefStack(const TParserCallStack& stack);
bool IsLikelyExistingTableStack(const TParserCallStack& stack);
+ bool IsLikelyTableArgStack(const TParserCallStack& stack);
+
bool IsLikelyClusterStack(const TParserCallStack& stack);
bool IsLikelyColumnStack(const TParserCallStack& stack);
diff --git a/yql/essentials/sql/v1/complete/core/name.h b/yql/essentials/sql/v1/complete/core/name.h
index 592dece8544..d6d718e19e0 100644
--- a/yql/essentials/sql/v1/complete/core/name.h
+++ b/yql/essentials/sql/v1/complete/core/name.h
@@ -10,6 +10,11 @@ namespace NSQLComplete {
Table,
};
+ enum class ENodeKind {
+ Any,
+ Table,
+ };
+
struct TTableId {
TString Cluster;
TString Path;
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 96d46718316..007d38dcb90 100644
--- a/yql/essentials/sql/v1/complete/name/service/name_service.h
+++ b/yql/essentials/sql/v1/complete/name/service/name_service.h
@@ -45,7 +45,9 @@ namespace NSQLComplete {
};
struct TFunctionName: TIdentifier, TDescribed {
- struct TConstraints: TNamespaced {};
+ struct TConstraints: TNamespaced {
+ ENodeKind ReturnType;
+ };
};
struct THintName: TIdentifier {
diff --git a/yql/essentials/sql/v1/complete/name/service/static/name_service.cpp b/yql/essentials/sql/v1/complete/name/service/static/name_service.cpp
index 520452e13bc..c8c8746634e 100644
--- a/yql/essentials/sql/v1/complete/name/service/static/name_service.cpp
+++ b/yql/essentials/sql/v1/complete/name/service/static/name_service.cpp
@@ -178,14 +178,35 @@ namespace NSQLComplete {
TFunctionNameService(IRanking::TPtr ranking, TVector<TString> functions)
: IRankingNameService(std::move(ranking))
, Functions_(BuildNameIndex(std::move(functions), NormalizeName))
+ , TableFunctions_(BuildNameIndex(
+ {
+ "CONCAT",
+ "RANGE",
+ "LIKE",
+ "REGEXP",
+ "FILTER",
+ "FOLDER",
+ "WalkFolders",
+ "EACH",
+ }, NormalizeName))
{
}
NThreading::TFuture<TNameResponse> LookupAllUnranked(const TNameRequest& request) const override {
TNameResponse response;
- if (request.Constraints.Function) {
+ if (auto function = request.Constraints.Function) {
+ const TNameIndex* index = nullptr;
+ switch (function->ReturnType) {
+ case ENodeKind::Any: {
+ index = &Functions_;
+ } break;
+ case ENodeKind::Table: {
+ index = &TableFunctions_;
+ } break;
+ }
+
NameIndexScan<TFunctionName>(
- Functions_,
+ *index,
request.Prefix,
request.Constraints,
response.RankedNames);
@@ -195,6 +216,7 @@ namespace NSQLComplete {
private:
TNameIndex Functions_;
+ TNameIndex TableFunctions_;
};
class THintNameService: public IRankingNameService {
diff --git a/yql/essentials/sql/v1/complete/sql_complete.cpp b/yql/essentials/sql/v1/complete/sql_complete.cpp
index cf93c07a190..253e4731835 100644
--- a/yql/essentials/sql/v1/complete/sql_complete.cpp
+++ b/yql/essentials/sql/v1/complete/sql_complete.cpp
@@ -65,6 +65,8 @@ namespace NSQLComplete {
TGlobalContext global = GlobalAnalysis_->Analyze(input, std::move(env));
+ local = Enriched(std::move(local), global);
+
TNameRequest request = NameRequestFrom(input, local, global);
if (request.IsEmpty()) {
return NThreading::MakeFuture<TCompletion>({
@@ -128,6 +130,7 @@ namespace NSQLComplete {
if (local.Function) {
TFunctionName::TConstraints constraints;
constraints.Namespace = local.Function->Namespace;
+ constraints.ReturnType = local.Function->ReturnType;
request.Constraints.Function = std::move(constraints);
}
@@ -159,14 +162,6 @@ namespace NSQLComplete {
request.Constraints.Cluster = std::move(constraints);
}
- if (auto name = global.EnclosingFunction.Transform(NormalizeName);
- name && name == "concat") {
- auto& object = request.Constraints.Object;
- object = object.Defined() ? object : TObjectNameConstraints();
- object->Kinds.emplace(EObjectKind::Folder);
- object->Kinds.emplace(EObjectKind::Table);
- }
-
if (local.Column && global.Column) {
TMaybe<TStringBuf> table = local.Column->Table;
table = !table->empty() ? table : Nothing();
@@ -198,6 +193,31 @@ namespace NSQLComplete {
return completion;
}
+ static TLocalSyntaxContext Enriched(TLocalSyntaxContext local, const TGlobalContext& global) {
+ TMaybe<TFunctionContext> function = global.EnclosingFunction;
+ TMaybe<TLocalSyntaxContext::TObject>& object = local.Object;
+ if (!function || !object) {
+ return local;
+ }
+
+ auto& name = function->Name;
+ size_t number = function->ArgumentNumber;
+
+ name = NormalizeName(name);
+
+ if (name == "concat") {
+ object->Kinds.emplace(EObjectKind::Folder);
+ object->Kinds.emplace(EObjectKind::Table);
+ } else if ((number == 0) &&
+ (name == "range" || name == "like" ||
+ name == "regexp" || name == "filter" ||
+ name == "folder" || name == "walkfolders")) {
+ object->Kinds.emplace(EObjectKind::Folder);
+ }
+
+ return local;
+ }
+
TConfiguration Configuration_;
ILocalSyntaxAnalysis::TPtr SyntaxAnalysis_;
IGlobalAnalysis::TPtr GlobalAnalysis_;
diff --git a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp
index 1b32f0983d7..c7451c39d53 100644
--- a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp
+++ b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp
@@ -157,8 +157,8 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
return engine->Complete(SharpedInput(sharped), std::move(env)).GetValueSync().Candidates;
}
- TVector<TCandidate> CompleteTop(size_t limit, ISqlCompletionEngine::TPtr& engine, TString sharped) {
- auto candidates = Complete(engine, std::move(sharped));
+ TVector<TCandidate> CompleteTop(size_t limit, ISqlCompletionEngine::TPtr& engine, TString sharped, TEnvironment env = {}) {
+ auto candidates = Complete(engine, std::move(sharped), std::move(env));
candidates.crop(limit);
return candidates;
}
@@ -232,7 +232,8 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
{Keyword, "ANY"},
};
UNIT_ASSERT_VALUES_EQUAL(
- Complete(
+ CompleteTop(
+ 4,
engine,
"USE yt:$cluster_name; SELECT * FROM ",
{.Parameters = {{"$cluster_name", "saurus"}}}),
@@ -249,7 +250,8 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
{Keyword, "ANY"},
};
UNIT_ASSERT_VALUES_EQUAL(
- Complete(
+ CompleteTop(
+ 7,
engine,
"USE yt:$cluster_name; SELECT * FROM ",
{.Parameters = {}}),
@@ -560,6 +562,14 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
{ClusterName, "example"},
{ClusterName, "saurus"},
{Keyword, "ANY"},
+ {FunctionName, "CONCAT()", 1},
+ {FunctionName, "EACH()", 1},
+ {FunctionName, "FILTER()", 1},
+ {FunctionName, "FOLDER()", 1},
+ {FunctionName, "LIKE()", 1},
+ {FunctionName, "RANGE()", 1},
+ {FunctionName, "REGEXP()", 1},
+ {FunctionName, "WalkFolders()", 1},
};
UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "SELECT * FROM "), expected);
}
@@ -643,7 +653,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
{FolderName, "prod/`", 1},
{FolderName, "test/`", 1},
};
- UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "SELECT * FROM `#"), expected);
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(4, engine, "SELECT * FROM `#"), expected);
}
{
TVector<TCandidate> expected = {
@@ -673,7 +683,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
TVector<TCandidate> expected = {
{TableName, "`maxim`"},
};
- UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "SELECT * FROM yt:saurus."), expected);
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(1, engine, "SELECT * FROM yt:saurus."), expected);
}
{
TVector<TCandidate> expected = {
@@ -698,14 +708,14 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
{ClusterName, "saurus"},
{Keyword, "ANY"},
};
- UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "USE yt:saurus; SELECT * FROM "), expected);
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(4, engine, "USE yt:saurus; SELECT * FROM "), expected);
}
{
TVector<TCandidate> expected = {
{TableName, "`people`"},
{FolderName, "`yql/`", 1},
};
- UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "USE yt:saurus; SELECT * FROM example."), expected);
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(2, engine, "USE yt:saurus; SELECT * FROM example."), expected);
}
{
TVector<TCandidate> expected = {
@@ -714,7 +724,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
{ClusterName, "saurus"},
{Keyword, "ANY"},
};
- UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "USE example; USE yt:saurus; SELECT * FROM "), expected);
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(4, engine, "USE example; USE yt:saurus; SELECT * FROM "), expected);
}
{
TVector<TCandidate> expected = {
@@ -724,7 +734,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
{ClusterName, "saurus"},
{Keyword, "ANY"},
};
- UNIT_ASSERT_VALUES_EQUAL(Complete(engine, R"(
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(5, engine, R"(
USE example;
DEFINE ACTION $hello() AS
USE yt:saurus;
@@ -741,7 +751,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
{ClusterName, "saurus"},
{Keyword, "ANY"},
};
- UNIT_ASSERT_VALUES_EQUAL(Complete(engine, R"(
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(6, engine, R"(
USE example;
DEFINE ACTION $action() AS
@@ -1065,18 +1075,53 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
}
}
- Y_UNIT_TEST(TableAsFunctionArgument) {
+ Y_UNIT_TEST(TableFunction) {
auto engine = MakeSqlCompletionEngineUT();
+ {
+ TVector<TCandidate> expected = {
+ {FunctionName, "CONCAT()", 1},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(1, engine, "SELECT * FROM Conca#"), expected);
+ }
+ {
+ TVector<TCandidate> expected = {};
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(1, engine, "SELECT Conca#"), expected);
+ }
+ }
- UNIT_ASSERT_VALUES_EQUAL(
- CompleteTop(1, engine, "SELECT * FROM Concat(#)").at(0).Kind, FolderName);
- UNIT_ASSERT_VALUES_EQUAL(
- CompleteTop(1, engine, "SELECT * FROM CONCAT(#)").at(0).Kind, FolderName);
- UNIT_ASSERT_VALUES_EQUAL(
- CompleteTop(1, engine, "SELECT * FROM CONCAT(a, #)").at(0).Kind, FolderName);
-
- UNIT_ASSERT_VALUES_UNEQUAL(
- CompleteTop(1, engine, "SELECT Max(#)").at(0).Kind, FolderName);
+ Y_UNIT_TEST(TableAsFunctionArgument) {
+ auto engine = MakeSqlCompletionEngineUT();
+ {
+ TVector<TCandidate> expected = {
+ {FolderName, "`.sys/`", 1},
+ {FolderName, "`local/`", 1},
+ {FolderName, "`prod/`", 1},
+ {FolderName, "`test/`", 1},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(4, engine, "SELECT * FROM CONCAT(#)"), expected);
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(4, engine, "SELECT * FROM CONCAT(a, #)"), expected);
+ }
+ {
+ TVector<TCandidate> expected = {
+ {TableName, "`people`"},
+ {FolderName, "`yql/`", 1},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(CompleteTop(2, engine, "USE example; SELECT * FROM Concat(#)"), expected);
+ }
+ {
+ UNIT_ASSERT_VALUES_EQUAL(
+ CompleteTop(1, engine, "SELECT * FROM Concat(`#`)").at(0).Kind, FolderName);
+ }
+ {
+ UNIT_ASSERT_VALUES_EQUAL(
+ CompleteTop(1, engine, "SELECT * FROM Range(#)").at(0).Kind, FolderName);
+ UNIT_ASSERT_VALUES_UNEQUAL(
+ CompleteTop(1, engine, "SELECT * FROM Range(``, #)").at(0).Kind, FolderName);
+ }
+ {
+ UNIT_ASSERT_VALUES_UNEQUAL(CompleteTop(1, engine, "SELECT Max(#)").at(0).Kind, FolderName);
+ UNIT_ASSERT_VALUES_UNEQUAL(CompleteTop(1, engine, "SELECT Concat(#)").at(0).Kind, FolderName);
+ }
}
Y_UNIT_TEST(ColumnsAtSimpleSelect) {