diff options
author | shishmak <shishmak@yandex-team.com> | 2024-09-19 16:27:03 +0300 |
---|---|---|
committer | shishmak <shishmak@yandex-team.com> | 2024-09-19 16:41:50 +0300 |
commit | f4a740ff0d5b53d8a44150c09e019eaa6d331821 (patch) | |
tree | 89a423f89845db654d6433580c2b499f206a62cd | |
parent | aa20162565ccc09b8d98b4c8d3fa73766c9cc2e8 (diff) | |
download | ydb-f4a740ff0d5b53d8a44150c09e019eaa6d331821.tar.gz |
YT: Fix fail on WriteSchema for null object of type TYsonStruct
commit_hash:771e910a67daff1e39c97a2518d523db3714002e
-rw-r--r-- | yt/yt/core/ytree/unittests/yson_schema_ut.cpp | 38 | ||||
-rw-r--r-- | yt/yt/core/ytree/yson_schema-inl.h | 21 |
2 files changed, 58 insertions, 1 deletions
diff --git a/yt/yt/core/ytree/unittests/yson_schema_ut.cpp b/yt/yt/core/ytree/unittests/yson_schema_ut.cpp index 220e38975a..88df8268a2 100644 --- a/yt/yt/core/ytree/unittests/yson_schema_ut.cpp +++ b/yt/yt/core/ytree/unittests/yson_schema_ut.cpp @@ -157,6 +157,20 @@ struct TTestStructWithCustomType } }; +struct TTestStructWithUndefinedType + : public TYsonStruct +{ + NYT::NYTree::TYsonStructPtr UndefinedTypeField; + + REGISTER_YSON_STRUCT(TTestStructWithUndefinedType); + + static void Register(TRegistrar registrar) + { + registrar.Parameter("undefined_type_field", &TThis::UndefinedTypeField) + .Optional(); + } +}; + //////////////////////////////////////////////////////////////////////////////// void CheckSchema(const TYsonStructPtr& ysonStruct, TStringBuf expected) @@ -236,6 +250,30 @@ TEST(TYsonStructSchemaTest, TestYsonStructWithCustomType) ]})"); } +TEST(TYsonStructSchemaTest, TestYsonStructWithUndefinedType) +{ + auto ysonStruct = New<TTestStructWithUndefinedType>(); + CheckSchema( + ysonStruct, + R"({type_name="struct"; + members=[ + { + name="undefined_type_field"; + type={type_name="optional";item={type_name="struct";members=[];};}; + }; + ]})"); + ysonStruct->UndefinedTypeField = New<TTestSubStruct>(); + CheckSchema( + ysonStruct, + R"({type_name="struct"; + members=[ + { + name="undefined_type_field"; + type={type_name="optional";item={type_name="struct";members=[{name="my_uint";type="uint32";}]}}; + }; + ]})"); +} + //////////////////////////////////////////////////////////////////////////////// } // namespace diff --git a/yt/yt/core/ytree/yson_schema-inl.h b/yt/yt/core/ytree/yson_schema-inl.h index 821048f19f..2f7b98912a 100644 --- a/yt/yt/core/ytree/yson_schema-inl.h +++ b/yt/yt/core/ytree/yson_schema-inl.h @@ -90,13 +90,32 @@ void WriteSchema(const T&, NYson::IYsonConsumer* consumer) } template <CYsonStructDerived T> +void WriteSchemaForNull(NYson::IYsonConsumer* consumer) +{ + if constexpr (std::is_same_v<T, TYsonStruct>) { + // It is not allowed to instantiate object of type `TYsonStruct`. + BuildYsonFluently(consumer) + .BeginMap() + .Item("type_name").Value("struct") + .Item("members").BeginList().EndList() + .EndMap(); + } else { + New<T>()->WriteSchema(consumer); + } +} + +template <CYsonStructDerived T> void WriteSchema(const NYT::TIntrusivePtr<T>& value, NYson::IYsonConsumer* consumer) { BuildYsonFluently(consumer) .BeginMap() .Item("type_name").Value("optional") .Item("item").Do([&] (auto fluent) { - (value ? value : New<T>())->WriteSchema(fluent.GetConsumer()); + if (value) { + value->WriteSchema(fluent.GetConsumer()); + } else { + WriteSchemaForNull<T>(fluent.GetConsumer()); + } }) .EndMap(); } |