Browse Source

YQ-418 Дополнить политику конвертации в json новыми правилами

ref:6db01b780daa657314673fbc150eb7ae4150f957
hrustyashko 3 years ago
parent
commit
797beae740

+ 1 - 0
ydb/library/yql/providers/common/codec/CMakeLists.txt

@@ -11,6 +11,7 @@ target_link_libraries(providers-common-codec PUBLIC
   cpp-yson-node
   library-cpp-yson
   library-cpp-json
+  library-cpp-enumbitset
   tools-enum_parser-enum_serialization_runtime
 )
 target_sources(providers-common-codec PRIVATE

+ 1 - 0
ydb/library/yql/providers/common/codec/ya.make

@@ -23,6 +23,7 @@ PEERDIR(
     library/cpp/yson/node
     library/cpp/yson
     library/cpp/json
+    library/cpp/enumbitset
 )
 
 YQL_LAST_ABI_VERSION()

+ 61 - 39
ydb/library/yql/providers/common/codec/yql_json_codec.cpp

@@ -8,8 +8,11 @@
 #include <library/cpp/string_utils/base64/base64.h>
 #include <util/string/join.h>
 
+#include <cmath>
+
 namespace NYql {
 namespace NCommon {
+namespace NJsonCodec {
 
 using namespace NKikimr;
 using namespace NKikimr::NMiniKQL;
@@ -34,13 +37,13 @@ TJsonWriterConfig MakeJsonConfig() {
     config.SortKeys = false;
     config.ValidateUtf8 = false;
     config.DontEscapeStrings = true;
-    config.WriteNanAsString = false;
+    config.WriteNanAsString = true;
 
     return config;
 }
 
 void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod& value,
-                      NKikimr::NMiniKQL::TType* type, std::set<EValueConvertPolicy> convertPolicy) {
+                      NKikimr::NMiniKQL::TType* type, TValueConvertPolicy convertPolicy) {
 
     switch (type->GetKind()) {
     case TType::EKind::Void:
@@ -54,12 +57,18 @@ void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod
         break;
     case TType::EKind::Data:
         {
-            bool numberToStr = convertPolicy.contains(EValueConvertPolicy::WriteNumberString);
+            bool numberToStr = convertPolicy.Test(EValueConvertPolicy::NUMBER_AS_STRING);
             auto dataType = AS_TYPE(TDataType, type);
             switch (dataType->GetSchemeType()) {
-            case NUdf::TDataType<bool>::Id:
-                writer.Write(value.Get<bool>());
+            case NUdf::TDataType<bool>::Id: {
+                auto boolValue = value.Get<bool>();
+                if (convertPolicy.Test(EValueConvertPolicy::BOOL_AS_STRING)) {
+                    writer.Write(boolValue ? "true" : "false");
+                } else {
+                    writer.Write(boolValue);
+                }
                 break;
+            }
             case NUdf::TDataType<i32>::Id: {
                 auto number = value.Get<i32>();
                 if (numberToStr) {
@@ -82,7 +91,7 @@ void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod
                 auto number = value.Get<i64>();
                 if (numberToStr) {
                     writer.Write(ToString(number));
-                } else if (convertPolicy.contains(EValueConvertPolicy::WriteUnsafeNumberString)) {
+                } else if (convertPolicy.Test(EValueConvertPolicy::UNSAFE_NUMBER_AS_STRING)) {
                     if (number > MAX_JS_SAFE_INTEGER || number < MIN_JS_SAFE_INTEGER) {
                         writer.Write(ToString(number));
                     } else {
@@ -97,7 +106,7 @@ void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod
                 auto number = value.Get<ui64>();
                 if (numberToStr) {
                     writer.Write(ToString(number));
-                } else if (convertPolicy.contains(EValueConvertPolicy::WriteUnsafeNumberString)) {
+                } else if (convertPolicy.Test(EValueConvertPolicy::UNSAFE_NUMBER_AS_STRING)) {
                     if (number > MAX_JS_SAFE_INTEGER) {
                         writer.Write(ToString(number));
                     } else {
@@ -144,25 +153,37 @@ void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod
                 }
                 break;
             }
-            case NUdf::TDataType<float>::Id:
+            case NUdf::TDataType<float>::Id: {
+                auto floatValue = value.Get<float>();
+                bool isUndetermined = std::isnan(floatValue) || std::isinf(floatValue);
+                if (convertPolicy.Test(EValueConvertPolicy::DISALLOW_NaN) && isUndetermined) {
+                    YQL_ENSURE(false, "NaN and Inf aren't allowed");
+                }
+
                 if (numberToStr) {
-                    TString number = FloatToString(value.Get<float>(), FLOAT_MODE, FLOAT_N_DIGITS);
+                    TString number = FloatToString(floatValue, FLOAT_MODE, FLOAT_N_DIGITS);
                     writer.Write(number);
                 } else {
-                    writer.Write(value.Get<float>());
+                    writer.Write(floatValue);
                 }
                 break;
-            case NUdf::TDataType<double>::Id:
+            }
+            case NUdf::TDataType<double>::Id: {
+                auto doubleValue = value.Get<double>();
+                bool isUndetermined = std::isnan(doubleValue) || std::isinf(doubleValue);
+                if (convertPolicy.Test(EValueConvertPolicy::DISALLOW_NaN) && isUndetermined) {
+                    YQL_ENSURE(false, "NaN and Inf aren't allowed");
+                }
+
                 if (numberToStr) {
-                    TString number = FloatToString(value.Get<double>(), FLOAT_MODE, DOUBLE_N_DIGITS);
+                    TString number = FloatToString(doubleValue, FLOAT_MODE, DOUBLE_N_DIGITS);
                     writer.Write(number);
                 } else {
-                    writer.Write(value.Get<double>());
+                    writer.Write(doubleValue);
                 }
                 break;
+            }
             case NUdf::TDataType<NUdf::TJson>::Id:
-                writer.UnsafeWrite(value.AsStringRef());
-                break;
             case NUdf::TDataType<NUdf::TUtf8>::Id:
                 writer.Write(value.AsStringRef());
                 break;
@@ -225,9 +246,7 @@ void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod
     case TType::EKind::Optional:
     {
         writer.OpenArray();
-        if (!value.GetOptionalValue()) {
-            writer.WriteNull();
-        } else {
+        if (value.GetOptionalValue()) {
             auto optionalType = AS_TYPE(TOptionalType, type);
             WriteValueToJson(writer, value.GetOptionalValue(), optionalType->GetItemType(), convertPolicy);
         }
@@ -239,11 +258,18 @@ void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod
         writer.OpenArray();
         auto dictType = AS_TYPE(TDictType, type);
         const auto it = value.GetDictIterator();
-        for (NUdf::TUnboxedValue key, payload; it.NextPair(key, payload);) {
-            writer.OpenArray();
-            WriteValueToJson(writer, key, dictType->GetKeyType(), convertPolicy);
-            WriteValueToJson(writer, payload, dictType->GetPayloadType(), convertPolicy);
-            writer.CloseArray();
+        // is Set<>
+        if (dictType->GetPayloadType()->GetKind() == TType::EKind::Void) {
+            for (NUdf::TUnboxedValue key, payload; it.NextPair(key, payload);) {
+                WriteValueToJson(writer, key, dictType->GetKeyType(), convertPolicy);
+            }
+        } else {
+            for (NUdf::TUnboxedValue key, payload; it.NextPair(key, payload);) {
+                writer.OpenArray();
+                WriteValueToJson(writer, key, dictType->GetKeyType(), convertPolicy);
+                WriteValueToJson(writer, payload, dictType->GetPayloadType(), convertPolicy);
+                writer.CloseArray();
+            }
         }
         writer.CloseArray();
         break;
@@ -262,15 +288,15 @@ void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod
     {
         writer.OpenArray();
         auto index = value.GetVariantIndex();
-        writer.Write(index);
-
         auto underlyingType = AS_TYPE(TVariantType, type)->GetUnderlyingType();
         if (underlyingType->IsTuple()) {
+            writer.Write(index);
             WriteValueToJson(writer, value.GetVariantItem(),
                              AS_TYPE(TTupleType, underlyingType)->GetElementType(index), convertPolicy);
         } else {
-            WriteValueToJson(writer, value.GetVariantItem(),
-                             AS_TYPE(TStructType, underlyingType)->GetMemberType(index), convertPolicy);
+            auto structType = AS_TYPE(TStructType, underlyingType);
+            writer.Write(structType->GetMemberName(index));
+            WriteValueToJson(writer, value.GetVariantItem(), structType->GetMemberType(index), convertPolicy);
         }
         writer.CloseArray();
         break;
@@ -351,11 +377,16 @@ NKikimr::NUdf::TUnboxedValue ReadJsonValue(TJsonValue& json, NKikimr::NMiniKQL::
     }
     case TType::EKind::Optional:
     {
-        if (json.IsNull()) {
-            return NUdf::TUnboxedValuePod();
+        YQL_ENSURE(json.IsArray()
+                    && json.GetArray().size() <= 1
+                   , "Unexpected json type (expected array no more than one element, but got " << jsonType << ")");
+
+        auto array = json.GetArray();
+        if (array.empty()) {
+            return NUdf::TUnboxedValuePod().MakeOptional();
         }
         auto optionalType = AS_TYPE(TOptionalType, type);
-        auto value = ReadJsonValue(json, optionalType->GetItemType(), holderFactory);
+        auto value = ReadJsonValue(array.front(), optionalType->GetItemType(), holderFactory);
         return value.Release().MakeOptional();
     }
     case TType::EKind::Data:
@@ -444,15 +475,6 @@ NKikimr::NUdf::TUnboxedValue ReadJsonValue(TJsonValue& json, NKikimr::NMiniKQL::
     return NKikimr::NUdf::TUnboxedValuePod();
 }
 
-NKikimr::NUdf::TUnboxedValue ReadJsonValue(IInputStream* in, NKikimr::NMiniKQL::TType* type,
-    const NMiniKQL::THolderFactory& holderFactory)
-{
-    TJsonValue json;
-    if (!ReadJsonTree(in, &json, false)) {
-        YQL_ENSURE(false, "Error parse json");
-    }
-    return ReadJsonValue(json, type, holderFactory);
 }
-
 }
 }

+ 45 - 13
ydb/library/yql/providers/common/codec/yql_json_codec.h

@@ -4,27 +4,59 @@
 #include <library/cpp/json/json_reader.h>
 #include <ydb/library/yql/minikql/mkql_node.h>
 #include <ydb/library/yql/minikql/computation/mkql_computation_node_holders.h>
-
-using namespace NKikimr;
+#include <library/cpp/enumbitset/enumbitset.h>
 
 namespace NYql {
 namespace NCommon {
+namespace NJsonCodec {
+
+using namespace NKikimr;
 
-enum class EValueConvertPolicy : ui8 {
-    WriteNumberString = 1,
-    WriteUnsafeNumberString = 2,
-    //WriteNumberAsString = 4,
-    //WriteNumberAsString = 8,
+enum EValueConvertPolicy {
+    CONVERT_POLICY_BEGIN,
+    NUMBER_AS_STRING = CONVERT_POLICY_BEGIN,
+    UNSAFE_NUMBER_AS_STRING,
+    BOOL_AS_STRING,
+    DISALLOW_NaN,
+    CONVERT_POLICY_END
 };
 
+using TValueConvertPolicy = TEnumBitSet<EValueConvertPolicy, EValueConvertPolicy::CONVERT_POLICY_BEGIN, EValueConvertPolicy::CONVERT_POLICY_END>;
+
+class DefaultPolicy {
+public:
+    static DefaultPolicy& getInstance() {
+        static DefaultPolicy instance;
+        return instance;
+    }
+
+private:
+    DefaultPolicy() {}
+
+public:
+    DefaultPolicy(DefaultPolicy &) = delete;
+    void operator=(const DefaultPolicy &) = delete;
+
+    TValueConvertPolicy CloudFunction() const {
+        return CloudFunctionPolicy;
+    }
+
+    TValueConvertPolicy Export() const {
+        return ExportPolicy;
+    }
+
+private:
+    TValueConvertPolicy CloudFunctionPolicy = TValueConvertPolicy{NUMBER_AS_STRING, BOOL_AS_STRING};
+    TValueConvertPolicy ExportPolicy = TValueConvertPolicy{DISALLOW_NaN};
+};
+
+
 NJson::TJsonWriterConfig MakeJsonConfig();
 
 void WriteValueToJson(NJson::TJsonWriter& writer, const NUdf::TUnboxedValuePod& value,
-                      NMiniKQL::TType* type, std::set<EValueConvertPolicy> convertPolicy = {});
+                      NMiniKQL::TType* type, TValueConvertPolicy convertPolicy = {});
 
 NUdf::TUnboxedValue ReadJsonValue(NJson::TJsonValue& json, NMiniKQL::TType* type, const NMiniKQL::THolderFactory& holderFactory);
-
-NUdf::TUnboxedValue ReadJsonValue(IInputStream* in, NMiniKQL::TType* type, const NMiniKQL::THolderFactory& holderFactory);
-
-}
-}
+} // NJsonCodec
+} // NCommon
+} // NYql

+ 121 - 24
ydb/library/yql/providers/common/codec/yql_json_codec_ut.cpp

@@ -2,12 +2,15 @@
 
 #include <ydb/library/yql/minikql/computation/mkql_value_builder.h>
 #include <ydb/library/yql/minikql/mkql_type_ops.h>
+#include <ydb/library/yql/utils/yql_panic.h>
 #include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/json/json_reader.h>
 
 #include <util/string/cast.h>
 
 namespace NYql {
 namespace NCommon {
+namespace NJsonCodec {
 
 using namespace NYql::NCommon;
 using namespace NKikimr;
@@ -33,10 +36,10 @@ struct TTestContext {
     }
 };
 
-TString WriteValueToExportJsonStr(const NUdf::TUnboxedValuePod& value, NMiniKQL::TType* type) {
+TString WriteValueToExportJsonStr(const NUdf::TUnboxedValuePod& value, NMiniKQL::TType* type, TValueConvertPolicy policy = {}) {
     TStringStream out;
     NJson::TJsonWriter jsonWriter(&out, MakeJsonConfig());
-    WriteValueToJson(jsonWriter,value, type, {});
+    WriteValueToJson(jsonWriter,value, type, policy);
     jsonWriter.Flush();
     return out.Str();
 }
@@ -44,10 +47,21 @@ TString WriteValueToExportJsonStr(const NUdf::TUnboxedValuePod& value, NMiniKQL:
 TString WriteValueToFuncJsonStr(const NUdf::TUnboxedValuePod& value, NMiniKQL::TType* type) {
     TStringStream out;
     NJson::TJsonWriter jsonWriter(&out, MakeJsonConfig());
-    WriteValueToJson(jsonWriter,value, type, {EValueConvertPolicy::WriteNumberString});
+    TValueConvertPolicy policy;
+    policy.Set(EValueConvertPolicy::NUMBER_AS_STRING);
+    WriteValueToJson(jsonWriter,value, type, policy);
     jsonWriter.Flush();
     return out.Str();
 }
+
+NUdf::TUnboxedValue ReadJsonStrValue(IInputStream* in, NMiniKQL::TType* type, const NMiniKQL::THolderFactory& holderFactory)
+{
+    NJson::TJsonValue json;
+    if (!NJson::ReadJsonTree(in, &json, false)) {
+        YQL_ENSURE(false, "Error parse json");
+    }
+    return ReadJsonValue(json, type, holderFactory);
+}
 }
 
 Y_UNIT_TEST_SUITE(SerializeVoid) {
@@ -72,6 +86,14 @@ Y_UNIT_TEST_SUITE(SerializeBool) {
         auto json2 = WriteValueToFuncJsonStr(NUdf::TUnboxedValuePod(false), type);
         UNIT_ASSERT_VALUES_EQUAL(json2, "false");
     }
+
+    Y_UNIT_TEST(StringBool) {
+        TTestContext ctx;
+        auto type = TDataType::Create(NUdf::TDataType<bool>::Id, ctx.TypeEnv);
+        TValueConvertPolicy policy{EValueConvertPolicy::BOOL_AS_STRING};
+        auto json = WriteValueToExportJsonStr(NUdf::TUnboxedValuePod(true), type, policy);
+        UNIT_ASSERT_VALUES_EQUAL(json, "\"true\"");
+    }
 }
 
 Y_UNIT_TEST_SUITE(SerializeUuid) {
@@ -90,7 +112,7 @@ Y_UNIT_TEST_SUITE(SerializeJson) {
         auto type = TDataType::Create(NUdf::TDataType<NUdf::TJson>::Id, ctx.TypeEnv);
         auto value = ctx.Vb.NewString("\"some string с русскими йЁ\"");
         auto json = WriteValueToFuncJsonStr(value, type);
-        UNIT_ASSERT_VALUES_EQUAL(json, "\"some string с русскими йЁ\"");
+        UNIT_ASSERT_VALUES_EQUAL(json, "\"\"some string с русскими йЁ\"\"");
     }
 
     Y_UNIT_TEST(ComplexJson) {
@@ -107,7 +129,7 @@ Y_UNIT_TEST_SUITE(SerializeJson) {
         items[1] = NUdf::TUnboxedValuePod(ui32(73));
 
         auto json = WriteValueToExportJsonStr(value, type);
-        UNIT_ASSERT_VALUES_EQUAL(json, "{\"X\":{\"a\":500,\"b\":[1,2,3]},\"Y\":73}");
+        UNIT_ASSERT_VALUES_EQUAL(json, "{\"X\":\"{\"a\":500,\"b\":[1,2,3]}\",\"Y\":73}");
     }
 }
 
@@ -196,6 +218,20 @@ Y_UNIT_TEST_SUITE(SerializeContainers) {
         UNIT_ASSERT_VALUES_EQUAL(json, "[[\"key_b\",-500],[\"key_a\",781]]");
     }
 
+    Y_UNIT_TEST(SetType) {
+        TTestContext ctx;
+        auto type = TDictType::Create(
+            TDataType::Create(NUdf::TDataType<NUdf::TUtf8>::Id, ctx.TypeEnv),
+            ctx.TypeEnv.GetTypeOfVoid(),
+            ctx.TypeEnv
+        );
+        auto dictBuilder = ctx.Vb.NewDict(type, NUdf::TDictFlags::EDictKind::Hashed);
+        dictBuilder->Add(ctx.Vb.NewString("key_a"), NUdf::TUnboxedValuePod());
+        dictBuilder->Add(ctx.Vb.NewString("key_b"), NUdf::TUnboxedValuePod());
+        auto json = WriteValueToExportJsonStr(dictBuilder->Build(), type);
+        UNIT_ASSERT_VALUES_EQUAL(json, "[\"key_b\",\"key_a\"]");
+    }
+
     Y_UNIT_TEST(Tagged) {
         TTestContext ctx;
         auto type = TTaggedType::Create(TDataType::Create(NUdf::TDataType<NUdf::TDatetime>::Id, ctx.TypeEnv),
@@ -236,11 +272,11 @@ Y_UNIT_TEST_SUITE(SerializeContainers) {
 
         auto value0 = ctx.HolderFactory.CreateVariantHolder(NUdf::TUnboxedValuePod(true), 0);
         auto json0 = WriteValueToExportJsonStr(value0, type);
-        UNIT_ASSERT_VALUES_EQUAL(json0, "[0,true]");
+        UNIT_ASSERT_VALUES_EQUAL(json0, "[\"A\",true]");
 
         auto value1 = ctx.HolderFactory.CreateVariantHolder(NUdf::TUnboxedValuePod(200), 1);
         auto json1 = WriteValueToExportJsonStr(value1, type);
-        UNIT_ASSERT_VALUES_EQUAL(json1, "[1,200]");
+        UNIT_ASSERT_VALUES_EQUAL(json1, "[\"B\",200]");
     }
 
     Y_UNIT_TEST(StructType) {
@@ -276,15 +312,25 @@ Y_UNIT_TEST_SUITE(SerializeOptional) {
         UNIT_ASSERT_VALUES_EQUAL(json, "[[0,67,4]]");
     }
 
+    Y_UNIT_TEST(SimpleJust) {
+        TTestContext ctx;
+        auto elementType = TDataType::Create(NUdf::TDataType<ui32>::Id, ctx.TypeEnv);
+        TType* type = TOptionalType::Create(elementType, ctx.TypeEnv);
+        auto value = NUdf::TUnboxedValuePod(ui32(6641)).MakeOptional();
+        auto json = WriteValueToExportJsonStr(value, type);
+        UNIT_ASSERT_VALUES_EQUAL(json, "[6641]");
+    }
+
     Y_UNIT_TEST(NothingOptional) {
         TTestContext ctx;
         auto value = NUdf::TUnboxedValuePod().MakeOptional();
         auto elementType = TListType::Create(TDataType::Create(NUdf::TDataType<ui8>::Id, ctx.TypeEnv), ctx.TypeEnv);
         auto type = TOptionalType::Create(elementType, ctx.TypeEnv);
         auto json = WriteValueToFuncJsonStr(value, type);
-        UNIT_ASSERT_VALUES_EQUAL(json, "[null]");
+        UNIT_ASSERT_VALUES_EQUAL(json, "[]");
     }
 
+
     Y_UNIT_TEST(SeveralOptionals) {
         TTestContext ctx;
         auto elementType = TDataType::Create(NUdf::TDataType<ui8>::Id, ctx.TypeEnv);
@@ -294,7 +340,7 @@ Y_UNIT_TEST_SUITE(SerializeOptional) {
 
         auto value1 = NUdf::TUnboxedValuePod().MakeOptional().MakeOptional().MakeOptional();
         auto json1 = WriteValueToFuncJsonStr(value1, type);
-        UNIT_ASSERT_VALUES_EQUAL(json1, "[[[null]]]");
+        UNIT_ASSERT_VALUES_EQUAL(json1, "[[[]]]");
 
         auto value2 = NUdf::TUnboxedValuePod(ui8(120)).MakeOptional().MakeOptional().MakeOptional();
         auto json2 = WriteValueToExportJsonStr(value2, type);
@@ -390,8 +436,58 @@ Y_UNIT_TEST_SUITE(SerializeNumbers) {
         auto json1 = WriteValueToFuncJsonStr(value, type);
         UNIT_ASSERT_VALUES_EQUAL(json1, "\"788765.43\"");
     }
+
+    Y_UNIT_TEST(InfValue) {
+        TTestContext ctx;
+        auto value = NUdf::TUnboxedValuePod(std::numeric_limits<float>::infinity());
+        auto json1 = WriteValueToExportJsonStr(value, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv));
+        UNIT_ASSERT_VALUES_EQUAL(json1, "\"inf\"");
+
+        auto json2 = WriteValueToFuncJsonStr(value, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv));
+        UNIT_ASSERT_VALUES_EQUAL(json2, "\"inf\"");
+    }
+
+    Y_UNIT_TEST(NaNValue) {
+        TTestContext ctx;
+        auto value = NUdf::TUnboxedValuePod(std::numeric_limits<double>::quiet_NaN());
+        auto json1 = WriteValueToExportJsonStr(value, TDataType::Create(NUdf::TDataType<double>::Id, ctx.TypeEnv));
+        UNIT_ASSERT_VALUES_EQUAL(json1, "\"nan\"");
+
+        auto json2 = WriteValueToFuncJsonStr(value, TDataType::Create(NUdf::TDataType<double>::Id, ctx.TypeEnv));
+        UNIT_ASSERT_VALUES_EQUAL(json2, "\"nan\"");
+    }
+
+    Y_UNIT_TEST(DisallowNaN) {
+        TTestContext ctx;
+        auto valueNan = NUdf::TUnboxedValuePod(std::numeric_limits<float>::quiet_NaN());
+        TValueConvertPolicy policy{EValueConvertPolicy::DISALLOW_NaN};
+
+        UNIT_ASSERT_EXCEPTION_CONTAINS(
+            WriteValueToExportJsonStr(valueNan, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv), policy),
+            yexception,
+            "NaN and Inf aren't allowed"
+        );
+
+        auto valueInf = NUdf::TUnboxedValuePod(std::numeric_limits<double>::infinity());
+        UNIT_ASSERT_EXCEPTION_CONTAINS(
+            WriteValueToExportJsonStr(valueInf, TDataType::Create(NUdf::TDataType<double>::Id, ctx.TypeEnv), policy),
+            yexception,
+            "NaN and Inf aren't allowed"
+        );
+    }
 }
 
+Y_UNIT_TEST_SUITE(DefaultPolicy) {
+    Y_UNIT_TEST(CloudFunction) {
+        TTestContext ctx;
+        auto value = NUdf::TUnboxedValuePod(i64(540138));
+        auto policy = DefaultPolicy::getInstance().CloudFunction();
+        auto json = WriteValueToExportJsonStr(value, TDataType::Create(NUdf::TDataType<i64>::Id, ctx.TypeEnv), policy);
+        UNIT_ASSERT_VALUES_EQUAL(json, "\"540138\"");
+    }
+}
+
+
 Y_UNIT_TEST_SUITE(DeserializeNumbers) {
 
 #define TEST_DESERIALIZE_NUMBER_TYPE(type, wideType) \
@@ -400,18 +496,18 @@ Y_UNIT_TEST_SUITE(DeserializeNumbers) {
             \
         TStringStream maxJson; \
         maxJson << ToString(std::numeric_limits<type>::max()); \
-        auto maxValue = ReadJsonValue(&maxJson, TDataType::Create(NUdf::TDataType<type>::Id, ctx.TypeEnv), ctx.HolderFactory); \
+        auto maxValue = ReadJsonStrValue(&maxJson, TDataType::Create(NUdf::TDataType<type>::Id, ctx.TypeEnv), ctx.HolderFactory); \
         UNIT_ASSERT_VALUES_EQUAL(maxValue.Get<type>(), std::numeric_limits<type>::max()); \
             \
         TStringStream minJson; \
         minJson << ToString(std::numeric_limits<type>::min()); \
-        auto minValue = ReadJsonValue(&minJson, TDataType::Create(NUdf::TDataType<type>::Id, ctx.TypeEnv), ctx.HolderFactory); \
+        auto minValue = ReadJsonStrValue(&minJson, TDataType::Create(NUdf::TDataType<type>::Id, ctx.TypeEnv), ctx.HolderFactory); \
         UNIT_ASSERT_VALUES_EQUAL(minValue.Get<type>(), std::numeric_limits<type>::min()); \
             \
         TStringStream exceededJson; \
         exceededJson << ToString(wideType(std::numeric_limits<type>::max() + wideType(1))); \
         UNIT_ASSERT_EXCEPTION_CONTAINS( \
-            ReadJsonValue(&exceededJson, TDataType::Create(NUdf::TDataType<type>::Id, ctx.TypeEnv), ctx.HolderFactory), \
+            ReadJsonStrValue(&exceededJson, TDataType::Create(NUdf::TDataType<type>::Id, ctx.TypeEnv), ctx.HolderFactory), \
             yexception, \
             "Exceeded the range" \
         ); \
@@ -431,13 +527,13 @@ Y_UNIT_TEST_SUITE(DeserializeNumbers) {
         TTestContext ctx;
         TStringStream json;
         json << "0.0431";
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv), ctx.HolderFactory);
         UNIT_ASSERT_VALUES_EQUAL(value.Get<float>(), 0.0431f);
 
         TStringStream exceededJson;
         exceededJson << ToString(std::numeric_limits<double>::max());
         UNIT_ASSERT_EXCEPTION_CONTAINS(
-            ReadJsonValue(&exceededJson, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv), ctx.HolderFactory),
+            ReadJsonStrValue(&exceededJson, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv), ctx.HolderFactory),
             yexception,
             "Exceeded the range"
         );
@@ -447,7 +543,7 @@ Y_UNIT_TEST_SUITE(DeserializeNumbers) {
         TTestContext ctx;
         TStringStream json;
         json << "1766718243";
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<float>::Id, ctx.TypeEnv), ctx.HolderFactory);
         UNIT_ASSERT_VALUES_EQUAL(value.Get<float>(), 1766718243.0f);
     }
 
@@ -455,7 +551,7 @@ Y_UNIT_TEST_SUITE(DeserializeNumbers) {
         TTestContext ctx;
         TStringStream json;
         json << "7773.13";
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<double>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<double>::Id, ctx.TypeEnv), ctx.HolderFactory);
         UNIT_ASSERT_VALUES_EQUAL(value.Get<double>(), 7773.13);
     }
 
@@ -463,7 +559,7 @@ Y_UNIT_TEST_SUITE(DeserializeNumbers) {
         TTestContext ctx;
         TStringStream json;
         json << "-667319001";
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<double>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<double>::Id, ctx.TypeEnv), ctx.HolderFactory);
         UNIT_ASSERT_VALUES_EQUAL(value.Get<double>(), -667319001.0l);
     }
 
@@ -497,7 +593,7 @@ Y_UNIT_TEST_SUITE(DeserializeStringTypes) {
         TTestContext ctx;
         TStringStream json;
         json << "\"fffaaae423\"";
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TUtf8>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TUtf8>::Id, ctx.TypeEnv), ctx.HolderFactory);
         UNIT_ASSERT_VALUES_EQUAL(TStringBuf("fffaaae423"), TStringBuf(value.AsStringRef()));
     }
 }
@@ -570,7 +666,7 @@ Y_UNIT_TEST_SUITE(DeserializeDateTypes) {
         TTestContext ctx;
         TStringStream json;
         json << "\"2020-09-11\"";
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TDate>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TDate>::Id, ctx.TypeEnv), ctx.HolderFactory);
         ui16 date;
         ctx.Vb.MakeDate(2020, 9, 11, date);
         UNIT_ASSERT_VALUES_EQUAL(value.Get<ui16>(), date);
@@ -580,7 +676,7 @@ Y_UNIT_TEST_SUITE(DeserializeDateTypes) {
         TTestContext ctx;
         TStringStream json;
         json << "\"2021-07-14T00:00:43Z\"";
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TDatetime>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TDatetime>::Id, ctx.TypeEnv), ctx.HolderFactory);
         ui32 datetime;
         ctx.Vb.MakeDatetime(2021, 7, 14, 0, 0, 43, datetime);
         UNIT_ASSERT_VALUES_EQUAL(value.Get<ui32>(), datetime);
@@ -590,7 +686,7 @@ Y_UNIT_TEST_SUITE(DeserializeDateTypes) {
         TTestContext ctx;
         TStringStream json;
         json << "\"2020-09-11,Europe/Moscow\""; // timeZoneId == 1
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TTzDate>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TTzDate>::Id, ctx.TypeEnv), ctx.HolderFactory);
         ui16 date;
         ctx.Vb.MakeDate(2020, 9, 10, date);
         UNIT_ASSERT_VALUES_EQUAL(value.GetTimezoneId(), 1);
@@ -601,7 +697,7 @@ Y_UNIT_TEST_SUITE(DeserializeDateTypes) {
         TTestContext ctx;
         TStringStream json;
         json << "\"2020-09-11T01:11:05,Europe/Moscow\""; // timeZoneId == 1
-        auto value = ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TTzDatetime>::Id, ctx.TypeEnv), ctx.HolderFactory);
+        auto value = ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TTzDatetime>::Id, ctx.TypeEnv), ctx.HolderFactory);
         ui32 datetime;
         ctx.Vb.MakeDatetime(2020, 9, 11, 1, 11, 5, datetime, 1);
         UNIT_ASSERT_VALUES_EQUAL(value.GetTimezoneId(), 1);
@@ -613,7 +709,7 @@ Y_UNIT_TEST_SUITE(DeserializeDateTypes) {
         TStringStream json;
         json << "[\"2020-22-12\"]";
         UNIT_ASSERT_EXCEPTION_CONTAINS(
-            ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TDate>::Id, ctx.TypeEnv), ctx.HolderFactory),
+            ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TDate>::Id, ctx.TypeEnv), ctx.HolderFactory),
             yexception,
             "Unexpected json type (expected string"
         );
@@ -624,7 +720,7 @@ Y_UNIT_TEST_SUITE(DeserializeDateTypes) {
         TStringStream json;
         json << "\"2020-18-43\"";
         UNIT_ASSERT_EXCEPTION_CONTAINS(
-            ReadJsonValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TDate>::Id, ctx.TypeEnv), ctx.HolderFactory),
+            ReadJsonStrValue(&json, TDataType::Create(NUdf::TDataType<NUdf::TDate>::Id, ctx.TypeEnv), ctx.HolderFactory),
             yexception,
             "Invalid date format"
         );
@@ -633,4 +729,5 @@ Y_UNIT_TEST_SUITE(DeserializeDateTypes) {
 
 } // namespace
 } // namespace
+} // namespace