Skip to content

Commit c150dd0

Browse files
author
Bogdan Degtyariov
committed
wl10981: added addOrReplace() method
1 parent d55b348 commit c150dd0

File tree

4 files changed

+93
-22
lines changed

4 files changed

+93
-22
lines changed

devapi/collection_crud.cc

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,15 @@ class Op_collection_add
8585
std::vector<mysqlx::GUID> m_id_list;
8686
bool m_generated_id;
8787
unsigned m_pos;
88+
bool m_upsert = false;
8889

8990

90-
Op_collection_add(Collection &coll)
91+
Op_collection_add(Collection &coll, bool upsert = false)
9192
: Op_base(coll)
9293
, m_coll(coll)
9394
, m_generated_id(true)
9495
, m_pos(0)
96+
, m_upsert(upsert)
9597
{}
9698

9799
Executable_impl* clone() const override
@@ -116,7 +118,8 @@ class Op_collection_add
116118
// Issue coll_add statement where documents are described by list
117119
// of expressions defined by this instance.
118120

119-
return new cdk::Reply(get_cdk_session().coll_add(m_coll, *this, NULL));
121+
return new cdk::Reply(get_cdk_session()
122+
.coll_add(m_coll, *this, NULL, m_upsert));
120123
}
121124

122125

@@ -214,6 +217,7 @@ class Op_collection_add
214217

215218

216219
friend mysqlx::CollectionAdd;
220+
friend mysqlx::internal::CollectionReplace;
217221
};
218222

219223

@@ -664,26 +668,46 @@ CollectionModify::CollectionModify(
664668

665669
internal::CollectionReplace::CollectionReplace(Collection &coll,
666670
const mysqlx::string &id,
667-
mysqlx::internal::ExprValue &&val)
671+
mysqlx::internal::ExprValue &&val,
672+
bool upsert)
668673
{
669674
try
670675
{
671-
reset(new Op_collection_modify(coll, "_id = :id"));
672-
673-
if (val.isExpression() || val.getType() != Value::STRING)
676+
if (upsert)
674677
{
675-
get_impl()->add_operation(Op_collection_modify::SET,
676-
"$",
677-
std::move(val));
678+
Op_collection_add *add_impl = new Op_collection_add(coll, upsert);
679+
reset(add_impl);
680+
string str = val;
681+
str.erase(str.rfind('}'));
682+
683+
std::stringstream sstream;
684+
// If ':' is present in the string the document is not empty
685+
if (str.find(':'))
686+
sstream << ", ";
687+
// It is safe to append the _id at the end
688+
sstream << "\"_id\": \"" << id << "\"}";
689+
str.append((string)sstream.str());
690+
add_impl->add_json(str);
678691
}
679692
else
680693
{
681-
get_impl()->add_operation(Op_collection_modify::SET,
682-
"$",
683-
internal::expr(std::move(val)));
694+
reset(new Op_collection_modify(coll, "_id = :id"));
695+
696+
if (val.isExpression() || val.getType() != Value::STRING)
697+
{
698+
get_impl()->add_operation(Op_collection_modify::SET,
699+
"$",
700+
std::move(val));
701+
}
702+
else
703+
{
704+
get_impl()->add_operation(Op_collection_modify::SET,
705+
"$",
706+
internal::expr(std::move(val)));
707+
}
708+
709+
get_impl()->add_param("id", id);
684710
}
685-
686-
get_impl()->add_param("id", id);
687711
}
688712
CATCH_AND_WRAP
689713
}

devapi/tests/crud-t.cc

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2209,7 +2209,7 @@ TEST_F(Crud, single_document)
22092209
{
22102210
SKIP_IF_NO_XPLUGIN;
22112211

2212-
SKIP_IF_SERVER_VERSION_LESS(8, 0, 2);
2212+
SKIP_IF_SERVER_VERSION_LESS(8, 0, 3);
22132213

22142214
cout << "Creating session..." << endl;
22152215

@@ -2241,7 +2241,7 @@ TEST_F(Crud, single_document)
22412241

22422242
// Ignore _id field on document and replace existing docment
22432243
// Document passed as string
2244-
EXPECT_EQ(1, coll.replaceOne("id3", "{\"_id\": \"id4\", \"name\": \"baz\" }"));
2244+
EXPECT_TRUE(coll.replaceOne("id3", "{\"_id\": \"id4\", \"name\": \"baz\" }"));
22452245
EXPECT_EQ(string("baz"), coll.getOne("id3")["name"].get<string>());
22462246
EXPECT_EQ(string("id3"), coll.getOne("id3")["_id"].get<string>());
22472247

@@ -2255,4 +2255,33 @@ TEST_F(Crud, single_document)
22552255
EXPECT_EQ(string("quux"), coll.getOne("id3")["name"].get<string>());
22562256
}
22572257

2258+
TEST_F(Crud, add_or_replace)
2259+
{
2260+
SKIP_IF_NO_XPLUGIN;
2261+
SKIP_IF_SERVER_VERSION_LESS(8, 0, 3)
2262+
2263+
cout << "Creating session..." << endl;
2264+
2265+
Session sess(this);
2266+
2267+
cout << "Session accepted, creating collection..." << endl;
2268+
2269+
Schema sch = sess.getSchema("test");
2270+
sess.dropCollection("test", "c1");
2271+
Collection coll = sch.createCollection("c1", true);
2272+
2273+
coll.add("{\"_id\":\"id1\", \"name\":\"foo\" }")
2274+
.add("{\"_id\":\"id2\", \"name\":\"bar\" }")
2275+
.add("{\"_id\":\"id3\", \"name\":\"baz\" }")
2276+
.execute();
2277+
2278+
EXPECT_TRUE(coll.addOrReplace("id4", "{\"name\":\"zaz\"}"));
2279+
// Check that the document was added
2280+
EXPECT_EQ(string("zaz"), coll.getOne("id4")["name"].get<string>());
2281+
2282+
EXPECT_FALSE(coll.addOrReplace("id4", "{\"name\":\"zzz\"}"));
2283+
// Check that the document was replaced
2284+
EXPECT_EQ(string("zzz"), coll.getOne("id4")["name"].get<string>());
2285+
2286+
}
22582287

include/devapi/collection_crud.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,8 @@ class PUBLIC_API CollectionReplace
429429
*/
430430
CollectionReplace(Collection &base,
431431
const string &id,
432-
internal::ExprValue &&val);
432+
internal::ExprValue &&val,
433+
bool upsert = false);
433434

434435
CollectionReplace(const internal::Collection_replace_cmd &other)
435436
{

include/mysql_devapi.h

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,12 @@ class PUBLIC_API Collection
420420
}
421421

422422
/**
423-
Returns an operation which, when executed, replaces document with given id
424-
in the collection with new document doc. Parameter doc can be either DbDoc
425-
object, or JSON string, or expr(docexpr) where docexpr is like JSON string
426-
but field values are expressions. It is possible to bind values of named
427-
parameters with .bind() before executing the statement.
423+
Replaces the document identified by id if it exists and returns true.
424+
Otherwise false is returned. Parameter document can be either DbDoc object,
425+
or JSON string, or expr(docexpr) where docexpr is like JSON
426+
string but field values are expressions.
427+
It is not possible to bind values of named parameters with .bind()
428+
because the statement gets executed upon calling of this function.
428429
*/
429430

430431
bool replaceOne(string id, internal::ExprValue &&document)
@@ -433,6 +434,22 @@ class PUBLIC_API Collection
433434
internal::CollectionReplace(*this, id, std::move(document)).execute().getAffectedItemsCount() == 1;
434435
}
435436

437+
/**
438+
Adds a new document and returns true if a document identified
439+
by id does not exist. Otherwise an existing document is
440+
replaced and false is returned.
441+
Parameter document can be either DbDoc object,
442+
or JSON string, or expr(docexpr) where docexpr is like JSON
443+
string but field values are expressions.
444+
It is not possible to bind values of named parameters with .bind()
445+
because the statement gets executed upon calling of this function.
446+
*/
447+
448+
bool addOrReplace(string id, internal::ExprValue &&document)
449+
{
450+
return internal::CollectionReplace(*this, id, std::move(document), true).execute().getAffectedItemsCount() == 1;
451+
}
452+
436453
};
437454

438455

0 commit comments

Comments
 (0)