Skip to content

Commit 35abb2f

Browse files
committed
Merge branch 'refs/heads/wl11205'
2 parents 80c7195 + bd371f3 commit 35abb2f

File tree

10 files changed

+280
-6
lines changed

10 files changed

+280
-6
lines changed

common/op_impl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,6 +2080,10 @@ class Op_collection_modify
20802080
case Impl::ARRAY_DELETE:
20812081
prc.remove(&doc_field);
20822082
break;
2083+
2084+
case Impl::MERGE_PATCH:
2085+
m_update_it->process_if(prc.patch());
2086+
break;
20832087
}
20842088
}
20852089

devapi/tests/crud-t.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,3 +2335,52 @@ TEST_F(Crud, add_or_replace)
23352335
cout << "Done!" << endl;
23362336

23372337
}
2338+
2339+
TEST_F(Crud, merge_patch)
2340+
{
2341+
SKIP_IF_NO_XPLUGIN;
2342+
SKIP_IF_SERVER_VERSION_LESS(8, 0, 3)
2343+
2344+
cout << "Creating collection..." << endl;
2345+
2346+
Schema sch = getSchema("test");
2347+
Collection coll = sch.createCollection("c1", true);
2348+
2349+
coll.remove("true").execute();
2350+
2351+
add_data(coll);
2352+
2353+
coll.modify("true").patch(R"(
2354+
{
2355+
"age" : null,
2356+
"birth" : { "year": year(CURDATE())-age }
2357+
}
2358+
)").execute();
2359+
2360+
auto res = coll.find().execute();
2361+
for (auto row : res)
2362+
{
2363+
EXPECT_FALSE(row.hasField("age"));
2364+
std::cout << row["birth"]["year"] << std::endl;
2365+
}
2366+
2367+
coll.modify("true")
2368+
.patch(R"(
2369+
{
2370+
"food":["Falcoaria"],
2371+
"fullname": concat("Silva", ', ', name)
2372+
}
2373+
)")
2374+
.execute();
2375+
2376+
res = coll.find().execute();
2377+
for (auto doc : res)
2378+
{
2379+
EXPECT_EQ(string("Falcoaria"), doc["food"][0].get<string>());
2380+
EXPECT_THROW(doc["food"][1], std::out_of_range);
2381+
std::cout << doc["fullname"] << std::endl;
2382+
string fullname = string("Silva, ") + doc["name"].get<string>();
2383+
EXPECT_EQ(fullname, doc["fullname"].get<string>());
2384+
}
2385+
2386+
}

include/mysqlx/common/op_if.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@ struct Collection_modify_if : public Select_if<Sort_if>
249249
UNSET,
250250
ARRAY_INSERT,
251251
ARRAY_APPEND,
252-
ARRAY_DELETE
252+
ARRAY_DELETE,
253+
MERGE_PATCH
253254
};
254255

255256
virtual void add_operation(Operation, const string&, const Value&) = 0;

include/mysqlx/devapi/collection_crud.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,35 @@ class CollectionModify
554554
CATCH_AND_WRAP
555555
}
556556

557+
/**
558+
Apply JSON Patch to a target JSON document.
559+
560+
The JSON Patch format is defined by
561+
<a href=https://tools.ietf.org/html/rfc7386>RFC7386</a>.
562+
563+
A document patch is similar to a JSON object, with the key difference that
564+
document field values can be nested expressions in addition to literal
565+
values.
566+
567+
The patch contains instructions of how the source document is to be modified
568+
producing a derived document. By default, all fields from the source
569+
document are copied to the resulting document. If patch sets a field to NULL,
570+
the field of that name in the source is skipped from the result, identifiers
571+
and function calls are evaluated against the original source document.
572+
573+
*/
574+
575+
CollectionModify& patch(const string &val)
576+
{
577+
try {
578+
get_impl()->add_operation(
579+
Impl::MERGE_PATCH, L"$", (const common::Value&)expr(val)
580+
);
581+
return *this;
582+
}
583+
CATCH_AND_WRAP
584+
}
585+
557586
protected:
558587

559588
using Impl = common::Collection_modify_if;

include/mysqlx/devapi/document.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ class Field
8282
Field(const char *s) : m_fld(s)
8383
{}
8484

85+
Field()
86+
{}
87+
8588
operator const string&() const { return m_fld; }
8689

8790
bool operator <(const Field &other) const
@@ -597,7 +600,15 @@ class Expression
597600
set_as_expr();
598601
}
599602

603+
template <typename V>
604+
Expression(const V& val)
605+
: Value(val)
606+
{
607+
set_as_expr();
608+
}
609+
600610
friend Expression expr(string&& s);
611+
friend Expression expr(const string& s);
601612
};
602613

603614

@@ -626,6 +637,12 @@ mysqlx::internal::Expression expr(string&& e)
626637
return std::forward<string>(e);
627638
}
628639

640+
inline
641+
mysqlx::internal::Expression expr(const string& e)
642+
{
643+
return e;
644+
}
645+
629646
} // internal
630647

631648

include/mysqlx/xapi.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ typedef object_id* MYSQLX_GUID;
179179
#define MYSQLX_ERROR_AUTH_METHOD "Unknown authentication method"
180180
#define MYSQLX_ERROR_ROW_LOCKING "Row locking is supported only for SELECT and FIND"
181181
#define MYSQLX_ERROR_WRONG_LOCKING_MODE "Wrong value for the row locking mode"
182+
#define MYSQLX_ERROR_WRONG_EXPRESSION "Expression could not be parsed"
182183
#define MYSQLX_ERROR_EMPTY_JSON "Empty JSON document string"
183184

184185

@@ -1126,6 +1127,46 @@ mysqlx_collection_modify_unset(mysqlx_collection_t *collection,
11261127
const char *criteria, ...);
11271128

11281129

1130+
/**
1131+
Apply a given patch to documents in a collection.
1132+
1133+
@param collection collection handle
1134+
@param criteria criteria selecting documents to be modified; if this
1135+
parameter is NULL then all documents are modified
1136+
@param patch_spec patch specification given as a character string and
1137+
interpreted like a JSON documents, but values of fields are
1138+
interpreted as expressions
1139+
1140+
@return handle to the statement result.
1141+
NULL is returned only in case of an error. The error details
1142+
can be obtained using `mysqlx_error()` function
1143+
1144+
@ingroup xapi_coll
1145+
*/
1146+
1147+
PUBLIC_API mysqlx_result_t *
1148+
mysqlx_collection_modify_patch(mysqlx_collection_t *collection,
1149+
const char *criteria,
1150+
const char *patch_spec);
1151+
1152+
1153+
/**
1154+
Set a given patch for a modify statement to be applied to
1155+
documents in a collection after executing the statement.
1156+
1157+
@param stmt modify statement
1158+
@param patch_spec patch specification given as a character string and
1159+
interpreted like a JSON documents, but values of fields are
1160+
interpreted as expressions
1161+
1162+
@return `RESULT_OK` - on success; `RESULT_ERR` - on error
1163+
@ingroup xapi_coll
1164+
*/
1165+
1166+
PUBLIC_API int
1167+
mysqlx_set_modify_patch(mysqlx_stmt_t *stmt,
1168+
const char *patch_spec);
1169+
11291170
/*
11301171
Deferred statement execution
11311172
----------------------------

xapi/crud.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ int mysqlx_stmt_struct::add_coll_modify_values(va_list &args, mysqlx_modify_op m
309309
case MODIFY_ARRAY_INSERT: op = MImpl::ARRAY_INSERT; break;
310310
case MODIFY_ARRAY_APPEND: op = MImpl::ARRAY_APPEND; break;
311311
case MODIFY_ARRAY_DELETE: op = MImpl::ARRAY_DELETE; break;
312+
case MODIFY_MERGE_PATCH: op = MImpl::MERGE_PATCH; break;
312313
}
313314

314315
int rc = RESULT_ERROR;
@@ -324,6 +325,16 @@ int mysqlx_stmt_struct::add_coll_modify_values(va_list &args, mysqlx_modify_op m
324325
impl->add_operation(op, path);
325326
continue;
326327
}
328+
else if (modify_type == MODIFY_MERGE_PATCH)
329+
{
330+
/*
331+
Note: in this case path contains the patch to be applied, which should
332+
be trated as an expression, not a literal string.
333+
*/
334+
impl->add_operation(op, L"$", Value::Access::mk_expr(path));
335+
// For merge only one item is expected
336+
return RESULT_OK;
337+
}
327338

328339
impl->add_operation(op, path, get_value(args));
329340
}

xapi/def_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ typedef enum mysqlx_modify_op_enum
8181
MODIFY_UNSET = 2,
8282
MODIFY_ARRAY_INSERT = 3,
8383
MODIFY_ARRAY_APPEND = 4,
84-
MODIFY_ARRAY_DELETE = 5
84+
MODIFY_ARRAY_DELETE = 5,
85+
MODIFY_MERGE_PATCH = 6
8586
} mysqlx_modify_op;
8687

8788
#endif

xapi/mysqlx.cc

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ int STDCALL mysqlx_set_modify_set(mysqlx_stmt_struct *stmt, ...)
585585
}
586586

587587

588-
int STDCALL STDCALL mysqlx_set_modify_unset(mysqlx_stmt_struct *stmt, ...)
588+
int STDCALL mysqlx_set_modify_unset(mysqlx_stmt_struct *stmt, ...)
589589
{
590590
SAFE_EXCEPTION_BEGIN(stmt, RESULT_ERROR)
591591

@@ -602,7 +602,7 @@ int STDCALL STDCALL mysqlx_set_modify_unset(mysqlx_stmt_struct *stmt, ...)
602602
}
603603

604604

605-
int STDCALL STDCALL mysqlx_set_modify_array_insert(mysqlx_stmt_struct *stmt, ...)
605+
int STDCALL mysqlx_set_modify_array_insert(mysqlx_stmt_struct *stmt, ...)
606606
{
607607
SAFE_EXCEPTION_BEGIN(stmt, RESULT_ERROR)
608608

@@ -619,7 +619,7 @@ int STDCALL STDCALL mysqlx_set_modify_array_insert(mysqlx_stmt_struct *stmt, ...
619619
}
620620

621621

622-
int STDCALL STDCALL mysqlx_set_modify_array_append(mysqlx_stmt_struct *stmt, ...)
622+
int STDCALL mysqlx_set_modify_array_append(mysqlx_stmt_struct *stmt, ...)
623623
{
624624
SAFE_EXCEPTION_BEGIN(stmt, RESULT_ERROR)
625625

@@ -636,7 +636,7 @@ int STDCALL STDCALL mysqlx_set_modify_array_append(mysqlx_stmt_struct *stmt, ...
636636
}
637637

638638

639-
int STDCALL STDCALL mysqlx_set_modify_array_delete(mysqlx_stmt_struct *stmt, ...)
639+
int STDCALL mysqlx_set_modify_array_delete(mysqlx_stmt_struct *stmt, ...)
640640
{
641641
SAFE_EXCEPTION_BEGIN(stmt, RESULT_ERROR)
642642

@@ -653,6 +653,29 @@ int STDCALL STDCALL mysqlx_set_modify_array_delete(mysqlx_stmt_struct *stmt, ...
653653
}
654654

655655

656+
static int
657+
_mysqlx_set_modify_patch(mysqlx_stmt_struct *stmt, ...)
658+
{
659+
int res = RESULT_OK;
660+
va_list args;
661+
SAFE_EXCEPTION_BEGIN(stmt, RESULT_ERROR)
662+
663+
va_start(args, stmt);
664+
res = stmt->add_coll_modify_values(args, MODIFY_MERGE_PATCH);
665+
va_end(args);
666+
667+
SAFE_EXCEPTION_END(stmt, RESULT_ERROR)
668+
return res;
669+
}
670+
671+
int STDCALL
672+
mysqlx_set_modify_patch(mysqlx_stmt_struct *stmt,
673+
const char *patch_spec)
674+
{
675+
return _mysqlx_set_modify_patch(stmt, patch_spec);
676+
}
677+
678+
656679
/*
657680
Fetch one row from the result and advance to the next row
658681
PARAMETERS:
@@ -1446,10 +1469,12 @@ mysqlx_collection_modify_set(mysqlx_collection_struct *collection,
14461469
{
14471470
mysqlx_result_struct *res;
14481471
va_list args;
1472+
SAFE_EXCEPTION_BEGIN(collection, NULL)
14491473
va_start(args, criteria);
14501474
res = _mysqlx_collection_modify_exec(collection, criteria, MODIFY_SET, args);
14511475
va_end(args);
14521476
return res;
1477+
SAFE_EXCEPTION_END(collection, NULL)
14531478
}
14541479

14551480

@@ -1459,10 +1484,38 @@ mysqlx_collection_modify_unset(mysqlx_collection_struct *collection,
14591484
{
14601485
mysqlx_result_struct *res;
14611486
va_list args;
1487+
SAFE_EXCEPTION_BEGIN(collection, NULL)
1488+
14621489
va_start(args, criteria);
14631490
res = _mysqlx_collection_modify_exec(collection, criteria, MODIFY_UNSET, args);
14641491
va_end(args);
14651492
return res;
1493+
SAFE_EXCEPTION_END(collection, NULL)
1494+
}
1495+
1496+
static mysqlx_result_t *
1497+
_mysqlx_collection_modify_patch(mysqlx_collection_t *collection,
1498+
const char *criteria, ...)
1499+
{
1500+
mysqlx_result_t *res;
1501+
va_list args;
1502+
SAFE_EXCEPTION_BEGIN(collection, NULL)
1503+
1504+
va_start(args, criteria);
1505+
res = _mysqlx_collection_modify_exec(collection, criteria,
1506+
MODIFY_MERGE_PATCH, args);
1507+
va_end(args);
1508+
return res;
1509+
SAFE_EXCEPTION_END(collection, NULL)
1510+
}
1511+
1512+
mysqlx_result_t * STDCALL
1513+
mysqlx_collection_modify_patch(mysqlx_collection_t *collection,
1514+
const char *criteria,
1515+
const char *patch_spec)
1516+
{
1517+
return _mysqlx_collection_modify_patch(collection, criteria,
1518+
patch_spec);
14661519
}
14671520

14681521

0 commit comments

Comments
 (0)