Type-aware UDF-функции

Type awareness реализована с помощью аргумента TType* userType методов DeclareSignature(...) и buildReturnSignature(...). Этот аргумент позволяет посмотреть, с какими аргументами была вызвана UDF-функция из YQL, и построить нужную сигнатуру. Пользовательский тип можно распарсить с помощью ITypeInfoHelper::TPtr, который принимает в конструкторе builder.TypeInfoHelper() , из которого в свою очередь конструируются TypeInspector'ы: TTupleTypeInspector, TCallableTypeInspector, TOptionalTypeInspector и др.

Важно

Для того чтобы движок YQL передавал на вход DeclareSignature() не пустой userType, класс вашей UDF должен содержать определение подтипа:

typedef bool TTypeAwareMarker;

С помощью таких функций можно:

  • Поддержать опциональные или дефолтные аргументы:

    SomeTypeAwareUdfFunc(Double, Double) -> Bool

    SomeTypeAwareUdfFunc(Double, Double, Double) -> Bool

    TMemberIndices TSomeTypeAwareUdfFunc::buildReturnSignature(IFunctionTypeInfoBuilder& builder, TType* userType) {
        ...
        auto userTypeInspector = TTupleTypeInspector(*typeHelper, userType);
        auto argsTypeTuple = userTypeInspector.GetElementType(0);
        auto argsTypeInspector = TTupleTypeInspector(*typeHelper, argsTypeTuple);
    
        // Build right signature by number of arguments
        if (argsTypeInspector.GetElementsCount() == 2) {
            /* Build one signature */
            ...
        } else if (argsTypeInspector.GetElementsCount() == 3) {
            /* Build other signature */
            ...
        } else {
            ...
        }
    ...
    }
    
    TUnboxedValue TSomeTypeAwareUdfFunc::Run(IValueBuilder* valueBuilder, TUnboxedValuePod* args) {
        ...
        double value = 0.0;  // default
        if (/* hasThirdElement */) {
            value = args[2].Get<double>(); // non-default
        }
        ...
    }
    
  • Поддержать перегрузку:

    SomeTypeAwareUdfFunc(List<Int>) -> String

    SomeTypeAwareUdfFunc(Stream<Int>) -> String

    TMemberIndices buildReturnSignature(IFunctionTypeInfoBuilder& builder, TType* userType) {
        ...
        auto userTypeInspector = TTupleTypeInspector(*typeHelper, userType);
        auto argsTypeTuple = userTypeInspector.GetElementType(0);
        auto argsTypeInspector = TTupleTypeInspector(*typeHelper, argsTypeTuple);
    
        auto typeKind = typeHelper->GetTypeKind(argsTypeInspector.GetElementType(0));
        if (typeKind == ETypeKind::List) {
            ...
        } else if (typeKind == ETypeKind::Stream) {
            ...
        } else {
            ...
        }
        ...
    }
    
  • Поддержать изменение типа ответа по возвращаемому типу пользовательского колбэка:

    SomeTypeAwareUdfFunc(Callable<...>->Int)->List<Int>

    SomeTypeAwareUdfFunc(Callable<...>->Double)->List<Double>

    SomeTypeAwareUdfFunc(Callable<...>->CallbackReturnType)->List<CallbackReturnType>

    TMemberIndices buildReturnSignature(IFunctionTypeInfoBuilder& builder, TType* userType) {
        ...
        auto userTypeInspector = TTupleTypeInspector(*typeHelper, userType);
        auto argsTypeTuple = userTypeInspector.GetElementType(0);
        auto argsTypeInspector = TTupleTypeInspector(*typeHelper, argsTypeTuple);
        auto callbackInspector = TCallableTypeInspector(*typeHelper, argsTypeInspector.GetElementType(0));
    
        auto resultType = builder.List()->Item(callbackInspector.GetReturnType()).Build();
        builder.Returns(resultType).Args()->Add(argsTypeInspector.GetElementType(0)).Done();
        ...
    }