#include "yql_expr_schema.h" #include #include #include #include #include #include #include #include #include #include #include namespace NYql { namespace NCommon { template class TSaver> class TExprTypeSaver: public TSaver> { typedef TSaver> TBase; struct TStructAdaptor { const TStructExprType* Type; TStructAdaptor(const TStructExprType* type) : Type(type) { } ui32 GetMembersCount() const { return Type->GetItems().size(); } const TStringBuf& GetMemberName(ui32 idx) const { return Type->GetItems()[idx]->GetName(); } const TTypeAnnotationNode* GetMemberType(ui32 idx) const { return Type->GetItems()[idx]->GetItemType(); } }; struct TMappingOrderedStructAdaptor { TVector> Members; TMappingOrderedStructAdaptor(const TStructMemberMapper& mapper, const TMaybe& columns, const TStructExprType* type, bool writePhysical = true) { TMap members; for (auto& item: type->GetItems()) { TMaybe name = mapper ? mapper(item->GetName()) : item->GetName(); if (!name) { continue; } members[*name] = item->GetItemType(); } if (columns) { for (auto& [column, gen_column] : *columns) { auto it = members.find(gen_column); if (it != members.end()) { Members.emplace_back(writePhysical ? gen_column : column, it->second); } } } else { Members.insert(Members.end(), members.begin(), members.end()); } } ui32 GetMembersCount() const { return Members.size(); } const TStringBuf& GetMemberName(ui32 idx) const { return Members[idx].first; } const TTypeAnnotationNode* GetMemberType(ui32 idx) const { return Members[idx].second; } }; struct TTupleAdaptor { const TTupleExprType* Type; TTupleAdaptor(const TTupleExprType* type) : Type(type) { } ui32 GetElementsCount() const { return Type->GetItems().size(); } const TTypeAnnotationNode* GetElementType(ui32 idx) const { return Type->GetItems()[idx]; } }; struct TCallableAdaptor { const TCallableExprType* Type; TCallableAdaptor(const TCallableExprType* type) : Type(type) { } size_t GetOptionalArgsCount() const { return Type->GetOptionalArgumentsCount(); } TStringBuf GetPayload() const { return Type->GetPayload(); } const TTypeAnnotationNode* GetReturnType() const { return Type->GetReturnType(); } size_t GetArgumentsCount() const { return Type->GetArgumentsSize(); } TStringBuf GetArgumentName(size_t i) const { return Type->GetArguments().at(i).Name; } ui64 GetArgumentFlags(size_t i) const { return Type->GetArguments().at(i).Flags; } const TTypeAnnotationNode* GetArgumentType(size_t i) const { return Type->GetArguments().at(i).Type; } }; void SaveErrorType(const TErrorExprType& errorType) { TBase::SaveTypeHeader("ErrorType"); auto err = errorType.GetError(); TBase::Writer.OnListItem(); TBase::Writer.OnInt64Scalar(err.Position.Row); TBase::Writer.OnListItem(); TBase::Writer.OnInt64Scalar(err.Position.Column); TBase::Writer.OnListItem(); TBase::Writer.OnStringScalar(err.Position.File); TBase::Writer.OnListItem(); TBase::Writer.OnStringScalar(err.GetMessage()); TBase::Writer.OnEndList(); } public: TExprTypeSaver(typename TBase::TConsumer& consumer, bool extendedForm) : TBase(consumer, extendedForm) { } void Save(const TTypeAnnotationNode* type) { switch (type->GetKind()) { case ETypeAnnotationKind::Data: { const auto dataType = type->Cast(); if (const auto dataParamsType = dynamic_cast(dataType)) { TBase::SaveDataTypeParams(dataType->GetName(), dataParamsType->GetParamOne(), dataParamsType->GetParamTwo()); } else { TBase::SaveDataType(dataType->GetName()); } break; } case ETypeAnnotationKind::Pg: TBase::SavePgType(type->Cast()->GetName()); break; case ETypeAnnotationKind::Struct: TBase::SaveStructType(TStructAdaptor(type->Cast())); break; case ETypeAnnotationKind::List: TBase::SaveListType(*type->Cast()); break; case ETypeAnnotationKind::Optional: TBase::SaveOptionalType(*type->Cast()); break; case ETypeAnnotationKind::Tuple: TBase::SaveTupleType(TTupleAdaptor(type->Cast())); break; case ETypeAnnotationKind::Dict: TBase::SaveDictType(*type->Cast()); break; case ETypeAnnotationKind::Type: TBase::SaveType(); break; case ETypeAnnotationKind::Generic: TBase::SaveGenericType(); break; case ETypeAnnotationKind::Void: TBase::SaveVoidType(); break; case ETypeAnnotationKind::Null: TBase::SaveNullType(); break; case ETypeAnnotationKind::Unit: TBase::SaveUnitType(); break; case ETypeAnnotationKind::EmptyList: TBase::SaveEmptyListType(); break; case ETypeAnnotationKind::EmptyDict: TBase::SaveEmptyDictType(); break; case ETypeAnnotationKind::Resource: TBase::SaveResourceType(type->Cast()->GetTag()); break; case ETypeAnnotationKind::Tagged: TBase::SaveTaggedType(*type->Cast()); break; case ETypeAnnotationKind::Error: SaveErrorType(*type->Cast()); break; case ETypeAnnotationKind::Callable: TBase::SaveCallableType(TCallableAdaptor(type->Cast())); break; case ETypeAnnotationKind::Variant: TBase::SaveVariantType(*type->Cast()); break; case ETypeAnnotationKind::Stream: TBase::SaveStreamType(*type->Cast()); break; default: YQL_ENSURE(false, "Unsupported type annotation kind: " << type->GetKind()); } } void SaveStructType(const TStructExprType* type, const TMaybe& columns, const TStructMemberMapper& mapper, bool physical = true) { if (mapper || columns) { TBase::SaveStructType(TMappingOrderedStructAdaptor(mapper, columns, type, physical)); } else { Save(type); } } }; void SaveStructTypeToYson(NYson::TYsonConsumerBase& writer, const TStructExprType* type, const TMaybe& columns, const TStructMemberMapper& mapper, bool extendedForm) { TExprTypeSaver saver(writer, extendedForm); saver.SaveStructType(type, columns, mapper, true); } void SaveStructTypeToYsonWithLogicalNames(NYson::TYsonConsumerBase& writer, const TStructExprType* type, const TMaybe& columns, const TStructMemberMapper& mapper, bool extendedForm) { TExprTypeSaver saver(writer, extendedForm); saver.SaveStructType(type, columns, mapper, false); } void WriteTypeToYson(NYson::TYsonConsumerBase& writer, const TTypeAnnotationNode* type, bool extendedForm) { TExprTypeSaver saver(writer, extendedForm); saver.Save(type); } NYT::TNode TypeToYsonNode(const TTypeAnnotationNode* type, bool extendedForm) { NYT::TNode res; NYT::TNodeBuilder builder(&res); WriteTypeToYson(builder, type, extendedForm); return res; } TString WriteTypeToYson(const TTypeAnnotationNode* type, NYson::EYsonFormat format, bool extendedForm) { TStringStream stream; NYson::TYsonWriter writer(&stream, format); WriteTypeToYson(writer, type, extendedForm); return stream.Str(); } struct TExprTypeLoader { typedef const TTypeAnnotationNode* TType; TExprContext& Ctx; TPosition Pos; TExprTypeLoader(TExprContext& ctx, const TPosition& pos = TPosition()) : Ctx(ctx) , Pos(pos) { } TMaybe LoadVoidType(ui32 /*level*/) { return Ctx.MakeType(); } TMaybe LoadNullType(ui32 /*level*/) { return Ctx.MakeType(); } TMaybe LoadUnitType(ui32 /*level*/) { return Ctx.MakeType(); } TMaybe LoadGenericType(ui32 /*level*/) { return Ctx.MakeType(); } TMaybe LoadEmptyListType(ui32 /*level*/) { return Ctx.MakeType(); } TMaybe LoadEmptyDictType(ui32 /*level*/) { return Ctx.MakeType(); } TMaybe LoadDataType(const TString& dataType, ui32 /*level*/) { return Ctx.MakeType(NYql::NUdf::GetDataSlot(dataType)); } TMaybe LoadPgType(const TString& name, ui32 /*level*/) { return Ctx.MakeType(NYql::NPg::LookupType(name).TypeId); } TMaybe LoadDataTypeParams(const TString& dataType, const TString& paramOne, const TString& paramTwo, ui32 /*level*/) { auto ret = Ctx.MakeType(NYql::NUdf::GetDataSlot(dataType), paramOne, paramTwo); YQL_ENSURE(ret->Validate(TPosition(), Ctx)); return ret; } TMaybe LoadResourceType(const TString& tag, ui32 /*level*/) { return Ctx.MakeType(tag); } TMaybe LoadTaggedType(TType baseType, const TString& tag, ui32 /*level*/) { auto ret = Ctx.MakeType(baseType, tag); YQL_ENSURE(ret->Validate(TPosition(), Ctx)); return ret; } TMaybe LoadErrorType(ui32 row, ui32 column, const TString& file, const TString& msg, ui32 /*level*/) { return Ctx.MakeType(TIssue(TPosition(column, row, file), msg)); } TMaybe LoadStructType(const TVector>& members, ui32 /*level*/) { TVector items; TColumnOrder order; for (auto& member: members) { items.push_back(Ctx.MakeType(order.AddColumn(member.first), member.second)); } auto ret = Ctx.MakeType(items); YQL_ENSURE(ret->Validate(TPosition(), Ctx)); return ret; } TMaybe LoadListType(TType itemType, ui32 /*level*/) { return Ctx.MakeType(itemType); } TMaybe LoadStreamType(TType itemType, ui32 /*level*/) { return Ctx.MakeType(itemType); } TMaybe LoadOptionalType(TType itemType, ui32 /*level*/) { return Ctx.MakeType(itemType); } TMaybe LoadTupleType(const TVector& elements, ui32 /*level*/) { auto ret = Ctx.MakeType(elements); YQL_ENSURE(ret->Validate(TPosition(), Ctx)); return ret; } TMaybe LoadDictType(TType keyType, TType valType, ui32 /*level*/) { auto ret = Ctx.MakeType(keyType, valType); YQL_ENSURE(ret->Validate(TPosition(), Ctx)); return ret; } TMaybe LoadCallableType(TType returnType, const TVector& argTypes, const TVector& argNames, const TVector& argFlags, size_t optionalCount, const TString& payload, ui32 /*level*/) { YQL_ENSURE(argTypes.size() == argNames.size() && argTypes.size() == argFlags.size()); TVector args; for (size_t i = 0; i < argTypes.size(); ++i) { args.emplace_back(); args.back().Type = argTypes[i]; args.back().Name = Ctx.AppendString(argNames[i]); args.back().Flags = argFlags[i]; } auto ret = Ctx.MakeType(returnType, args, optionalCount, Ctx.AppendString(payload)); YQL_ENSURE(ret->Validate(TPosition(), Ctx)); return ret; } TMaybe LoadVariantType(TType underlyingType, ui32 /*level*/) { auto ret = Ctx.MakeType(underlyingType); YQL_ENSURE(ret->Validate(TPosition(), Ctx)); return ret; } void Error(const TString& info) { Ctx.AddError(TIssue(Pos, info)); } }; const TTypeAnnotationNode* ParseTypeFromYson(const TStringBuf yson, TExprContext& ctx, const TPosition& pos) { NYT::TNode node; TStringStream err; if (!ParseYson(node, yson, err)) { ctx.AddError(TIssue(pos, err.Str())); return nullptr; } return ParseTypeFromYson(node, ctx, pos); } const TTypeAnnotationNode* ParseOrderAwareTypeFromYson(const TStringBuf yson, TColumnOrder& topLevelColumns, TExprContext& ctx, const TPosition& pos) { NYT::TNode node; TStringStream err; if (!ParseYson(node, yson, err)) { ctx.AddError(TIssue(pos, err.Str())); return nullptr; } return ParseOrderAwareTypeFromYson(node, topLevelColumns, ctx, pos); } const TTypeAnnotationNode* ParseTypeFromYson(const NYT::TNode& node, TExprContext& ctx, const TPosition& pos) { TExprTypeLoader loader(ctx, pos); return DoLoadTypeFromYson(loader, node, 0).GetOrElse(nullptr); } struct TOrderAwareExprTypeLoader: public TExprTypeLoader { typedef const TTypeAnnotationNode* TType; TColumnOrder& TopLevelColumns; TOrderAwareExprTypeLoader(TExprContext& ctx, const TPosition& pos, TColumnOrder& topLevelColumns) : TExprTypeLoader(ctx, pos) , TopLevelColumns(topLevelColumns) { TopLevelColumns.Clear(); } TMaybe LoadStructType(const TVector>& members, ui32 level) { if (level == 0) { YQL_ENSURE(TopLevelColumns.Size() == 0); for (auto& [column, type] : members) { TopLevelColumns.AddColumn(column); } } return TExprTypeLoader::LoadStructType(members, level); } }; const TTypeAnnotationNode* ParseOrderAwareTypeFromYson(const NYT::TNode& node, TColumnOrder& topLevelColumns, TExprContext& ctx, const TPosition& pos) { TOrderAwareExprTypeLoader loader(ctx, pos, topLevelColumns); return DoLoadTypeFromYson(loader, node, 0).GetOrElse(nullptr); } void WriteResOrPullType(NYson::TYsonConsumerBase& writer, const TTypeAnnotationNode* type, const TColumnOrder& columns) { if (columns.Size() == 0 || type->GetKind() != ETypeAnnotationKind::List || type->Cast()->GetItemType()->GetKind() != ETypeAnnotationKind::Struct) { WriteTypeToYson(writer, type, true); } else { writer.OnBeginList(); writer.OnListItem(); writer.OnStringScalar("ListType"); writer.OnListItem(); SaveStructTypeToYsonWithLogicalNames(writer, type->Cast()->GetItemType()->Cast(), columns, {}, true); writer.OnEndList(); } } } // namespace NCommon } // namespace NYql