@@ -106,6 +106,53 @@ ParseResult<WrappedJsonPath> ParseJsonPath(std::string_view path) {
106
106
107
107
} // namespace json_parser
108
108
109
+ namespace reply_generic {
110
+
111
+ void Send (std::size_t value, RedisReplyBuilder* rb) {
112
+ rb->SendLong (value);
113
+ }
114
+
115
+ template <typename T> void Send (const std::optional<T>& opt, RedisReplyBuilder* rb) {
116
+ if (opt.has_value ()) {
117
+ Send (opt.value (), rb);
118
+ } else {
119
+ rb->SendNull ();
120
+ }
121
+ }
122
+
123
+ template <typename T> void Send (const std::vector<T>& vec, RedisReplyBuilder* rb) {
124
+ if (vec.empty ()) {
125
+ rb->SendNullArray ();
126
+ } else {
127
+ rb->StartArray (vec.size ());
128
+ for (auto && x : vec) {
129
+ Send (x, rb);
130
+ }
131
+ }
132
+ }
133
+
134
+ template <typename T> void Send (const JsonCallbackResult<T>& result, RedisReplyBuilder* rb) {
135
+ if (result.IsV1 ()) {
136
+ /* The specified path was restricted (JSON legacy mode), then the result consists only of a
137
+ * single value */
138
+ Send (result.AsV1 (), rb);
139
+ } else {
140
+ /* The specified path was enhanced (starts with '$'), then the result is an array of multiple
141
+ * values */
142
+ Send (result.AsV2 (), rb);
143
+ }
144
+ }
145
+
146
+ template <typename T> void Send (const OpResult<T>& result, RedisReplyBuilder* rb) {
147
+ if (result) {
148
+ Send (result.value (), rb);
149
+ } else {
150
+ rb->SendError (result.status ());
151
+ }
152
+ }
153
+
154
+ } // namespace reply_generic
155
+
109
156
using JsonPathV2 = variant<json::Path, JsonExpression>;
110
157
using ExprCallback = absl::FunctionRef<void (string_view, const JsonType&)>;
111
158
@@ -241,6 +288,35 @@ error_code JsonReplace(JsonType& instance, string_view path, json::MutateCallbac
241
288
return ec;
242
289
}
243
290
291
+ template <typename T>
292
+ OpResult<JsonCallbackResult<T>> UpdateEntry (const OpArgs& op_args, std::string_view key,
293
+ const WrappedJsonPath& json_path,
294
+ JsonPathMutateCallback<T> cb,
295
+ JsonReplaceVerify verify_op = {}) {
296
+ auto it_res = op_args.GetDbSlice ().FindMutable (op_args.db_cntx , key, OBJ_JSON);
297
+ RETURN_ON_BAD_STATUS (it_res);
298
+
299
+ PrimeValue& pv = it_res->it ->second ;
300
+
301
+ JsonType* json_val = pv.GetJson ();
302
+ DCHECK (json_val) << " should have a valid JSON object for key '" << key << " ' the type for it is '"
303
+ << pv.ObjType () << " '" ;
304
+
305
+ op_args.shard ->search_indices ()->RemoveDoc (key, op_args.db_cntx , pv);
306
+
307
+ auto mutate_res = json_path.Mutate (json_val, cb);
308
+
309
+ // Make sure that we don't have other internal issue with the operation
310
+ if (mutate_res && verify_op) {
311
+ verify_op (*json_val);
312
+ }
313
+
314
+ it_res->post_updater .Run ();
315
+ op_args.shard ->search_indices ()->AddDoc (key, op_args.db_cntx , pv);
316
+
317
+ return mutate_res;
318
+ }
319
+
244
320
// jsoncons version
245
321
OpStatus UpdateEntry (const OpArgs& op_args, std::string_view key, std::string_view path,
246
322
json::MutateCallback callback, JsonReplaceVerify verify_op = {}) {
@@ -837,37 +913,23 @@ OpResult<vector<StringVec>> OpObjKeys(const OpArgs& op_args, string_view key,
837
913
return vec;
838
914
}
839
915
840
- // Retruns array of string lengths after a successful operation.
841
- OpResult<vector<OptSizeT>> OpStrAppend (const OpArgs& op_args, string_view key, string_view path,
842
- JsonPathV2 expression, facade::ArgRange strs) {
843
- vector<OptSizeT> vec;
844
- OpStatus status;
845
- auto cb = [&](const auto &, JsonType* val) {
916
+ auto OpStrAppend (const OpArgs& op_args, string_view key, const WrappedJsonPath& path,
917
+ facade::ArgRange strs) {
918
+ auto cb = [&](const auto &, JsonType* val) -> MutateCallbackResult<std::optional<std::size_t >> {
846
919
if (val->is_string ()) {
847
920
string new_val = val->as_string ();
848
921
for (string_view str : strs) {
849
922
new_val += str;
850
923
}
851
924
852
925
*val = new_val;
853
- vec.emplace_back (new_val.size ());
854
- } else {
855
- vec.emplace_back (nullopt);
926
+ return {false , new_val.size ()};
856
927
}
857
- return false ;
858
- };
859
- if (holds_alternative<json::Path>(expression)) {
860
- const json::Path& json_path = std::get<json::Path>(expression);
861
- status = UpdateEntry (op_args, key, json_path, cb);
862
- } else {
863
- status = UpdateEntry (op_args, key, path, cb);
864
- }
865
928
866
- if (status != OpStatus::OK) {
867
- return status;
868
- }
929
+ return {false , std::nullopt};
930
+ };
869
931
870
- return vec ;
932
+ return UpdateEntry<std::optional<std:: size_t >>(op_args, key, path, std::move (cb)) ;
871
933
}
872
934
873
935
// Returns the numbers of values cleared.
@@ -1891,22 +1953,17 @@ void JsonFamily::StrAppend(CmdArgList args, ConnectionContext* cntx) {
1891
1953
string_view key = ArgS (args, 0 );
1892
1954
string_view path = ArgS (args, 1 );
1893
1955
1894
- JsonPathV2 expression = PARSE_PATHV2 ( path);
1956
+ WrappedJsonPath json_path = GET_OR_SEND_UNEXPECTED ( json_parser::ParseJsonPath ( path) );
1895
1957
auto strs = args.subspan (2 );
1896
1958
1897
1959
auto cb = [&](Transaction* t, EngineShard* shard) {
1898
- return OpStrAppend (t->GetOpArgs (shard), key, path, std::move (expression),
1899
- facade::ArgRange{strs});
1960
+ return OpStrAppend (t->GetOpArgs (shard), key, json_path, facade::ArgRange{strs});
1900
1961
};
1901
1962
1902
1963
Transaction* trans = cntx->transaction ;
1903
- OpResult<vector<OptSizeT>> result = trans->ScheduleSingleHopT (std::move (cb));
1904
-
1905
- if (result) {
1906
- PrintOptVec (cntx, result);
1907
- } else {
1908
- cntx->SendError (result.status ());
1909
- }
1964
+ auto result = trans->ScheduleSingleHopT (std::move (cb));
1965
+ auto * rb = static_cast <RedisReplyBuilder*>(cntx->reply_builder ());
1966
+ reply_generic::Send (result, rb);
1910
1967
}
1911
1968
1912
1969
void JsonFamily::ObjKeys (CmdArgList args, ConnectionContext* cntx) {
0 commit comments