Skip to content

Commit 31d9c01

Browse files
committed
WL13061: Add Schema Validation to create/modify collection.
1 parent 0986c4c commit 31d9c01

File tree

16 files changed

+1866
-43
lines changed

16 files changed

+1866
-43
lines changed

common/collection.cc

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,110 @@ void Op_idx_create::process(cdk::Any::Document::Processor &prc) const
344344

345345
prc.doc_end();
346346
}
347+
348+
/*
349+
Collection create/modify json options
350+
*/
351+
352+
353+
struct Collection_options_converter
354+
: public cdk::Converter< cdk::Doc_prc_converter<JSON_val_conv> >
355+
{
356+
typedef cdk::Converter< cdk::Doc_prc_converter<JSON_val_conv> > Base;
357+
358+
typedef typename Base::Prc_from Prc_from;
359+
typedef typename Base::Prc_to Prc_to;
360+
using Base::m_proc;
361+
362+
typedef cdk::Any_prc_converter<JSON_val_conv> Any_conv;
363+
typedef typename Prc_from::Any_prc Any_prc;
364+
365+
void doc_begin() { m_proc->doc_begin(); }
366+
void doc_end() { m_proc->doc_end(); }
367+
368+
Any_conv m_any_conv;
369+
370+
Any_prc* key_val(const string &key)
371+
{
372+
typename Prc_to::Any_prc *ap;
373+
if(key == "reuseExisting")
374+
{
375+
ap = m_proc->key_val("reuse_existing");
376+
}
377+
else {
378+
ap = m_proc->key_val(key);
379+
}
380+
381+
if (!ap)
382+
return NULL;
383+
m_any_conv.reset(*ap);
384+
return &m_any_conv;
385+
}
386+
387+
};
388+
389+
void Op_create_modify_base::process(cdk::Any::Document::Processor &prc) const
390+
{
391+
392+
prc.doc_begin();
393+
394+
for (auto it : m_map)
395+
{
396+
Value_scalar val(it.second);
397+
val.process_if(prc.key_val(it.first));
398+
}
399+
400+
if(!m_options.empty())
401+
{
402+
const parser::JSON_parser parser(m_options);
403+
Collection_options_converter conv;
404+
auto * options =
405+
m_validation_options ?
406+
prc.key_val("options")->doc()->key_val("validation")->doc()
407+
: prc.key_val("options")->doc();
408+
if(options)
409+
{
410+
conv.reset(*options);
411+
parser.process(conv);
412+
}
413+
prc.doc_end();
414+
return;
415+
}
416+
417+
if(!m_validation_level.empty() || !m_validation_schema.empty())
418+
{
419+
auto options =safe_prc(prc.key_val("options"))->doc();
420+
options->doc_begin();
421+
422+
if (!m_validation_level.empty() || !m_validation_schema.empty())
423+
{
424+
//validation
425+
auto validation = options->key_val("validation")->doc();
426+
validation->doc_begin();
427+
428+
if(!m_validation_level.empty())
429+
{
430+
validation->key_val("level")->scalar()->str(m_validation_level);
431+
}
432+
433+
if(!m_validation_schema.empty())
434+
{
435+
const parser::JSON_parser parser(m_validation_schema);
436+
cdk::Doc_prc_converter<JSON_val_conv> conv;
437+
auto schema = validation->key_val("schema")->doc();
438+
if(schema)
439+
{
440+
conv.reset(*schema);
441+
parser.process(conv);
442+
}
443+
}
444+
445+
validation->doc_end();
446+
}
447+
448+
options->doc_end();
449+
}
450+
prc.doc_end();
451+
return;
452+
453+
}

common/op_impl.h

Lines changed: 160 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,27 +1522,91 @@ struct Op_create<Object_type::SCHEMA>
15221522
{}
15231523
};
15241524

1525-
1526-
template<>
1527-
struct Op_create<Object_type::COLLECTION>
1528-
: public Op_admin
1525+
struct Op_create_modify_base
1526+
: public Op_admin
15291527
{
1530-
Op_create(
1531-
Shared_session_impl sess,
1532-
const cdk::api::Object_ref &coll,
1533-
bool reuse = true
1534-
)
1535-
: Op_admin(sess, "create_collection")
1528+
//TODO:
1529+
//Allow validation schema and m_options to be a document, not only a JSON string.
1530+
//Currently not possible because common layer does not have a document class
1531+
//like DbDoc.
1532+
std::string m_options;
1533+
std::string m_validation_level;
1534+
std::string m_validation_schema;
1535+
//If true, means m_options refers to validation json, not the full options
1536+
bool m_validation_options = false;
1537+
1538+
Op_create_modify_base(Shared_session_impl sess, const char *cmd,
1539+
const cdk::api::Object_ref &coll,
1540+
std::string level,
1541+
std::string validation_schema)
1542+
: Op_admin(sess, cmd)
1543+
, m_validation_level(std::move(level))
1544+
, m_validation_schema(std::move(validation_schema))
15361545
{
15371546
if (coll.schema())
15381547
add_param("schema", Value::Access::mk_str(coll.schema()->name()));
15391548
else
15401549
common::throw_error("No schema specified for create collection operation");
15411550
add_param("name", Value::Access::mk_str(coll.name()));
1551+
}
1552+
1553+
Op_create_modify_base(Shared_session_impl sess, const char *cmd,
1554+
const cdk::api::Object_ref &coll,
1555+
std::string json,
1556+
bool validation_json = false)
1557+
: Op_create_modify_base(sess, cmd, coll, std::string(),std::string() )
1558+
{
1559+
m_options = std::move(json);
1560+
m_validation_options = validation_json;
1561+
}
1562+
// cdk::Param_source
1563+
1564+
void process(cdk::Any::Document::Processor &prc) const override;
1565+
1566+
};
1567+
1568+
template<>
1569+
struct Op_create<Object_type::COLLECTION>
1570+
: public Op_create_modify_base
1571+
{
1572+
Op_create(
1573+
Shared_session_impl sess,
1574+
const cdk::api::Object_ref &coll,
1575+
bool reuse,
1576+
std::string validation_level,
1577+
std::string validation_schema
1578+
)
1579+
: Op_create_modify_base(sess, "create_collection", coll,
1580+
std::move(validation_level), std::move(validation_schema))
1581+
{
15421582
// 1050 = table already exists
15431583
if (reuse)
15441584
skip_error(cdk::server_error(1050));
15451585
}
1586+
1587+
Op_create(
1588+
Shared_session_impl sess,
1589+
const cdk::api::Object_ref &coll,
1590+
bool reuse,
1591+
std::string validation_json
1592+
)
1593+
: Op_create_modify_base(sess, "create_collection", coll,
1594+
std::move(validation_json), true)
1595+
{
1596+
// 1050 = table already exists
1597+
if (reuse)
1598+
skip_error(cdk::server_error(1050));
1599+
}
1600+
1601+
Op_create(
1602+
Shared_session_impl sess,
1603+
const cdk::api::Object_ref &coll,
1604+
std::string json,
1605+
bool validation_json = false
1606+
)
1607+
: Op_create_modify_base(sess, "create_collection", coll, std::move(json), validation_json)
1608+
{}
1609+
15461610
};
15471611

15481612

@@ -1557,9 +1621,92 @@ void create_object(
15571621
Shared_session_impl sess, Ty&&... args
15581622
)
15591623
{
1560-
Op_create<T> create(sess, std::forward<Ty>(args)...);
1561-
Result_impl res(create.execute());
1562-
res.next_result();
1624+
try{
1625+
Op_create<T> create(sess, std::forward<Ty>(args)...);
1626+
Result_impl res(create.execute());
1627+
res.next_result();
1628+
}
1629+
catch(const cdk::Error &err)
1630+
{
1631+
if(err.code().value() == 5015)
1632+
{ //Old server... doesn't support schema validation
1633+
common::throw_error(
1634+
"The server doesn't support the requested operation. " \
1635+
"Please update the MySQL Server and or Client library");
1636+
}
1637+
throw;
1638+
}
1639+
1640+
}
1641+
1642+
1643+
// ----------------------------------------------------------------------
1644+
1645+
/*
1646+
Operations which modify database objects.
1647+
1648+
They are implemented as Op_modify<> template parametrized by the type of the
1649+
object to modify.
1650+
*/
1651+
1652+
template <Object_type T>
1653+
struct Op_modify;
1654+
1655+
1656+
template<>
1657+
struct Op_modify<Object_type::COLLECTION>
1658+
: public Op_create_modify_base
1659+
{
1660+
1661+
Op_modify(
1662+
Shared_session_impl sess,
1663+
const cdk::api::Object_ref &coll,
1664+
std::string validation_level,
1665+
std::string validation_schema
1666+
) : Op_create_modify_base(sess, "modify_collection_options", coll,
1667+
std::move(validation_level),
1668+
std::move(validation_schema))
1669+
{}
1670+
1671+
Op_modify(
1672+
Shared_session_impl sess,
1673+
const cdk::api::Object_ref &coll,
1674+
std::string json,
1675+
bool validation_json = false
1676+
)
1677+
: Op_create_modify_base(sess, "modify_collection_options",
1678+
coll,
1679+
std::move(json), validation_json)
1680+
{}
1681+
1682+
};
1683+
1684+
/*
1685+
A helper function which constructs an operation that modifies a database object
1686+
and executes it.
1687+
*/
1688+
1689+
template <Object_type T, typename... Ty>
1690+
inline
1691+
void modify_object(
1692+
Shared_session_impl sess, Ty&&... args
1693+
)
1694+
{
1695+
try{
1696+
Op_modify<T> modify(sess, std::forward<Ty>(args)...);
1697+
Result_impl res(modify.execute());
1698+
res.next_result();
1699+
}
1700+
catch(const cdk::Error &err)
1701+
{
1702+
if(err.code().value() == 5157)
1703+
{ //Old server... doesn't support modify collection
1704+
common::throw_error(
1705+
"The server doesn't support the requested operation. " \
1706+
"Please update the MySQL Server and or Client library");
1707+
}
1708+
throw;
1709+
}
15631710
}
15641711

15651712

common/value.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,3 @@ const std::u16string& Value::get_ustring() const
185185
throw Error("Value cannot be converted to string");
186186
}
187187
}
188-

devapi/document.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ DbDoc::DbDoc(const std::shared_ptr<Impl> &impl)
7676

7777
const char* DbDoc::get_json() const
7878
{
79-
return m_impl ? m_impl->get_json() : nullptr;
79+
return m_impl ? m_impl->get_json() : "";
8080
}
8181

8282

0 commit comments

Comments
 (0)