diff options
| author | vvvv <[email protected]> | 2024-11-06 23:54:28 +0300 |
|---|---|---|
| committer | vvvv <[email protected]> | 2024-11-07 00:04:25 +0300 |
| commit | cf2a23963ac10add28c50cc114fbf48953eca5aa (patch) | |
| tree | 174b849b8ecfa96b0c8e4409ab3287721a9210c8 /yql/essentials/minikql/jsonpath/jsonpath.cpp | |
| parent | 3a3113a2bf5a7fab32bde414932082b264c559fc (diff) | |
Prepare move yql/minikql YQL-19206
types,jsonpath,dom
commit_hash:6b54be5968b6a30b6d97fe3a1611574bcefc749e
Diffstat (limited to 'yql/essentials/minikql/jsonpath/jsonpath.cpp')
| -rw-r--r-- | yql/essentials/minikql/jsonpath/jsonpath.cpp | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/yql/essentials/minikql/jsonpath/jsonpath.cpp b/yql/essentials/minikql/jsonpath/jsonpath.cpp new file mode 100644 index 00000000000..c48bb08cf1a --- /dev/null +++ b/yql/essentials/minikql/jsonpath/jsonpath.cpp @@ -0,0 +1,129 @@ +#include "jsonpath.h" + +#include "binary.h" +#include "ast_builder.h" +#include "executor.h" +#include "type_check.h" +#include "value.h" + +#include <yql/essentials/core/issue/protos/issue_id.pb.h> +#include <yql/essentials/parser/proto_ast/gen/jsonpath/JsonPathLexer.h> +#include <yql/essentials/parser/proto_ast/gen/jsonpath/JsonPathParser.h> +#include <yql/essentials/parser/proto_ast/gen/jsonpath/JsonPathParser.pb.h> +#include <yql/essentials/parser/proto_ast/antlr3/proto_ast_antlr3.h> + +#include <google/protobuf/message.h> + +#include <util/string/strip.h> + +#if defined(_tsan_enabled_) +#include <util/system/mutex.h> +#endif + +using namespace NYql; +using namespace NYql::NUdf; +using namespace NJson; + +namespace { + +#if defined(_tsan_enabled_) +TMutex SanitizerJsonPathTranslationMutex; +#endif + +class TParseErrorsCollector : public NProtoAST::IErrorCollector { +public: + TParseErrorsCollector(TIssues& issues, size_t maxErrors) + : IErrorCollector(maxErrors) + , Issues(issues) + { + } + +private: + void AddError(ui32 line, ui32 column, const TString& message) override { + Issues.AddIssue(TPosition(column, line, "jsonpath"), StripString(message)); + Issues.back().SetCode(TIssuesIds::JSONPATH_PARSE_ERROR, TSeverityIds::S_ERROR); + } + + TIssues& Issues; +}; + +} + +namespace NYql::NJsonPath { + +const TAstNodePtr ParseJsonPathAst(const TStringBuf path, TIssues& issues, size_t maxParseErrors) { + if (!IsUtf(path)) { + issues.AddIssue(TPosition(1, 1, "jsonpath"), "JsonPath must be UTF-8 encoded string"); + issues.back().SetCode(TIssuesIds::JSONPATH_PARSE_ERROR, TSeverityIds::S_ERROR); + return {}; + } + + google::protobuf::Arena arena; + const google::protobuf::Message* rawAst = nullptr; + { + #if defined(_tsan_enabled_) + TGuard<TMutex> guard(SanitizerJsonPathTranslationMutex); + #endif + NProtoAST::TProtoASTBuilder3<NALP::JsonPathParser, NALP::JsonPathLexer> builder(path, "JsonPath", &arena); + TParseErrorsCollector collector(issues, maxParseErrors); + rawAst = builder.BuildAST(collector); + } + + if (rawAst == nullptr) { + return nullptr; + } + + const google::protobuf::Descriptor* descriptor = rawAst->GetDescriptor(); + if (descriptor && descriptor->name() != "TJsonPathParserAST") { + return nullptr; + } + + const auto* protoAst = static_cast<const NJsonPathGenerated::TJsonPathParserAST*>(rawAst); + TAstBuilder astBuilder(issues); + TAstNodePtr ast = astBuilder.Build(*protoAst); + if (!issues.Empty()) { + return nullptr; + } + + // At this point AST is guaranteed to be valid. We return it even if + // type checker finds some logical errors. + TJsonPathTypeChecker checker(issues); + ast->Accept(checker); + return ast; +} + +const TJsonPathPtr PackBinaryJsonPath(const TAstNodePtr ast) { + TJsonPathBuilder builder; + ast->Accept(builder); + return builder.ShrinkAndGetResult(); +} + +const TJsonPathPtr ParseJsonPath(const TStringBuf path, TIssues& issues, size_t maxParseErrors) { + const auto ast = ParseJsonPathAst(path, issues, maxParseErrors); + if (!issues.Empty()) { + return {}; + } + return PackBinaryJsonPath(ast); +} + +TResult ExecuteJsonPath( + const TJsonPathPtr jsonPath, + const TValue& json, + const TVariablesMap& variables, + const NUdf::IValueBuilder* valueBuilder) { + TExecutor executor(jsonPath, {json}, variables, valueBuilder); + return executor.Execute(); +} + +TVariablesMap DictToVariables(const NUdf::TUnboxedValue& dict) { + TVariablesMap variables; + TUnboxedValue key; + TUnboxedValue payload; + auto it = dict.GetDictIterator(); + while (it.NextPair(key, payload)) { + variables[key.AsStringRef()] = TValue(payload); + } + return variables; +} + +} |
