#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace NKikimr::NMiniKQL::NTest { using NYql::NUdf::NTest::TDecimalLiteral; using NYql::NUdf::NTest::TPgInt; using NYql::NUdf::NTest::TSingularNull; using NYql::NUdf::NTest::TSingularVoid; using NYql::NUdf::NTest::TStructMember; using NYql::NUdf::NTest::TStructMemberName; using NYql::NUdf::NTest::TStructType; using NYql::NUdf::NTest::TStructVariant; using NYql::NUdf::NTest::TTag; using NYql::NUdf::NTest::TTagged; using NYql::NUdf::NTest::TTestDyNumber; using NYql::NUdf::NTest::TUtf8; namespace NPrivate { template struct TMaybeTraits { static constexpr ui32 value = 0; using ResultType = T; }; template struct TMaybeTraits> { static constexpr ui32 value = 1 + TMaybeTraits::value; using ResultType = TMaybeTraits::ResultType; }; template const TMaybeTraits::ResultType* GetInnerValue(const T& value) { if constexpr (TMaybeTraits::value == 0) { return &value; } else { if (value.Defined()) { return GetInnerValue(value.GetRef()); } else { return nullptr; } } } template ui32 GetSettedLevel(const T& value) { if constexpr (TMaybeTraits::value == 0) { return 0; } else { if (value.Defined()) { return 1 + GetSettedLevel(value.GetRef()); } else { return 0; } } } template struct TUnpackedMaybe { ui32 SettedLevel; ui32 MaybeLevel; const T* Value = nullptr; }; } // namespace NPrivate // Forward declarations so all overloads are visible to each other's template bodies. template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TMaybe& maybeNode); template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const std::tuple& node); template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TStructType& node); template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const std::variant& v); template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TVector& nodes); template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TStructVariant& value); template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, T simpleNode) requires(NYql::NUdf::TPrimitiveDataType::Result) { return pb.NewDataLiteral(simpleNode); } inline TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, TSingularVoid simpleNode) { Y_UNUSED(simpleNode); return pb.NewVoid(); } inline TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, TSingularNull simpleNode) { Y_UNUSED(simpleNode); return pb.NewNull(); } inline TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, TPgInt simpleNode) { auto* type = pb.NewPgType(NYql::NPg::LookupType("int4").TypeId); if (simpleNode.Value()) { return pb.PgConst(static_cast(type), std::to_string(*simpleNode.Value())); } else { return pb.Nop(pb.NewNull(), type); } } inline TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, TStringBuf simpleNode) { Y_UNUSED(simpleNode); return pb.NewDataLiteral(simpleNode); } inline TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TGUID& uuid) { return pb.NewDataLiteral( NUdf::TStringRef(reinterpret_cast(&uuid), sizeof(uuid))); } inline TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, TTestDyNumber value) { const auto parsed = NDyNumber::ParseDyNumberString(value.Value); MKQL_ENSURE(parsed, "Invalid DyNumber literal: " << value.Value); return pb.NewDataLiteral(*parsed); } inline TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TUtf8& utf8Node) { return pb.NewDataLiteral(utf8Node.Value); } template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TDecimalLiteral& decimalNode) { return pb.NewDecimalLiteral(decimalNode.Value, Precision, Scale); } template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TTagged& taggedNode) { auto node = ConvertValueToLiteralNode(pb, taggedNode.Value()); return pb.Nop(node, pb.NewTaggedType(node.GetStaticType(), taggedNode.Tag())); } template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TMaybe& maybeNode) { NPrivate::TUnpackedMaybe unpacked{.SettedLevel = NPrivate::GetSettedLevel(maybeNode), .MaybeLevel = NPrivate::TMaybeTraits>::value, .Value = NPrivate::GetInnerValue(maybeNode)}; decltype(*unpacked.Value) defaultValue{}; auto data = ConvertValueToLiteralNode(pb, unpacked.Value ? *unpacked.Value : defaultValue); for (ui32 i = unpacked.SettedLevel; i < unpacked.MaybeLevel; i++) { data = pb.NewEmptyOptional(pb.NewOptionalType(data.GetStaticType())); } for (ui32 i = 0; i < unpacked.SettedLevel; i++) { data = pb.NewOptional(data); } return data; } template TRuntimeNode ConvertValueToLiteralNodeTuple(TProgramBuilder& pb, const std::tuple& maybeNode, std::index_sequence) { auto data = TVector{ConvertValueToLiteralNode(pb, std::get(maybeNode))...}; return pb.NewTuple(data); } template TRuntimeNode ConvertValueToLiteralNodeStruct(TProgramBuilder& pb, const TStructType& structNode, std::index_sequence) { TVector> members = { {std::tuple_element_t>::MemberName(), ConvertValueToLiteralNode(pb, std::get(structNode.Members).Value)}...}; return pb.NewStruct(members); } template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const std::tuple& node) { return ConvertValueToLiteralNodeTuple(pb, node, std::index_sequence_for{}); } template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TStructType& node) { return ConvertValueToLiteralNodeStruct(pb, node, std::index_sequence_for{}); } template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const std::variant& v) { TVector types = {ConvertValueToLiteralNode(pb, Args{}).GetStaticType()...}; TType* varType = pb.NewVariantType(pb.NewTupleType(types)); const ui32 idx = static_cast(v.index()); TRuntimeNode result; [&](std::index_sequence) { Y_UNUSED(((Is == idx && (result = pb.NewVariant(ConvertValueToLiteralNode(pb, std::get(v)), idx, varType), true)) || ...)); }(std::index_sequence_for{}); return result; } template TType* ConvertToMinikqlType(TProgramBuilder& pb) { return ConvertValueToLiteralNode(pb, T{}).GetStaticType(); } template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TVector& nodes) { TRuntimeNode::TList convertedNodes; convertedNodes.reserve(nodes.size()); for (const auto& node : nodes) { convertedNodes.push_back(ConvertValueToLiteralNode(pb, node)); } TType* const type = nodes.empty() ? ConvertToMinikqlType(pb) : convertedNodes.front().GetStaticType(); return pb.NewList(type, std::move(convertedNodes)); } template TRuntimeNode ConvertValueToLiteralNode(TProgramBuilder& pb, const TStructVariant& value) { TVector> members = { {TMembers::MemberName(), ConvertValueToLiteralNode(pb, std::remove_cvref_t().Value)>{}).GetStaticType()}...}; auto varType = pb.NewVariantType(pb.NewStructType(members)); auto alternative = value.VisitActive([&](const auto& inner) { return ConvertValueToLiteralNode(pb, inner); }); return pb.NewVariant(alternative, value.Name(), varType); } } // namespace NKikimr::NMiniKQL::NTest