Skip to content

Commit 2b05744

Browse files
committed
chore: preparations for adding flat json support
1. More test fixes to support both types 2. Adjust Aggregation functions to work with both types 3. jsonpath_test build from both types and passes for JsonType, the tests are skipped for flexbuffers Signed-off-by: Roman Gershman <[email protected]>
1 parent 2d246ad commit 2b05744

File tree

5 files changed

+348
-60
lines changed

5 files changed

+348
-60
lines changed

src/core/json/detail/flat_dfs.cc

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,105 @@ auto FlatDfsItem::Init(const PathSegment& segment) -> AdvanceResult {
2121
}
2222

2323
auto FlatDfsItem::Advance(const PathSegment& segment) -> AdvanceResult {
24-
return AdvanceResult{};
24+
if (state_ == kInit) {
25+
return Init(segment);
26+
}
27+
28+
if (!ShouldIterateAll(segment.type()))
29+
return Exhausted();
30+
31+
++state_;
32+
auto vec = obj().AsVector();
33+
if (state_ >= vec.size())
34+
return Exhausted();
35+
return Next(vec[state_]);
2536
}
2637

2738
FlatDfs FlatDfs::Traverse(absl::Span<const PathSegment> path, const flexbuffers::Reference root,
2839
const PathFlatCallback& callback) {
2940
DCHECK(!path.empty());
3041
FlatDfs dfs;
3142

43+
if (path.size() == 1) {
44+
dfs.PerformStep(path[0], root, callback);
45+
return dfs;
46+
}
47+
48+
using ConstItem = FlatDfsItem;
49+
vector<ConstItem> stack;
50+
stack.emplace_back(root);
51+
52+
do {
53+
unsigned segment_index = stack.back().segment_idx();
54+
const auto& path_segment = path[segment_index];
55+
56+
// init or advance the current object
57+
ConstItem::AdvanceResult res = stack.back().Advance(path_segment);
58+
if (res && !res->first.IsNull()) {
59+
const flexbuffers::Reference next = res->first;
60+
DVLOG(2) << "Handling now " << next.GetType() << " " << next.ToString();
61+
62+
// We descent only if next is object or an array.
63+
if (IsRecursive(next.GetType())) {
64+
unsigned next_seg_id = res->second;
65+
66+
if (next_seg_id + 1 < path.size()) {
67+
stack.emplace_back(next, next_seg_id);
68+
} else {
69+
// terminal step
70+
// TODO: to take into account MatchStatus
71+
// for `json.set foo $.a[10]` or for `json.set foo $.*.b`
72+
dfs.PerformStep(path[next_seg_id], next, callback);
73+
}
74+
}
75+
} else {
76+
stack.pop_back();
77+
}
78+
} while (!stack.empty());
79+
3280
return dfs;
3381
}
3482

3583
auto FlatDfs::PerformStep(const PathSegment& segment, const flexbuffers::Reference node,
3684
const PathFlatCallback& callback) -> nonstd::expected<void, MatchStatus> {
85+
switch (segment.type()) {
86+
case SegmentType::IDENTIFIER: {
87+
if (!node.IsMap())
88+
return make_unexpected(MISMATCH);
89+
auto map = node.AsMap();
90+
flexbuffers::Reference value = map[segment.identifier().c_str()];
91+
if (!value.IsNull()) {
92+
DoCall(callback, string_view{segment.identifier()}, value);
93+
}
94+
} break;
95+
case SegmentType::INDEX: {
96+
if (!node.IsVector())
97+
return make_unexpected(MISMATCH);
98+
auto vec = node.AsVector();
99+
if (segment.index() >= vec.size()) {
100+
return make_unexpected(OUT_OF_BOUNDS);
101+
}
102+
DoCall(callback, nullopt, vec[segment.index()]);
103+
} break;
104+
105+
case SegmentType::DESCENT:
106+
case SegmentType::WILDCARD: {
107+
auto vec = node.AsVector(); // always succeeds
108+
auto keys = node.AsMap().Keys(); // always succeeds
109+
string str;
110+
for (size_t i = 0; i < vec.size(); ++i) {
111+
flexbuffers::Reference key = keys[i];
112+
optional<string_view> opt_key;
113+
if (key.IsString()) {
114+
str = key.ToString();
115+
opt_key = str;
116+
}
117+
DoCall(callback, opt_key, vec[i]);
118+
}
119+
} break;
120+
default:
121+
LOG(DFATAL) << "Unknown segment " << SegmentName(segment.type());
122+
}
37123
return {};
38124
}
39125

src/core/json/driver.cc

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,8 @@ namespace dfly::json {
1717
namespace {
1818

1919
class SingleValueImpl : public AggFunction {
20-
JsonType GetResultImpl() const final {
21-
return visit(Overloaded{
22-
[](monostate) { return JsonType::null(); },
23-
[](double d) { return JsonType(d); },
24-
[](int64_t i) { return JsonType(i); },
25-
},
26-
val_);
20+
Result GetResultImpl() const final {
21+
return val_;
2722
}
2823

2924
protected:
@@ -35,7 +30,15 @@ class SingleValueImpl : public AggFunction {
3530
}
3631
}
3732

38-
variant<monostate, double, int64_t> val_;
33+
void Init(const flexbuffers::Reference src) {
34+
if (src.IsFloat()) {
35+
val_.emplace<double>(src.AsDouble());
36+
} else {
37+
val_.emplace<int64_t>(src.AsInt64());
38+
}
39+
}
40+
41+
Result val_;
3942
};
4043

4144
class MaxImpl : public SingleValueImpl {
@@ -58,6 +61,25 @@ class MaxImpl : public SingleValueImpl {
5861

5962
return true;
6063
}
64+
65+
bool ApplyImpl(flexbuffers::Reference src) final {
66+
if (!src.IsNumeric()) {
67+
return false;
68+
}
69+
70+
visit(Overloaded{
71+
[&](monostate) { Init(src); },
72+
[&](double d) { val_ = max(d, src.AsDouble()); },
73+
[&](int64_t i) {
74+
if (src.IsFloat())
75+
val_ = max(double(i), src.AsDouble());
76+
else
77+
val_ = max(i, src.AsInt64());
78+
},
79+
},
80+
val_);
81+
return true;
82+
}
6183
};
6284

6385
class MinImpl : public SingleValueImpl {
@@ -81,6 +103,25 @@ class MinImpl : public SingleValueImpl {
81103

82104
return true;
83105
}
106+
107+
bool ApplyImpl(flexbuffers::Reference src) final {
108+
if (!src.IsNumeric()) {
109+
return false;
110+
}
111+
112+
visit(Overloaded{
113+
[&](monostate) { Init(src); },
114+
[&](double d) { val_ = min(d, src.AsDouble()); },
115+
[&](int64_t i) {
116+
if (src.IsFloat())
117+
val_ = min(double(i), src.AsDouble());
118+
else
119+
val_ = min(i, src.AsInt64());
120+
},
121+
},
122+
val_);
123+
return true;
124+
}
84125
};
85126

86127
class AvgImpl : public AggFunction {
@@ -95,9 +136,19 @@ class AvgImpl : public AggFunction {
95136
return true;
96137
}
97138

98-
JsonType GetResultImpl() const final {
139+
bool ApplyImpl(flexbuffers::Reference src) final {
140+
if (!src.IsNumeric()) {
141+
return false;
142+
}
143+
sum_ += src.AsDouble();
144+
count_++;
145+
146+
return true;
147+
}
148+
149+
Result GetResultImpl() const final {
99150
DCHECK_GT(count_, 0u); // AggFunction guarantees that
100-
return JsonType(sum_ / count_);
151+
return Result(double(sum_ / count_));
101152
}
102153

103154
double sum_ = 0;

0 commit comments

Comments
 (0)