summaryrefslogtreecommitdiffstats
path: root/yql/essentials/sql/v1/ide/completion/name/service/column/name_service.cpp
blob: bcc5dc58515d62784bac4ecea75df4f0aceacdf9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "name_service.h"

#include <yql/essentials/sql/v1/ide/completion/name/object/simple/static/schema.h>

namespace NSQLComplete {

namespace {

class TNameService: public INameService {
public:
    explicit TNameService(TVector<TColumnId> columns) {
        TSchemaData data;
        for (auto& column : columns) {
            Tables_.emplace(column.TableAlias);

            data.Tables[""]["/" + Escaped(column.TableAlias)]
                .Columns
                .emplace_back(std::move(column.Name));
        }

        Schema_ = MakeSimpleSchema(MakeStaticSimpleSchema(std::move(data)));
    }

    NThreading::TFuture<TNameResponse> Lookup(const TNameRequest& request) const override {
        if (!request.Constraints.Column) {
            return NThreading::MakeFuture<TNameResponse>({});
        }

        TNameResponse response;

        for (const TString& tableName : Tables_) {
            const auto& withoutByTableAlias = request.Constraints.Column->WithoutByTableAlias;

            THashSet<TString> without;
            if (auto it = withoutByTableAlias.find(tableName); it != withoutByTableAlias.end()) {
                without.insert(begin(it->second), end(it->second));
            }
            if (auto it = withoutByTableAlias.find(""); it != withoutByTableAlias.end()) {
                without.insert(begin(it->second), end(it->second));
            }

            TString columnPrefix = request.Prefix;
            if (tableName.StartsWith(request.Prefix)) {
                columnPrefix = "";
            }

            TDescribeTableRequest describeRequest = {
                .TableCluster = "",
                .TablePath = Escaped(tableName),
                .ColumnPrefix = columnPrefix,
                .ColumnsLimit = request.Limit,
            };

            TDescribeTableResponse table =
                Schema_
                    ->Describe(std::move(describeRequest))
                    .ExtractValue();

            Y_ENSURE(table.IsExisting);
            for (TString& column : table.Columns) {
                if (without.contains(column)) {
                    continue;
                }

                TColumnName name;
                name.TableAlias = tableName;
                name.Identifier = std::move(column);

                response.RankedNames.emplace_back(std::move(name));
            }
        }

        response.RankedNames.crop(request.Limit);

        return NThreading::MakeFuture(std::move(response));
    }

private:
    static TString Escaped(TString tableName) {
        if (tableName.empty()) {
            tableName.prepend("table_");
        }

        SubstGlobal(tableName, "/", "%2F");

        return tableName;
    }

    THashSet<TString> Tables_;
    ISchema::TPtr Schema_;
};

} // namespace

INameService::TPtr MakeColumnNameService(TVector<TColumnId> columns) {
    return new TNameService(std::move(columns));
}

} // namespace NSQLComplete