1
0
Fork 0
mirror of https://github.com/dragonflydb/dragonfly.git synced 2024-12-14 11:58:02 +00:00

feat: jsonpath supports index/wildcard expressions (#2578)

Signed-off-by: Roman Gershman <roman@dragonflydb.io>
This commit is contained in:
Roman Gershman 2024-02-12 20:38:05 +02:00 committed by GitHub
parent 21e725774c
commit 4afe278487
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 79 additions and 56 deletions

View file

@ -20,7 +20,7 @@ Driver::~Driver() {
void Driver::SetInput(string str) {
cur_str_ = std::move(str);
lexer_->in(cur_str_);
path_.Clear();
path_.clear();
}
void Driver::ResetScanner() {

View file

@ -6,7 +6,8 @@
#include <memory>
#include <string>
#include <vector>
#include "src/core/json/path.h"
namespace dfly {
namespace json {
@ -14,54 +15,6 @@ namespace json {
class Lexer;
class location; // from jsonpath_grammar.hh
enum class SegmentType {
IDENTIFIER = 1, // $.identifier
INDEX = 2, // $.array[0]
WILDCARD = 3, // $.array[*] or $.*
};
class PathSegment {
public:
PathSegment(SegmentType type, std::string identifier = std::string())
: type_(type), identifier_(std::move(identifier)) {
}
SegmentType type() const {
return type_;
}
const std::string& identifier() const {
return identifier_;
}
private:
SegmentType type_;
std::string identifier_;
int index_;
};
class Path {
public:
void AddSegment(PathSegment segment) {
segments_.push_back(std::move(segment));
}
size_t size() const {
return segments_.size();
}
const PathSegment& operator[](size_t i) const {
return segments_[i];
}
void Clear() {
segments_.clear();
}
private:
std::vector<PathSegment> segments_;
};
class Driver {
public:
Driver();
@ -76,7 +29,15 @@ class Driver {
virtual void Error(const location& l, const std::string& msg) = 0;
void AddIdentifier(const std::string& identifier) {
path_.AddSegment(PathSegment(SegmentType::IDENTIFIER, identifier));
AddSegment(PathSegment(SegmentType::IDENTIFIER, identifier));
}
void AddWildcard() {
AddSegment(PathSegment(SegmentType::WILDCARD));
}
void AddSegment(PathSegment segment) {
path_.push_back(std::move(segment));
}
Path TakePath() {

View file

@ -12,6 +12,7 @@
// Added to header file before parser declaration.
%code requires {
#include "src/core/json/path.h"
namespace dfly {
namespace json {
class Driver;
@ -56,6 +57,8 @@ using namespace std;
%token <unsigned> UINT "integer"
%nterm <std::string> identifier
%nterm <PathSegment> bracket_expr index_expr
%%
// Based on the following specification:
@ -67,19 +70,19 @@ opt_relative_location:
| relative_location
relative_location: DOT relative_path
| LBRACKET bracket_expr RBRACKET
| LBRACKET bracket_expr RBRACKET { driver->AddSegment($2); }
relative_path: identifier { driver->AddIdentifier($1); } opt_relative_location
| WILDCARD opt_relative_location
| WILDCARD { driver->AddWildcard(); } opt_relative_location
identifier: UNQ_STR
// | single_quoted_string | double_quoted_string
bracket_expr: WILDCARD
| index_expr
bracket_expr: WILDCARD { $$ = PathSegment{SegmentType::WILDCARD}; }
| index_expr { $$ = $1; }
index_expr: UINT
index_expr: UINT { $$ = PathSegment(SegmentType::INDEX, $1); }
%%

View file

@ -119,6 +119,15 @@ TEST_F(JsonPathTest, Parser) {
EXPECT_THAT(path[1], SegType(SegmentType::IDENTIFIER));
EXPECT_EQ("foo", path[0].identifier());
EXPECT_EQ("bar", path[1].identifier());
EXPECT_EQ(0, Parse("$.*.bar[1]"));
path = driver_.TakePath();
ASSERT_EQ(3, path.size());
EXPECT_THAT(path[0], SegType(SegmentType::WILDCARD));
EXPECT_THAT(path[1], SegType(SegmentType::IDENTIFIER));
EXPECT_THAT(path[2], SegType(SegmentType::INDEX));
EXPECT_EQ("bar", path[1].identifier());
EXPECT_EQ(1, path[2].index());
}
} // namespace dfly::json

50
src/core/json/path.h Normal file
View file

@ -0,0 +1,50 @@
// Copyright 2024, DragonflyDB authors. All rights reserved.
// See LICENSE for licensing terms.
//
#pragma once
#include <string>
#include <variant>
#include <vector>
namespace dfly::json {
enum class SegmentType {
IDENTIFIER = 1, // $.identifier
INDEX = 2, // $.array[0]
WILDCARD = 3, // $.array[*] or $.*
};
class PathSegment {
public:
PathSegment() : PathSegment(SegmentType::IDENTIFIER) {
}
PathSegment(SegmentType type, std::string identifier = std::string())
: type_(type), value_(std::move(identifier)) {
}
PathSegment(SegmentType type, unsigned index) : type_(type), value_(index) {
}
SegmentType type() const {
return type_;
}
const std::string& identifier() const {
return std::get<std::string>(value_);
}
unsigned index() const {
return std::get<unsigned>(value_);
}
private:
SegmentType type_;
std::variant<std::string, unsigned> value_;
};
using Path = std::vector<PathSegment>;
} // namespace dfly::json