Files
email-tracker/external/duckdb/extension/json/json_serializer.cpp
2025-10-24 19:21:19 -05:00

220 lines
5.3 KiB
C++

#include "json_serializer.hpp"
#include "duckdb/common/types/blob.hpp"
namespace duckdb {
void JsonSerializer::PushValue(yyjson_mut_val *val) {
auto current = Current();
// Array case, just append the value
if (yyjson_mut_is_arr(current)) {
yyjson_mut_arr_append(current, val);
}
// Object case, use the currently set tag.
else if (yyjson_mut_is_obj(current)) {
yyjson_mut_obj_add(current, current_tag, val);
}
// Else throw
else {
throw InternalException("Cannot add value to non-array/object json value");
}
}
void JsonSerializer::OnPropertyBegin(const field_id_t, const char *tag) {
current_tag = yyjson_mut_strcpy(doc, tag);
}
void JsonSerializer::OnPropertyEnd() {
}
void JsonSerializer::OnOptionalPropertyBegin(const field_id_t, const char *tag, bool) {
current_tag = yyjson_mut_strcpy(doc, tag);
}
void JsonSerializer::OnOptionalPropertyEnd(bool) {
}
//-------------------------------------------------------------------------
// Nested Types
//-------------------------------------------------------------------------
void JsonSerializer::OnNullableBegin(bool present) {
if (!present && !skip_if_null) {
WriteNull();
}
}
void JsonSerializer::OnNullableEnd() {
}
void JsonSerializer::OnListBegin(idx_t count) {
auto new_value = yyjson_mut_arr(doc);
// We always push a value to the stack, we just don't add it as a child to the current value
// if skipping empty. Even though it is "unnecessary" to create an empty value just to discard it,
// this allows the rest of the code to keep on like normal.
if (!(count == 0 && skip_if_empty)) {
PushValue(new_value);
}
stack.push_back(new_value);
}
void JsonSerializer::OnListEnd() {
stack.pop_back();
}
void JsonSerializer::OnObjectBegin() {
auto new_value = yyjson_mut_obj(doc);
PushValue(new_value);
stack.push_back(new_value);
}
void JsonSerializer::OnObjectEnd() {
auto obj = Current();
auto count = yyjson_mut_obj_size(obj);
stack.pop_back();
if (count == 0 && skip_if_empty && !stack.empty()) {
// remove obj from parent since it was empty
auto parent = Current();
if (yyjson_mut_is_arr(parent)) {
size_t idx;
size_t max;
yyjson_mut_val *item;
size_t found;
yyjson_mut_arr_foreach(parent, idx, max, item) {
if (item == obj) {
found = idx;
}
}
yyjson_mut_arr_remove(parent, found);
} else if (yyjson_mut_is_obj(parent)) {
size_t idx;
size_t max;
yyjson_mut_val *item;
yyjson_mut_val *key;
const char *found;
yyjson_mut_obj_foreach(parent, idx, max, key, item) {
if (item == obj) {
found = yyjson_mut_get_str(key);
}
}
yyjson_mut_obj_remove_key(parent, found);
}
}
}
//-------------------------------------------------------------------------
// Primitive Types
//-------------------------------------------------------------------------
void JsonSerializer::WriteNull() {
if (skip_if_null) {
return;
}
auto val = yyjson_mut_null(doc);
PushValue(val);
}
void JsonSerializer::WriteValue(uint8_t value) {
auto val = yyjson_mut_uint(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(int8_t value) {
auto val = yyjson_mut_sint(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(uint16_t value) {
auto val = yyjson_mut_uint(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(int16_t value) {
auto val = yyjson_mut_sint(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(uint32_t value) {
auto val = yyjson_mut_uint(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(int32_t value) {
auto val = yyjson_mut_sint(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(uint64_t value) {
auto val = yyjson_mut_uint(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(int64_t value) {
auto val = yyjson_mut_sint(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(hugeint_t value) {
auto val = yyjson_mut_obj(doc);
PushValue(val);
stack.push_back(val);
WriteProperty(100, "upper", value.upper);
WriteProperty(101, "lower", value.lower);
stack.pop_back();
}
void JsonSerializer::WriteValue(uhugeint_t value) {
auto val = yyjson_mut_obj(doc);
PushValue(val);
stack.push_back(val);
WriteProperty(100, "upper", value.upper);
WriteProperty(101, "lower", value.lower);
stack.pop_back();
}
void JsonSerializer::WriteValue(float value) {
auto val = yyjson_mut_real(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(double value) {
auto val = yyjson_mut_real(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(const string &value) {
if (skip_if_empty && value.empty()) {
return;
}
auto val = yyjson_mut_strncpy(doc, value.c_str(), value.size());
PushValue(val);
}
void JsonSerializer::WriteValue(const string_t value) {
if (skip_if_empty && value.GetSize() == 0) {
return;
}
auto val = yyjson_mut_strncpy(doc, value.GetData(), value.GetSize());
PushValue(val);
}
void JsonSerializer::WriteValue(const char *value) {
if (skip_if_empty && strlen(value) == 0) {
return;
}
auto val = yyjson_mut_strcpy(doc, value);
PushValue(val);
}
void JsonSerializer::WriteValue(bool value) {
auto val = yyjson_mut_bool(doc, value);
PushValue(val);
}
void JsonSerializer::WriteDataPtr(const_data_ptr_t ptr, idx_t count) {
auto blob = Blob::ToString(string_t(const_char_ptr_cast(ptr), count));
auto val = yyjson_mut_strcpy(doc, blob.c_str());
PushValue(val);
}
} // namespace duckdb