#include "json_deserializer.hpp" #include "duckdb/common/types/blob.hpp" namespace duckdb { void JsonDeserializer::OnPropertyBegin(const field_id_t, const char *tag) { current_tag = tag; } void JsonDeserializer::OnPropertyEnd() { } bool JsonDeserializer::OnOptionalPropertyBegin(const field_id_t, const char *tag) { auto parent = Current(); auto present = yyjson_obj_get(parent.val, tag) != nullptr; if (present) { current_tag = tag; } return present; } void JsonDeserializer::OnOptionalPropertyEnd(bool) { } // If inside an object, return the value associated by the current tag (property name) // If inside an array, return the next element in the sequence yyjson_val *JsonDeserializer::GetNextValue() { auto &parent_val = Current(); yyjson_val *val; if (yyjson_is_obj(parent_val.val)) { val = yyjson_obj_get(parent_val.val, current_tag); if (!val) { const char *json = yyjson_val_write(Current().val, 0, nullptr); auto msg = StringUtil::Format("Expected but did not find property '%s' in json object: '%s'", current_tag, json); free((void *)json); throw ParserException(msg); } } else if (yyjson_is_arr(parent_val.val)) { val = yyjson_arr_iter_next(&parent_val.arr_iter); if (!val) { const char *json = yyjson_val_write(Current().val, 0, nullptr); auto msg = StringUtil::Format("Expected but did not find another value after exhausting json array: '%s'", json); free((void *)json); throw ParserException(msg); } } else { // unreachable? throw InternalException("Cannot get value from non-array/object"); } return val; } void JsonDeserializer::ThrowTypeError(yyjson_val *val, const char *expected) { auto actual = yyjson_get_type_desc(val); auto &parent = Current(); if (yyjson_is_obj(parent.val)) { auto msg = StringUtil::Format("property '%s' expected type '%s', but got type: '%s'", current_tag, expected, actual); throw ParserException(msg); } else if (yyjson_is_arr(parent.val)) { auto msg = StringUtil::Format("Sequence expect child of type '%s', but got type: %s", expected, actual); throw ParserException(msg); } else { // unreachable? throw InternalException("cannot get nested value from non object or array-type"); } } void JsonDeserializer::DumpDoc() { const char *json = yyjson_write(doc, 0, nullptr); printf("json: %s\n", json); free((void *)json); } void JsonDeserializer::DumpCurrent() { const char *json = yyjson_val_write(Current().val, 0, nullptr); printf("json: %s\n", json); free((void *)json); } void JsonDeserializer::Dump(yyjson_mut_val *val) { const char *json = yyjson_mut_val_write(val, 0, nullptr); printf("json: %s\n", json); free((void *)json); } void JsonDeserializer::Dump(yyjson_val *val) { const char *json = yyjson_val_write(val, 0, nullptr); printf("json: %s\n", json); free((void *)json); } //===--------------------------------------------------------------------===// // Nested Types Hooks //===--------------------------------------------------------------------===// void JsonDeserializer::OnObjectBegin() { auto val = GetNextValue(); if (!yyjson_is_obj(val)) { ThrowTypeError(val, "object"); } Push(val); } void JsonDeserializer::OnObjectEnd() { stack.pop_back(); } idx_t JsonDeserializer::OnListBegin() { auto val = GetNextValue(); if (!yyjson_is_arr(val)) { ThrowTypeError(val, "array"); } Push(val); return yyjson_arr_size(val); } void JsonDeserializer::OnListEnd() { Pop(); } bool JsonDeserializer::OnNullableBegin() { auto &parent_val = Current(); yyjson_arr_iter iter; if (yyjson_is_arr(parent_val.val)) { iter = parent_val.arr_iter; } auto val = GetNextValue(); // Recover the iterator if we are inside an array if (yyjson_is_arr(parent_val.val)) { parent_val.arr_iter = iter; } if (yyjson_is_null(val)) { return false; } return true; } void JsonDeserializer::OnNullableEnd() { } //===--------------------------------------------------------------------===// // Primitive Types //===--------------------------------------------------------------------===// bool JsonDeserializer::ReadBool() { auto val = GetNextValue(); if (!yyjson_is_bool(val)) { ThrowTypeError(val, "bool"); } return yyjson_get_bool(val); } int8_t JsonDeserializer::ReadSignedInt8() { auto val = GetNextValue(); if (!yyjson_is_int(val)) { ThrowTypeError(val, "int8_t"); } return yyjson_get_sint(val); } uint8_t JsonDeserializer::ReadUnsignedInt8() { auto val = GetNextValue(); if (!yyjson_is_uint(val)) { ThrowTypeError(val, "uint8_t"); } return yyjson_get_uint(val); } int16_t JsonDeserializer::ReadSignedInt16() { auto val = GetNextValue(); if (!yyjson_is_int(val)) { ThrowTypeError(val, "int16_t"); } return yyjson_get_sint(val); } uint16_t JsonDeserializer::ReadUnsignedInt16() { auto val = GetNextValue(); if (!yyjson_is_uint(val)) { ThrowTypeError(val, "uint16_t"); } return yyjson_get_uint(val); } int32_t JsonDeserializer::ReadSignedInt32() { auto val = GetNextValue(); if (!yyjson_is_int(val)) { ThrowTypeError(val, "int32_t"); } return yyjson_get_sint(val); } uint32_t JsonDeserializer::ReadUnsignedInt32() { auto val = GetNextValue(); if (!yyjson_is_uint(val)) { ThrowTypeError(val, "uint32_t"); } return yyjson_get_uint(val); } int64_t JsonDeserializer::ReadSignedInt64() { auto val = GetNextValue(); if (!yyjson_is_int(val)) { ThrowTypeError(val, "int64_t"); } return yyjson_get_sint(val); } uint64_t JsonDeserializer::ReadUnsignedInt64() { auto val = GetNextValue(); if (!yyjson_is_uint(val)) { ThrowTypeError(val, "uint64_t"); } return yyjson_get_uint(val); } float JsonDeserializer::ReadFloat() { auto val = GetNextValue(); if (!yyjson_is_real(val)) { ThrowTypeError(val, "float"); } return yyjson_get_real(val); } double JsonDeserializer::ReadDouble() { auto val = GetNextValue(); if (!yyjson_is_real(val)) { ThrowTypeError(val, "double"); } return yyjson_get_real(val); } string JsonDeserializer::ReadString() { auto val = GetNextValue(); if (!yyjson_is_str(val)) { ThrowTypeError(val, "string"); } return yyjson_get_str(val); } hugeint_t JsonDeserializer::ReadHugeInt() { auto val = GetNextValue(); if (!yyjson_is_obj(val)) { ThrowTypeError(val, "object"); } Push(val); hugeint_t result; ReadProperty(100, "upper", result.upper); ReadProperty(101, "lower", result.lower); Pop(); return result; } uhugeint_t JsonDeserializer::ReadUhugeInt() { auto val = GetNextValue(); if (!yyjson_is_obj(val)) { ThrowTypeError(val, "object"); } Push(val); uhugeint_t result; ReadProperty(100, "upper", result.upper); ReadProperty(101, "lower", result.lower); Pop(); return result; } void JsonDeserializer::ReadDataPtr(data_ptr_t &ptr, idx_t count) { auto val = GetNextValue(); if (!yyjson_is_str(val)) { ThrowTypeError(val, "string"); } auto str = yyjson_get_str(val); auto len = yyjson_get_len(val); D_ASSERT(len == count); auto blob = string_t(str, len); Blob::ToString(blob, char_ptr_cast(ptr)); } } // namespace duckdb