@@ -22,25 +22,27 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
2222 TJsonSettings JsonSettings;
2323 ui32 Timeout = 0 ;
2424
25+ TAutoPtr<TEvViewer::TEvViewerResponse> ProxyResult;
2526 TAutoPtr<NConsole::TEvConsole::TEvListTenantsResponse> ConsoleResult;
2627 TAutoPtr<TEvTxProxySchemeCache::TEvNavigateKeySetResult> CacheResult;
2728
28- struct SchemaWordData {
29+ struct TSchemaWordData {
2930 TString Name;
30- TString Type;
31+ NKikimrViewer::EAutocompleteType Type;
3132 TString Table;
32- SchemaWordData () {}
33- SchemaWordData (const TString& name, const TString& type, const TString& table = " " )
33+ TSchemaWordData () {}
34+ TSchemaWordData (const TString& name, const NKikimrViewer::EAutocompleteType type, const TString& table = " " )
3435 : Name(name)
3536 , Type(type)
3637 , Table(table)
3738 {}
3839 };
39- THashMap<TString, SchemaWordData > Dictionary;
40+ THashMap<TString, TSchemaWordData > Dictionary;
4041 TString Database;
42+ TVector<TString> Tables;
4143 TVector<TString> Paths;
4244 TString Prefix;
43- TString PrefixPath ;
45+ TString SearchWord ;
4446 ui32 Limit = 10 ;
4547 NKikimrViewer::TQueryAutocomplete Result;
4648
@@ -63,6 +65,7 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
6365 TStringBuf content = Event->Get ()->Request .GetPostContent ();
6466 ParsePostContent (content);
6567 }
68+ PrepareParameters ();
6669 }
6770
6871 // proxied request
@@ -72,43 +75,49 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
7275 auto & request = ViewerRequest->Get ()->Record .GetAutocompleteRequest ();
7376
7477 Database = request.GetDatabase ();
75- for (auto & path : request.GetTables ()) {
76- Paths .emplace_back (path );
78+ for (auto & table : request.GetTables ()) {
79+ Tables .emplace_back (table );
7780 }
7881 Prefix = request.GetPrefix ();
7982
8083 Timeout = ViewerRequest->Get ()->Record .GetTimeout ();
8184 Direct = true ;
85+ PrepareParameters ();
8286 }
8387
84- void PreparePaths () {
85- if (Paths.size () == 0 ) {
86- Paths.emplace_back (" " );
87- }
88- TString prefixPath = " " ;
89- auto splitPos = Prefix.find_last_of (' /' );
90- if (splitPos != std::string::npos) {
91- prefixPath += " /" + Prefix.substr (0 , splitPos);
92- Prefix = Prefix.substr (splitPos + 1 );
93- }
94- for (TString& path: Paths) {
95- if (!path.StartsWith (Database)) {
96- path = Database + " /" + path;
97- }
98- path += prefixPath;
88+ void PrepareParameters () {
89+ if (Database) {
90+ TString prefixUpToLastSlash = " " ;
9991 auto splitPos = Prefix.find_last_of (' /' );
10092 if (splitPos != std::string::npos) {
101- path += " /" + Prefix.substr (0 , splitPos);
102- Prefix = Prefix.substr (splitPos + 1 );
93+ prefixUpToLastSlash += Prefix.substr (0 , splitPos);
94+ SearchWord = Prefix.substr (splitPos + 1 );
95+ } else {
96+ SearchWord = Prefix;
97+ }
98+
99+ if (Tables.size () == 0 ) {
100+ Paths.emplace_back (Database);
101+ } else {
102+ for (TString& table: Tables) {
103+ TString path = table;
104+ if (!table.StartsWith (Database)) {
105+ path = Database + " /" + path;
106+ }
107+ path += " /" + prefixUpToLastSlash;
108+ Paths.emplace_back (path);
109+ }
103110 }
111+ } else {
112+ SearchWord = Prefix;
104113 }
105114 }
106115
107116 void ParseCgiParameters (const TCgiParameters& params) {
108117 JsonSettings.EnumAsNumbers = !FromStringWithDefault<bool >(params.Get (" enums" ), true );
109118 JsonSettings.UI64AsString = !FromStringWithDefault<bool >(params.Get (" ui64" ), false );
110119 Database = params.Get (" database" );
111- StringSplitter (params.Get (" table" )).Split (' ,' ).SkipEmpty ().Collect (&Paths );
120+ StringSplitter (params.Get (" table" )).Split (' ,' ).SkipEmpty ().Collect (&Tables );
112121 Prefix = params.Get (" prefix" );
113122 Limit = FromStringWithDefault<ui32>(params.Get (" limit" ), Limit);
114123 Direct = FromStringWithDefault<bool >(params.Get (" direct" ), Direct);
@@ -121,8 +130,10 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
121130 bool success = NJson::ReadJsonTree (content, &JsonConfig, &requestData);
122131 if (success) {
123132 Database = Database.empty () ? requestData[" database" ].GetStringSafe ({}) : Database;
124- for (auto & table: requestData[" tables" ].GetArraySafe ()) {
125- Paths.emplace_back (table.GetStringSafe ());
133+ if (requestData[" table" ].IsArray ()) {
134+ for (auto & table: requestData[" table" ].GetArraySafe ()) {
135+ Tables.emplace_back (table.GetStringSafe ());
136+ }
126137 }
127138 Prefix = Prefix.empty () ? requestData[" prefix" ].GetStringSafe ({}) : Prefix;
128139 }
@@ -157,38 +168,41 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
157168
158169 void Bootstrap () {
159170 if (ViewerRequest) {
160- // proxied request
161- PreparePaths ();
171+ // handle proxied request
162172 SendSchemeCacheRequest ();
163173 } else if (!Database) {
164- // autocomplete databases via console request
174+ // autocomplete database list via console request
165175 RequestConsoleListTenants ();
166176 } else {
167177 if (!Direct) {
168- // autocomplete with proxy
169- RequestStateStorageEndpointsLookup (Database); // to find some dynamic node and redirect there
178+ // proxy request to a dynamic node of the specified database
179+ RequestStateStorageEndpointsLookup (Database);
170180 }
171181 if (Requests == 0 ) {
172- // autocomplete without proxy
173- PreparePaths ();
182+ // perform autocomplete without proxying
174183 SendSchemeCacheRequest ();
175184 }
176185 }
177186
178-
179187 Become (&TThis::StateRequestedDescribe, TDuration::MilliSeconds (Timeout), new TEvents::TEvWakeup ());
180188 }
181189
182190 void Connected (TEvInterconnect::TEvNodeConnected::TPtr &) {}
183191
184192 void Undelivered (TEvents::TEvUndelivered::TPtr &ev) {
185- if (ev->Get ()->SourceType == NViewer::TEvViewer::EvViewerRequest) {
186- SendSchemeCacheRequest ();
193+ if (!Direct && ev->Get ()->SourceType == NViewer::TEvViewer::EvViewerRequest) {
194+ Direct = true ;
195+ SendSchemeCacheRequest (); // fallback
196+ RequestDone ();
187197 }
188198 }
189199
190200 void Disconnected (TEvInterconnect::TEvNodeDisconnected::TPtr &) {
191- SendSchemeCacheRequest ();
201+ if (!Direct) {
202+ Direct = true ;
203+ SendSchemeCacheRequest (); // fallback
204+ RequestDone ();
205+ }
192206 }
193207
194208 void Handle (TEvStateStorage::TEvBoardInfo::TPtr& ev) {
@@ -203,6 +217,7 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
203217 } else {
204218 SendDynamicNodeAutocompleteRequest ();
205219 }
220+ RequestDone ();
206221 }
207222
208223 void SendSchemeCacheRequest () {
@@ -253,90 +268,106 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
253268 }
254269 }
255270
256- TString ConvertType (TNavigate::EKind navigate) {
271+ void ParseProxyResult () {
272+ if (ProxyResult == nullptr ) {
273+ Result.add_error (" Failed to collect information from ProxyResult" );
274+ return ;
275+ }
276+ if (ProxyResult->Record .HasAutocompleteResponse ()) {
277+ Result = ProxyResult->Record .GetAutocompleteResponse ();
278+ } else {
279+ Result.add_error (" Proxying return empty response" );
280+ }
281+
282+ }
283+
284+ void ParseConsoleResult () {
285+ if (ConsoleResult == nullptr ) {
286+ Result.add_error (" Failed to collect information from ConsoleResult" );
287+ return ;
288+ }
289+
290+ Ydb::Cms::ListDatabasesResult listTenantsResult;
291+ ConsoleResult->Record .GetResponse ().operation ().result ().UnpackTo (&listTenantsResult);
292+ for (const TString& path : listTenantsResult.paths ()) {
293+ Dictionary[path] = TSchemaWordData (path, NKikimrViewer::ext_sub_domain);
294+ }
295+ }
296+
297+ NKikimrViewer::EAutocompleteType ConvertType (TNavigate::EKind navigate) {
257298 switch (navigate) {
258299 case TNavigate::KindSubdomain:
259- return " subdomain " ;
300+ return NKikimrViewer::sub_domain ;
260301 case TNavigate::KindPath:
261- return " directory " ;
302+ return NKikimrViewer::dir ;
262303 case TNavigate::KindExtSubdomain:
263- return " database " ;
304+ return NKikimrViewer::ext_sub_domain ;
264305 case TNavigate::KindTable:
265- return " table" ;
306+ return NKikimrViewer:: table;
266307 case TNavigate::KindOlapStore:
267- return " columnStore " ;
308+ return NKikimrViewer::column_store ;
268309 case TNavigate::KindColumnTable:
269- return " columnTable " ;
310+ return NKikimrViewer::column_table ;
270311 case TNavigate::KindRtmr:
271- return " rtmrVolume " ;
312+ return NKikimrViewer::rtmr_volume ;
272313 case TNavigate::KindKesus:
273- return " kesus" ;
314+ return NKikimrViewer:: kesus;
274315 case TNavigate::KindSolomon:
275- return " solomonVolume " ;
316+ return NKikimrViewer::solomon_volume ;
276317 case TNavigate::KindTopic:
277- return " persQueueGroup " ;
318+ return NKikimrViewer::pers_queue_group ;
278319 case TNavigate::KindCdcStream:
279- return " cdcStream " ;
320+ return NKikimrViewer::cdc_stream ;
280321 case TNavigate::KindSequence:
281- return " sequence" ;
322+ return NKikimrViewer:: sequence;
282323 case TNavigate::KindReplication:
283- return " replication" ;
324+ return NKikimrViewer:: replication;
284325 case TNavigate::KindBlobDepot:
285- return " blobDepot " ;
326+ return NKikimrViewer::blob_depot ;
286327 case TNavigate::KindExternalTable:
287- return " externalTable " ;
328+ return NKikimrViewer::external_table ;
288329 case TNavigate::KindExternalDataSource:
289- return " externalDataSource " ;
330+ return NKikimrViewer::external_data_source ;
290331 case TNavigate::KindBlockStoreVolume:
291- return " blockStoreVolume " ;
332+ return NKikimrViewer::block_store_volume ;
292333 case TNavigate::KindFileStore:
293- return " fileStore " ;
334+ return NKikimrViewer::file_store ;
294335 case TNavigate::KindView:
295- return " view" ;
336+ return NKikimrViewer:: view;
296337 default :
297- return " directory" ;
298- }
299- }
300-
301- void ParseConsoleResult () {
302- if (ConsoleResult == nullptr ) {
303- Result.add_error (" Failed to collect information" );
304- return ;
305- }
306-
307- Ydb::Cms::ListDatabasesResult listTenantsResult;
308- ConsoleResult->Record .GetResponse ().operation ().result ().UnpackTo (&listTenantsResult);
309- for (const TString& path : listTenantsResult.paths ()) {
310- Dictionary[path] = SchemaWordData (path, " database" );
338+ return NKikimrViewer::dir;
311339 }
312- RequestDone ();
313340 }
314341
315342 void ParseCacheResult () {
316343 if (CacheResult == nullptr ) {
317- Result.add_error (" Failed to collect information" );
344+ Result.add_error (" Failed to collect information from CacheResult " );
318345 return ;
319346 }
320347 NSchemeCache::TSchemeCacheNavigate *navigate = CacheResult->Request .Get ();
321348 if (navigate->ErrorCount > 0 ) {
322- Result.add_error (" Inner errors while collected information" );
349+ for (auto & entry: CacheResult->Request .Get ()->ResultSet ) {
350+ if (entry.Status != TSchemeCacheNavigate::EStatus::Ok) {
351+ Result.add_error (TStringBuilder () << " Error receiving Navigate response: `" << CanonizePath (entry.Path ) << " ` has <" << ToString (entry.Status ) << " > status" );
352+ }
353+ }
323354 return ;
324355 }
325356 for (auto & entry: CacheResult->Request .Get ()->ResultSet ) {
326357 TString path = CanonizePath (entry.Path );
327358 if (entry.ListNodeEntry ) {
328359 for (const auto & child : entry.ListNodeEntry ->Children ) {
329- Dictionary[child.Name ] = SchemaWordData (child.Name , ConvertType (child.Kind ), path);
360+ Dictionary[child.Name ] = TSchemaWordData (child.Name , ConvertType (child.Kind ), path);
330361 }
331362 };
332363 for (const auto & [id, column] : entry.Columns ) {
333- Dictionary[column.Name ] = SchemaWordData (column.Name , path, " column " );
364+ Dictionary[column.Name ] = TSchemaWordData (column.Name , NKikimrViewer::column, path );
334365 }
335366 for (const auto & index : entry.Indexes ) {
336- Dictionary[index.GetName ()] = SchemaWordData (index.GetName (), path, " index " );
367+ Dictionary[index.GetName ()] = TSchemaWordData (index.GetName (), NKikimrViewer::index, path );
337368 }
338369 for (const auto & cdcStream : entry.CdcStreams ) {
339- Dictionary[cdcStream.GetName ()] = SchemaWordData (cdcStream.GetName (), path, " cdcstream " );
370+ Dictionary[cdcStream.GetName ()] = TSchemaWordData (cdcStream.GetName (), NKikimrViewer::cdc_stream, path );
340371 }
341372 }
342373 }
@@ -364,23 +395,27 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
364395 }
365396
366397 void ReplyAndPassAway () {
367- if (!Database ) {
368- ParseConsoleResult ();
369- } else {
398+ if (ProxyResult ) {
399+ ParseProxyResult ();
400+ } else if (Database) {
370401 ParseCacheResult ();
402+ } else {
403+ ParseConsoleResult ();
371404 }
372405
373- Result.set_success (Result.error_size () == 0 );
374- if (Result.error_size () == 0 ) {
375- auto fuzzy = FuzzySearcher<SchemaWordData>(Dictionary);
376- auto autocomplete = fuzzy.Search (Prefix, Limit);
377- Result.MutableResult ()->SetTotal (autocomplete.size ());
378- for (SchemaWordData& wordData: autocomplete) {
379- auto entity = Result.MutableResult ()->AddEntities ();
380- entity->SetName (wordData.Name );
381- entity->SetType (wordData.Type );
382- if (wordData.Table ) {
383- entity->SetParent (wordData.Table );
406+ if (!ProxyResult) {
407+ Result.set_success (Result.error_size () == 0 );
408+ if (Result.error_size () == 0 ) {
409+ auto fuzzy = FuzzySearcher<TSchemaWordData>(Dictionary);
410+ auto autocomplete = fuzzy.Search (SearchWord, Limit);
411+ Result.MutableResult ()->SetTotal (autocomplete.size ());
412+ for (TSchemaWordData& wordData: autocomplete) {
413+ auto entity = Result.MutableResult ()->AddEntities ();
414+ entity->SetName (wordData.Name );
415+ entity->SetType (wordData.Type );
416+ if (wordData.Table ) {
417+ entity->SetParent (wordData.Table );
418+ }
384419 }
385420 }
386421 }
@@ -390,10 +425,8 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
390425 }
391426
392427 void Handle (TEvViewer::TEvViewerResponse::TPtr& ev) {
393- if (ev.Get ()->Get ()->Record .HasAutocompleteResponse ()) {
394- Result = ev.Get ()->Get ()->Record .GetAutocompleteResponse ();
395- }
396- SendAutocompleteResponse ();
428+ ProxyResult = ev.Release ()->Release ();
429+ RequestDone ();
397430 }
398431
399432 void HandleTimeout () {
0 commit comments