aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/minikql/comp_nodes/mkql_weakmember.cpp
blob: 2d53545910499cd7dfacd373c2634cd847b2d41c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include "mkql_fromyson.h"
#include <library/cpp/yson/varint.h>
#include <library/cpp/yson/detail.h>
#include <yql/essentials/minikql/computation/mkql_computation_node_holders.h>
#include <yql/essentials/minikql/mkql_node_cast.h>
#include <yql/essentials/minikql/mkql_node_builder.h>
#include <yql/essentials/minikql/mkql_string_util.h>
#include <yql/essentials/minikql/mkql_unboxed_value_stream.h>

namespace NKikimr {
namespace NMiniKQL {
namespace {

class TTryWeakMemberFromDictWrapper : public TMutableComputationNode<TTryWeakMemberFromDictWrapper> {
    typedef TMutableComputationNode<TTryWeakMemberFromDictWrapper> TBaseComputation;
public:
    TTryWeakMemberFromDictWrapper(TComputationMutables& mutables, IComputationNode* otherDict, IComputationNode* restDict, NUdf::TDataTypeId schemeType,
            NUdf::TUnboxedValue&& memberName, NUdf::TUnboxedValue&& otherIsStrMemberName)
        : TBaseComputation(mutables)
        , OtherDict(otherDict)
        , RestDict(restDict)
        , SchemeType(NUdf::GetDataSlot(schemeType))
        , MemberName(std::move(memberName))
        , OtherIsStringMemberName(std::move(otherIsStrMemberName))
    {
    }

    NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
        if (const auto& restDict = RestDict->GetValue(ctx)) {
            if (const auto& tryMember = restDict.Lookup(MemberName)) {
                return SimpleValueFromYson(SchemeType, tryMember.AsStringRef());
            }
        }

        if (const auto& otherDict = OtherDict->GetValue(ctx)) {
            if (auto tryMember = otherDict.Lookup(MemberName)) {
                const bool isString = otherDict.Contains(OtherIsStringMemberName);
                if (isString) {
                    if (SchemeType == NUdf::EDataSlot::Yson) {
                        const auto& ref = tryMember.AsStringRef();
                        const auto size = ref.Size();
                        MKQL_ENSURE(size <= std::numeric_limits<i32>::max(), "TryWeakMemberFromDict: Unable to fit string to i32");
                        TUnboxedValueStream stringStream;
                        stringStream.DoWrite(&NYson::NDetail::StringMarker, 1);
                        NYson::WriteVarInt32(&stringStream, size);
                        stringStream.DoWrite(ref.Data(), size);
                        return stringStream.Value();
                    } else if (SchemeType == NUdf::EDataSlot::String) {
                        return tryMember.Release();
                    } else {
                        return {};
                    }
                } else {
                    return SimpleValueFromYson(SchemeType, tryMember.AsStringRef());
                }
            }
        }

        return NUdf::TUnboxedValuePod();
    }

private:
    void RegisterDependencies() const final {
        DependsOn(OtherDict);
        DependsOn(RestDict);
    }

    IComputationNode* const OtherDict;
    IComputationNode* const RestDict;
    const NUdf::EDataSlot SchemeType;
    const NUdf::TUnboxedValue MemberName;
    const NUdf::TUnboxedValue OtherIsStringMemberName;
};

}

IComputationNode* WrapTryWeakMemberFromDict(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
    MKQL_ENSURE(callable.GetInputsCount() == 4, "Expected 4 args");

    auto otherType = AS_TYPE(TOptionalType, callable.GetInput(0));
    auto otherDictType = AS_TYPE(TDictType, otherType->GetItemType());
    auto otherDictKeyType = AS_TYPE(TDataType, otherDictType->GetKeyType());
    auto otherDictPayloadType = AS_TYPE(TDataType, otherDictType->GetPayloadType());
    MKQL_ENSURE(otherDictKeyType->GetSchemeType() == NUdf::TDataType<char*>::Id, "Expected String");
    MKQL_ENSURE(otherDictPayloadType->GetSchemeType() == NUdf::TDataType<char*>::Id, "Expected String");

    auto restType = AS_TYPE(TOptionalType, callable.GetInput(1));
    auto restDictType = AS_TYPE(TDictType, restType->GetItemType());
    auto restDictKeyType = AS_TYPE(TDataType, restDictType->GetKeyType());
    auto restDictPayloadType = AS_TYPE(TDataType, restDictType->GetPayloadType());
    MKQL_ENSURE(restDictKeyType->GetSchemeType() == NUdf::TDataType<char*>::Id, "Expected String");
    MKQL_ENSURE(restDictPayloadType->GetSchemeType() == NUdf::TDataType<NUdf::TYson>::Id, "Expected String");

    TDataLiteral* schemeTypeData = AS_VALUE(TDataLiteral, callable.GetInput(2));
    auto schemeType = schemeTypeData->AsValue().Get<ui32>();

    auto memberNameValue = AS_VALUE(TDataLiteral, callable.GetInput(3));
    const TString memberName(memberNameValue->AsValue().AsStringRef());

    auto otherDict = LocateNode(ctx.NodeLocator, callable, 0);
    auto restDict = LocateNode(ctx.NodeLocator, callable, 1);
    auto memberNameStr = MakeString(memberName);
    auto otherIsStringMemberNameStr = MakeString("_yql_" + memberName);
    return new TTryWeakMemberFromDictWrapper(ctx.Mutables, otherDict, restDict, static_cast<NUdf::TDataTypeId>(schemeType),
            std::move(memberNameStr), std::move(otherIsStringMemberNameStr));
}

}
}