Separate star from ranges for better code

This commit is contained in:
l1tsolaiki 2021-06-18 01:37:59 +03:00
parent 0c2d0b55a4
commit e2765991b0
9 changed files with 163 additions and 79 deletions

View File

@ -0,0 +1,15 @@
#pragma once
#include <Parsers/IAST.h>
namespace DB
{
class ASTJSONPathStar : public IAST
{
public:
String getID(char) const override { return "ASTJSONPathStar"; }
ASTPtr clone() const override { return std::make_shared<ASTJSONPathStar>(*this); }
};
}

View File

@ -4,6 +4,7 @@
#include <Functions/JSONPath/Generators/VisitorJSONPathMemberAccess.h> #include <Functions/JSONPath/Generators/VisitorJSONPathMemberAccess.h>
#include <Functions/JSONPath/Generators/VisitorJSONPathRange.h> #include <Functions/JSONPath/Generators/VisitorJSONPathRange.h>
#include <Functions/JSONPath/Generators/VisitorJSONPathRoot.h> #include <Functions/JSONPath/Generators/VisitorJSONPathRoot.h>
#include <Functions/JSONPath/Generators/VisitorJSONPathStar.h>
#include <Functions/JSONPath/Generators/VisitorStatus.h> #include <Functions/JSONPath/Generators/VisitorStatus.h>
#include <Functions/JSONPath/ASTs/ASTJSONPath.h> #include <Functions/JSONPath/ASTs/ASTJSONPath.h>
@ -36,7 +37,8 @@ public:
for (auto child_ast : query->children) for (auto child_ast : query->children)
{ {
if (typeid_cast<ASTJSONPathRoot *>(child_ast.get())) { if (typeid_cast<ASTJSONPathRoot *>(child_ast.get()))
{
visitors.push_back(std::make_shared<VisitorJSONPathRoot<JSONParser>>(child_ast)); visitors.push_back(std::make_shared<VisitorJSONPathRoot<JSONParser>>(child_ast));
} }
else if (typeid_cast<ASTJSONPathMemberAccess *>(child_ast.get())) else if (typeid_cast<ASTJSONPathMemberAccess *>(child_ast.get()))
@ -47,6 +49,10 @@ public:
{ {
visitors.push_back(std::make_shared<VisitorJSONPathRange<JSONParser>>(child_ast)); visitors.push_back(std::make_shared<VisitorJSONPathRange<JSONParser>>(child_ast));
} }
else if (typeid_cast<ASTJSONPathStar *>(child_ast.get()))
{
visitors.push_back(std::make_shared<VisitorJSONPathStar<JSONParser>>(child_ast));
}
} }
} }

View File

@ -10,15 +10,15 @@ template <typename JSONParser>
class VisitorJSONPathMemberAccess : public IVisitor<JSONParser> class VisitorJSONPathMemberAccess : public IVisitor<JSONParser>
{ {
public: public:
VisitorJSONPathMemberAccess(ASTPtr member_access_ptr_) : member_access_ptr(member_access_ptr_) { } VisitorJSONPathMemberAccess(ASTPtr member_access_ptr_)
: member_access_ptr(member_access_ptr_->as<ASTJSONPathMemberAccess>()) { }
const char * getName() const override { return "VisitorJSONPathMemberAccess"; } const char * getName() const override { return "VisitorJSONPathMemberAccess"; }
VisitorStatus apply(typename JSONParser::Element & element) const override VisitorStatus apply(typename JSONParser::Element & element) const override
{ {
const auto * member_access = member_access_ptr->as<ASTJSONPathMemberAccess>();
typename JSONParser::Element result; typename JSONParser::Element result;
element.getObject().find(std::string_view(member_access->member_name), result); element.getObject().find(std::string_view(member_access_ptr->member_name), result);
element = result; element = result;
return VisitorStatus::Ok; return VisitorStatus::Ok;
} }
@ -30,9 +30,8 @@ public:
this->setExhausted(true); this->setExhausted(true);
return VisitorStatus::Error; return VisitorStatus::Error;
} }
const auto * member_access = member_access_ptr->as<ASTJSONPathMemberAccess>();
typename JSONParser::Element result; typename JSONParser::Element result;
if (!element.getObject().find(std::string_view(member_access->member_name), result)) if (!element.getObject().find(std::string_view(member_access_ptr->member_name), result))
{ {
this->setExhausted(true); this->setExhausted(true);
return VisitorStatus::Error; return VisitorStatus::Error;
@ -47,7 +46,7 @@ public:
void updateState() override { } void updateState() override { }
private: private:
ASTPtr member_access_ptr; ASTJSONPathMemberAccess * member_access_ptr;
}; };
} }

View File

@ -10,18 +10,10 @@ template <typename JSONParser>
class VisitorJSONPathRange : public IVisitor<JSONParser> class VisitorJSONPathRange : public IVisitor<JSONParser>
{ {
public: public:
VisitorJSONPathRange(ASTPtr range_ptr_) : range_ptr(range_ptr_) VisitorJSONPathRange(ASTPtr range_ptr_) : range_ptr(range_ptr_->as<ASTJSONPathRange>())
{ {
const auto * range = range_ptr->as<ASTJSONPathRange>();
current_range = 0; current_range = 0;
if (range->is_star) current_index = range_ptr->ranges[current_range].first;
{
current_index = 0;
}
else
{
current_index = range->ranges[current_range].first;
}
} }
const char * getName() const override { return "VisitorJSONPathRange"; } const char * getName() const override { return "VisitorJSONPathRange"; }
@ -30,12 +22,7 @@ public:
{ {
typename JSONParser::Element result; typename JSONParser::Element result;
typename JSONParser::Array array = element.getArray(); typename JSONParser::Array array = element.getArray();
if (current_index >= array.size()) element = array[current_index];
{
return VisitorStatus::Error;
}
result = array[current_index];
element = result;
return VisitorStatus::Ok; return VisitorStatus::Ok;
} }
@ -47,32 +34,21 @@ public:
return VisitorStatus::Error; return VisitorStatus::Error;
} }
const auto * range = range_ptr->as<ASTJSONPathRange>();
VisitorStatus status; VisitorStatus status;
if (current_index < element.getArray().size()) if (current_index < element.getArray().size())
{ {
apply(element); apply(element);
status = VisitorStatus::Ok; status = VisitorStatus::Ok;
} }
else if (!range->is_star)
{
status = VisitorStatus::Ignore;
}
else else
{ {
status = VisitorStatus::Ignore; status = VisitorStatus::Ignore;
this->setExhausted(true);
} }
if (!range->is_star) if (current_index + 1 == range_ptr->ranges[current_range].second
&& current_range + 1 == range_ptr->ranges.size())
{ {
if (current_index + 1 == range->ranges[current_range].second) this->setExhausted(true);
{
if (current_range + 1 == range->ranges.size())
{
this->setExhausted(true);
}
}
} }
return status; return status;
@ -80,36 +56,23 @@ public:
void reinitialize() override void reinitialize() override
{ {
const auto * range = range_ptr->as<ASTJSONPathRange>();
current_range = 0; current_range = 0;
if (range->is_star) current_index = range_ptr->ranges[current_range].first;
{
current_index = 0;
}
else
{
current_index = range->ranges[current_range].first;
}
this->setExhausted(false); this->setExhausted(false);
} }
void updateState() override void updateState() override
{ {
const auto * range = range_ptr->as<ASTJSONPathRange>();
current_index++; current_index++;
if (range->is_star) if (current_index == range_ptr->ranges[current_range].second)
{
return;
}
if (current_index == range->ranges[current_range].second)
{ {
current_range++; current_range++;
current_index = range->ranges[current_range].first; current_index = range_ptr->ranges[current_range].first;
} }
} }
private: private:
ASTPtr range_ptr; ASTJSONPathRange * range_ptr;
size_t current_range; size_t current_range;
UInt32 current_index; UInt32 current_index;
}; };

View File

@ -0,0 +1,66 @@
#pragma once
#include <Functions/JSONPath/ASTs/ASTJSONPathStar.h>
#include <Functions/JSONPath/Generators/IVisitor.h>
#include <Functions/JSONPath/Generators/VisitorStatus.h>
namespace DB
{
template <typename JSONParser>
class VisitorJSONPathStar : public IVisitor<JSONParser>
{
public:
VisitorJSONPathStar(ASTPtr)
{
current_index = 0;
}
const char * getName() const override { return "VisitorJSONPathStar"; }
VisitorStatus apply(typename JSONParser::Element & element) const override
{
typename JSONParser::Element result;
typename JSONParser::Array array = element.getArray();
element = array[current_index];
return VisitorStatus::Ok;
}
VisitorStatus visit(typename JSONParser::Element & element) override
{
if (!element.isArray())
{
this->setExhausted(true);
return VisitorStatus::Error;
}
VisitorStatus status;
if (current_index < element.getArray().size())
{
apply(element);
status = VisitorStatus::Ok;
}
else
{
status = VisitorStatus::Ignore;
this->setExhausted(true);
}
return status;
}
void reinitialize() override
{
current_index = 0;
this->setExhausted(false);
}
void updateState() override
{
current_index++;
}
private:
UInt32 current_index;
};
}

View File

@ -3,6 +3,7 @@
#include <Functions/JSONPath/Parsers/ParserJSONPathRoot.h> #include <Functions/JSONPath/Parsers/ParserJSONPathRoot.h>
#include <Functions/JSONPath/Parsers/ParserJSONPathMemberAccess.h> #include <Functions/JSONPath/Parsers/ParserJSONPathMemberAccess.h>
#include <Functions/JSONPath/Parsers/ParserJSONPathRange.h> #include <Functions/JSONPath/Parsers/ParserJSONPathRange.h>
#include <Functions/JSONPath/Parsers/ParserJSONPathStar.h>
namespace DB namespace DB
@ -19,17 +20,20 @@ bool ParserJSONPathQuery::parseImpl(Pos & pos, ASTPtr & query, Expected & expect
query = std::make_shared<ASTJSONPathQuery>(); query = std::make_shared<ASTJSONPathQuery>();
ParserJSONPathMemberAccess parser_jsonpath_member_access; ParserJSONPathMemberAccess parser_jsonpath_member_access;
ParserJSONPathRange parser_jsonpath_range; ParserJSONPathRange parser_jsonpath_range;
ParserJSONPathStar parser_jsonpath_star;
ParserJSONPathRoot parser_jsonpath_root; ParserJSONPathRoot parser_jsonpath_root;
ASTPtr path_root; ASTPtr path_root;
if (!parser_jsonpath_root.parse(pos, path_root, expected)) { if (!parser_jsonpath_root.parse(pos, path_root, expected))
{
return false; return false;
} }
query->children.push_back(path_root); query->children.push_back(path_root);
ASTPtr accessor; ASTPtr accessor;
while (parser_jsonpath_member_access.parse(pos, accessor, expected) while (parser_jsonpath_member_access.parse(pos, accessor, expected)
|| parser_jsonpath_range.parse(pos, accessor, expected)) || parser_jsonpath_range.parse(pos, accessor, expected)
|| parser_jsonpath_star.parse(pos, accessor, expected))
{ {
if (accessor) if (accessor)
{ {

View File

@ -5,6 +5,7 @@
#include <Parsers/ASTIdentifier.h> #include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/CommonParsers.h>
namespace DB namespace DB
{ {
@ -31,26 +32,16 @@ bool ParserJSONPathRange::parseImpl(Pos & pos, ASTPtr & node, Expected & expecte
auto range = std::make_shared<ASTJSONPathRange>(); auto range = std::make_shared<ASTJSONPathRange>();
node = range; node = range;
ParserNumber number_p;
ASTPtr number_ptr;
while (pos->type != TokenType::ClosingSquareBracket) while (pos->type != TokenType::ClosingSquareBracket)
{ {
if (pos->type != TokenType::Number && pos->type != TokenType::Asterisk) if (pos->type != TokenType::Number)
{ {
return false; return false;
} }
if (pos->type == TokenType::Asterisk)
{
if (range->is_star)
{
throw Exception("Multiple asterisks in square array range are not allowed", ErrorCodes::BAD_ARGUMENTS);
}
range->is_star = true;
++pos;
continue;
}
std::pair<UInt32, UInt32> range_indices; std::pair<UInt32, UInt32> range_indices;
ParserNumber number_p;
ASTPtr number_ptr;
if (!number_p.parse(pos, number_ptr, expected)) if (!number_p.parse(pos, number_ptr, expected))
{ {
return false; return false;
@ -64,16 +55,7 @@ bool ParserJSONPathRange::parseImpl(Pos & pos, ASTPtr & node, Expected & expecte
} }
else if (pos->type == TokenType::BareWord) else if (pos->type == TokenType::BareWord)
{ {
/// Range case if (!ParserKeyword("TO").ignore(pos, expected)) {
ParserIdentifier name_p;
ASTPtr word;
if (!name_p.parse(pos, word, expected))
{
return false;
}
String to_identifier;
if (!tryGetIdentifierNameInto(word, to_identifier) || to_identifier != "to")
{
return false; return false;
} }
if (!number_p.parse(pos, number_ptr, expected)) if (!number_p.parse(pos, number_ptr, expected))

View File

@ -0,0 +1,31 @@
#include <Functions/JSONPath/Parsers/ParserJSONPathStar.h>
#include <Functions/JSONPath/ASTs/ASTJSONPathStar.h>
namespace DB
{
bool ParserJSONPathStar::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
if (pos->type != TokenType::OpeningSquareBracket)
{
return false;
}
++pos;
if (pos->type != TokenType::Asterisk) {
return false;
}
++pos;
if (pos->type != TokenType::ClosingSquareBracket) {
expected.add(pos, "Closing square bracket");
return false;
}
++pos;
auto star = std::make_shared<ASTJSONPathStar>();
node = star;
return true;
}
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <Parsers/IParserBase.h>
namespace DB
{
class ParserJSONPathStar : public IParserBase
{
private:
const char * getName() const override { return "ParserJSONPathStar"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
public:
explicit ParserJSONPathStar() = default;
};
}