diff options
author | vvvv <[email protected]> | 2025-10-06 13:26:25 +0300 |
---|---|---|
committer | vvvv <[email protected]> | 2025-10-06 14:06:25 +0300 |
commit | eca8ce9cb1613d5c983185c4e43c20651a9638aa (patch) | |
tree | 61ee5ae779948e61af9a7691d19eaa2c09869121 /yql/essentials/udfs/common/json2 | |
parent | 4adf7eecae16a9b228b28cc5f64c27ef69ad5ec2 (diff) |
YQL-20086 udfs
init
commit_hash:f9684778bf1ea956965f2360b80b91edb7d4ffbe
Diffstat (limited to 'yql/essentials/udfs/common/json2')
-rw-r--r-- | yql/essentials/udfs/common/json2/as_json_node.h | 171 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/compile_path.h | 101 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/json2_udf.cpp | 60 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/parse.h | 91 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/resource.h | 17 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/serialize.h | 127 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/sql_exists.h | 205 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/sql_query.h | 281 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/sql_value.h | 472 | ||||
-rw-r--r-- | yql/essentials/udfs/common/json2/ya.make | 2 |
10 files changed, 761 insertions, 766 deletions
diff --git a/yql/essentials/udfs/common/json2/as_json_node.h b/yql/essentials/udfs/common/json2/as_json_node.h index 6060f03bea8..82c51802433 100644 --- a/yql/essentials/udfs/common/json2/as_json_node.h +++ b/yql/essentials/udfs/common/json2/as_json_node.h @@ -8,108 +8,107 @@ #include <yql/essentials/minikql/dom/json.h> namespace NJson2Udf { - using namespace NKikimr; - using namespace NUdf; - using namespace NYql; - using namespace NDom; - - template <typename TSource> - class TAsJsonNode: public TBoxedValue { - public: - TAsJsonNode(TSourcePosition pos) - : Pos_(pos) - { +using namespace NKikimr; +using namespace NUdf; +using namespace NYql; +using namespace NDom; + +template <typename TSource> +class TAsJsonNode: public TBoxedValue { +public: + TAsJsonNode(TSourcePosition pos) + : Pos_(pos) + { + } + + static TStringRef Name(); + + static bool DeclareSignature( + const TStringRef& name, + TType* userType, + IFunctionTypeInfoBuilder& builder, + bool typesOnly) { + Y_UNUSED(userType); + if (name != Name()) { + return false; } - static TStringRef Name(); + auto optionalSourceType = builder.Optional()->Item<TSource>().Build(); + auto resourceType = builder.Resource(JSON_NODE_RESOURCE_NAME); + builder.Args() + ->Add(optionalSourceType) + .Done() + .Returns(resourceType); - static bool DeclareSignature( - const TStringRef& name, - TType* userType, - IFunctionTypeInfoBuilder& builder, - bool typesOnly) { - Y_UNUSED(userType); - if (name != Name()) { - return false; - } + if (!typesOnly) { + builder.Implementation(new TAsJsonNode<TSource>(builder.GetSourcePosition())); + } - auto optionalSourceType = builder.Optional()->Item<TSource>().Build(); - auto resourceType = builder.Resource(JSON_NODE_RESOURCE_NAME); - builder.Args() - ->Add(optionalSourceType) - .Done() - .Returns(resourceType); + builder.IsStrict(); + return true; + } - if (!typesOnly) { - builder.Implementation(new TAsJsonNode<TSource>(builder.GetSourcePosition())); - } +private: + const size_t MaxParseErrors_ = 10; - builder.IsStrict(); - return true; - } + static TUnboxedValue Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder); - private: - const size_t MaxParseErrors_ = 10; - - static TUnboxedValue Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder); - - TUnboxedValue Run( - const IValueBuilder* valueBuilder, - const TUnboxedValuePod* args) const final { - Y_UNUSED(valueBuilder); - try { - if (!args[0].HasValue()) { - return MakeEntity(); - } - return Interpret(args[0], valueBuilder); - } catch (const std::exception& e) { - UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + TUnboxedValue Run( + const IValueBuilder* valueBuilder, + const TUnboxedValuePod* args) const final { + Y_UNUSED(valueBuilder); + try { + if (!args[0].HasValue()) { + return MakeEntity(); } + return Interpret(args[0], valueBuilder); + } catch (const std::exception& e) { + UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); } - - TSourcePosition Pos_; - }; - - template <> - TStringRef TAsJsonNode<TUtf8>::Name() { - return TStringRef::Of("Utf8AsJsonNode"); } - template <> - TUnboxedValue TAsJsonNode<TUtf8>::Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder) { - return MakeString(sourceValue.AsStringRef(), valueBuilder); - } + TSourcePosition Pos_; +}; - template <> - TStringRef TAsJsonNode<double>::Name() { - return TStringRef::Of("DoubleAsJsonNode"); - } +template <> +TStringRef TAsJsonNode<TUtf8>::Name() { + return TStringRef::Of("Utf8AsJsonNode"); +} - template <> - TUnboxedValue TAsJsonNode<double>::Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder) { - Y_UNUSED(valueBuilder); - return MakeDouble(sourceValue.Get<double>()); - } +template <> +TUnboxedValue TAsJsonNode<TUtf8>::Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder) { + return MakeString(sourceValue.AsStringRef(), valueBuilder); +} - template <> - TStringRef TAsJsonNode<bool>::Name() { - return TStringRef::Of("BoolAsJsonNode"); - } +template <> +TStringRef TAsJsonNode<double>::Name() { + return TStringRef::Of("DoubleAsJsonNode"); +} - template <> - TUnboxedValue TAsJsonNode<bool>::Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder) { - Y_UNUSED(valueBuilder); - return MakeBool(sourceValue.Get<bool>()); - } +template <> +TUnboxedValue TAsJsonNode<double>::Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder) { + Y_UNUSED(valueBuilder); + return MakeDouble(sourceValue.Get<double>()); +} - template <> - TStringRef TAsJsonNode<TJson>::Name() { - return TStringRef::Of("JsonAsJsonNode"); - } +template <> +TStringRef TAsJsonNode<bool>::Name() { + return TStringRef::Of("BoolAsJsonNode"); +} - template <> - TUnboxedValue TAsJsonNode<TJson>::Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder) { - return TryParseJsonDom(sourceValue.AsStringRef(), valueBuilder); - } +template <> +TUnboxedValue TAsJsonNode<bool>::Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder) { + Y_UNUSED(valueBuilder); + return MakeBool(sourceValue.Get<bool>()); } +template <> +TStringRef TAsJsonNode<TJson>::Name() { + return TStringRef::Of("JsonAsJsonNode"); +} + +template <> +TUnboxedValue TAsJsonNode<TJson>::Interpret(const TUnboxedValue& sourceValue, const IValueBuilder* valueBuilder) { + return TryParseJsonDom(sourceValue.AsStringRef(), valueBuilder); +} +} // namespace NJson2Udf diff --git a/yql/essentials/udfs/common/json2/compile_path.h b/yql/essentials/udfs/common/json2/compile_path.h index 220bd4fbaf6..f932c6df60c 100644 --- a/yql/essentials/udfs/common/json2/compile_path.h +++ b/yql/essentials/udfs/common/json2/compile_path.h @@ -6,65 +6,64 @@ #include <yql/essentials/public/udf/udf_helpers.h> namespace NJson2Udf { - using namespace NKikimr; - using namespace NUdf; - using namespace NYql; +using namespace NKikimr; +using namespace NUdf; +using namespace NYql; - class TCompilePath: public TBoxedValue { - public: - TCompilePath(TSourcePosition pos) - : Pos_(pos) - { - } +class TCompilePath: public TBoxedValue { +public: + TCompilePath(TSourcePosition pos) + : Pos_(pos) + { + } - static const TStringRef& Name() { - static auto name = TStringRef::Of("CompilePath"); - return name; - } + static const TStringRef& Name() { + static auto name = TStringRef::Of("CompilePath"); + return name; + } - static bool DeclareSignature( - const TStringRef& name, - TType* userType, - IFunctionTypeInfoBuilder& builder, - bool typesOnly) { - Y_UNUSED(userType); - if (name != Name()) { - return false; - } + static bool DeclareSignature( + const TStringRef& name, + TType* userType, + IFunctionTypeInfoBuilder& builder, + bool typesOnly) { + Y_UNUSED(userType); + if (name != Name()) { + return false; + } - auto resourceType = builder.Resource(JSONPATH_RESOURCE_NAME); - builder.Args() - ->Add<NUdf::TUtf8>() - .Done() - .Returns(resourceType); + auto resourceType = builder.Resource(JSONPATH_RESOURCE_NAME); + builder.Args() + ->Add<NUdf::TUtf8>() + .Done() + .Returns(resourceType); - if (!typesOnly) { - builder.Implementation(new TCompilePath(builder.GetSourcePosition())); - } - return true; + if (!typesOnly) { + builder.Implementation(new TCompilePath(builder.GetSourcePosition())); } + return true; + } - private: - const size_t MaxParseErrors_ = 10; - - TUnboxedValue Run( - const IValueBuilder* valueBuilder, - const TUnboxedValuePod* args) const final { - Y_UNUSED(valueBuilder); - try { - TIssues issues; - const auto jsonPath = NJsonPath::ParseJsonPath(args[0].AsStringRef(), issues, MaxParseErrors_); - if (!issues.Empty()) { - ythrow yexception() << "Error parsing jsonpath:" << Endl << issues.ToString(); - } +private: + const size_t MaxParseErrors_ = 10; - return TUnboxedValuePod(new TJsonPathResource(jsonPath)); - } catch (const std::exception& e) { - UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + TUnboxedValue Run( + const IValueBuilder* valueBuilder, + const TUnboxedValuePod* args) const final { + Y_UNUSED(valueBuilder); + try { + TIssues issues; + const auto jsonPath = NJsonPath::ParseJsonPath(args[0].AsStringRef(), issues, MaxParseErrors_); + if (!issues.Empty()) { + ythrow yexception() << "Error parsing jsonpath:" << Endl << issues.ToString(); } - } - TSourcePosition Pos_; - }; -} + return TUnboxedValuePod(new TJsonPathResource(jsonPath)); + } catch (const std::exception& e) { + UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + } + } + TSourcePosition Pos_; +}; +} // namespace NJson2Udf diff --git a/yql/essentials/udfs/common/json2/json2_udf.cpp b/yql/essentials/udfs/common/json2/json2_udf.cpp index 96ef6ccf00b..76c4ef786db 100644 --- a/yql/essentials/udfs/common/json2/json2_udf.cpp +++ b/yql/essentials/udfs/common/json2/json2_udf.cpp @@ -9,35 +9,35 @@ #include <yql/essentials/public/udf/udf_helpers.h> namespace NJson2Udf { - SIMPLE_MODULE(TJson2Module, - TParse, - TSerialize<EDataSlot::Json>, - TSerialize<EDataSlot::JsonDocument>, - TCompilePath, - TSqlValue<EDataSlot::Json, TUtf8>, - TSqlValue<EDataSlot::Json, TUtf8, true>, - TSqlValue<EDataSlot::Json, i64>, - TSqlValue<EDataSlot::Json, double>, - TSqlValue<EDataSlot::Json, bool>, - TSqlValue<EDataSlot::JsonDocument, TUtf8>, - TSqlValue<EDataSlot::JsonDocument, TUtf8, true>, - TSqlValue<EDataSlot::JsonDocument, i64>, - TSqlValue<EDataSlot::JsonDocument, double>, - TSqlValue<EDataSlot::JsonDocument, bool>, - TSqlExists<EDataSlot::Json, false>, - TSqlExists<EDataSlot::Json, true>, - TSqlExists<EDataSlot::JsonDocument, false>, - TSqlExists<EDataSlot::JsonDocument, true>, - TSqlQuery<EDataSlot::Json, EJsonQueryWrap::NoWrap>, - TSqlQuery<EDataSlot::Json, EJsonQueryWrap::Wrap>, - TSqlQuery<EDataSlot::Json, EJsonQueryWrap::ConditionalWrap>, - TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::NoWrap>, - TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::Wrap>, - TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::ConditionalWrap>, - TAsJsonNode<TUtf8>, - TAsJsonNode<double>, - TAsJsonNode<bool>, - TAsJsonNode<TJson>) -} +SIMPLE_MODULE(TJson2Module, + TParse, + TSerialize<EDataSlot::Json>, + TSerialize<EDataSlot::JsonDocument>, + TCompilePath, + TSqlValue<EDataSlot::Json, TUtf8>, + TSqlValue<EDataSlot::Json, TUtf8, true>, + TSqlValue<EDataSlot::Json, i64>, + TSqlValue<EDataSlot::Json, double>, + TSqlValue<EDataSlot::Json, bool>, + TSqlValue<EDataSlot::JsonDocument, TUtf8>, + TSqlValue<EDataSlot::JsonDocument, TUtf8, true>, + TSqlValue<EDataSlot::JsonDocument, i64>, + TSqlValue<EDataSlot::JsonDocument, double>, + TSqlValue<EDataSlot::JsonDocument, bool>, + TSqlExists<EDataSlot::Json, false>, + TSqlExists<EDataSlot::Json, true>, + TSqlExists<EDataSlot::JsonDocument, false>, + TSqlExists<EDataSlot::JsonDocument, true>, + TSqlQuery<EDataSlot::Json, EJsonQueryWrap::NoWrap>, + TSqlQuery<EDataSlot::Json, EJsonQueryWrap::Wrap>, + TSqlQuery<EDataSlot::Json, EJsonQueryWrap::ConditionalWrap>, + TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::NoWrap>, + TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::Wrap>, + TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::ConditionalWrap>, + TAsJsonNode<TUtf8>, + TAsJsonNode<double>, + TAsJsonNode<bool>, + TAsJsonNode<TJson>) +} // namespace NJson2Udf REGISTER_MODULES(NJson2Udf::TJson2Module) diff --git a/yql/essentials/udfs/common/json2/parse.h b/yql/essentials/udfs/common/json2/parse.h index 6df4bce9b0a..72db2106fa5 100644 --- a/yql/essentials/udfs/common/json2/parse.h +++ b/yql/essentials/udfs/common/json2/parse.h @@ -9,58 +9,57 @@ #include <library/cpp/json/json_reader.h> namespace NJson2Udf { - using namespace NKikimr; - using namespace NUdf; - using namespace NYql; - using namespace NDom; +using namespace NKikimr; +using namespace NUdf; +using namespace NYql; +using namespace NDom; - class TParse: public TBoxedValue { - public: - TParse(TSourcePosition pos) - : Pos_(pos) - { - } +class TParse: public TBoxedValue { +public: + TParse(TSourcePosition pos) + : Pos_(pos) + { + } - static const TStringRef& Name() { - static auto name = TStringRef::Of("Parse"); - return name; - } + static const TStringRef& Name() { + static auto name = TStringRef::Of("Parse"); + return name; + } - static bool DeclareSignature( - const TStringRef& name, - TType* userType, - IFunctionTypeInfoBuilder& builder, - bool typesOnly) { - Y_UNUSED(userType); - if (name != Name()) { - return false; - } + static bool DeclareSignature( + const TStringRef& name, + TType* userType, + IFunctionTypeInfoBuilder& builder, + bool typesOnly) { + Y_UNUSED(userType); + if (name != Name()) { + return false; + } - builder.Args() - ->Add<TAutoMap<TJson>>() - .Done() - .Returns<TJsonNodeResource>(); + builder.Args() + ->Add<TAutoMap<TJson>>() + .Done() + .Returns<TJsonNodeResource>(); - if (!typesOnly) { - builder.Implementation(new TParse(builder.GetSourcePosition())); - } - return true; + if (!typesOnly) { + builder.Implementation(new TParse(builder.GetSourcePosition())); } + return true; + } - private: - TUnboxedValue Run( - const IValueBuilder* valueBuilder, - const TUnboxedValuePod* args) const final { - Y_UNUSED(valueBuilder); - try { - const auto json = args[0].AsStringRef(); - return TryParseJsonDom(json, valueBuilder); - } catch (const std::exception& e) { - UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); - } +private: + TUnboxedValue Run( + const IValueBuilder* valueBuilder, + const TUnboxedValuePod* args) const final { + Y_UNUSED(valueBuilder); + try { + const auto json = args[0].AsStringRef(); + return TryParseJsonDom(json, valueBuilder); + } catch (const std::exception& e) { + UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); } + } - TSourcePosition Pos_; - }; -} - + TSourcePosition Pos_; +}; +} // namespace NJson2Udf diff --git a/yql/essentials/udfs/common/json2/resource.h b/yql/essentials/udfs/common/json2/resource.h index aa65b14818d..5d2cc6e7b0b 100644 --- a/yql/essentials/udfs/common/json2/resource.h +++ b/yql/essentials/udfs/common/json2/resource.h @@ -4,14 +4,13 @@ #include <yql/essentials/minikql/jsonpath/jsonpath.h> namespace NJson2Udf { - using namespace NKikimr; - using namespace NUdf; - using namespace NYql; +using namespace NKikimr; +using namespace NUdf; +using namespace NYql; - extern const char JSONPATH_RESOURCE_NAME[] = "JsonPath"; - using TJsonPathResource = TBoxedResource<NJsonPath::TJsonPathPtr, JSONPATH_RESOURCE_NAME>; - - extern const char JSON_NODE_RESOURCE_NAME[] = "JsonNode"; - using TJsonNodeResource = TResource<JSON_NODE_RESOURCE_NAME>; -} +extern const char JSONPATH_RESOURCE_NAME[] = "JsonPath"; +using TJsonPathResource = TBoxedResource<NJsonPath::TJsonPathPtr, JSONPATH_RESOURCE_NAME>; +extern const char JSON_NODE_RESOURCE_NAME[] = "JsonNode"; +using TJsonNodeResource = TResource<JSON_NODE_RESOURCE_NAME>; +} // namespace NJson2Udf diff --git a/yql/essentials/udfs/common/json2/serialize.h b/yql/essentials/udfs/common/json2/serialize.h index cda95e77f5a..2443259fbee 100644 --- a/yql/essentials/udfs/common/json2/serialize.h +++ b/yql/essentials/udfs/common/json2/serialize.h @@ -9,81 +9,80 @@ #include <yql/essentials/types/binary_json/write.h> namespace NJson2Udf { - using namespace NKikimr; - using namespace NUdf; - using namespace NYql; - using namespace NDom; - using namespace NBinaryJson; - - template <EDataSlot ResultType> - class TSerialize : public TBoxedValue { - public: - TSerialize(TSourcePosition pos) - : Pos_(pos) - { - } +using namespace NKikimr; +using namespace NUdf; +using namespace NYql; +using namespace NDom; +using namespace NBinaryJson; + +template <EDataSlot ResultType> +class TSerialize: public TBoxedValue { +public: + TSerialize(TSourcePosition pos) + : Pos_(pos) + { + } - static const TStringRef& Name(); + static const TStringRef& Name(); - static bool DeclareSignature( - const TStringRef& name, - TType* userType, - IFunctionTypeInfoBuilder& builder, - bool typesOnly) { - Y_UNUSED(userType); - if (name != Name()) { - return false; - } + static bool DeclareSignature( + const TStringRef& name, + TType* userType, + IFunctionTypeInfoBuilder& builder, + bool typesOnly) { + Y_UNUSED(userType); + if (name != Name()) { + return false; + } - TType* resultType = nullptr; - if constexpr (ResultType == EDataSlot::Json) { - resultType = builder.SimpleType<TJson>(); - } else { - resultType = builder.SimpleType<TJsonDocument>(); - } + TType* resultType = nullptr; + if constexpr (ResultType == EDataSlot::Json) { + resultType = builder.SimpleType<TJson>(); + } else { + resultType = builder.SimpleType<TJsonDocument>(); + } - builder.Args() - ->Add<TAutoMap<TJsonNodeResource>>() - .Done() - .Returns(resultType); + builder.Args() + ->Add<TAutoMap<TJsonNodeResource>>() + .Done() + .Returns(resultType); - if (!typesOnly) { - builder.Implementation(new TSerialize(builder.GetSourcePosition())); - } - return true; + if (!typesOnly) { + builder.Implementation(new TSerialize(builder.GetSourcePosition())); } + return true; + } - private: - TUnboxedValue Run( - const IValueBuilder* valueBuilder, - const TUnboxedValuePod* args) const final { - try { - const TUnboxedValue& jsonDom = args[0]; +private: + TUnboxedValue Run( + const IValueBuilder* valueBuilder, + const TUnboxedValuePod* args) const final { + try { + const TUnboxedValue& jsonDom = args[0]; - if constexpr (ResultType == EDataSlot::Json) { - return valueBuilder->NewString(SerializeJsonDom(jsonDom)); - } else { - const auto binaryJson = SerializeToBinaryJson(jsonDom); - return valueBuilder->NewString(TStringBuf(binaryJson.Data(), binaryJson.Size())); - } - } catch (const std::exception& e) { - UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + if constexpr (ResultType == EDataSlot::Json) { + return valueBuilder->NewString(SerializeJsonDom(jsonDom)); + } else { + const auto binaryJson = SerializeToBinaryJson(jsonDom); + return valueBuilder->NewString(TStringBuf(binaryJson.Data(), binaryJson.Size())); } + } catch (const std::exception& e) { + UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); } - - TSourcePosition Pos_; - }; - - template <> - const TStringRef& TSerialize<EDataSlot::Json>::Name() { - static auto name = TStringRef::Of("Serialize"); - return name; } - template <> - const TStringRef& TSerialize<EDataSlot::JsonDocument>::Name() { - static auto name = TStringRef::Of("SerializeToJsonDocument"); - return name; - } + TSourcePosition Pos_; +}; + +template <> +const TStringRef& TSerialize<EDataSlot::Json>::Name() { + static auto name = TStringRef::Of("Serialize"); + return name; } +template <> +const TStringRef& TSerialize<EDataSlot::JsonDocument>::Name() { + static auto name = TStringRef::Of("SerializeToJsonDocument"); + return name; +} +} // namespace NJson2Udf diff --git a/yql/essentials/udfs/common/json2/sql_exists.h b/yql/essentials/udfs/common/json2/sql_exists.h index cb89f20ec21..955c1b1ce7f 100644 --- a/yql/essentials/udfs/common/json2/sql_exists.h +++ b/yql/essentials/udfs/common/json2/sql_exists.h @@ -10,126 +10,125 @@ #include <util/generic/yexception.h> namespace NJson2Udf { - using namespace NKikimr; - using namespace NUdf; - using namespace NYql; - using namespace NJsonPath; - - template <EDataSlot InputType, bool ThrowException> - class TSqlExists: public TBoxedValue { - public: - explicit TSqlExists(TSourcePosition pos) - : Pos_(pos) - { +using namespace NKikimr; +using namespace NUdf; +using namespace NYql; +using namespace NJsonPath; + +template <EDataSlot InputType, bool ThrowException> +class TSqlExists: public TBoxedValue { +public: + explicit TSqlExists(TSourcePosition pos) + : Pos_(pos) + { + } + + static TStringRef Name(); + + static bool DeclareSignature( + const TStringRef& name, + TType* userType, + IFunctionTypeInfoBuilder& builder, + bool typesOnly) { + Y_UNUSED(userType); + if (name != Name()) { + return false; } - static TStringRef Name(); + auto jsonType = builder.Resource(JSON_NODE_RESOURCE_NAME); + TType* inputType = nullptr; + if constexpr (InputType == EDataSlot::JsonDocument) { + inputType = builder.SimpleType<TJsonDocument>(); + } else { + inputType = jsonType; + } + auto inputOptionalType = builder.Optional()->Item(inputType).Build(); + auto jsonPathType = builder.Resource(JSONPATH_RESOURCE_NAME); + auto dictType = builder.Dict()->Key<TUtf8>().Value(jsonType).Build(); + auto optionalBoolType = builder.Optional()->Item<bool>().Build(); + + if constexpr (ThrowException) { + builder.Args() + ->Add(inputOptionalType) + .Add(jsonPathType) + .Add(dictType) + .Done() + .Returns(optionalBoolType); + } else { + builder.Args() + ->Add(inputOptionalType) + .Add(jsonPathType) + .Add(dictType) + .Add(optionalBoolType) + .Done() + .Returns(optionalBoolType); + } - static bool DeclareSignature( - const TStringRef& name, - TType* userType, - IFunctionTypeInfoBuilder& builder, - bool typesOnly) { - Y_UNUSED(userType); - if (name != Name()) { - return false; + if (!typesOnly) { + builder.Implementation(new TSqlExists(builder.GetSourcePosition())); + } + if constexpr (!ThrowException) { + builder.IsStrict(); + } + return true; + } + +private: + TUnboxedValue Run( + const IValueBuilder* valueBuilder, + const TUnboxedValuePod* args) const final { + Y_UNUSED(valueBuilder); + try { + if (!args[0].HasValue()) { + return TUnboxedValuePod(); } - auto jsonType = builder.Resource(JSON_NODE_RESOURCE_NAME); - TType* inputType = nullptr; + TValue jsonDom; if constexpr (InputType == EDataSlot::JsonDocument) { - inputType = builder.SimpleType<TJsonDocument>(); - } else { - inputType = jsonType; - } - auto inputOptionalType = builder.Optional()->Item(inputType).Build(); - auto jsonPathType = builder.Resource(JSONPATH_RESOURCE_NAME); - auto dictType = builder.Dict()->Key<TUtf8>().Value(jsonType).Build(); - auto optionalBoolType = builder.Optional()->Item<bool>().Build(); - - if constexpr (ThrowException) { - builder.Args() - ->Add(inputOptionalType) - .Add(jsonPathType) - .Add(dictType) - .Done() - .Returns(optionalBoolType); + jsonDom = TValue(NBinaryJson::TBinaryJsonReader::Make(args[0].AsStringRef())->GetRootCursor()); } else { - builder.Args() - ->Add(inputOptionalType) - .Add(jsonPathType) - .Add(dictType) - .Add(optionalBoolType) - .Done() - .Returns(optionalBoolType); + jsonDom = TValue(args[0]); } - if (!typesOnly) { - builder.Implementation(new TSqlExists(builder.GetSourcePosition())); - } - if constexpr (!ThrowException) { - builder.IsStrict(); - } - return true; - } + auto* jsonPathResource = static_cast<TJsonPathResource*>(args[1].AsBoxed().Get()); + const auto& jsonPath = *jsonPathResource->Get(); + const auto variables = DictToVariables(args[2]); - private: - TUnboxedValue Run( - const IValueBuilder* valueBuilder, - const TUnboxedValuePod* args) const final { - Y_UNUSED(valueBuilder); - try { - if (!args[0].HasValue()) { - return TUnboxedValuePod(); - } - - TValue jsonDom; - if constexpr (InputType == EDataSlot::JsonDocument) { - jsonDom = TValue(NBinaryJson::TBinaryJsonReader::Make(args[0].AsStringRef())->GetRootCursor()); + const auto result = ExecuteJsonPath(jsonPath, jsonDom, variables, valueBuilder); + if (result.IsError()) { + if constexpr (ThrowException) { + ythrow yexception() << "Error executing jsonpath:" << Endl << result.GetError() << Endl; } else { - jsonDom = TValue(args[0]); - } - - auto* jsonPathResource = static_cast<TJsonPathResource*>(args[1].AsBoxed().Get()); - const auto& jsonPath = *jsonPathResource->Get(); - const auto variables = DictToVariables(args[2]); - - const auto result = ExecuteJsonPath(jsonPath, jsonDom, variables, valueBuilder); - if (result.IsError()) { - if constexpr (ThrowException) { - ythrow yexception() << "Error executing jsonpath:" << Endl << result.GetError() << Endl; - } else { - return args[3]; - } + return args[3]; } - - return TUnboxedValuePod(!result.GetNodes().empty()); - } catch (const std::exception& e) { - UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); } - } - - TSourcePosition Pos_; - }; - template <> - TStringRef TSqlExists<EDataSlot::Json, false>::Name() { - return "SqlExists"; + return TUnboxedValuePod(!result.GetNodes().empty()); + } catch (const std::exception& e) { + UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + } } - template <> - TStringRef TSqlExists<EDataSlot::Json, true>::Name() { - return "SqlTryExists"; - } + TSourcePosition Pos_; +}; - template <> - TStringRef TSqlExists<EDataSlot::JsonDocument, false>::Name() { - return "JsonDocumentSqlExists"; - } +template <> +TStringRef TSqlExists<EDataSlot::Json, false>::Name() { + return "SqlExists"; +} - template <> - TStringRef TSqlExists<EDataSlot::JsonDocument, true>::Name() { - return "JsonDocumentSqlTryExists"; - } +template <> +TStringRef TSqlExists<EDataSlot::Json, true>::Name() { + return "SqlTryExists"; } +template <> +TStringRef TSqlExists<EDataSlot::JsonDocument, false>::Name() { + return "JsonDocumentSqlExists"; +} + +template <> +TStringRef TSqlExists<EDataSlot::JsonDocument, true>::Name() { + return "JsonDocumentSqlTryExists"; +} +} // namespace NJson2Udf diff --git a/yql/essentials/udfs/common/json2/sql_query.h b/yql/essentials/udfs/common/json2/sql_query.h index 1c2d610f923..00bf6fb2d74 100644 --- a/yql/essentials/udfs/common/json2/sql_query.h +++ b/yql/essentials/udfs/common/json2/sql_query.h @@ -12,173 +12,172 @@ #include <util/generic/yexception.h> namespace NJson2Udf { - using namespace NKikimr; - using namespace NUdf; - using namespace NYql; - using namespace NDom; - using namespace NJsonPath; - - template <EDataSlot InputType, EJsonQueryWrap Mode> - class TSqlQuery: public TBoxedValue { - public: - explicit TSqlQuery(TSourcePosition pos) - : Pos_(pos) - { +using namespace NKikimr; +using namespace NUdf; +using namespace NYql; +using namespace NDom; +using namespace NJsonPath; + +template <EDataSlot InputType, EJsonQueryWrap Mode> +class TSqlQuery: public TBoxedValue { +public: + explicit TSqlQuery(TSourcePosition pos) + : Pos_(pos) + { + } + + static TStringRef Name(); + + static bool DeclareSignature( + const TStringRef& name, + TType* userType, + IFunctionTypeInfoBuilder& builder, + bool typesOnly) { + Y_UNUSED(userType); + if (name != Name()) { + return false; } - static TStringRef Name(); + auto jsonType = builder.Resource(JSON_NODE_RESOURCE_NAME); + auto optionalJsonType = builder.Optional()->Item(jsonType).Build(); + TType* inputType = nullptr; + if constexpr (InputType == EDataSlot::JsonDocument) { + inputType = builder.SimpleType<TJsonDocument>(); + } else { + inputType = jsonType; + } + auto inputOptionalType = builder.Optional()->Item(inputType).Build(); + auto jsonPathType = builder.Resource(JSONPATH_RESOURCE_NAME); + auto dictType = builder.Dict()->Key<TUtf8>().Value(jsonType).Build(); + + /* + Arguments: + 0. Resource<JsonNode>? or JsonDocument?. Input json + 1. Resource<JsonPath>. Jsonpath to execute on json + 2. Dict<TUtf8, Resource<JsonNode>>. Variables to pass into jsonpath + 3. Bool. True - throw on empty result, false otherwise + 4. Resource<JsonNode>?. Default value to return on empty result. Ignored if 2d argument is true + 5. Bool. True - throw on error, false - otherwise + 6. Resource<JsonNode>?. Default value to return on error. Ignored if 4th argument is true + */ + // we can't mark TSqlQuery as strict due to runtime throw policy setting + // TODO: optimizer can mark SqlQuery as strict if 3th/5th arguments are literal booleans + builder.Args() + ->Add(inputOptionalType) + .Add(jsonPathType) + .Add(dictType) + .Add<bool>() + .Add(optionalJsonType) + .Add<bool>() + .Add(optionalJsonType) + .Done() + .Returns(optionalJsonType); + + if (!typesOnly) { + builder.Implementation(new TSqlQuery(builder.GetSourcePosition())); + } + return true; + } - static bool DeclareSignature( - const TStringRef& name, - TType* userType, - IFunctionTypeInfoBuilder& builder, - bool typesOnly) { - Y_UNUSED(userType); - if (name != Name()) { - return false; +private: + TUnboxedValue Run( + const IValueBuilder* valueBuilder, + const TUnboxedValuePod* args) const final { + Y_UNUSED(valueBuilder); + try { + if (!args[0].HasValue()) { + return TUnboxedValuePod(); } - auto jsonType = builder.Resource(JSON_NODE_RESOURCE_NAME); - auto optionalJsonType = builder.Optional()->Item(jsonType).Build(); - TType* inputType = nullptr; + TValue jsonDom; if constexpr (InputType == EDataSlot::JsonDocument) { - inputType = builder.SimpleType<TJsonDocument>(); + jsonDom = TValue(NBinaryJson::TBinaryJsonReader::Make(args[0].AsStringRef())->GetRootCursor()); } else { - inputType = jsonType; - } - auto inputOptionalType = builder.Optional()->Item(inputType).Build(); - auto jsonPathType = builder.Resource(JSONPATH_RESOURCE_NAME); - auto dictType = builder.Dict()->Key<TUtf8>().Value(jsonType).Build(); - - /* - Arguments: - 0. Resource<JsonNode>? or JsonDocument?. Input json - 1. Resource<JsonPath>. Jsonpath to execute on json - 2. Dict<TUtf8, Resource<JsonNode>>. Variables to pass into jsonpath - 3. Bool. True - throw on empty result, false otherwise - 4. Resource<JsonNode>?. Default value to return on empty result. Ignored if 2d argument is true - 5. Bool. True - throw on error, false - otherwise - 6. Resource<JsonNode>?. Default value to return on error. Ignored if 4th argument is true - */ - // we can't mark TSqlQuery as strict due to runtime throw policy setting - // TODO: optimizer can mark SqlQuery as strict if 3th/5th arguments are literal booleans - builder.Args() - ->Add(inputOptionalType) - .Add(jsonPathType) - .Add(dictType) - .Add<bool>() - .Add(optionalJsonType) - .Add<bool>() - .Add(optionalJsonType) - .Done() - .Returns(optionalJsonType); - - if (!typesOnly) { - builder.Implementation(new TSqlQuery(builder.GetSourcePosition())); + jsonDom = TValue(args[0]); } - return true; - } - private: - TUnboxedValue Run( - const IValueBuilder* valueBuilder, - const TUnboxedValuePod* args) const final { - Y_UNUSED(valueBuilder); - try { - if (!args[0].HasValue()) { - return TUnboxedValuePod(); - } + auto* jsonPathResource = static_cast<TJsonPathResource*>(args[1].AsBoxed().Get()); + const auto& jsonPath = *jsonPathResource->Get(); - TValue jsonDom; - if constexpr (InputType == EDataSlot::JsonDocument) { - jsonDom = TValue(NBinaryJson::TBinaryJsonReader::Make(args[0].AsStringRef())->GetRootCursor()); - } else { - jsonDom = TValue(args[0]); - } - - auto* jsonPathResource = static_cast<TJsonPathResource*>(args[1].AsBoxed().Get()); - const auto& jsonPath = *jsonPathResource->Get(); - - const bool throwOnEmpty = args[3].Get<bool>(); - const auto emptyDefault = args[4]; - const bool throwOnError = args[5].Get<bool>(); - const auto errorDefault = args[6]; - const auto variables = DictToVariables(args[2]); - - auto result = ExecuteJsonPath(jsonPath, jsonDom, variables, valueBuilder); + const bool throwOnEmpty = args[3].Get<bool>(); + const auto emptyDefault = args[4]; + const bool throwOnError = args[5].Get<bool>(); + const auto errorDefault = args[6]; + const auto variables = DictToVariables(args[2]); - const auto handleCase = [](TStringBuf message, bool throws, const TUnboxedValuePod& caseDefault) { - if (throws) { - ythrow yexception() << message; - } - return caseDefault; - }; + auto result = ExecuteJsonPath(jsonPath, jsonDom, variables, valueBuilder); - if (result.IsError()) { - return handleCase(TStringBuilder() << "Error executing jsonpath:" << Endl << result.GetError() << Endl, throwOnError, errorDefault); + const auto handleCase = [](TStringBuf message, bool throws, const TUnboxedValuePod& caseDefault) { + if (throws) { + ythrow yexception() << message; } + return caseDefault; + }; - auto& nodes = result.GetNodes(); - const bool isSingleStruct = nodes.size() == 1 && (nodes[0].Is(EValueType::Array) || nodes[0].Is(EValueType::Object)); - if (Mode == EJsonQueryWrap::Wrap || (Mode == EJsonQueryWrap::ConditionalWrap && !isSingleStruct)) { - TVector<TUnboxedValue> converted; - converted.reserve(nodes.size()); - for (auto& node : nodes) { - converted.push_back(node.ConvertToUnboxedValue(valueBuilder)); - } - return MakeList(converted.data(), converted.size(), valueBuilder); - } - - if (nodes.empty()) { - return handleCase("Empty result", throwOnEmpty, emptyDefault); - } + if (result.IsError()) { + return handleCase(TStringBuilder() << "Error executing jsonpath:" << Endl << result.GetError() << Endl, throwOnError, errorDefault); + } - // No wrapping is applicable and result is not empty. Result must be a single object or array - if (nodes.size() > 1) { - return handleCase("Result consists of multiple items", throwOnError, errorDefault); + auto& nodes = result.GetNodes(); + const bool isSingleStruct = nodes.size() == 1 && (nodes[0].Is(EValueType::Array) || nodes[0].Is(EValueType::Object)); + if (Mode == EJsonQueryWrap::Wrap || (Mode == EJsonQueryWrap::ConditionalWrap && !isSingleStruct)) { + TVector<TUnboxedValue> converted; + converted.reserve(nodes.size()); + for (auto& node : nodes) { + converted.push_back(node.ConvertToUnboxedValue(valueBuilder)); } + return MakeList(converted.data(), converted.size(), valueBuilder); + } - if (!nodes[0].Is(EValueType::Array) && !nodes[0].Is(EValueType::Object)) { - return handleCase("Result is neither object nor array", throwOnError, errorDefault); - } + if (nodes.empty()) { + return handleCase("Empty result", throwOnEmpty, emptyDefault); + } - return nodes[0].ConvertToUnboxedValue(valueBuilder); - } catch (const std::exception& e) { - UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + // No wrapping is applicable and result is not empty. Result must be a single object or array + if (nodes.size() > 1) { + return handleCase("Result consists of multiple items", throwOnError, errorDefault); } - } - TSourcePosition Pos_; - }; + if (!nodes[0].Is(EValueType::Array) && !nodes[0].Is(EValueType::Object)) { + return handleCase("Result is neither object nor array", throwOnError, errorDefault); + } - template <> - TStringRef TSqlQuery<EDataSlot::Json, EJsonQueryWrap::NoWrap>::Name() { - return "SqlQuery"; + return nodes[0].ConvertToUnboxedValue(valueBuilder); + } catch (const std::exception& e) { + UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + } } - template <> - TStringRef TSqlQuery<EDataSlot::Json, EJsonQueryWrap::Wrap>::Name() { - return "SqlQueryWrap"; - } + TSourcePosition Pos_; +}; - template <> - TStringRef TSqlQuery<EDataSlot::Json, EJsonQueryWrap::ConditionalWrap>::Name() { - return "SqlQueryConditionalWrap"; - } +template <> +TStringRef TSqlQuery<EDataSlot::Json, EJsonQueryWrap::NoWrap>::Name() { + return "SqlQuery"; +} - template <> - TStringRef TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::NoWrap>::Name() { - return "JsonDocumentSqlQuery"; - } +template <> +TStringRef TSqlQuery<EDataSlot::Json, EJsonQueryWrap::Wrap>::Name() { + return "SqlQueryWrap"; +} - template <> - TStringRef TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::Wrap>::Name() { - return "JsonDocumentSqlQueryWrap"; - } +template <> +TStringRef TSqlQuery<EDataSlot::Json, EJsonQueryWrap::ConditionalWrap>::Name() { + return "SqlQueryConditionalWrap"; +} - template <> - TStringRef TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::ConditionalWrap>::Name() { - return "JsonDocumentSqlQueryConditionalWrap"; - } +template <> +TStringRef TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::NoWrap>::Name() { + return "JsonDocumentSqlQuery"; +} + +template <> +TStringRef TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::Wrap>::Name() { + return "JsonDocumentSqlQueryWrap"; } +template <> +TStringRef TSqlQuery<EDataSlot::JsonDocument, EJsonQueryWrap::ConditionalWrap>::Name() { + return "JsonDocumentSqlQueryConditionalWrap"; +} +} // namespace NJson2Udf diff --git a/yql/essentials/udfs/common/json2/sql_value.h b/yql/essentials/udfs/common/json2/sql_value.h index 53b451c6275..525d1296a6b 100644 --- a/yql/essentials/udfs/common/json2/sql_value.h +++ b/yql/essentials/udfs/common/json2/sql_value.h @@ -15,282 +15,282 @@ #include <util/string/cast.h> namespace NJson2Udf { - using namespace NKikimr; - using namespace NUdf; - using namespace NYql; - using namespace NDom; - using namespace NJsonPath; - - namespace { - template <class TValueType, bool ForceConvert = false> - TUnboxedValue TryConvertJson(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { - Y_UNUSED(valueBuilder); - Y_UNUSED(source); - Y_ABORT("Unsupported type"); - } +using namespace NKikimr; +using namespace NUdf; +using namespace NYql; +using namespace NDom; +using namespace NJsonPath; + +namespace { +template <class TValueType, bool ForceConvert = false> +TUnboxedValue TryConvertJson(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { + Y_UNUSED(valueBuilder); + Y_UNUSED(source); + Y_ABORT("Unsupported type"); +} - template <> - TUnboxedValue TryConvertJson<TUtf8>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { - Y_UNUSED(valueBuilder); - if (IsNodeType(source, ENodeType::String)) { - return source; - } +template <> +TUnboxedValue TryConvertJson<TUtf8>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { + Y_UNUSED(valueBuilder); + if (IsNodeType(source, ENodeType::String)) { + return source; + } + return {}; +} + +template <> +TUnboxedValue TryConvertJson<TUtf8, true>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { + switch (GetNodeType(source)) { + case ENodeType::String: + return source; + case ENodeType::Uint64: + return valueBuilder->NewString(ToString(source.Get<ui64>())).Release(); + case ENodeType::Int64: + return valueBuilder->NewString(ToString(source.Get<i64>())).Release(); + case ENodeType::Bool: + return source.Get<bool>() ? TUnboxedValuePod::Embedded("true") : TUnboxedValuePod::Embedded("false"); + case ENodeType::Double: + return valueBuilder->NewString(ToString(source.Get<double>())).Release(); + case ENodeType::Entity: + return TUnboxedValuePod::Embedded("null"); + case ENodeType::List: + case ENodeType::Dict: + case ENodeType::Attr: return {}; - } + } +} - template <> - TUnboxedValue TryConvertJson<TUtf8, true>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { - switch (GetNodeType(source)) { - case ENodeType::String: - return source; - case ENodeType::Uint64: - return valueBuilder->NewString(ToString(source.Get<ui64>())).Release(); - case ENodeType::Int64: - return valueBuilder->NewString(ToString(source.Get<i64>())).Release(); - case ENodeType::Bool: - return source.Get<bool>() ? TUnboxedValuePod::Embedded("true") : TUnboxedValuePod::Embedded("false"); - case ENodeType::Double: - return valueBuilder->NewString(ToString(source.Get<double>())).Release(); - case ENodeType::Entity: - return TUnboxedValuePod::Embedded("null"); - case ENodeType::List: - case ENodeType::Dict: - case ENodeType::Attr: - return {}; - } - } +template <> +TUnboxedValue TryConvertJson<i64>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { + Y_UNUSED(valueBuilder); + if (!source.IsEmbedded()) { + return {}; + } - template <> - TUnboxedValue TryConvertJson<i64>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { - Y_UNUSED(valueBuilder); - if (!source.IsEmbedded()) { - return {}; - } + if (IsNodeType(source, ENodeType::Int64)) { + return TUnboxedValuePod(source.Get<i64>()); + } else if (IsNodeType(source, ENodeType::Uint64) && source.Get<ui64>() < Max<i64>()) { + return TUnboxedValuePod(static_cast<i64>(source.Get<ui64>())); + } else if (IsNodeType(source, ENodeType::Double) && static_cast<i64>(source.Get<double>()) == source.Get<double>()) { + return TUnboxedValuePod(static_cast<i64>(source.Get<double>())); + } - if (IsNodeType(source, ENodeType::Int64)) { - return TUnboxedValuePod(source.Get<i64>()); - } else if (IsNodeType(source, ENodeType::Uint64) && source.Get<ui64>() < Max<i64>()) { - return TUnboxedValuePod(static_cast<i64>(source.Get<ui64>())); - } else if (IsNodeType(source, ENodeType::Double) && static_cast<i64>(source.Get<double>()) == source.Get<double>()) { - return TUnboxedValuePod(static_cast<i64>(source.Get<double>())); - } + return {}; +} - return {}; - } +template <> +TUnboxedValue TryConvertJson<double>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { + Y_UNUSED(valueBuilder); + if (!source.IsEmbedded()) { + return {}; + } - template <> - TUnboxedValue TryConvertJson<double>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { - Y_UNUSED(valueBuilder); - if (!source.IsEmbedded()) { - return {}; - } + if (IsNodeType(source, ENodeType::Double)) { + return TUnboxedValuePod(source.Get<double>()); + } else if (IsNodeType(source, ENodeType::Int64)) { + return TUnboxedValuePod(static_cast<double>(source.Get<i64>())); + } else if (IsNodeType(source, ENodeType::Uint64)) { + return TUnboxedValuePod(static_cast<double>(source.Get<ui64>())); + } - if (IsNodeType(source, ENodeType::Double)) { - return TUnboxedValuePod(source.Get<double>()); - } else if (IsNodeType(source, ENodeType::Int64)) { - return TUnboxedValuePod(static_cast<double>(source.Get<i64>())); - } else if (IsNodeType(source, ENodeType::Uint64)) { - return TUnboxedValuePod(static_cast<double>(source.Get<ui64>())); - } + return {}; +} - return {}; +template <> +TUnboxedValue TryConvertJson<bool>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { + Y_UNUSED(valueBuilder); + if (!source.IsEmbedded() || !IsNodeType(source, ENodeType::Bool)) { + return {}; + } + return {TUnboxedValuePod(source.Get<bool>())}; +} +} // namespace + +template <EDataSlot InputType, class TValueType, bool ForceConvert = false> +class TSqlValue: public TBoxedValue { +public: + enum class TErrorCode: ui8 { + Empty = 0, + Error = 1 + }; + + TSqlValue(TSourcePosition pos) + : Pos_(pos) + { + } + + static TStringRef Name(); + + static bool DeclareSignature( + const TStringRef& name, + TType* userType, + IFunctionTypeInfoBuilder& builder, + bool typesOnly) { + Y_UNUSED(userType); + if (name != Name()) { + return false; } - template <> - TUnboxedValue TryConvertJson<bool>(const IValueBuilder* valueBuilder, const TUnboxedValue& source) { - Y_UNUSED(valueBuilder); - if (!source.IsEmbedded() || !IsNodeType(source, ENodeType::Bool)) { - return {}; - } - return {TUnboxedValuePod(source.Get<bool>())}; + auto optionalValueType = builder.Optional()->Item<TValueType>().Build(); + auto errorTupleType = builder.Tuple(2)->Add<ui8>().Add<char*>().Build(); + auto returnTypeTuple = builder.Tuple(2) + ->Add(errorTupleType) + .Add(optionalValueType) + .Build(); + auto returnType = builder.Variant()->Over(returnTypeTuple).Build(); + + TType* jsonType = nullptr; + if constexpr (InputType == EDataSlot::Json) { + jsonType = builder.Resource(JSON_NODE_RESOURCE_NAME); + } else { + jsonType = builder.SimpleType<TJsonDocument>(); } - } + auto optionalJsonType = builder.Optional()->Item(jsonType).Build(); + auto jsonPathType = builder.Resource(JSONPATH_RESOURCE_NAME); + auto dictType = builder.Dict()->Key<TUtf8>().Value(builder.Resource(JSON_NODE_RESOURCE_NAME)).Build(); + + builder.Args() + ->Add(optionalJsonType) + .Add(jsonPathType) + .Add(dictType) + .Done() + .Returns(returnType); - template <EDataSlot InputType, class TValueType, bool ForceConvert = false> - class TSqlValue: public TBoxedValue { - public: - enum class TErrorCode : ui8 { - Empty = 0, - Error = 1 - }; - - TSqlValue(TSourcePosition pos) - : Pos_(pos) - { + builder.IsStrict(); + + if (!typesOnly) { + builder.Implementation(new TSqlValue(builder.GetSourcePosition())); } + return true; + } - static TStringRef Name(); +private: + TUnboxedValue BuildErrorResult(const IValueBuilder* valueBuilder, TErrorCode code, const TStringBuf message) const { + TUnboxedValue* items = nullptr; + auto errorTuple = valueBuilder->NewArray(2, items); + items[0] = TUnboxedValuePod(static_cast<ui8>(code)); + items[1] = valueBuilder->NewString(message); + return valueBuilder->NewVariant(0, std::move(errorTuple)); + } + + TUnboxedValue BuildSuccessfulResult(const IValueBuilder* valueBuilder, TUnboxedValue&& value) const { + return valueBuilder->NewVariant(1, std::move(value)); + } - static bool DeclareSignature( - const TStringRef& name, - TType* userType, - IFunctionTypeInfoBuilder& builder, - bool typesOnly) { - Y_UNUSED(userType); - if (name != Name()) { - return false; + TUnboxedValue Run( + const IValueBuilder* valueBuilder, + const TUnboxedValuePod* args) const final { + try { + if (!args[0].HasValue()) { + return BuildSuccessfulResult(valueBuilder, TUnboxedValuePod()); } - auto optionalValueType = builder.Optional()->Item<TValueType>().Build(); - auto errorTupleType = builder.Tuple(2)->Add<ui8>().Add<char*>().Build(); - auto returnTypeTuple = builder.Tuple(2) - ->Add(errorTupleType) - .Add(optionalValueType) - .Build(); - auto returnType = builder.Variant()->Over(returnTypeTuple).Build(); - - TType* jsonType = nullptr; - if constexpr (InputType == EDataSlot::Json) { - jsonType = builder.Resource(JSON_NODE_RESOURCE_NAME); + TValue jsonDom; + if constexpr (InputType == EDataSlot::JsonDocument) { + jsonDom = TValue(NBinaryJson::TBinaryJsonReader::Make(args[0].AsStringRef())->GetRootCursor()); } else { - jsonType = builder.SimpleType<TJsonDocument>(); + jsonDom = TValue(args[0]); } - auto optionalJsonType = builder.Optional()->Item(jsonType).Build(); - auto jsonPathType = builder.Resource(JSONPATH_RESOURCE_NAME); - auto dictType = builder.Dict()->Key<TUtf8>().Value(builder.Resource(JSON_NODE_RESOURCE_NAME)).Build(); - builder.Args() - ->Add(optionalJsonType) - .Add(jsonPathType) - .Add(dictType) - .Done() - .Returns(returnType); + auto* jsonPathResource = static_cast<TJsonPathResource*>(args[1].AsBoxed().Get()); + const auto& jsonPath = *jsonPathResource->Get(); + const auto variables = DictToVariables(args[2]); - builder.IsStrict(); + const auto result = ExecuteJsonPath(jsonPath, jsonDom, variables, valueBuilder); - if (!typesOnly) { - builder.Implementation(new TSqlValue(builder.GetSourcePosition())); + if (result.IsError()) { + return BuildErrorResult(valueBuilder, TErrorCode::Error, TStringBuilder() << "Error executing jsonpath:" << Endl << result.GetError() << Endl); } - return true; - } - private: - TUnboxedValue BuildErrorResult(const IValueBuilder* valueBuilder, TErrorCode code, const TStringBuf message) const { - TUnboxedValue* items = nullptr; - auto errorTuple = valueBuilder->NewArray(2, items); - items[0] = TUnboxedValuePod(static_cast<ui8>(code)); - items[1] = valueBuilder->NewString(message); - return valueBuilder->NewVariant(0, std::move(errorTuple)); - } + const auto& nodes = result.GetNodes(); + if (nodes.empty()) { + return BuildErrorResult(valueBuilder, TErrorCode::Empty, "Result is empty"); + } - TUnboxedValue BuildSuccessfulResult(const IValueBuilder* valueBuilder, TUnboxedValue&& value) const { - return valueBuilder->NewVariant(1, std::move(value)); - } + if (nodes.size() > 1) { + return BuildErrorResult(valueBuilder, TErrorCode::Error, "Result consists of multiple items"); + } - TUnboxedValue Run( - const IValueBuilder* valueBuilder, - const TUnboxedValuePod* args) const final { - try { - if (!args[0].HasValue()) { - return BuildSuccessfulResult(valueBuilder, TUnboxedValuePod()); - } - - TValue jsonDom; - if constexpr (InputType == EDataSlot::JsonDocument) { - jsonDom = TValue(NBinaryJson::TBinaryJsonReader::Make(args[0].AsStringRef())->GetRootCursor()); - } else { - jsonDom = TValue(args[0]); - } - - auto* jsonPathResource = static_cast<TJsonPathResource*>(args[1].AsBoxed().Get()); - const auto& jsonPath = *jsonPathResource->Get(); - const auto variables = DictToVariables(args[2]); - - const auto result = ExecuteJsonPath(jsonPath, jsonDom, variables, valueBuilder); - - if (result.IsError()) { - return BuildErrorResult(valueBuilder, TErrorCode::Error, TStringBuilder() << "Error executing jsonpath:" << Endl << result.GetError() << Endl); - } - - const auto& nodes = result.GetNodes(); - if (nodes.empty()) { - return BuildErrorResult(valueBuilder, TErrorCode::Empty, "Result is empty"); - } - - if (nodes.size() > 1) { - return BuildErrorResult(valueBuilder, TErrorCode::Error, "Result consists of multiple items"); - } - - const auto& value = nodes[0]; - if (value.Is(EValueType::Array) || value.Is(EValueType::Object)) { - // SqlValue can return only scalar values - return BuildErrorResult(valueBuilder, TErrorCode::Error, "Extracted JSON value is either object or array"); - } - - if (value.Is(EValueType::Null)) { - // JSON nulls must be converted to SQL nulls - return BuildSuccessfulResult(valueBuilder, TUnboxedValuePod()); - } - - const auto source = value.ConvertToUnboxedValue(valueBuilder); - TUnboxedValue convertedValue = TryConvertJson<TValueType, ForceConvert>(valueBuilder, source); - if (!convertedValue) { - // error while converting JSON value type to TValueType - return BuildErrorResult(valueBuilder, TErrorCode::Error, "Cannot convert extracted JSON value to target type"); - } - - return BuildSuccessfulResult(valueBuilder, std::move(convertedValue)); - } catch (const std::exception& e) { - UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + const auto& value = nodes[0]; + if (value.Is(EValueType::Array) || value.Is(EValueType::Object)) { + // SqlValue can return only scalar values + return BuildErrorResult(valueBuilder, TErrorCode::Error, "Extracted JSON value is either object or array"); } - } - TSourcePosition Pos_; - }; + if (value.Is(EValueType::Null)) { + // JSON nulls must be converted to SQL nulls + return BuildSuccessfulResult(valueBuilder, TUnboxedValuePod()); + } - template <EDataSlot InputType, class TValueType, bool ForceConvert> - TStringRef TSqlValue<InputType, TValueType, ForceConvert>::Name() { - Y_ABORT("Unknown name"); - } + const auto source = value.ConvertToUnboxedValue(valueBuilder); + TUnboxedValue convertedValue = TryConvertJson<TValueType, ForceConvert>(valueBuilder, source); + if (!convertedValue) { + // error while converting JSON value type to TValueType + return BuildErrorResult(valueBuilder, TErrorCode::Error, "Cannot convert extracted JSON value to target type"); + } - template<> - TStringRef TSqlValue<EDataSlot::Json, TUtf8, true>::Name() { - return TStringRef::Of("SqlValueConvertToUtf8"); + return BuildSuccessfulResult(valueBuilder, std::move(convertedValue)); + } catch (const std::exception& e) { + UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).c_str()); + } } - template <> - TStringRef TSqlValue<EDataSlot::Json, TUtf8>::Name() { - return TStringRef::Of("SqlValueUtf8"); - } + TSourcePosition Pos_; +}; - template <> - TStringRef TSqlValue<EDataSlot::Json, i64>::Name() { - return TStringRef::Of("SqlValueInt64"); - } +template <EDataSlot InputType, class TValueType, bool ForceConvert> +TStringRef TSqlValue<InputType, TValueType, ForceConvert>::Name() { + Y_ABORT("Unknown name"); +} - template <> - TStringRef TSqlValue<EDataSlot::Json, double>::Name() { - return TStringRef::Of("SqlValueNumber"); - } +template <> +TStringRef TSqlValue<EDataSlot::Json, TUtf8, true>::Name() { + return TStringRef::Of("SqlValueConvertToUtf8"); +} - template <> - TStringRef TSqlValue<EDataSlot::Json, bool>::Name() { - return TStringRef::Of("SqlValueBool"); - } +template <> +TStringRef TSqlValue<EDataSlot::Json, TUtf8>::Name() { + return TStringRef::Of("SqlValueUtf8"); +} - template<> - TStringRef TSqlValue<EDataSlot::JsonDocument, TUtf8, true>::Name() { - return TStringRef::Of("JsonDocumentSqlValueConvertToUtf8"); - } +template <> +TStringRef TSqlValue<EDataSlot::Json, i64>::Name() { + return TStringRef::Of("SqlValueInt64"); +} - template <> - TStringRef TSqlValue<EDataSlot::JsonDocument, TUtf8>::Name() { - return TStringRef::Of("JsonDocumentSqlValueUtf8"); - } +template <> +TStringRef TSqlValue<EDataSlot::Json, double>::Name() { + return TStringRef::Of("SqlValueNumber"); +} - template <> - TStringRef TSqlValue<EDataSlot::JsonDocument, i64>::Name() { - return TStringRef::Of("JsonDocumentSqlValueInt64"); - } +template <> +TStringRef TSqlValue<EDataSlot::Json, bool>::Name() { + return TStringRef::Of("SqlValueBool"); +} - template <> - TStringRef TSqlValue<EDataSlot::JsonDocument, double>::Name() { - return TStringRef::Of("JsonDocumentSqlValueNumber"); - } +template <> +TStringRef TSqlValue<EDataSlot::JsonDocument, TUtf8, true>::Name() { + return TStringRef::Of("JsonDocumentSqlValueConvertToUtf8"); +} - template <> - TStringRef TSqlValue<EDataSlot::JsonDocument, bool>::Name() { - return TStringRef::Of("JsonDocumentSqlValueBool"); - } +template <> +TStringRef TSqlValue<EDataSlot::JsonDocument, TUtf8>::Name() { + return TStringRef::Of("JsonDocumentSqlValueUtf8"); +} +template <> +TStringRef TSqlValue<EDataSlot::JsonDocument, i64>::Name() { + return TStringRef::Of("JsonDocumentSqlValueInt64"); } + +template <> +TStringRef TSqlValue<EDataSlot::JsonDocument, double>::Name() { + return TStringRef::Of("JsonDocumentSqlValueNumber"); +} + +template <> +TStringRef TSqlValue<EDataSlot::JsonDocument, bool>::Name() { + return TStringRef::Of("JsonDocumentSqlValueBool"); +} + +} // namespace NJson2Udf diff --git a/yql/essentials/udfs/common/json2/ya.make b/yql/essentials/udfs/common/json2/ya.make index 52289125941..fa5e47018ce 100644 --- a/yql/essentials/udfs/common/json2/ya.make +++ b/yql/essentials/udfs/common/json2/ya.make @@ -5,6 +5,8 @@ YQL_UDF_CONTRIB(json2_udf) 28 0 ) + + ENABLE(YQL_STYLE_CPP) SRCS( json2_udf.cpp |