protobuf_table_schema_ut.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. #include "common_ut.h"
  2. #include <yt/cpp/mapreduce/interface/common.h>
  3. #include <yt/cpp/mapreduce/interface/errors.h>
  4. #include <yt/cpp/mapreduce/interface/ut/proto3_ut.pb.h>
  5. #include <yt/cpp/mapreduce/interface/ut/protobuf_table_schema_ut.pb.h>
  6. #include <yt/cpp/mapreduce/tests/yt_unittest_lib/yt_unittest_lib.h>
  7. #include <library/cpp/testing/gtest/gtest.h>
  8. #include <util/generic/fwd.h>
  9. #include <algorithm>
  10. using namespace NYT;
  11. bool IsFieldPresent(const TTableSchema& schema, TStringBuf name)
  12. {
  13. for (const auto& field : schema.Columns()) {
  14. if (field.Name() == name) {
  15. return true;
  16. }
  17. }
  18. return false;
  19. }
  20. TEST(TProtoSchemaSimpleTest, TIntegral)
  21. {
  22. const auto schema = CreateTableSchema<NUnitTesting::TIntegral>();
  23. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  24. .AddColumn(TColumnSchema().Name("DoubleField").Type(ToTypeV3(EValueType::VT_DOUBLE, false)))
  25. .AddColumn(TColumnSchema().Name("FloatField").Type(ToTypeV3(EValueType::VT_DOUBLE, false)))
  26. .AddColumn(TColumnSchema().Name("Int32Field").Type(ToTypeV3(EValueType::VT_INT32, false)))
  27. .AddColumn(TColumnSchema().Name("Int64Field").Type(ToTypeV3(EValueType::VT_INT64, false)))
  28. .AddColumn(TColumnSchema().Name("Uint32Field").Type(ToTypeV3(EValueType::VT_UINT32, false)))
  29. .AddColumn(TColumnSchema().Name("Uint64Field").Type(ToTypeV3(EValueType::VT_UINT64, false)))
  30. .AddColumn(TColumnSchema().Name("Sint32Field").Type(ToTypeV3(EValueType::VT_INT32, false)))
  31. .AddColumn(TColumnSchema().Name("Sint64Field").Type(ToTypeV3(EValueType::VT_INT64, false)))
  32. .AddColumn(TColumnSchema().Name("Fixed32Field").Type(ToTypeV3(EValueType::VT_UINT32, false)))
  33. .AddColumn(TColumnSchema().Name("Fixed64Field").Type(ToTypeV3(EValueType::VT_UINT64, false)))
  34. .AddColumn(TColumnSchema().Name("Sfixed32Field").Type(ToTypeV3(EValueType::VT_INT32, false)))
  35. .AddColumn(TColumnSchema().Name("Sfixed64Field").Type(ToTypeV3(EValueType::VT_INT64, false)))
  36. .AddColumn(TColumnSchema().Name("BoolField").Type(ToTypeV3(EValueType::VT_BOOLEAN, false)))
  37. .AddColumn(TColumnSchema().Name("EnumField").Type(ToTypeV3(EValueType::VT_STRING, false))));
  38. }
  39. TEST(TProtoSchemaSimpleTest, TOneOf)
  40. {
  41. const auto schema = CreateTableSchema<NUnitTesting::TOneOf>();
  42. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  43. .AddColumn(TColumnSchema().Name("DoubleField").Type(ToTypeV3(EValueType::VT_DOUBLE, false)))
  44. .AddColumn(TColumnSchema().Name("Int32Field").Type(ToTypeV3(EValueType::VT_INT32, false)))
  45. .AddColumn(TColumnSchema().Name("BoolField").Type(ToTypeV3(EValueType::VT_BOOLEAN, false))));
  46. }
  47. TEST(TProtoSchemaSimpleTest, TWithRequired)
  48. {
  49. const auto schema = CreateTableSchema<NUnitTesting::TWithRequired>();
  50. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  51. .AddColumn(TColumnSchema().Name("RequiredField").Type(ToTypeV3(EValueType::VT_STRING, true)))
  52. .AddColumn(TColumnSchema().Name("NotRequiredField").Type(ToTypeV3(EValueType::VT_STRING, false))));
  53. }
  54. TEST(TProtoSchemaSimpleTest, TAggregated)
  55. {
  56. const auto schema = CreateTableSchema<NUnitTesting::TAggregated>();
  57. EXPECT_EQ(6u, schema.Columns().size());
  58. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  59. .AddColumn(TColumnSchema().Name("StringField").Type(ToTypeV3(EValueType::VT_STRING, false)))
  60. .AddColumn(TColumnSchema().Name("BytesField").Type(ToTypeV3(EValueType::VT_STRING, false)))
  61. .AddColumn(TColumnSchema().Name("NestedField").Type(ToTypeV3(EValueType::VT_STRING, false)))
  62. .AddColumn(TColumnSchema().Name("NestedRepeatedField").Type(ToTypeV3(EValueType::VT_STRING, false)))
  63. .AddColumn(TColumnSchema().Name("NestedOneOfField").Type(ToTypeV3(EValueType::VT_STRING, false)))
  64. .AddColumn(TColumnSchema().Name("NestedRecursiveField").Type(ToTypeV3(EValueType::VT_STRING, false))));
  65. }
  66. TEST(TProtoSchemaSimpleTest, TAliased)
  67. {
  68. const auto schema = CreateTableSchema<NUnitTesting::TAliased>();
  69. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  70. .AddColumn(TColumnSchema().Name("key").Type(ToTypeV3(EValueType::VT_INT32, false)))
  71. .AddColumn(TColumnSchema().Name("subkey").Type(ToTypeV3(EValueType::VT_DOUBLE, false)))
  72. .AddColumn(TColumnSchema().Name("Data").Type(ToTypeV3(EValueType::VT_STRING, false))));
  73. }
  74. TEST(TProtoSchemaSimpleTest, SortColumns)
  75. {
  76. const TSortColumns keys = {"key", "subkey"};
  77. const auto schema = CreateTableSchema<NUnitTesting::TAliased>(keys);
  78. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  79. .AddColumn(TColumnSchema()
  80. .Name("key")
  81. .Type(ToTypeV3(EValueType::VT_INT32, false))
  82. .SortOrder(ESortOrder::SO_ASCENDING))
  83. .AddColumn(TColumnSchema()
  84. .Name("subkey")
  85. .Type(ToTypeV3(EValueType::VT_DOUBLE, false))
  86. .SortOrder(ESortOrder::SO_ASCENDING))
  87. .AddColumn(TColumnSchema().Name("Data").Type(ToTypeV3(EValueType::VT_STRING, false))));
  88. }
  89. TEST(TProtoSchemaSimpleTest, SortColumnsReordered)
  90. {
  91. const TSortColumns keys = {"subkey"};
  92. const auto schema = CreateTableSchema<NUnitTesting::TAliased>(keys);
  93. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  94. .AddColumn(TColumnSchema()
  95. .Name("subkey")
  96. .Type(ToTypeV3(EValueType::VT_DOUBLE, false))
  97. .SortOrder(ESortOrder::SO_ASCENDING))
  98. .AddColumn(TColumnSchema().Name("key").Type(ToTypeV3(EValueType::VT_INT32, false)))
  99. .AddColumn(TColumnSchema().Name("Data").Type(ToTypeV3(EValueType::VT_STRING, false))));
  100. }
  101. TEST(TProtoSchemaSimpleTest, SortColumnsInvalid)
  102. {
  103. EXPECT_THROW(CreateTableSchema<NUnitTesting::TAliased>({"subkey", "subkey"}), yexception);
  104. EXPECT_THROW(CreateTableSchema<NUnitTesting::TAliased>({"key", "junk"}), yexception);
  105. }
  106. TEST(TProtoSchemaSimpleTest, KeepFieldsWithoutExtensionTrue)
  107. {
  108. const auto schema = CreateTableSchema<NUnitTesting::TAliased>({}, true);
  109. EXPECT_TRUE(IsFieldPresent(schema, "key"));
  110. EXPECT_TRUE(IsFieldPresent(schema, "subkey"));
  111. EXPECT_TRUE(IsFieldPresent(schema, "Data"));
  112. EXPECT_TRUE(schema.Strict());
  113. }
  114. TEST(TProtoSchemaSimpleTest, KeepFieldsWithoutExtensionFalse)
  115. {
  116. const auto schema = CreateTableSchema<NUnitTesting::TAliased>({}, false);
  117. EXPECT_TRUE(IsFieldPresent(schema, "key"));
  118. EXPECT_TRUE(IsFieldPresent(schema, "subkey"));
  119. EXPECT_TRUE(!IsFieldPresent(schema, "Data"));
  120. EXPECT_TRUE(schema.Strict());
  121. }
  122. TEST(TProtoSchemaSimpleTest, ProtobufTypeOption)
  123. {
  124. const auto schema = CreateTableSchema<NUnitTesting::TWithTypeOptions>({});
  125. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  126. .Strict(false)
  127. .AddColumn(TColumnSchema().Name("ColorIntField").Type(ToTypeV3(EValueType::VT_INT64, false)))
  128. .AddColumn(TColumnSchema().Name("ColorStringField").Type(ToTypeV3(EValueType::VT_STRING, false)))
  129. .AddColumn(TColumnSchema().Name("AnyField").Type(ToTypeV3(EValueType::VT_ANY, false)))
  130. .AddColumn(TColumnSchema().Name("EmbeddedField").Type(
  131. NTi::Optional(NTi::Struct({
  132. {"ColorIntField", ToTypeV3(EValueType::VT_INT64, false)},
  133. {"ColorStringField", ToTypeV3(EValueType::VT_STRING, false)},
  134. {"AnyField", ToTypeV3(EValueType::VT_ANY, false)}}))))
  135. .AddColumn(TColumnSchema().Name("RepeatedEnumIntField").Type(NTi::List(NTi::Int64()))));
  136. }
  137. TEST(TProtoSchemaSimpleTest, ProtobufTypeOption_TypeMismatch)
  138. {
  139. EXPECT_THROW(
  140. CreateTableSchema<NUnitTesting::TWithTypeOptions_TypeMismatch_EnumInt>({}),
  141. yexception);
  142. EXPECT_THROW(
  143. CreateTableSchema<NUnitTesting::TWithTypeOptions_TypeMismatch_EnumString>({}),
  144. yexception);
  145. EXPECT_THROW(
  146. CreateTableSchema<NUnitTesting::TWithTypeOptions_TypeMismatch_Any>({}),
  147. yexception);
  148. EXPECT_THROW(
  149. CreateTableSchema<NUnitTesting::TWithTypeOptions_TypeMismatch_OtherColumns>({}),
  150. yexception);
  151. }
  152. NTi::TTypePtr GetUrlRowType_ColumnNames(bool required)
  153. {
  154. static const NTi::TTypePtr type = NTi::Struct({
  155. {"Host_ColumnName", ToTypeV3(EValueType::VT_STRING, false)},
  156. {"Path_KeyColumnName", ToTypeV3(EValueType::VT_STRING, false)},
  157. {"HttpCode", ToTypeV3(EValueType::VT_INT32, false)},
  158. });
  159. return required ? type : NTi::TTypePtr(NTi::Optional(type));
  160. }
  161. TEST(TProtoSchemaComplexTest, TRepeated)
  162. {
  163. EXPECT_THROW(CreateTableSchema<NUnitTesting::TRepeated>(), yexception);
  164. const auto schema = CreateTableSchema<NUnitTesting::TRepeatedYtMode>();
  165. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  166. .AddColumn(TColumnSchema().Name("Int32Field").Type(NTi::List(ToTypeV3(EValueType::VT_INT32, true)))));
  167. }
  168. TEST(TProtoSchemaComplexTest, TRepeatedOptionalList)
  169. {
  170. const auto schema = CreateTableSchema<NUnitTesting::TOptionalList>();
  171. auto type = NTi::Optional(NTi::List(NTi::Int64()));
  172. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  173. .AddColumn(TColumnSchema().Name("OptionalListInt64").TypeV3(type)));
  174. }
  175. NTi::TTypePtr GetUrlRowType(bool required)
  176. {
  177. static const NTi::TTypePtr structType = NTi::Struct({
  178. {"Host", ToTypeV3(EValueType::VT_STRING, false)},
  179. {"Path", ToTypeV3(EValueType::VT_STRING, false)},
  180. {"HttpCode", ToTypeV3(EValueType::VT_INT32, false)}});
  181. return required ? structType : NTi::TTypePtr(NTi::Optional(structType));
  182. }
  183. TEST(TProtoSchemaComplexTest, TRowFieldSerializationOption)
  184. {
  185. const auto schema = CreateTableSchema<NUnitTesting::TRowFieldSerializationOption>();
  186. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  187. .AddColumn(TColumnSchema().Name("UrlRow_1").Type(GetUrlRowType(false)))
  188. .AddColumn(TColumnSchema().Name("UrlRow_2").Type(ToTypeV3(EValueType::VT_STRING, false))));
  189. }
  190. TEST(TProtoSchemaComplexTest, TRowMessageSerializationOption)
  191. {
  192. const auto schema = CreateTableSchema<NUnitTesting::TRowMessageSerializationOption>();
  193. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  194. .AddColumn(TColumnSchema().Name("UrlRow_1").Type(GetUrlRowType(false)))
  195. .AddColumn(TColumnSchema().Name("UrlRow_2").Type(GetUrlRowType(false))));
  196. }
  197. TEST(TProtoSchemaComplexTest, TRowMixedSerializationOptions)
  198. {
  199. const auto schema = CreateTableSchema<NUnitTesting::TRowMixedSerializationOptions>();
  200. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  201. .AddColumn(TColumnSchema().Name("UrlRow_1").Type(GetUrlRowType(false)))
  202. .AddColumn(TColumnSchema().Name("UrlRow_2").Type(ToTypeV3(EValueType::VT_STRING, false))));
  203. }
  204. TEST(TProtoSchemaComplexTest, TRowMixedSerializationOptions_ColumnNames)
  205. {
  206. const auto schema = CreateTableSchema<NUnitTesting::TRowMixedSerializationOptions_ColumnNames>();
  207. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  208. .AddColumn(TColumnSchema().Name("UrlRow_1").Type(GetUrlRowType_ColumnNames(false)))
  209. .AddColumn(TColumnSchema().Name("UrlRow_2").Type(ToTypeV3(EValueType::VT_STRING, false))));
  210. }
  211. TEST(TProtoSchemaComplexTest, NoOptionInheritance)
  212. {
  213. auto deepestEmbedded = NTi::Optional(NTi::Struct({{"x", ToTypeV3(EValueType::VT_INT64, false)}}));
  214. const auto schema = CreateTableSchema<NUnitTesting::TNoOptionInheritance>();
  215. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  216. .AddColumn(TColumnSchema()
  217. .Name("EmbeddedYt_YtOption")
  218. .Type(NTi::Optional(NTi::Struct({{"embedded", deepestEmbedded}}))))
  219. .AddColumn(TColumnSchema().Name("EmbeddedYt_ProtobufOption").Type(ToTypeV3(EValueType::VT_STRING, false)))
  220. .AddColumn(TColumnSchema().Name("EmbeddedYt_NoOption").Type(ToTypeV3(EValueType::VT_STRING, false)))
  221. .AddColumn(TColumnSchema()
  222. .Name("EmbeddedProtobuf_YtOption")
  223. .Type(NTi::Optional(NTi::Struct({{"embedded", ToTypeV3(EValueType::VT_STRING, false)}}))))
  224. .AddColumn(TColumnSchema().Name("EmbeddedProtobuf_ProtobufOption").Type(ToTypeV3(EValueType::VT_STRING, false)))
  225. .AddColumn(TColumnSchema().Name("EmbeddedProtobuf_NoOption").Type(ToTypeV3(EValueType::VT_STRING, false)))
  226. .AddColumn(TColumnSchema()
  227. .Name("Embedded_YtOption")
  228. .Type(NTi::Optional(NTi::Struct({{"embedded", ToTypeV3(EValueType::VT_STRING, false)}}))))
  229. .AddColumn(TColumnSchema().Name("Embedded_ProtobufOption").Type(ToTypeV3(EValueType::VT_STRING, false)))
  230. .AddColumn(TColumnSchema().Name("Embedded_NoOption").Type(ToTypeV3(EValueType::VT_STRING, false))));
  231. }
  232. TEST(TProtoSchemaComplexTest, Cyclic)
  233. {
  234. EXPECT_THROW(CreateTableSchema<NUnitTesting::TCyclic>(), TApiUsageError);
  235. EXPECT_THROW(CreateTableSchema<NUnitTesting::TCyclic::TA>(), TApiUsageError);
  236. EXPECT_THROW(CreateTableSchema<NUnitTesting::TCyclic::TB>(), TApiUsageError);
  237. EXPECT_THROW(CreateTableSchema<NUnitTesting::TCyclic::TC>(), TApiUsageError);
  238. EXPECT_THROW(CreateTableSchema<NUnitTesting::TCyclic::TD>(), TApiUsageError);
  239. ASSERT_SERIALIZABLES_EQ(
  240. TTableSchema().AddColumn(
  241. TColumnSchema().Name("d").TypeV3(NTi::Optional(NTi::String()))),
  242. CreateTableSchema<NUnitTesting::TCyclic::TE>());
  243. }
  244. TEST(TProtoSchemaComplexTest, FieldSortOrder)
  245. {
  246. const auto schema = CreateTableSchema<NUnitTesting::TFieldSortOrder>();
  247. auto byFieldNumber = NTi::Optional(NTi::Struct({
  248. {"z", NTi::Optional(NTi::Bool())},
  249. {"x", NTi::Optional(NTi::Int64())},
  250. {"y", NTi::Optional(NTi::String())},
  251. }));
  252. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  253. .AddColumn(TColumnSchema().Name("EmbeddedDefault").Type(byFieldNumber))
  254. .AddColumn(TColumnSchema()
  255. .Name("EmbeddedAsInProtoFile")
  256. .Type(NTi::Optional(NTi::Struct({
  257. {"x", NTi::Optional(NTi::Int64())},
  258. {"y", NTi::Optional(NTi::String())},
  259. {"z", NTi::Optional(NTi::Bool())},
  260. }))))
  261. .AddColumn(TColumnSchema().Name("EmbeddedByFieldNumber").Type(byFieldNumber)));
  262. }
  263. TEST(TProtoSchemaComplexTest, Map)
  264. {
  265. const auto schema = CreateTableSchema<NUnitTesting::TWithMap>();
  266. auto createKeyValueStruct = [] (NTi::TTypePtr key, NTi::TTypePtr value) {
  267. return NTi::List(NTi::Struct({
  268. {"key", NTi::Optional(key)},
  269. {"value", NTi::Optional(value)},
  270. }));
  271. };
  272. auto embedded = NTi::Struct({
  273. {"x", NTi::Optional(NTi::Int64())},
  274. {"y", NTi::Optional(NTi::String())},
  275. });
  276. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  277. .AddColumn(TColumnSchema()
  278. .Name("MapDefault")
  279. .Type(createKeyValueStruct(NTi::Int64(), NTi::String())))
  280. .AddColumn(TColumnSchema()
  281. .Name("MapListOfStructsLegacy")
  282. .Type(createKeyValueStruct(NTi::Int64(), NTi::String())))
  283. .AddColumn(TColumnSchema()
  284. .Name("MapListOfStructs")
  285. .Type(createKeyValueStruct(NTi::Int64(), embedded)))
  286. .AddColumn(TColumnSchema()
  287. .Name("MapOptionalDict")
  288. .Type(NTi::Optional(NTi::Dict(NTi::Int64(), embedded))))
  289. .AddColumn(TColumnSchema()
  290. .Name("MapDict")
  291. .Type(NTi::Dict(NTi::Int64(), embedded))));
  292. }
  293. TEST(TProtoSchemaComplexTest, Oneof)
  294. {
  295. const auto schema = CreateTableSchema<NUnitTesting::TWithOneof>();
  296. auto embedded = NTi::Struct({
  297. {"Oneof", NTi::Optional(NTi::Variant(NTi::Struct({
  298. {"x", NTi::Int64()},
  299. {"y", NTi::String()},
  300. })))},
  301. });
  302. auto createType = [&] (TString oneof2Name) {
  303. return NTi::Optional(NTi::Struct({
  304. {"field", NTi::Optional(NTi::String())},
  305. {oneof2Name, NTi::Optional(NTi::Variant(NTi::Struct({
  306. {"x2", NTi::Int64()},
  307. {"y2", NTi::String()},
  308. {"z2", embedded},
  309. })))},
  310. {"y1", NTi::Optional(NTi::String())},
  311. {"z1", NTi::Optional(embedded)},
  312. {"x1", NTi::Optional(NTi::Int64())},
  313. }));
  314. };
  315. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  316. .AddColumn(TColumnSchema()
  317. .Name("DefaultSeparateFields")
  318. .Type(createType("variant_field_name")))
  319. .AddColumn(TColumnSchema()
  320. .Name("NoDefault")
  321. .Type(createType("Oneof2")))
  322. .AddColumn(TColumnSchema()
  323. .Name("SerializationProtobuf")
  324. .Type(NTi::Optional(NTi::Struct({
  325. {"y1", NTi::Optional(NTi::String())},
  326. {"x1", NTi::Optional(NTi::Int64())},
  327. {"z1", NTi::Optional(NTi::String())},
  328. }))))
  329. .AddColumn(TColumnSchema()
  330. .Name("TopLevelOneof")
  331. .Type(
  332. NTi::Optional(
  333. NTi::Variant(NTi::Struct({
  334. {"MemberOfTopLevelOneof", NTi::Int64()}
  335. }))
  336. )
  337. ))
  338. );
  339. }
  340. TEST(TProtoSchemaComplexTest, Embedded)
  341. {
  342. const auto schema = CreateTableSchema<NUnitTesting::TEmbeddingMessage>();
  343. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  344. .Strict(false)
  345. .AddColumn(TColumnSchema().Name("embedded2_num").Type(NTi::Optional(NTi::Uint64())))
  346. .AddColumn(TColumnSchema().Name("embedded2_struct").Type(NTi::Optional(NTi::Struct({
  347. {"float1", NTi::Optional(NTi::Double())},
  348. {"string1", NTi::Optional(NTi::String())},
  349. }))))
  350. .AddColumn(TColumnSchema().Name("embedded2_repeated").Type(NTi::List(NTi::String())))
  351. .AddColumn(TColumnSchema().Name("embedded_num").Type(NTi::Optional(NTi::Uint64())))
  352. .AddColumn(TColumnSchema().Name("embedded_extra_field").Type(NTi::Optional(NTi::String())))
  353. .AddColumn(TColumnSchema().Name("variant").Type(NTi::Optional(NTi::Variant(NTi::Struct({
  354. {"str_variant", NTi::String()},
  355. {"uint_variant", NTi::Uint64()},
  356. })))))
  357. .AddColumn(TColumnSchema().Name("num").Type(NTi::Optional(NTi::Uint64())))
  358. .AddColumn(TColumnSchema().Name("extra_field").Type(NTi::Optional(NTi::String())))
  359. );
  360. }
  361. TEST(TProtoSchemaProto3Test, TWithOptional)
  362. {
  363. const auto schema = CreateTableSchema<NTestingProto3::TWithOptional>();
  364. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  365. .AddColumn(TColumnSchema()
  366. .Name("x").Type(NTi::Optional(NTi::Int64()))
  367. )
  368. );
  369. }
  370. TEST(TProtoSchemaProto3Test, TWithOptionalMessage)
  371. {
  372. const auto schema = CreateTableSchema<NTestingProto3::TWithOptionalMessage>();
  373. ASSERT_SERIALIZABLES_EQ(schema, TTableSchema()
  374. .AddColumn(TColumnSchema()
  375. .Name("x").Type(
  376. NTi::Optional(
  377. NTi::Struct({{"x", NTi::Optional(NTi::Int64())}})
  378. )
  379. )
  380. )
  381. );
  382. }