diff options
author | robot-piglet <[email protected]> | 2025-04-22 19:01:12 +0300 |
---|---|---|
committer | robot-piglet <[email protected]> | 2025-04-22 19:45:00 +0300 |
commit | 60665d3830d1f5e3252c2b7f5bb4db32cadadfc1 (patch) | |
tree | 0f03b5608e43c58113eccfaf7bd2299448609224 | |
parent | 9b729cf67c26251cd90ddaf5d921a6b0feb562e5 (diff) |
Intermediate changes
commit_hash:a1ac242ea5619c1e83dd638a82653e1d5c385821
9 files changed, 293 insertions, 0 deletions
diff --git a/yql/essentials/sql/v1/complete/name/object/schema_gateway.cpp b/yql/essentials/sql/v1/complete/name/object/schema_gateway.cpp new file mode 100644 index 00000000000..c802ddcb7a1 --- /dev/null +++ b/yql/essentials/sql/v1/complete/name/object/schema_gateway.cpp @@ -0,0 +1,6 @@ +#include "schema_gateway.h" + +template <> +void Out<NSQLComplete::TFolderEntry>(IOutputStream& out, const NSQLComplete::TFolderEntry& entry) { + out << "{" << entry.Type << ", " << entry.Name << "}"; +} diff --git a/yql/essentials/sql/v1/complete/name/object/schema_gateway.h b/yql/essentials/sql/v1/complete/name/object/schema_gateway.h new file mode 100644 index 00000000000..c09883d8bb7 --- /dev/null +++ b/yql/essentials/sql/v1/complete/name/object/schema_gateway.h @@ -0,0 +1,49 @@ +#pragma once + +#include <library/cpp/threading/future/core/future.h> + +#include <util/generic/string.h> +#include <util/generic/vector.h> +#include <util/generic/hash_set.h> +#include <util/generic/maybe.h> + +namespace NSQLComplete { + + struct TFolderEntry { + TString Type; + TString Name; + + friend bool operator==(const TFolderEntry& lhs, const TFolderEntry& rhs) = default; + }; + + struct TListFilter { + TMaybe<THashSet<TString>> Types; + }; + + struct TListRequest { + TString Cluster; + + // `Path` structure is defined by a `System`. + // Can end with a folder entry name hint. + // For example, `/local/exa` lists a folder `/local`, + // but can rank and filter entries by a hint `exa`. + TString Path; + + TListFilter Filter; + size_t Limit = 128; + }; + + struct TListResponse { + size_t NameHintLength = 0; + TVector<TFolderEntry> Entries; + }; + + class ISchemaGateway { + public: + using TPtr = THolder<ISchemaGateway>; + + virtual ~ISchemaGateway() = default; + virtual NThreading::TFuture<TListResponse> List(const TListRequest& request) = 0; + }; + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/name/object/static/schema_gateway.cpp b/yql/essentials/sql/v1/complete/name/object/static/schema_gateway.cpp new file mode 100644 index 00000000000..974c1ee5922 --- /dev/null +++ b/yql/essentials/sql/v1/complete/name/object/static/schema_gateway.cpp @@ -0,0 +1,68 @@ +#include "schema_gateway.h" + +#include <yql/essentials/sql/v1/complete/text/case.h> + +#include <util/charset/utf8.h> + +namespace NSQLComplete { + + namespace { + + class TSchemaGateway: public ISchemaGateway { + static constexpr size_t MaxLimit = 4 * 1024; + + public: + explicit TSchemaGateway(THashMap<TString, TVector<TFolderEntry>> data) + : Data_(std::move(data)) + { + for (const auto& [k, _] : Data_) { + Y_ENSURE(k.StartsWith("/"), k << " must start with the '/'"); + Y_ENSURE(k.EndsWith("/"), k << " must end with the '/'"); + } + } + + NThreading::TFuture<TListResponse> List(const TListRequest& request) override { + auto [path, prefix] = ParsePath(request.Path); + + TVector<TFolderEntry> entries = Data_[path]; + EraseIf(entries, [prefix = ToLowerUTF8(prefix)](const TFolderEntry& entry) { + return !entry.Name.StartsWith(prefix); + }); + + EraseIf(entries, [types = std::move(request.Filter.Types)](const TFolderEntry& entry) { + return types && !types->contains(entry.Type); + }); + + Y_ENSURE(request.Limit <= MaxLimit); + entries.crop(request.Limit); + + TListResponse response = { + .NameHintLength = prefix.size(), + .Entries = std::move(entries), + }; + + return NThreading::MakeFuture(std::move(response)); + } + + private: + static std::tuple<TStringBuf, TStringBuf> ParsePath(TString path Y_LIFETIME_BOUND) { + size_t pos = path.find_last_of('/'); + if (pos == TString::npos) { + return {"", path}; + } + + TStringBuf head, tail; + TStringBuf(path).SplitAt(pos + 1, head, tail); + return {head, tail}; + } + + THashMap<TString, TVector<TFolderEntry>> Data_; + }; + + } // namespace + + ISchemaGateway::TPtr MakeStaticSchemaGateway(THashMap<TString, TVector<TFolderEntry>> fs) { + return MakeHolder<TSchemaGateway>(std::move(fs)); + } + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/name/object/static/schema_gateway.h b/yql/essentials/sql/v1/complete/name/object/static/schema_gateway.h new file mode 100644 index 00000000000..fd23a956d25 --- /dev/null +++ b/yql/essentials/sql/v1/complete/name/object/static/schema_gateway.h @@ -0,0 +1,9 @@ +#pragma once + +#include <yql/essentials/sql/v1/complete/name/object/schema_gateway.h> + +namespace NSQLComplete { + + ISchemaGateway::TPtr MakeStaticSchemaGateway(THashMap<TString, TVector<TFolderEntry>> fs); + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/name/object/static/schema_gateway_ut.cpp b/yql/essentials/sql/v1/complete/name/object/static/schema_gateway_ut.cpp new file mode 100644 index 00000000000..86c8118f197 --- /dev/null +++ b/yql/essentials/sql/v1/complete/name/object/static/schema_gateway_ut.cpp @@ -0,0 +1,123 @@ +#include "schema_gateway.h" + +#include <library/cpp/testing/unittest/registar.h> + +using namespace NSQLComplete; + +Y_UNIT_TEST_SUITE(StaticSchemaGatewayTests) { + + ISchemaGateway::TPtr MakeStaticSchemaGatewayUT() { + THashMap<TString, TVector<TFolderEntry>> fs = { + {"/", {{"Folder", "local"}, + {"Folder", "test"}, + {"Folder", "prod"}}}, + {"/local/", {{"Table", "example"}, + {"Table", "account"}, + {"Table", "abacaba"}}}, + {"/test/", {{"Folder", "service"}, + {"Table", "meta"}}}, + {"/test/service/", {{"Table", "example"}}}, + }; + return MakeStaticSchemaGateway(std::move(fs)); + } + + Y_UNIT_TEST(ListFolderBasic) { + auto gateway = MakeStaticSchemaGatewayUT(); + { + TVector<TFolderEntry> expected = { + {"Folder", "local"}, + {"Folder", "test"}, + {"Folder", "prod"}, + }; + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/"}).GetValueSync().Entries, expected); + } + { + TVector<TFolderEntry> expected = { + {"Table", "example"}, + {"Table", "account"}, + {"Table", "abacaba"}, + }; + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/local/"}).GetValueSync().Entries, expected); + } + { + TVector<TFolderEntry> expected = { + {"Folder", "service"}, + {"Table", "meta"}, + }; + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/test/"}).GetValueSync().Entries, expected); + } + { + TVector<TFolderEntry> expected = { + {"Table", "example"}}; + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/test/service/"}).GetValueSync().Entries, expected); + } + } + + Y_UNIT_TEST(ListFolderHint) { + auto gateway = MakeStaticSchemaGatewayUT(); + { + TVector<TFolderEntry> expected = { + {"Folder", "local"}, + }; + auto actual = gateway->List({.Path = "/l"}).GetValueSync(); + UNIT_ASSERT_VALUES_EQUAL(actual.Entries, expected); + UNIT_ASSERT_VALUES_EQUAL(actual.NameHintLength, 1); + } + { + TVector<TFolderEntry> expected = { + {"Table", "account"}, + {"Table", "abacaba"}, + }; + auto actual = gateway->List({.Path = "/local/a"}).GetValueSync(); + UNIT_ASSERT_VALUES_EQUAL(actual.Entries, expected); + UNIT_ASSERT_VALUES_EQUAL(actual.NameHintLength, 1); + } + { + TVector<TFolderEntry> expected = { + {"Folder", "service"}, + }; + auto actual = gateway->List({.Path = "/test/service"}).GetValueSync(); + UNIT_ASSERT_VALUES_EQUAL(actual.Entries, expected); + UNIT_ASSERT_VALUES_EQUAL(actual.NameHintLength, 7); + } + } + + Y_UNIT_TEST(ListFolderFilterByType) { + auto gateway = MakeStaticSchemaGatewayUT(); + { + TVector<TFolderEntry> expected = { + {"Folder", "service"}, + }; + TListRequest request = { + .Path = "/test/", + .Filter = { + .Types = THashSet<TString>{"Folder"}, + }, + }; + UNIT_ASSERT_VALUES_EQUAL(gateway->List(request).GetValueSync().Entries, expected); + } + { + TVector<TFolderEntry> expected = { + {"Table", "meta"}, + }; + TListRequest request = { + .Path = "/test/", + .Filter = { + .Types = THashSet<TString>{"Table"}, + }, + }; + UNIT_ASSERT_VALUES_EQUAL(gateway->List(request).GetValueSync().Entries, expected); + } + } + + Y_UNIT_TEST(ListFolderLimit) { + auto gateway = MakeStaticSchemaGatewayUT(); + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/", .Limit = 0}).GetValueSync().Entries.size(), 0); + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/", .Limit = 1}).GetValueSync().Entries.size(), 1); + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/", .Limit = 2}).GetValueSync().Entries.size(), 2); + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/", .Limit = 3}).GetValueSync().Entries.size(), 3); + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/", .Limit = 4}).GetValueSync().Entries.size(), 3); + UNIT_ASSERT_VALUES_EQUAL(gateway->List({.Path = "/", .Limit = 5}).GetValueSync().Entries.size(), 3); + } + +} // Y_UNIT_TEST_SUITE(StaticSchemaGatewayTests) diff --git a/yql/essentials/sql/v1/complete/name/object/static/ut/ya.make b/yql/essentials/sql/v1/complete/name/object/static/ut/ya.make new file mode 100644 index 00000000000..877f015d806 --- /dev/null +++ b/yql/essentials/sql/v1/complete/name/object/static/ut/ya.make @@ -0,0 +1,7 @@ +UNITTEST_FOR(yql/essentials/sql/v1/complete/name/object/static) + +SRCS( + schema_gateway_ut.cpp +) + +END() diff --git a/yql/essentials/sql/v1/complete/name/object/static/ya.make b/yql/essentials/sql/v1/complete/name/object/static/ya.make new file mode 100644 index 00000000000..d3dd658468c --- /dev/null +++ b/yql/essentials/sql/v1/complete/name/object/static/ya.make @@ -0,0 +1,15 @@ +LIBRARY() + +SRCS( + schema_gateway.cpp +) + +PEERDIR( + yql/essentials/sql/v1/complete/name/object +) + +END() + +RECURSE_FOR_TESTS( + ut +) diff --git a/yql/essentials/sql/v1/complete/name/object/ya.make b/yql/essentials/sql/v1/complete/name/object/ya.make new file mode 100644 index 00000000000..1254e60dc6c --- /dev/null +++ b/yql/essentials/sql/v1/complete/name/object/ya.make @@ -0,0 +1,15 @@ +LIBRARY() + +SRCS( + schema_gateway.cpp +) + +PEERDIR( + library/cpp/threading/future +) + +END() + +RECURSE( + static +) diff --git a/yql/essentials/sql/v1/complete/name/ya.make b/yql/essentials/sql/v1/complete/name/ya.make index 43f7dc2c1b3..9b64891e4d6 100644 --- a/yql/essentials/sql/v1/complete/name/ya.make +++ b/yql/essentials/sql/v1/complete/name/ya.make @@ -8,5 +8,6 @@ END() RECURSE( fallback + object static ) |