Skip to content

Commit 9d3252e

Browse files
committed
MYCPP-373: Single Document methods implementation
1 parent d6bbd9e commit 9d3252e

File tree

6 files changed

+180
-2
lines changed

6 files changed

+180
-2
lines changed

devapi/collection_crud.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,14 @@ class Op_collection_modify
545545
add_where(expr);
546546
}
547547

548+
Op_collection_modify(const Op_collection_modify &other)
549+
: Op_select(other)
550+
, m_coll(other.m_coll)
551+
, m_update(other.m_update)
552+
{
553+
m_update_it = m_update.end();
554+
}
555+
548556
Executable_impl* clone() const override
549557
{
550558
return new Op_collection_modify(*this);
@@ -639,6 +647,7 @@ class Op_collection_modify
639647
}
640648

641649
friend mysqlx::CollectionModify;
650+
friend mysqlx::CollectionReplace;
642651
};
643652

644653

@@ -652,3 +661,28 @@ CollectionModify::CollectionModify(
652661
}
653662
CATCH_AND_WRAP
654663
}
664+
665+
CollectionReplace::CollectionReplace(Collection &coll, const mysqlx::string &id
666+
, mysqlx::internal::ExprValue &&val)
667+
{
668+
try
669+
{
670+
reset(new Op_collection_modify(coll, "_id = :id"));
671+
672+
if (val.isExpression() || val.getType() != Value::STRING)
673+
{
674+
get_impl()->add_operation(Op_collection_modify::SET,
675+
"$",
676+
std::move(val));
677+
}
678+
else
679+
{
680+
get_impl()->add_operation(Op_collection_modify::SET,
681+
"$",
682+
internal::expr(std::move(val)));
683+
}
684+
685+
get_impl()->add_param("id", id);
686+
}
687+
CATCH_AND_WRAP
688+
}

devapi/tests/crud-t.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,3 +2204,59 @@ TEST_F(Crud, expr_in_expr)
22042204
EXPECT_EQ( string("baz") , (string)tbl_res.fetchOne()[0]);
22052205

22062206
}
2207+
2208+
TEST_F(Crud, single_document)
2209+
{
2210+
SKIP_IF_NO_XPLUGIN;
2211+
2212+
cout << "Creating session..." << endl;
2213+
2214+
Session sess(this);
2215+
2216+
cout << "Session accepted, creating collection..." << endl;
2217+
2218+
Schema sch = sess.getSchema("test");
2219+
sess.dropCollection("test", "c1");
2220+
Collection coll = sch.createCollection("c1", true);
2221+
2222+
coll.add("{\"_id\":\"id1\", \"name\":\"foo\" }" )
2223+
.add("{\"_id\":\"id2\", \"name\":\"bar\" }" )
2224+
.add("{\"_id\":\"id3\", \"name\":\"baz\" }" )
2225+
.execute();
2226+
2227+
EXPECT_EQ(string("foo"), coll.getOne("id1")["name"].get<string>());
2228+
EXPECT_EQ(string("bar"), coll.getOne("id2")["name"].get<string>());
2229+
EXPECT_TRUE(coll.getOne("idZ").isNull());
2230+
2231+
EXPECT_EQ(1, coll.removeOne("id1").getAffectedItemsCount());
2232+
EXPECT_EQ(0, coll.removeOne("id1").getAffectedItemsCount());
2233+
2234+
EXPECT_TRUE(coll.getOne("id1").isNull());
2235+
2236+
// Replace existing document
2237+
CollectionReplace replace = coll.replaceOne("id3", expr("{\"name\": :name }"))
2238+
.bind("name", "qux");
2239+
EXPECT_EQ(1, replace.execute().getAffectedItemsCount()
2240+
);
2241+
EXPECT_EQ(string("qux"), coll.getOne("id3")["name"].get<string>());
2242+
2243+
// Ignore _id field on document and replace existing docment
2244+
// Document passed as string
2245+
replace = coll.replaceOne("id3", "{\"_id\": \"id4\", \"name\": \"baz\" }");
2246+
EXPECT_EQ(1, replace.execute().getAffectedItemsCount());
2247+
EXPECT_EQ(string("baz"), coll.getOne("id3")["name"].get<string>());
2248+
EXPECT_EQ(string("id3"), coll.getOne("id3")["_id"].get<string>());
2249+
2250+
// should not affect none
2251+
replace = coll.replaceOne("id4", expr("{\"_id\":\"id4\", \"name\": :name }"));
2252+
EXPECT_EQ(0, replace.bind("name", "baz").execute().getAffectedItemsCount());
2253+
2254+
// Using DbDoc
2255+
DbDoc doc("{\"_id\":\"id4\", \"name\": \"quux\" }");
2256+
2257+
replace = coll.replaceOne("id3", doc);
2258+
EXPECT_EQ(1, replace.execute().getAffectedItemsCount());
2259+
EXPECT_EQ(string("quux"), coll.getOne("id3")["name"].get<string>());
2260+
}
2261+
2262+

devapi/tests/first-t.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,14 @@ TEST_F(First, api)
232232
CollectionModify modify2 = x;
233233
}
234234

235+
{
236+
CollectionReplace replace = c.replaceOne("...", "...");
237+
replace = replace.bind("...", 0);
238+
auto x = replace.bind("...", 0);
239+
CollectionReplace replace1 = replace;
240+
CollectionReplace replace2 = x;
241+
}
242+
235243
// Test copy semantics for table operations
236244

237245
{

include/devapi/collection_crud.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ DLL_WARNINGS_POP
393393
*/
394394

395395
class CollectionModify;
396+
class CollectionReplace;
396397

397398
namespace internal {
398399

@@ -404,6 +405,14 @@ struct Collection_modify_base
404405
: public Sort< Limit< Bind_parameters< Collection_modify_cmd > > >
405406
{};
406407

408+
struct Collection_replace_cmd
409+
: public Executable<Result, CollectionReplace>
410+
{};
411+
412+
struct Collection_replace_base
413+
: public Bind_parameters< Collection_replace_cmd >
414+
{};
415+
407416
} // internal namespace
408417

409418

@@ -528,6 +537,45 @@ class PUBLIC_API CollectionModify
528537
};
529538

530539

540+
/**
541+
Operation which replaces a document, using the id by a new one
542+
543+
@ingroup devapi_op
544+
*/
545+
546+
class PUBLIC_API CollectionReplace
547+
: public internal::Collection_replace_base
548+
{
549+
550+
public:
551+
552+
/**
553+
Create operation which replaces document with specified _id in a collection.
554+
*/
555+
CollectionReplace(Collection &base,
556+
const string &id,
557+
internal::ExprValue &&val);
558+
559+
CollectionReplace(const internal::Collection_replace_cmd &other)
560+
{
561+
internal::Collection_replace_cmd::operator=(other);
562+
}
563+
564+
CollectionReplace(internal::Collection_replace_cmd &&other)
565+
{
566+
internal::Collection_replace_cmd::operator=(std::move(other));
567+
}
568+
569+
protected:
570+
571+
using Impl = internal::Collection_modify_impl;
572+
573+
Impl* get_impl()
574+
{
575+
return static_cast<Impl*>(internal::Collection_replace_base::get_impl());
576+
}
577+
};
578+
531579
} // mysqlx namespace
532580

533581
#endif

include/devapi/document.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ class PUBLIC_API Value : public internal::Printable
405405
operator DbDoc() const;
406406

407407
template<typename T>
408-
T get() { return static_cast<T>(*this); }
408+
T get() const { return static_cast<T>(*this); }
409409

410410
//@}
411411

@@ -605,7 +605,7 @@ internal::ExprValue expr(V s)
605605
{
606606
internal::ExprValue val(s);
607607
val.m_is_expr = true;
608-
return std::move(val);
608+
return val;
609609
}
610610

611611
} // internal

include/mysql_devapi.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,38 @@ class PUBLIC_API Collection
400400
CATCH_AND_WRAP;
401401
}
402402

403+
/**
404+
Returns Document with the giver id.
405+
Returns empty document if not found.
406+
*/
407+
408+
DbDoc getOne(const string &id)
409+
{
410+
return find("_id = :id").bind("id", id).execute().fetchOne();
411+
}
412+
413+
/**
414+
Removes the document with the given id.
415+
*/
416+
417+
Result removeOne(const string &id)
418+
{
419+
return remove("_id = :id").bind("id", id).execute();
420+
}
421+
422+
/**
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.
428+
*/
429+
430+
CollectionReplace replaceOne(string id, internal::ExprValue &&document)
431+
{
432+
return CollectionReplace(*this, id, std::move(document));
433+
}
434+
403435
};
404436

405437

0 commit comments

Comments
 (0)