YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/common/json_util.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include "yb/common/json_util.h"
15
16
#include <rapidjson/prettywriter.h>
17
18
#include "yb/bfql/bfunc_convert.h"
19
20
#include "yb/common/jsonb.h"
21
#include "yb/common/ql_value.h"
22
23
#include "yb/util/status_format.h"
24
#include "yb/util/string_case.h"
25
26
namespace yb {
27
namespace common {
28
29
Status ConvertQLValuePBToRapidJson(const QLValuePB& ql_value_pb,
30
                                   rapidjson::Value* rapidjson_value,
31
297
                                   rapidjson::Document::AllocatorType* alloc) {
32
26
  auto is_nan_or_inf = [](double number) -> bool {
33
26
    const string str = SimpleDtoa(number);
34
26
    return str == "nan"|| str == "-nan"|| str == "inf" || str == "-inf";
35
26
  };
36
37
297
  auto seq_to_json = [](rapidjson::Value* value,
38
297
                        const QLSeqValuePB& seq_pb,
39
18
                        rapidjson::Document::AllocatorType* alloc) -> Status {
40
18
    value->SetArray();
41
18
    rapidjson::Value seq_value;
42
53
    for (int i = 0; i < seq_pb.elems_size(); ++i) {
43
35
      RETURN_NOT_OK(ConvertQLValuePBToRapidJson(seq_pb.elems(i), &seq_value, alloc));
44
35
      value->PushBack(seq_value, *alloc);
45
35
    }
46
18
    return Status::OK();
47
18
  };
48
49
297
  switch (ql_value_pb.value_case()) {
50
2
    case QLValuePB::ValueCase::VALUE_NOT_SET: // NULL -> null.
51
2
      rapidjson_value->SetNull();
52
2
      break;
53
54
2
    case QLValuePB::ValueCase::kJsonbValue: { // JSONB -> RapidJson.
55
2
        common::Jsonb jsonb(ql_value_pb.jsonb_value());
56
2
        rapidjson::Document doc;
57
2
        RETURN_NOT_OK(jsonb.ToRapidJson(&doc));
58
2
        rapidjson_value->CopyFrom(doc, *alloc);
59
2
      }
60
2
      break;
61
62
17
    case QLValuePB::ValueCase::kFloatValue:
63
17
      if (is_nan_or_inf(ql_value_pb.float_value())) {
64
14
        rapidjson_value->SetNull();
65
3
      } else {
66
3
        rapidjson_value->SetFloat(ql_value_pb.float_value());
67
3
      }
68
17
      break;
69
9
    case QLValuePB::ValueCase::kDoubleValue:
70
9
      if (is_nan_or_inf(ql_value_pb.double_value())) {
71
6
        rapidjson_value->SetNull();
72
3
      } else {
73
3
        rapidjson_value->SetDouble(ql_value_pb.double_value());
74
3
      }
75
9
      break;
76
77
3
    case QLValuePB::ValueCase::kInt8Value:
78
3
      rapidjson_value->SetInt(ql_value_pb.int8_value());
79
3
      break;
80
3
    case QLValuePB::ValueCase::kInt16Value:
81
3
      rapidjson_value->SetInt(ql_value_pb.int16_value());
82
3
      break;
83
90
    case QLValuePB::ValueCase::kInt32Value:
84
90
      rapidjson_value->SetInt(ql_value_pb.int32_value());
85
90
      break;
86
3
    case QLValuePB::ValueCase::kInt64Value:
87
3
      rapidjson_value->SetInt64(ql_value_pb.int64_value());
88
3
      break;
89
86
    case QLValuePB::ValueCase::kStringValue:
90
86
      rapidjson_value->SetString(ql_value_pb.string_value().c_str(), *alloc);
91
86
      break;
92
3
    case QLValuePB::ValueCase::kBoolValue:
93
3
      rapidjson_value->SetBool(ql_value_pb.bool_value());
94
3
      break;
95
96
3
    case QLValuePB::ValueCase::kVarintValue: { // VARINT -> INT64
97
3
        util::VarInt varint;
98
3
        size_t num_decoded_bytes = 0;
99
3
        RETURN_NOT_OK(varint.DecodeFromComparable(ql_value_pb.varint_value(), &num_decoded_bytes));
100
3
        rapidjson_value->SetInt64(VERIFY_RESULT(varint.ToInt64()));
101
3
      }
102
3
      break;
103
104
5
    case QLValuePB::ValueCase::kDecimalValue: { // DECIMAL -> INT64 or DOUBLE
105
5
        util::Decimal d;
106
5
        RETURN_NOT_OK(d.DecodeFromComparable(ql_value_pb.decimal_value()));
107
5
        if (d.is_integer()) {
108
4
          rapidjson_value->SetInt64(VERIFY_RESULT(VERIFY_RESULT(d.ToVarInt()).ToInt64()));
109
3
        } else {
110
3
          rapidjson_value->SetDouble(VERIFY_RESULT(d.ToDouble()));
111
3
        }
112
5
      }
113
5
      break;
114
115
3
    case QLValuePB::ValueCase::kTimestampValue: FALLTHROUGH_INTENDED;
116
6
    case QLValuePB::ValueCase::kDateValue: FALLTHROUGH_INTENDED;
117
9
    case QLValuePB::ValueCase::kTimeValue: FALLTHROUGH_INTENDED;
118
12
    case QLValuePB::ValueCase::kUuidValue: FALLTHROUGH_INTENDED;
119
14
    case QLValuePB::ValueCase::kTimeuuidValue: FALLTHROUGH_INTENDED;
120
17
    case QLValuePB::ValueCase::kBinaryValue: FALLTHROUGH_INTENDED;
121
20
    case QLValuePB::ValueCase::kInetaddressValue: {
122
        // Any simple type -> String.
123
20
        QLValue::SharedPtr source(new QLValue(ql_value_pb));
124
20
        QLValue::SharedPtr target(new QLValue);
125
20
        RETURN_NOT_OK(bfql::ConvertToString(source, target));
126
20
        rapidjson_value->SetString(target->string_value().c_str(), *alloc);
127
20
      }
128
20
      break;
129
130
5
    case QLValuePB::ValueCase::kSetValue: // SET -> RapidJson.
131
5
      RETURN_NOT_OK(seq_to_json(rapidjson_value, ql_value_pb.set_value(), alloc));
132
5
      break;
133
4
    case QLValuePB::ValueCase::kListValue: // LIST -> RapidJson.
134
4
      RETURN_NOT_OK(seq_to_json(rapidjson_value, ql_value_pb.list_value(), alloc));
135
4
      break;
136
137
9
    case QLValuePB::ValueCase::kFrozenValue: // FROZEN -> RapidJson.
138
      // Note: This implementation is correct for FROZEN<SET> & FROZEN<LIST> only.
139
      //       Implementation for other cases needs type info, the cases:
140
      //       FROZEN<MAP>, FROZEN<UDT>, FROZEN<SET<FROZEN<UDT>>>.
141
9
      RETURN_NOT_OK(seq_to_json(rapidjson_value, ql_value_pb.frozen_value(), alloc));
142
9
      break;
143
144
33
    case QLValuePB::ValueCase::kMapValue: { // MAP -> RapidJson.
145
33
      const QLMapValuePB& map_pb = ql_value_pb.map_value();
146
147
33
      if (map_pb.keys_size() != map_pb.values_size()) {
148
0
        return STATUS_SUBSTITUTE(QLError, "Invalid map: $0 keys and $1 values",
149
0
            map_pb.keys_size(), map_pb.values_size());
150
0
      }
151
152
33
      rapidjson_value->SetObject();
153
33
      rapidjson::Value map_key, map_value;
154
109
      for (int i = 0; i < map_pb.keys_size(); ++i) {
155
76
        RETURN_NOT_OK(ConvertQLValuePBToRapidJson(map_pb.keys(i), &map_key, alloc));
156
        // Quote the key if the key is not a string OR
157
        // if the key string contains characters in upper-case.
158
76
        if (!map_key.IsString() || ContainsUpperCase(map_key.GetString())) {
159
16
          string map_key_str = WriteRapidJsonToString(map_key);
160
16
          map_key.Swap(rapidjson::Value().SetString(map_key_str.c_str(), *alloc));
161
16
        }
162
163
76
        RETURN_NOT_OK(ConvertQLValuePBToRapidJson(map_pb.values(i), &map_value, alloc));
164
76
        rapidjson_value->AddMember(map_key, map_value, *alloc);
165
76
      }
166
33
    }
167
33
    break;
168
169
0
    default:
170
0
        return STATUS_SUBSTITUTE(
171
297
            QLError, "Unexpected value type: $0", ql_value_pb.ShortDebugString());
172
297
  }
173
174
297
  return Status::OK();
175
297
}
176
177
610
std::string WriteRapidJsonToString(const rapidjson::Value& document) {
178
610
  rapidjson::StringBuffer buffer;
179
610
  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
180
610
  document.Accept(writer);
181
610
  return std::string(buffer.GetString());
182
610
}
183
184
0
std::string PrettyWriteRapidJsonToString(const rapidjson::Value& document) {
185
0
  rapidjson::StringBuffer buffer;
186
0
  rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
187
0
  document.Accept(writer);
188
0
  return std::string(buffer.GetString());
189
0
}
190
191
} // namespace common
192
} // namespace yb