diff options
author | imunkin <[email protected]> | 2024-11-08 10:00:23 +0300 |
---|---|---|
committer | imunkin <[email protected]> | 2024-11-08 10:12:13 +0300 |
commit | a784a2f943d6e15caa6241e2e96d80aac6dbf375 (patch) | |
tree | 05f1e5366c916b988a8afb75bdab8ddeee0f6e6d /yql/essentials/udfs/common/json/json_udf.cpp | |
parent | d70137a7b530ccaa52834274913bbb5a3d1ca06e (diff) |
Move yql/udfs/common/ to /yql/essentials YQL-19206
Except the following directories:
* clickhouse/client
* datetime
* knn
* roaring
commit_hash:c7da95636144d28db109d6b17ddc762e9bacb59f
Diffstat (limited to 'yql/essentials/udfs/common/json/json_udf.cpp')
-rw-r--r-- | yql/essentials/udfs/common/json/json_udf.cpp | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/yql/essentials/udfs/common/json/json_udf.cpp b/yql/essentials/udfs/common/json/json_udf.cpp new file mode 100644 index 00000000000..3a7916bed74 --- /dev/null +++ b/yql/essentials/udfs/common/json/json_udf.cpp @@ -0,0 +1,120 @@ +#include <yql/essentials/public/udf/udf_helpers.h> + +#include <library/cpp/json/easy_parse/json_easy_parser.h> + +using namespace NKikimr; +using namespace NUdf; + +namespace { + class TGetField: public TBoxedValue { + public: + typedef bool TTypeAwareMarker; + + public: + static TStringRef Name() { + return TStringRef::Of("GetField"); + } + + TUnboxedValue Run( + const IValueBuilder* valueBuilder, + const TUnboxedValuePod* args) const override { + if (!args[0]) { + return valueBuilder->NewEmptyList(); + } + + const TString json(args[0].AsStringRef()); + const TString field(args[1].AsStringRef()); + + if (field.empty()) { + return valueBuilder->NewEmptyList(); + } + + NJson::TJsonParser parser; + parser.AddField(field, false); + + TVector<TString> result; + parser.Parse(json, &result); + + TUnboxedValue* items = nullptr; + const auto list = valueBuilder->NewArray(result.size(), items); + for (const TString& item : result) { + *items++ = valueBuilder->NewString(item); + } + + return list; + } + + static bool DeclareSignature( + const TStringRef& name, + TType* userType, + IFunctionTypeInfoBuilder& builder, + bool typesOnly) { + if (Name() == name) { + bool useString = true; + bool isOptional = true; + if (userType) { + // support of an overload with Json/Json? input type + auto typeHelper = builder.TypeInfoHelper(); + auto userTypeInspector = TTupleTypeInspector(*typeHelper, userType); + if (!userTypeInspector || userTypeInspector.GetElementsCount() < 1) { + builder.SetError("Missing or invalid user type."); + return true; + } + + auto argsTypeTuple = userTypeInspector.GetElementType(0); + auto argsTypeInspector = TTupleTypeInspector(*typeHelper, argsTypeTuple); + if (!argsTypeInspector) { + builder.SetError("Invalid user type - expected tuple."); + return true; + } + + if (argsTypeInspector.GetElementsCount() != 2) { + builder.SetError("Invalid user type - expected two arguments."); + return true; + } + + auto inputType = argsTypeInspector.GetElementType(0); + auto optInspector = TOptionalTypeInspector(*typeHelper, inputType); + auto dataType = inputType; + if (optInspector) { + dataType = optInspector.GetItemType(); + } else { + isOptional = false; + } + + auto dataInspector = TDataTypeInspector(*typeHelper, dataType); + if (dataInspector && dataInspector.GetTypeId() == TDataType<TJson>::Id) { + useString = false; + builder.UserType(userType); + } + } + + auto retType = builder.List()->Item<char*>().Build(); + if (useString) { + builder.Args()->Add(builder.Optional()->Item<char*>().Build()).Add<char*>().Done().Returns(retType); + } else { + auto type = builder.SimpleType<TJson>(); + if (isOptional) { + builder.Args()->Add(builder.Optional()->Item(type).Build()).Add<char*>().Done().Returns(retType); + } else { + builder.Args()->Add(type).Add<char*>().Done().Returns(retType); + } + } + + if (!typesOnly) { + builder.Implementation(new TGetField); + } + + builder.IsStrict(); + return true; + } else { + return false; + } + } + }; +} + +SIMPLE_MODULE(TJsonModule, + TGetField) + +REGISTER_MODULES(TJsonModule) |