aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/public/issue/yql_issue_id.h
blob: b4889319a77228b62dfefd08b0172ff99c14d15c (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#pragma once

#include <yql/essentials/public/issue/protos/issue_severity.pb.h>

#include <library/cpp/resource/resource.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/message.h>

#include <util/generic/hash.h>
#include <util/generic/singleton.h>
#include <util/generic/yexception.h>
#include <util/string/subst.h>

#ifdef _win_
#ifdef GetMessage
#undef GetMessage
#endif
#endif

namespace NYql {

using TIssueCode = ui32;
using ESeverity = NYql::TSeverityIds::ESeverityId;
const TIssueCode DEFAULT_ERROR = 0;
const TIssueCode UNEXPECTED_ERROR = 1;

inline TString SeverityToString(ESeverity severity)
{
    auto ret = NYql::TSeverityIds::ESeverityId_Name(severity);
    return ret.empty() ? "Unknown" : to_title(ret.substr(2)); //remove prefix "S_"
}

template <typename T>
inline TString IssueCodeToString(TIssueCode id) {
    auto ret = T::EIssueCode_Name(static_cast<typename T::EIssueCode>(id));
    if (!ret.empty()) {
        SubstGlobal(ret, '_', ' ');
        return to_title(ret);
    } else {
        return "Unknown";
    }
}

template<typename TProto, const char* ResourceName>
class TIssueId {
    TProto ProtoIssues_;
    THashMap<TIssueCode, NYql::TSeverityIds::ESeverityId> IssuesMap_;
    THashMap<TIssueCode, TString> IssuesFormatMap_;

    const google::protobuf::Descriptor* GetProtoDescriptor() const {
        auto ret = ProtoIssues_.GetDescriptor();
        Y_ENSURE(ret != nullptr, "Bad proto file");
        return ret;
    }

    bool CheckSeverityNameFormat(const TString& name) const {
        if (name.size() > 2 && name.substr(0,2) == "S_") {
            return true;
        }
        return false;
    }

public:
    ESeverity GetSeverity(TIssueCode id) const {
        auto it = IssuesMap_.find(id);
        Y_ENSURE(it != IssuesMap_.end(), "Unknown issue id: "
            << id << "(" << IssueCodeToString<TProto>(id) << ")");
        return it->second;
    }

    TString GetMessage(TIssueCode id) const {
        auto it = IssuesFormatMap_.find(id);
        Y_ENSURE(it != IssuesFormatMap_.end(), "Unknown issue id: "
            << id << "(" << IssueCodeToString<TProto>(id) << ")");
        return it->second;
    }

    TIssueId() {
        auto configData = NResource::Find(TStringBuf(ResourceName));
        if (!::google::protobuf::TextFormat::ParseFromString(configData, &ProtoIssues_)) {
            Y_ENSURE(false, "Bad format of protobuf data file, resource: " << ResourceName);
        }

        auto sDesc = TSeverityIds::ESeverityId_descriptor();
        for (int i = 0; i < sDesc->value_count(); i++) {
            const auto& name = sDesc->value(i)->name();
            Y_ENSURE(CheckSeverityNameFormat(name),
                "Wrong severity name: " << name << ". Severity must starts with \"S_\" prefix");
        }

        for (const auto& x : ProtoIssues_.ids()) {
            auto rv = IssuesMap_.insert(std::make_pair(x.code(), x.severity()));
            Y_ENSURE(rv.second, "Duplicate issue code found, code: "
                << static_cast<int>(x.code())
                << "(" << IssueCodeToString<TProto>(x.code()) <<")");
        }

        // Check all IssueCodes have mapping to severity
        auto eDesc = TProto::EIssueCode_descriptor();
        for (int i = 0; i < eDesc->value_count(); i++) {
            auto it = IssuesMap_.find(eDesc->value(i)->number());
            Y_ENSURE(it != IssuesMap_.end(), "IssueCode: "
                << eDesc->value(i)->name()
                << " is not found in protobuf data file");
        }

        for (const auto& x : ProtoIssues_.ids()) {
            auto rv = IssuesFormatMap_.insert(std::make_pair(x.code(), x.format()));
            Y_ENSURE(rv.second, "Duplicate issue code found, code: "
                << static_cast<int>(x.code())
                << "(" << IssueCodeToString<TProto>(x.code()) <<")");
        }
    }
};

template<typename TProto, const char* ResourceName>
inline ESeverity GetSeverity(TIssueCode id) {
    return Singleton<TIssueId<TProto, ResourceName>>()->GetSeverity(id);
}

template<typename TProto, const char* ResourceName>
inline TString GetMessage(TIssueCode id) {
    return Singleton<TIssueId<TProto, ResourceName>>()->GetMessage(id);
}

}