protobuf_udf.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #include <yql/essentials/minikql/protobuf_udf/type_builder.h>
  2. #include <yql/essentials/minikql/protobuf_udf/value_builder.h>
  3. #include <yql/essentials/public/udf/udf_value.h>
  4. #include <yql/essentials/public/udf/udf_registrator.h>
  5. #include <library/cpp/protobuf/yql/descriptor.h>
  6. using namespace NKikimr::NUdf;
  7. using namespace NProtoBuf;
  8. namespace {
  9. class TDynamicProtoValue: public TProtobufValue {
  10. public:
  11. TDynamicProtoValue(const TProtoInfo& info, TDynamicInfoRef dyn)
  12. : TProtobufValue(info)
  13. , Dynamic_(dyn)
  14. {
  15. Y_ASSERT(Dynamic_ != nullptr);
  16. }
  17. TAutoPtr<Message> Parse(const TStringBuf& data) const override {
  18. return Dynamic_->Parse(data);
  19. }
  20. private:
  21. TDynamicInfoRef Dynamic_;
  22. };
  23. class TDynamicProtoSerialize: public TProtobufSerialize {
  24. public:
  25. TDynamicProtoSerialize(const TProtoInfo& info, TDynamicInfoRef dyn)
  26. : TProtobufSerialize(info)
  27. , Dynamic_(dyn)
  28. {
  29. Y_ASSERT(Dynamic_ != nullptr);
  30. }
  31. TMaybe<TString> Serialize(const Message& proto) const override {
  32. return Dynamic_->Serialize(proto);
  33. }
  34. TAutoPtr<Message> MakeProto() const override {
  35. return Dynamic_->MakeProto();
  36. }
  37. private:
  38. TDynamicInfoRef Dynamic_;
  39. };
  40. class TDynamicProtoValueSafe: public TDynamicProtoValue {
  41. public:
  42. TDynamicProtoValueSafe(const TProtoInfo& info, TDynamicInfoRef dyn)
  43. : TDynamicProtoValue(info, dyn) {}
  44. TAutoPtr<Message> Parse(const TStringBuf& data) const override {
  45. try {
  46. return TDynamicProtoValue::Parse(data);
  47. } catch (const std::exception& e) {
  48. return nullptr;
  49. }
  50. }
  51. };
  52. class TProtobufModule: public IUdfModule {
  53. public:
  54. TStringRef Name() const {
  55. return TStringRef("Protobuf");
  56. }
  57. void CleanupOnTerminate() const final {
  58. }
  59. void GetAllFunctions(IFunctionsSink& sink) const final {
  60. sink.Add(TStringRef::Of("Parse"))->SetTypeAwareness();
  61. sink.Add(TStringRef::Of("TryParse"))->SetTypeAwareness();
  62. sink.Add(TStringRef::Of("Serialize"))->SetTypeAwareness();
  63. }
  64. void BuildFunctionTypeInfo(
  65. const TStringRef& name,
  66. TType* userType,
  67. const TStringRef& typeConfig,
  68. ui32 flags,
  69. IFunctionTypeInfoBuilder& builder) const final {
  70. Y_UNUSED(userType);
  71. try {
  72. auto dyn = TDynamicInfo::Create(TStringBuf(typeConfig.Data(), typeConfig.Size()));
  73. TProtoInfo typeInfo;
  74. ProtoTypeBuild(dyn->Descriptor(),
  75. dyn->GetEnumFormat(),
  76. dyn->GetRecursionTraits(),
  77. dyn->GetOptionalLists(),
  78. builder, &typeInfo,
  79. EProtoStringYqlType::Bytes,
  80. dyn->GetSyntaxAware(),
  81. false,
  82. dyn->GetYtMode());
  83. auto stringType = builder.SimpleType<char*>();
  84. auto structType = typeInfo.StructType;
  85. auto optionalStructType = builder.Optional()->Item(structType).Build();
  86. if (TStringRef::Of("Serialize") == name) {
  87. // function signature:
  88. // String Serialize(Protobuf value)
  89. builder.Returns(stringType)
  90. .Args()
  91. ->Add(structType)
  92. .Flags(ICallablePayload::TArgumentFlags::AutoMap)
  93. .Done();
  94. if ((flags & TFlags::TypesOnly) == 0) {
  95. builder.Implementation(new TDynamicProtoSerialize(typeInfo, dyn));
  96. }
  97. } else {
  98. // function signature:
  99. // Protobuf Parse(String value)
  100. builder.Returns((TStringRef::Of("TryParse") == name) ? optionalStructType : structType)
  101. .Args()
  102. ->Add(stringType)
  103. .Flags(ICallablePayload::TArgumentFlags::AutoMap)
  104. .Done();
  105. if (TStringRef::Of("Parse") == name) {
  106. if ((flags & TFlags::TypesOnly) == 0) {
  107. builder.Implementation(new TDynamicProtoValue(typeInfo, dyn));
  108. }
  109. } else if (TStringRef::Of("TryParse") == name) {
  110. if ((flags & TFlags::TypesOnly) == 0) {
  111. builder.Implementation(new TDynamicProtoValueSafe(typeInfo, dyn));
  112. }
  113. }
  114. }
  115. } catch (const std::exception& e) {
  116. builder.SetError(CurrentExceptionMessage());
  117. }
  118. }
  119. };
  120. }
  121. REGISTER_MODULES(TProtobufModule);