summaryrefslogtreecommitdiffstats
path: root/yql/essentials/minikql/jsonpath/jsonpath.cpp
diff options
context:
space:
mode:
authorvvvv <[email protected]>2024-11-06 23:54:28 +0300
committervvvv <[email protected]>2024-11-07 00:04:25 +0300
commitcf2a23963ac10add28c50cc114fbf48953eca5aa (patch)
tree174b849b8ecfa96b0c8e4409ab3287721a9210c8 /yql/essentials/minikql/jsonpath/jsonpath.cpp
parent3a3113a2bf5a7fab32bde414932082b264c559fc (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.cpp129
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;
+}
+
+}