drogon/orm_lib/tests/db_test.cc

1960 lines
63 KiB
C++

/**
*
* @file db_test.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
* Drogon database test program
*
*/
#define DROGON_TEST_MAIN
#include <drogon/config.h>
#include <drogon/orm/DbClient.h>
#include <drogon/orm/DbTypes.h>
#include <drogon/orm/CoroMapper.h>
#include <trantor/utils/Logger.h>
#include <drogon/drogon_test.h>
#include <drogon/HttpAppFramework.h>
#include <chrono>
#include <iostream>
#include <thread>
#include <stdlib.h>
#include "mysql/Users.h"
#include "postgresql/Users.h"
#include "sqlite3/Users.h"
using namespace std::chrono_literals;
using namespace drogon::orm;
void expFunction(const DrogonDbException &e)
{
}
#if USE_POSTGRESQL
DbClientPtr postgreClient;
DROGON_TEST(PostgreTest)
{
auto &clientPtr = postgreClient;
// Prepare the test environment
*clientPtr << "DROP TABLE IF EXISTS USERS" >> [TEST_CTX](const Result &r) {
SUCCESS();
clientPtr->execSqlAsync(
"select 1 as result",
[TEST_CTX](const drogon::orm::Result &r) {
MANDATE(r.size() == 1);
},
expFunction);
} >> [TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - Prepare the test environment(0) what():" +
std::string(e.base().what()));
};
*clientPtr << "CREATE TABLE users \
(\
user_id character varying(32),\
user_name character varying(64),\
password character varying(64),\
org_name character varying(20),\
signature character varying(50),\
avatar_id character varying(32),\
id serial PRIMARY KEY,\
salt character varying(20),\
admin boolean DEFAULT false,\
CONSTRAINT user_id_org UNIQUE(user_id, org_name)\
)" >>
[TEST_CTX](const Result &r) { SUCCESS(); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - Prepare the test environment(1) what():" +
std::string(e.base().what()));
};
/// Test1:DbClient streaming-type interface
/// 1.1 insert,non-blocking
*clientPtr << "insert into users (user_id,user_name,password,org_name) "
"values($1,$2,$3,$4) returning *"
<< "pg"
<< "postgresql"
<< "123"
<< "default" >>
[TEST_CTX](const Result &r) {
// std::cout << "id=" << r[0]["id"].as<int64_t>() << std::endl;
MANDATE(r[0]["id"].as<int64_t>() == 1);
} >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(0) what():" +
std::string(e.base().what()));
};
/// 1.2 insert,blocking
*clientPtr
<< "insert into users (user_id,user_name,admin,password,org_name) "
"values($1,$2,$3,$4,$5) returning *"
<< "pg1"
<< "postgresql1" << drogon::orm::DefaultValue{} << "123"
<< "default" << Mode::Blocking >>
[TEST_CTX](const Result &r) {
// std::cout << "id=" << r[0]["id"].as<int64_t>() << std::endl;
MANDATE(r[0]["id"].as<int64_t>() == 2);
} >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(1) what():" +
std::string(e.base().what()));
};
/// 1.3 query,no-blocking
*clientPtr << "select * from users where 1 = 1" << Mode::NonBlocking >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(2) what():" +
std::string(e.base().what()));
};
/// 1.4 query,blocking
*clientPtr << "select * from users where 1 = 1" << Mode::Blocking >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(3) what():" +
std::string(e.base().what()));
};
/// 1.5 query,blocking
int count = 0;
*clientPtr << "select user_name, user_id, id from users where 1 = 1"
<< Mode::Blocking >>
[&count, TEST_CTX](bool isNull,
const std::string &name,
std::string &&user_id,
int id) {
if (!isNull)
++count;
else
{
MANDATE(count == 2);
}
} >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(4) what():" +
std::string(e.base().what()));
};
/// 1.6 query, parameter binding
*clientPtr << "select * from users where id = $1" << 1 >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(5) what():" +
std::string(e.base().what()));
};
/// 1.7 query, parameter binding
*clientPtr << "select * from users where user_id = $1 and user_name = $2"
<< "pg1"
<< "postgresql1" >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(6) what():" +
std::string(e.base().what()));
};
/// 1.8 delete
*clientPtr << "delete from users where user_id = $1 and user_name = $2"
<< "pg1"
<< "postgresql1" >>
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(7) what():" +
std::string(e.base().what()));
};
/// 1.9 update
*clientPtr << "update users set user_id = $1, user_name = $2 where user_id "
"= $3 and user_name = $4"
<< "pg1"
<< "postgresql1"
<< "pg"
<< "postgresql" >>
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(8) what():" +
std::string(e.base().what()));
};
/// 1.10 clean up
*clientPtr << "truncate table users restart identity" >>
[TEST_CTX](const Result &r) { SUCCESS(); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient streaming-type interface(9) what():" +
std::string(e.base().what()));
};
/// Test asynchronous method
/// 2.1 insert
clientPtr->execSqlAsync(
"insert into users \
(user_id,user_name,password,org_name) \
values($1,$2,$3,$4) returning *",
[TEST_CTX](const Result &r) {
// std::cout << "id=" << r[0]["id"].as<int64_t>() << std::endl;
MANDATE(r[0]["id"].as<int64_t>() == 1);
},
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient asynchronous interface(0) what():" +
std::string(e.base().what()));
},
"pg",
"postgresql",
"123",
"default");
/// 2.2 insert
clientPtr->execSqlAsync(
"insert into users \
(user_id,user_name,password,org_name) \
values($1,$2,$3,$4)",
[TEST_CTX](const Result &r) {
// std::cout << "id=" << r[0]["id"].as<int64_t>() << std::endl;
MANDATE(r.affectedRows() == 1);
},
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient asynchronous interface(1) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1",
"123",
"default");
/// 2.3 query
clientPtr->execSqlAsync(
"select * from users where 1 = 1",
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient asynchronous interface(2) what():" +
std::string(e.base().what()));
});
/// 2.2 query, parameter binding
clientPtr->execSqlAsync(
"select * from users where id = $1",
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient asynchronous interface(3) what():" +
std::string(e.base().what()));
},
1);
/// 2.3 query, parameter binding
clientPtr->execSqlAsync(
"select * from users where user_id = $1 and user_name = $2",
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient asynchronous interface(4) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1");
/// 2.4 delete
clientPtr->execSqlAsync(
"delete from users where user_id = $1 and user_name = $2",
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient asynchronous interface(5) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1");
/// 2.5 update
clientPtr->execSqlAsync(
"update users set user_id = $1, user_name = $2 where user_id "
"= $3 and user_name = $4",
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient asynchronous interface(6) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1",
"pg",
"postgresql");
/// 2.6 clean up
clientPtr->execSqlAsync(
"truncate table users restart identity",
[TEST_CTX](const Result &r) { SUCCESS(); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - DbClient asynchronous interface(7) what():" +
std::string(e.base().what()));
});
/// Test synchronous method
/// 3.1 insert
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values($1,$2,$3,$4) returning *",
"pg",
"postgresql",
"123",
"default");
MANDATE(r[0]["id"].as<int64_t>() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient asynchronous interface(0) what():" +
std::string(e.base().what()));
}
/// 3.2 insert
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values($1,$2,$3,$4)",
"pg1",
"postgresql1",
"123",
"default");
MANDATE(r.affectedRows() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient asynchronous interface(1) what():" +
std::string(e.base().what()));
}
/// 3.3 query
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=$1 and user_name=$2",
"pg1",
"postgresql1");
MANDATE(r.size() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient asynchronous interface(2) what():" +
std::string(e.base().what()));
}
/// 3.4 query for none
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=$1 and user_name=$2",
"pg111",
"postgresql1");
MANDATE(r.size() == 0);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient asynchronous interface(3) what():" +
std::string(e.base().what()));
}
/// 3.5 bad sql
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=$1 and user_name='1234'",
"pg111",
"postgresql1");
MANDATE(r.size() == 0);
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// 3.6 clean up
try
{
auto r =
clientPtr->execSqlSync("truncate table users restart identity");
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient asynchronous interface(5) what():" +
std::string(e.base().what()));
}
/// Test future interface
/// 4.1 insert
auto f = clientPtr->execSqlAsyncFuture(
"insert into users (user_id,user_name,password,org_name) "
"values($1,$2,$3,$4) returning *",
"pg",
"postgresql",
"123",
"default");
try
{
auto r = f.get();
MANDATE(r[0]["id"].as<int64_t>() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient future interface(0) what():" +
std::string(e.base().what()));
}
/// 4.2 insert
f = clientPtr->execSqlAsyncFuture(
"insert into users (user_id,user_name,password,org_name) "
"values($1,$2,$3,$4)",
"pg1",
"postgresql1",
"123",
"default");
try
{
auto r = f.get();
MANDATE(r.affectedRows() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient future interface(1) what():" +
std::string(e.base().what()));
}
/// 4.3 query
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=$1 and user_name=$2",
"pg1",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient future interface(2) what():" +
std::string(e.base().what()));
}
/// 4.4 query for none
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=$1 and user_name=$2",
"pg111",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 0);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient future interface(3) what():" +
std::string(e.base().what()));
}
/// 4.5 bad sql
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=$1 and user_name='12'",
"pg111",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 0);
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// 4.6 clean up
f = clientPtr->execSqlAsyncFuture("truncate table users restart identity");
try
{
auto r = f.get();
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient future interface(5) what():" +
std::string(e.base().what()));
}
/// 5 Test Result and Row exception throwing
// 5.1 query for none and try to access
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=$1 and user_name=$2",
"pg111",
"postgresql1");
r.at(0);
FAULT("postgresql - Result throwing exceptions(0)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.2 insert one just for setup
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values($1,$2,$3,$4) returning *",
"pg",
"postgresql",
"123",
"default");
MANDATE(r[0]["id"].as<int64_t>() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - Row throwing exceptions(0) what():" +
std::string(e.base().what()));
}
// 5.3 try to access nonexistent column by name
try
{
auto r = clientPtr->execSqlSync("select * from users");
auto row = r.at(0);
row["imaginary_column"];
FAULT("postgresql - Row throwing exceptions(1)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.4 try to access nonexistent column by index
try
{
auto r = clientPtr->execSqlSync("select * from users");
auto row = r.at(0);
row.at(420);
FAULT("postgresql - Row throwing exceptions(2)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.5 cleanup
try
{
auto r =
clientPtr->execSqlSync("truncate table users restart identity");
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - Row throwing exceptions(3) what():" +
std::string(e.base().what()));
}
/// Test ORM mapper
/// 6.1 insert, noneblocking
using namespace drogon_model::postgres;
drogon::orm::Mapper<Users> mapper(clientPtr);
Users user;
user.setUserId("pg");
user.setUserName("postgres");
user.setPassword("123");
user.setOrgName("default");
mapper.insert(
user,
[TEST_CTX](Users ret) { MANDATE(ret.getPrimaryKey() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - ORM mapper asynchronous interface(0) what():" +
std::string(e.base().what()));
});
/// 6.1.5 insert future
user.setUserId("pg_future");
auto fu = mapper.insertFuture(user);
try
{
auto u = fu.get();
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT(
"postgresql - ORM mapper asynchronous future interface(0) what():" +
std::string(e.base().what()));
}
/// 6.2 insert
user.setUserId("pg1");
user.setUserName("postgres1");
mapper.insert(
user,
[TEST_CTX](Users ret) { MANDATE(ret.getPrimaryKey() == 3); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - ORM mapper asynchronous interface(1) what():" +
std::string(e.base().what()));
});
/// 6.3 select where in
mapper.findBy(
Criteria(Users::Cols::_id,
CompareOperator::In,
std::vector<int32_t>{2, 200}),
[TEST_CTX](std::vector<Users> users) { MANDATE(users.size() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - ORM mapper asynchronous interface(2) what():" +
std::string(e.base().what()));
});
/// 6.3.5 count
mapper.count(
drogon::orm::Criteria(Users::Cols::_id, CompareOperator::EQ, 2020),
[TEST_CTX](const size_t c) { MANDATE(c == 0); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("postgresql - ORM mapper asynchronous interface(3) what():" +
std::string(e.base().what()));
});
/// 6.4 find by primary key. blocking
try
{
auto user = mapper.findByPrimaryKey(2);
SUCCESS();
Users newUser;
newUser.setId(user.getValueOfId());
newUser.setSalt("xxx");
auto c = mapper.update(newUser);
MANDATE(c == 1);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - ORM mapper synchronous interface(0) what():" +
std::string(e.base().what()));
}
#ifdef __cpp_impl_coroutine
auto coro_test = [clientPtr, TEST_CTX]() -> drogon::Task<> {
/// 7 Test coroutines.
/// This is by no means comprehensive. But coroutine API is esentially a
/// wrapper arround callbacks. The purpose is to test the interface
/// works 7.1 Basic queries
try
{
auto result =
co_await clientPtr->execSqlCoro("select * from users;");
MANDATE(result.size() != 0);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient coroutine interface(0) what():" +
std::string(e.base().what()));
}
/// 7.2 Parameter binding
try
{
auto result = co_await clientPtr->execSqlCoro(
"select * from users where 1=$1;", 1);
MANDATE(result.size() != 0);
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - DbClient coroutine interface(1) what():" +
std::string(e.base().what()));
}
/// 7.3 CoroMapper
try
{
CoroMapper<Users> mapper(clientPtr);
auto user = co_await mapper.findByPrimaryKey(2);
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("postgresql - ORM mapper coroutine interface(0) what():" +
std::string(e.base().what()));
}
try
{
CoroMapper<Users> mapper(clientPtr);
auto user = co_await mapper.findByPrimaryKey(314);
FAULT("postgresql - ORM mapper coroutine interface(1)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
try
{
CoroMapper<Users> mapper(clientPtr);
auto users = co_await mapper.findAll();
auto count = co_await mapper.count();
MANDATE(users.size() == count);
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// 7.4 Transactions
try
{
auto trans = co_await clientPtr->newTransactionCoro();
auto result =
co_await trans->execSqlCoro("select * from users where 1=$1;",
1);
MANDATE(result.size() != 0);
}
catch (const DrogonDbException &e)
{
FAULT(
"postgresql - DbClient coroutine transaction interface(0) "
"what():" +
std::string(e.base().what()));
}
};
drogon::sync_wait(coro_test());
#endif
}
#endif
#if USE_MYSQL
DbClientPtr mysqlClient;
DROGON_TEST(MySQLTest)
{
auto &clientPtr = mysqlClient;
REQUIRE(clientPtr != nullptr);
// Prepare the test environment
*clientPtr << "CREATE DATABASE IF NOT EXISTS drogonTestMysql" >>
[TEST_CTX](const Result &r) {
SUCCESS();
clientPtr->execSqlAsync(
"select 1 as result",
[TEST_CTX](const drogon::orm::Result &r) {
MANDATE(r.size() == 1);
},
expFunction);
} >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - Prepare the test environment(0) what():" +
std::string(e.base().what()));
};
*clientPtr << "USE drogonTestMysql" >> [TEST_CTX](const Result &r) {
SUCCESS();
} >> [TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - Prepare the test environment(0) what():" +
std::string(e.base().what()));
};
// mysql is case sensitive
*clientPtr << "DROP TABLE IF EXISTS users" >> [TEST_CTX](const Result &r) {
SUCCESS();
} >> [TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - Prepare the test environment(1) what():" +
std::string(e.base().what()));
};
*clientPtr << "CREATE TABLE users \
(\
id int(11) auto_increment PRIMARY KEY,\
user_id varchar(32),\
user_name varchar(64),\
password varchar(64),\
org_name varchar(20),\
signature varchar(50),\
avatar_id varchar(32),\
salt character varying(20),\
admin boolean DEFAULT false,\
CONSTRAINT user_id_org UNIQUE(user_id, org_name)\
)" >>
[TEST_CTX](const Result &r) { SUCCESS(); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - Prepare the test environment(2) what():" +
std::string(e.base().what()));
};
/// Test1:DbClient streaming-type interface
/// 1.1 insert,non-blocking
*clientPtr
<< "insert into users (user_id,user_name,password,org_name,admin) "
"values(?,?,?,?,?)"
<< "pg"
<< "postgresql"
<< "123"
<< "default" << drogon::orm::DefaultValue{} >>
[TEST_CTX](const Result &r) { MANDATE(r.insertId() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(0) what():" +
std::string(e.base().what()));
};
/// 1.2 insert,blocking
*clientPtr << "insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)"
<< "pg1"
<< "postgresql1"
<< "123"
<< "default" << Mode::Blocking >>
[TEST_CTX](const Result &r) { MANDATE(r.insertId() == 2); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(1) what():" +
std::string(e.base().what()));
};
/// 1.3 query,no-blocking
*clientPtr << "select * from users where 1 = 1" << Mode::NonBlocking >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(2) what():" +
std::string(e.base().what()));
};
/// 1.4 query,blocking
*clientPtr << "select * from users where 1 = 1" << Mode::Blocking >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(3) what():" +
std::string(e.base().what()));
};
/// 1.5 query,blocking
int count = 0;
*clientPtr << "select user_name, user_id, id from users where 1 = 1"
<< Mode::Blocking >>
[&count, TEST_CTX](bool isNull,
const std::string &name,
std::string &&user_id,
int id) {
if (!isNull)
++count;
else
{
MANDATE(count == 2);
}
} >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(4) what():" +
std::string(e.base().what()));
};
/// 1.6 query, parameter binding
*clientPtr << "select * from users where id = ?" << 1 >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(5) what():" +
std::string(e.base().what()));
};
/// 1.7 query, parameter binding
*clientPtr << "select * from users where user_id = ? and user_name = ?"
<< "pg1"
<< "postgresql1" >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(6) what():" +
std::string(e.base().what()));
};
/// 1.8 delete
*clientPtr << "delete from users where user_id = ? and user_name = ?"
<< "pg1"
<< "postgresql1" >>
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(7) what():" +
std::string(e.base().what()));
};
/// 1.9 update
*clientPtr << "update users set user_id = ?, user_name = ? where user_id "
"= ? and user_name = ?"
<< "pg1"
<< "postgresql1"
<< "pg"
<< "postgresql" >>
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(8) what():" +
std::string(e.base().what()));
};
/// 1.10 truncate
*clientPtr << "truncate table users" >> [TEST_CTX](const Result &r) {
SUCCESS();
} >> [TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient streaming-type interface(9) what():" +
std::string(e.base().what()));
};
/// Test asynchronous method
/// 2.1 insert
clientPtr->execSqlAsync(
"insert into users \
(user_id,user_name,password,org_name) \
values(?,?,?,?)",
[TEST_CTX](const Result &r) { MANDATE(r.insertId() != 0); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient asynchronous interface(0) what():" +
std::string(e.base().what()));
},
"pg",
"postgresql",
"123",
"default");
/// 2.2 insert
clientPtr->execSqlAsync(
"insert into users \
(user_id,user_name,password,org_name) \
values(?,?,?,?)",
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient asynchronous interface(1) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1",
"123",
"default");
/// 2.3 query
clientPtr->execSqlAsync(
"select * from users where 1 = 1",
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient asynchronous interface(2) what():" +
std::string(e.base().what()));
});
/// 2.2 query, parameter binding
clientPtr->execSqlAsync(
"select * from users where id = ?",
[TEST_CTX](const Result &r) {
// std::cout << r.size() << "\n";
MANDATE(r.size() == 1);
},
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient asynchronous interface(3) what():" +
std::string(e.base().what()));
},
1);
/// 2.3 query, parameter binding
clientPtr->execSqlAsync(
"select * from users where user_id = ? and user_name = ?",
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient asynchronous interface(4) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1");
/// 2.4 delete
clientPtr->execSqlAsync(
"delete from users where user_id = ? and user_name = ?",
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient asynchronous interface(5) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1");
/// 2.5 update
clientPtr->execSqlAsync(
"update users set user_id = ?, user_name = ? where user_id "
"= ? and user_name = ?",
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient asynchronous interface(6) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1",
"pg",
"postgresql");
/// 2.6 truncate
clientPtr->execSqlAsync(
"truncate table users",
[TEST_CTX](const Result &r) { SUCCESS(); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - DbClient asynchronous interface(7) what():" +
std::string(e.base().what()));
});
/// Test synchronous method
/// 3.1 insert
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)",
"pg",
"postgresql",
"123",
"default");
// std::cout << r.insertId();
MANDATE(r.insertId() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient asynchronous interface(0) what():" +
std::string(e.base().what()));
}
/// 3.2 insert
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)",
"pg1",
"postgresql1",
"123",
"default");
MANDATE(r.affectedRows() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient asynchronous interface(1) what():" +
std::string(e.base().what()));
}
/// 3.3 query
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=? and user_name=?",
"pg1",
"postgresql1");
MANDATE(r.size() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient asynchronous interface(2) what():" +
std::string(e.base().what()));
}
/// 3.4 query for none
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=? and user_name=?",
"pg111",
"postgresql1");
MANDATE(r.size() == 0);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient asynchronous interface(3) what():" +
std::string(e.base().what()));
}
/// 3.5 bad sql
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=? and user_name='1234'",
"pg111",
"postgresql1");
MANDATE(r.size() == 0);
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// 3.6 truncate
try
{
auto r = clientPtr->execSqlSync("truncate table users");
SUCCESS();
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// Test future interface
/// 4.1 insert
auto f = clientPtr->execSqlAsyncFuture(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?) ",
"pg",
"postgresql",
"123",
"default");
try
{
auto r = f.get();
MANDATE(r.insertId() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient future interface(0) what():" +
std::string(e.base().what()));
}
/// 4.2 insert
f = clientPtr->execSqlAsyncFuture(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)",
"pg1",
"postgresql1",
"123",
"default");
try
{
auto r = f.get();
MANDATE(r.affectedRows() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient future interface(1) what():" +
std::string(e.base().what()));
}
/// 4.3 query
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=? and user_name=?",
"pg1",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient future interface(2) what():" +
std::string(e.base().what()));
}
/// 4.4 query for none
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=? and user_name=?",
"pg111",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 0);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient future interface(3) what():" +
std::string(e.base().what()));
}
/// 4.5 bad sql
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=? and user_name='12'",
"pg111",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 0);
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// 4.6 truncate
f = clientPtr->execSqlAsyncFuture("truncate table users");
try
{
auto r = f.get();
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient future interface(5) what():" +
std::string(e.base().what()));
}
/// 5 Test Result and Row exception throwing
// 5.1 query for none and try to access
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=? and user_name=?",
"pg111",
"postgresql1");
r.at(0);
FAULT("mysql - Result throwing exceptions(0)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.2 insert one just for setup
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)",
"pg",
"postgresql",
"123",
"default");
MANDATE(r.insertId() == 1);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - Row throwing exceptions(0) what():" +
std::string(e.base().what()));
}
// 5.3 try to access nonexistent column by name
try
{
auto r = clientPtr->execSqlSync("select * from users");
auto row = r.at(0);
row["imaginary_column"];
FAULT("mysql - Row throwing exceptions(1)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.4 try to access nonexistent column by index
try
{
auto r = clientPtr->execSqlSync("select * from users");
auto row = r.at(0);
row.at(420);
FAULT("mysql - Row throwing exceptions(2)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.5 cleanup
try
{
auto r = clientPtr->execSqlSync("truncate table users");
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("mysql - Row throwing exceptions(3) what():" +
std::string(e.base().what()));
}
/// Test ORM mapper
/// 6.1 insert, noneblocking
using namespace drogon_model::drogonTestMysql;
drogon::orm::Mapper<Users> mapper(clientPtr);
Users user;
user.setUserId("pg");
user.setUserName("postgres");
user.setPassword("123");
user.setOrgName("default");
mapper.insert(
user,
[TEST_CTX](Users ret) { MANDATE(ret.getPrimaryKey() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - ORM mapper asynchronous interface(0) what():" +
std::string(e.base().what()));
});
/// 6.1.5 count
mapper.count(
drogon::orm::Criteria(Users::Cols::_id, CompareOperator::EQ, 1),
[TEST_CTX](const size_t c) { MANDATE(c == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - ORM mapper asynchronous interface(1) what():" +
std::string(e.base().what()));
});
/// 6.2 insert
user.setUserId("pg1");
user.setUserName("postgres1");
mapper.insert(
user,
[TEST_CTX](Users ret) { MANDATE(ret.getPrimaryKey() == 2); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - ORM mapper asynchronous interface(2) what():" +
std::string(e.base().what()));
});
/// 6.3 select where in
mapper.findBy(
Criteria(Users::Cols::_id,
CompareOperator::In,
std::vector<int32_t>{2, 200}),
[TEST_CTX](std::vector<Users> users) { MANDATE(users.size() == 1); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("mysql - ORM mapper asynchronous interface(3) what():" +
std::string(e.base().what()));
});
/// 6.4 find by primary key. blocking
try
{
auto user = mapper.findByPrimaryKey(1);
SUCCESS();
Users newUser;
newUser.setId(user.getValueOfId());
newUser.setSalt("xxx");
auto c = mapper.update(newUser);
MANDATE(c == 1);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - ORM mapper synchronous interface(0) what():" +
std::string(e.base().what()));
}
#ifdef __cpp_impl_coroutine
auto coro_test = [clientPtr, TEST_CTX]() -> drogon::Task<> {
/// 7 Test coroutines.
/// This is by no means comprehensive. But coroutine API is esentially a
/// wrapper arround callbacks. The purpose is to test the interface
/// works 7.1 Basic queries
try
{
auto result =
co_await clientPtr->execSqlCoro("select * from users;");
MANDATE(result.size() != 0);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient coroutine interface(0) what():" +
std::string(e.base().what()));
}
/// 7.2 Parameter binding
try
{
auto result = co_await clientPtr->execSqlCoro(
"select * from users where 1=?;", 1);
MANDATE(result.size() != 0);
}
catch (const DrogonDbException &e)
{
FAULT("mysql - DbClient coroutine interface(1) what():" +
std::string(e.base().what()));
}
};
drogon::sync_wait(coro_test());
#endif
}
#endif
#if USE_SQLITE3
DbClientPtr sqlite3Client;
DROGON_TEST(SQLite3Test)
{
auto &clientPtr = sqlite3Client;
REQUIRE(clientPtr != nullptr);
// Prepare the test environment
*clientPtr << "DROP TABLE IF EXISTS users" >> [TEST_CTX](const Result &r) {
SUCCESS();
clientPtr->execSqlAsync(
"select 1 as result",
[TEST_CTX](const drogon::orm::Result &r) {
MANDATE(r.size() == 1);
},
expFunction);
} >> [TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - Prepare the test environment(0): what():" +
std::string(e.base().what()));
};
*clientPtr << "CREATE TABLE users \
(\
id INTEGER PRIMARY KEY autoincrement,\
user_id varchar(32),\
user_name varchar(64),\
password varchar(64),\
org_name varchar(20),\
signature varchar(50),\
avatar_id varchar(32),\
salt character varchar(20),\
admin boolean DEFAULT false,\
CONSTRAINT user_id_org UNIQUE(user_id, org_name)\
)" >>
[TEST_CTX](const Result &r) { SUCCESS(); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - Prepare the test environment(1) what():" +
std::string(e.base().what()));
};
/// Test1:DbClient streaming-type interface
/// 1.1 insert,non-blocking
*clientPtr << "insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)"
<< "pg"
<< "postgresql"
<< "123"
<< "default" >>
[TEST_CTX](const Result &r) { MANDATE(r.insertId() == 1ULL); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(0) what():" +
std::string(e.base().what()));
};
/// 1.2 insert,blocking
*clientPtr << "insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)"
<< "pg1"
<< "postgresql1"
<< "123"
<< "default" << Mode::Blocking >>
[TEST_CTX](const Result &r) { MANDATE(r.insertId() == 2ULL); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(1) what():" +
std::string(e.base().what()));
};
/// 1.3 query,no-blocking
*clientPtr << "select * from users where 1 = 1" << Mode::NonBlocking >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2UL); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(2) what():" +
std::string(e.base().what()));
};
/// 1.4 query,blocking
*clientPtr << "select * from users where 1 = 1" << Mode::Blocking >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2UL); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(3) what():" +
std::string(e.base().what()));
};
/// 1.5 query,blocking
int count = 0;
*clientPtr << "select user_name, user_id, id from users where 1 = 1"
<< Mode::Blocking >>
[&count, TEST_CTX](bool isNull,
const std::string &name,
std::string &&user_id,
int id) {
if (!isNull)
++count;
else
{
MANDATE(count == 2);
}
} >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(4) what():" +
std::string(e.base().what()));
};
/// 1.6 query, parameter binding
*clientPtr << "select * from users where id = ?" << 1 >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1UL); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(5) what():" +
std::string(e.base().what()));
};
/// 1.7 query, parameter binding
*clientPtr << "select * from users where user_id = ? and user_name = ?"
<< "pg1"
<< "postgresql1" >>
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1UL); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(6) what():" +
std::string(e.base().what()));
};
/// 1.8 delete
*clientPtr << "delete from users where user_id = ? and user_name = ?"
<< "pg1"
<< "postgresql1" >>
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1UL); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(7) what():" +
std::string(e.base().what()));
};
/// 1.9 update
*clientPtr << "update users set user_id = ?, user_name = ? where user_id "
"= ? and user_name = ?"
<< "pg1"
<< "postgresql1"
<< "pg"
<< "postgresql" >>
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1UL); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(8) what():" +
std::string(e.base().what()));
};
/// 1.10 clean up
*clientPtr << "delete from users" >> [TEST_CTX](const Result &r) {
SUCCESS();
} >> [TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(9.1) what():" +
std::string(e.base().what()));
};
*clientPtr << "UPDATE sqlite_sequence SET seq = 0" >>
[TEST_CTX](const Result &r) { SUCCESS(); } >>
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient streaming-type interface(9.2) what():" +
std::string(e.base().what()));
};
/// Test asynchronous method
/// 2.1 insert
clientPtr->execSqlAsync(
"insert into users \
(user_id,user_name,password,org_name) \
values(?,?,?,?)",
[TEST_CTX](const Result &r) { MANDATE(r.insertId() == 1ULL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(0) what():" +
std::string(e.base().what()));
},
"pg",
"postgresql",
"123",
"default");
/// 2.2 insert
clientPtr->execSqlAsync(
"insert into users \
(user_id,user_name,password,org_name) \
values(?,?,?,?)",
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(1) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1",
"123",
"default");
/// 2.3 query
clientPtr->execSqlAsync(
"select * from users where 1 = 1",
[TEST_CTX](const Result &r) { MANDATE(r.size() == 2UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(2) what():" +
std::string(e.base().what()));
});
/// 2.2 query, parameter binding
clientPtr->execSqlAsync(
"select * from users where id = ?",
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(3) what():" +
std::string(e.base().what()));
},
1);
/// 2.3 query, parameter binding
clientPtr->execSqlAsync(
"select * from users where user_id = ? and user_name = ?",
[TEST_CTX](const Result &r) { MANDATE(r.size() == 1UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(4) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1");
/// 2.4 delete
clientPtr->execSqlAsync(
"delete from users where user_id = ? and user_name = ?",
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(5) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1");
/// 2.5 update
clientPtr->execSqlAsync(
"update users set user_id = ?, user_name = ? where user_id "
"= ? and user_name = ?",
[TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(6) what():" +
std::string(e.base().what()));
},
"pg1",
"postgresql1",
"pg",
"postgresql");
/// 2.6 clean up
clientPtr->execSqlAsync(
"delete from users",
[TEST_CTX](const Result &r) { SUCCESS(); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(7.1) what():" +
std::string(e.base().what()));
});
clientPtr->execSqlAsync(
"UPDATE sqlite_sequence SET seq = 0",
[TEST_CTX](const Result &r) { SUCCESS(); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - DbClient asynchronous interface(7.2) what():" +
std::string(e.base().what()));
});
/// Test synchronous method
/// 3.1 insert
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)",
"pg",
"postgresql",
"123",
"default");
MANDATE(r.insertId() == 1ULL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient asynchronous interface(0) what():" +
std::string(e.base().what()));
}
/// 3.2 insert
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)",
"pg1",
"postgresql1",
"123",
"default");
MANDATE(r.affectedRows() == 1UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient asynchronous interface(1) what():" +
std::string(e.base().what()));
}
/// 3.3 query
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=? and user_name=?",
"pg1",
"postgresql1");
MANDATE(r.size() == 1UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient asynchronous interface(2) what():" +
std::string(e.base().what()));
}
/// 3.4 query for none
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=? and user_name=?",
"pg111",
"postgresql1");
MANDATE(r.size() == 0UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient asynchronous interface(3) what():" +
std::string(e.base().what()));
}
/// 3.5 bad sql
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=? and user_name='1234'",
"pg111",
"postgresql1");
MANDATE(r.size() == 0UL);
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// 3.6 clean up
try
{
auto r = clientPtr->execSqlSync("delete from users");
SUCCESS();
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
try
{
auto r = clientPtr->execSqlSync("UPDATE sqlite_sequence SET seq = 0");
SUCCESS();
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// Test future interface
/// 4.1 insert
auto f = clientPtr->execSqlAsyncFuture(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?) ",
"pg",
"postgresql",
"123",
"default");
try
{
auto r = f.get();
MANDATE(r.insertId() == 1ULL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient future interface(0) what():" +
std::string(e.base().what()));
}
/// 4.2 insert
f = clientPtr->execSqlAsyncFuture(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)",
"pg1",
"postgresql1",
"123",
"default");
try
{
auto r = f.get();
MANDATE(r.affectedRows() == 1UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient future interface(1) what():" +
std::string(e.base().what()));
}
/// 4.3 query
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=? and user_name=?",
"pg1",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 1UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient future interface(2) what():" +
std::string(e.base().what()));
}
/// 4.4 query for none
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=? and user_name=?",
"pg111",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 0UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient future interface(3) what():" +
std::string(e.base().what()));
}
/// 4.5 bad sql
f = clientPtr->execSqlAsyncFuture(
"select * from users where user_id=? and user_name='12'",
"pg111",
"postgresql1");
try
{
auto r = f.get();
MANDATE(r.size() == 0UL);
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
/// 4.6 clean up
f = clientPtr->execSqlAsyncFuture("delete from users");
try
{
auto r = f.get();
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient future interface(5.1) what():" +
std::string(e.base().what()));
}
f = clientPtr->execSqlAsyncFuture("UPDATE sqlite_sequence SET seq = 0");
try
{
auto r = f.get();
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient future interface(5.2) what():" +
std::string(e.base().what()));
}
/// 5 Test Result and Row exception throwing
// 5.1 query for none and try to access
try
{
auto r = clientPtr->execSqlSync(
"select * from users where user_id=? and user_name=?",
"pg111",
"postgresql1");
r.at(0);
FAULT("sqlite3 - Result throwing exceptions(0)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.2 insert one just for setup
try
{
auto r = clientPtr->execSqlSync(
"insert into users (user_id,user_name,password,org_name) "
"values(?,?,?,?)",
"pg",
"postgresql",
"123",
"default");
MANDATE(r.insertId() == 1ULL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - Row throwing exceptions(0) what():" +
std::string(e.base().what()));
}
// 5.3 try to access nonexistent column by name
try
{
auto r = clientPtr->execSqlSync("select * from users");
auto row = r.at(0);
row["imaginary_column"];
FAULT("sqlite3 - Row throwing exceptions(1)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.4 try to access nonexistent column by index
try
{
auto r = clientPtr->execSqlSync("select * from users");
auto row = r.at(0);
row.at(420);
FAULT("sqlite3 - Row throwing exceptions(2)");
}
catch (const DrogonDbException &e)
{
SUCCESS();
}
// 5.5 cleanup
try
{
auto r = clientPtr->execSqlSync("delete from users");
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - Row throwing exceptions(3) what():" +
std::string(e.base().what()));
}
try
{
auto r = clientPtr->execSqlSync("UPDATE sqlite_sequence SET seq = 0");
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - Row throwing exceptions(3) what():" +
std::string(e.base().what()));
}
/// Test ORM mapper TODO
/// 5.1 insert, noneblocking
using namespace drogon_model::sqlite3;
drogon::orm::Mapper<Users> mapper(clientPtr);
Users user;
user.setUserId("pg");
user.setUserName("postgres");
user.setPassword("123");
user.setOrgName("default");
mapper.insert(
user,
[TEST_CTX](Users ret) { MANDATE(ret.getPrimaryKey() == 1UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - ORM mapper asynchronous interface(0) what():" +
std::string(e.base().what()));
});
/// 5.2 insert
user.setUserId("pg1");
user.setUserName("postgres1");
mapper.insert(
user,
[TEST_CTX](Users ret) { MANDATE(ret.getPrimaryKey() == 2UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - ORM mapper asynchronous interface(1) what():" +
std::string(e.base().what()));
});
/// 5.3 select where in
mapper.findBy(
Criteria(Users::Cols::_id,
CompareOperator::In,
std::vector<int32_t>{2, 200}),
[TEST_CTX](std::vector<Users> users) { MANDATE(users.size() == 1UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - ORM mapper asynchronous interface(2) what():" +
std::string(e.base().what()));
});
/// 5.3.5 count
mapper.count(
drogon::orm::Criteria(Users::Cols::_id, CompareOperator::EQ, 2),
[TEST_CTX](const size_t c) { MANDATE(c == 1UL); },
[TEST_CTX](const DrogonDbException &e) {
FAULT("sqlite3 - ORM mapper asynchronous interface(3) what():" +
std::string(e.base().what()));
});
/// 5.4 find by primary key. blocking
try
{
auto user = mapper.findByPrimaryKey(1);
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - ORM mapper synchronous interface(0) what():" +
std::string(e.base().what()));
}
#ifdef __cpp_impl_coroutine
auto coro_test = [clientPtr, TEST_CTX]() -> drogon::Task<> {
/// 7 Test coroutines.
/// This is by no means comprehensive. But coroutine API is esentially a
/// wrapper arround callbacks. The purpose is to test the interface
/// works 7.1 Basic queries
try
{
auto result =
co_await clientPtr->execSqlCoro("select * from users;");
MANDATE(result.size() != 0UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient coroutine interface(0) what():" +
std::string(e.base().what()));
}
/// 7.2 Parameter binding
try
{
auto result = co_await clientPtr->execSqlCoro(
"select * from users where 1=?;", 1);
MANDATE(result.size() != 0UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - DbClient coroutine interface(1) what():" +
std::string(e.base().what()));
}
/// 7.3 ORM CoroMapper
try
{
auto mapper = CoroMapper<Users>(clientPtr);
auto user = co_await mapper.findOne(
Criteria(Users::Cols::_id, CompareOperator::EQ, 1));
SUCCESS();
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - CoroMapper coroutine interface(0) what():" +
std::string(e.base().what()));
}
try
{
auto mapper = CoroMapper<Users>(clientPtr);
auto users = co_await mapper.findBy(
Criteria(Users::Cols::_id, CompareOperator::EQ, 1));
MANDATE(users.size() == 1UL);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - CoroMapper coroutine interface(1) what():" +
std::string(e.base().what()));
}
try
{
auto mapper = CoroMapper<Users>(clientPtr);
auto n = co_await mapper.deleteByPrimaryKey(1);
MANDATE(n == 1);
}
catch (const DrogonDbException &e)
{
FAULT("sqlite3 - CoroMapper coroutine interface(2) what():" +
std::string(e.base().what()));
}
co_await drogon::sleepCoro(
trantor::EventLoop::getEventLoopOfCurrentThread(), 1.0s);
};
drogon::sync_wait(coro_test());
#endif
}
#endif
using namespace drogon;
int main(int argc, char **argv)
{
trantor::Logger::setLogLevel(trantor::Logger::LogLevel::kDebug);
#if USE_MYSQL
mysqlClient = DbClient::newMysqlClient(
"host=localhost port=3306 user=root client_encoding=utf8mb4", 1);
#endif
#if USE_POSTGRESQL
postgreClient = DbClient::newPgClient(
"host=127.0.0.1 port=5432 dbname=postgres user=postgres password=12345 "
"client_encoding=utf8",
1);
#endif
#if USE_SQLITE3
sqlite3Client = DbClient::newSqlite3Client("filename=:memory:", 1);
#endif
int testStatus = test::run(argc, argv);
return testStatus;
}