/** * * @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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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, clientPtr](const Result &r) { SUCCESS(); clientPtr->execSqlAsync( "select 1 as result", [TEST_CTX](const Result &r) { MANDATE(r.size() == 1); }, expFunction); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("postgresql - Prepare the test environment(0) what():", 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():", 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() << std::endl; MANDATE(r[0]["id"].as() == 1); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("postgresql - DbClient streaming-type interface(0) what():", 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" << DefaultValue{} << "123" << "default" << Mode::Blocking >> [TEST_CTX](const Result &r) { // std::cout << "id=" << r[0]["id"].as() << std::endl; MANDATE(r[0]["id"].as() == 2); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("postgresql - DbClient streaming-type interface(1) what():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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() << std::endl; MANDATE(r[0]["id"].as() == 1); }, [TEST_CTX](const DrogonDbException &e) { FAULT("postgresql - DbClient asynchronous interface(0) what():", 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() << std::endl; MANDATE(r.affectedRows() == 1); }, [TEST_CTX](const DrogonDbException &e) { FAULT("postgresql - DbClient asynchronous interface(1) what():", 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():", 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():", e.base().what()); }, 1); /// 2.3 query, parameter binding (string_view) 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():", e.base().what()); }, drogon::string_view("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():", 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():", 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():", 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() == 1); } catch (const DrogonDbException &e) { FAULT("postgresql - DbClient asynchronous interface(0) what():", 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():", 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():", 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():", 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():", 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() == 1); } catch (const DrogonDbException &e) { FAULT("postgresql - DbClient future interface(0) what():", 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():", 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():", 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():", 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():", 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() == 1); } catch (const DrogonDbException &e) { FAULT("postgresql - Row throwing exceptions(0) what():", 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():", e.base().what()); } /// Test ORM mapper /// 6.1 insert, noneblocking using namespace drogon_model::postgres; Mapper 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():", 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():", 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():", e.base().what()); }); /// 6.3 select where in mapper.findBy( Criteria(Users::Cols::_id, CompareOperator::In, std::vector{2, 200}), [TEST_CTX](std::vector users) { MANDATE(users.size() == 1); }, [TEST_CTX](const DrogonDbException &e) { FAULT("postgresql - ORM mapper asynchronous interface(2) what():", e.base().what()); }); /// 6.3.5 count mapper.count( 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():", e.base().what()); }); /// 6.3.6 custom where query mapper.findBy( Criteria("id <@ int4range($?, null)"_sql, 3), [TEST_CTX](std::vector users) { MANDATE(users.size() == 1); }, [TEST_CTX](const DrogonDbException &e) { FAULT("postgresql - ORM mapper asynchronous interface(4) what():", e.base().what()); }); /// 6.3.7 pagination mapper.paginate(2, 1).findAll( [TEST_CTX](std::vector users) { MANDATE(users.size() == 1); }, [TEST_CTX](const DrogonDbException &e) { FAULT("postgresql - ORM mapper asynchronous interface(5) what():", 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():", e.base().what()); } /// 6.5.1 update by criteria. blocking try { auto user = mapper.findByPrimaryKey(2); SUCCESS(); Users newUser; newUser.setId(user.getValueOfId()); newUser.setSalt("xxx"); newUser.setUserName(user.getValueOfUserName()); auto c = mapper.update(newUser); MANDATE(c == 1); c = mapper.updateBy({Users::Cols::_avatar_id, Users::Cols::_salt}, Criteria(Users::Cols::_user_id, CompareOperator::EQ, "pg"), "avatar of pg", "salt of pg"); MANDATE(c == 1); c = mapper.updateBy({Users::Cols::_avatar_id, Users::Cols::_salt}, Criteria(Users::Cols::_user_id, CompareOperator::EQ, "none"), "avatar of none", "salt of none"); MANDATE(c == 0); } catch (const DrogonDbException &e) { FAULT("postgresql - ORM mapper synchronous interface(1) what():", e.base().what()); } /// 6.5.2 update by criteria. asynchronous { std::vector cols{Users::Cols::_avatar_id, Users::Cols::_salt}; mapper.updateBy( cols, [TEST_CTX](const size_t c) { MANDATE(c == 1); }, [TEST_CTX](const DrogonDbException &e) { FAULT( "postgresql - ORM mapper asynchronous updateBy " "interface(0) " "what():", e.base().what()); }, Criteria(Users::Cols::_user_id, CompareOperator::EQ, "pg"), "avatar of pg", "salt of pg"); } #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():", 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():", e.base().what()); } /// 7.3 CoroMapper try { CoroMapper mapper(clientPtr); auto user = co_await mapper.findByPrimaryKey(2); SUCCESS(); } catch (const DrogonDbException &e) { FAULT("postgresql - ORM mapper coroutine interface(0) what():", e.base().what()); } try { CoroMapper mapper(clientPtr); auto user = co_await mapper.findByPrimaryKey(314); FAULT("postgresql - ORM mapper coroutine interface(1)"); } catch (const DrogonDbException &e) { SUCCESS(); } try { CoroMapper mapper(clientPtr); auto users = co_await mapper.findAll(); auto count = co_await mapper.count(); MANDATE(users.size() == count); } catch (const DrogonDbException &e) { SUCCESS(); } try { CoroMapper mapper(clientPtr); auto users = co_await mapper.orderBy(Users::Cols::_user_id) .limit(2) .findAll(); MANDATE(users.size() == 2); SUCCESS(); } catch (const DrogonDbException &e) { FAULT("postgresql - ORM mapper coroutine interface(2) what():", e.base().what()); } // CoroMapper::update try { CoroMapper mapper(clientPtr); auto user = co_await mapper.findByPrimaryKey(2); SUCCESS(); Users newUser; newUser.setId(user.getValueOfId()); newUser.setSalt("xxx"); size_t c = co_await mapper.update(newUser); MANDATE(c == 1); SUCCESS(); } catch (const DrogonDbException &e) { FAULT("postgresql - ORM mapper coroutine interface(3) what():", e.base().what()); } // CoroMapper::updateBy try { CoroMapper mapper(clientPtr); auto awaiter = mapper.updateBy( {Users::Cols::_avatar_id, Users::Cols::_salt}, Criteria(Users::Cols::_user_id, CompareOperator::EQ, "pg"), "avatar of pg", "salt of pg"); size_t c = co_await awaiter; MANDATE(c == 1); // Can not compile if use co_await and initilizer_list together. // Seems to be a bug in gcc. std::vector updateFields{Users::Cols::_avatar_id, Users::Cols::_salt}; c = co_await mapper.updateBy(updateFields, Criteria(Users::Cols::_user_id, CompareOperator::EQ, "none"), "avatar of none", "salt of none"); MANDATE(c == 0); auto count = co_await mapper.count(); // Use std::make_tuple to as an alternative to initializer_list c = co_await mapper.updateBy( std::make_tuple(Users::Cols::_avatar_id, Users::Cols::_salt), Criteria(), "avatar", "salt"); MANDATE(c == count); SUCCESS(); } catch (const DrogonDbException &e) { FAULT("postgresql - ORM mapper coroutine interface(4) what():", e.base().what()); } /// 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():", 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, clientPtr](const Result &r) { SUCCESS(); clientPtr->execSqlAsync( "select 1 as result", [TEST_CTX](const Result &r) { MANDATE(r.size() == 1); }, expFunction); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("mysql - Prepare the test environment(0) what():", 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():", 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():", 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():", 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" << DefaultValue{} >> [TEST_CTX](const Result &r) { MANDATE(r.insertId() == 1); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("mysql - DbClient streaming-type interface(0) what():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", e.base().what()); } /// Test ORM mapper /// 6.1 insert, noneblocking using namespace drogon_model::drogonTestMysql; Mapper 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():", e.base().what()); }); /// 6.1.5 count mapper.count( 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():", 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():", e.base().what()); }); /// 6.3 select where in mapper.findBy( Criteria(Users::Cols::_id, CompareOperator::In, std::vector{2, 200}), [TEST_CTX](std::vector users) { MANDATE(users.size() == 1); }, [TEST_CTX](const DrogonDbException &e) { FAULT("mysql - ORM mapper asynchronous interface(3) what():", e.base().what()); }); /// 6.3.6 custom where query mapper.findBy( Criteria("id between $? and $?"_sql, 2, 200), [TEST_CTX](std::vector users) { MANDATE(users.size() == 1); }, [TEST_CTX](const DrogonDbException &e) { FAULT("mysql - ORM mapper asynchronous interface(4) what():", 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():", e.base().what()); } /// 6.5 update by criteria. blocking try { auto user = mapper.findByPrimaryKey(2); SUCCESS(); Users newUser; newUser.setId(user.getValueOfId()); newUser.setSalt("xxx"); newUser.setUserName(user.getValueOfUserName()); auto c = mapper.update(newUser); MANDATE(c == 1); c = mapper.updateBy({Users::Cols::_avatar_id, Users::Cols::_salt}, Criteria(Users::Cols::_user_id, CompareOperator::EQ, "pg"), "avatar of pg", "salt of pg"); MANDATE(c == 1); c = mapper.updateBy({Users::Cols::_avatar_id, Users::Cols::_salt}, Criteria(Users::Cols::_user_id, CompareOperator::EQ, "none"), "avatar of none", "salt of none"); MANDATE(c == 0); } catch (const DrogonDbException &e) { FAULT("mysql - ORM mapper synchronous interface(1) what():", 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():", 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():", 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, clientPtr](const Result &r) { SUCCESS(); clientPtr->execSqlAsync( "select 1 as result", [TEST_CTX](const Result &r) { MANDATE(r.size() == 1); }, expFunction); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - Prepare the test environment(0): what():", 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," " create_time datetime," " 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():", e.base().what()); }; /// Test1:DbClient streaming-type interface /// 1.1 insert,non-blocking *clientPtr << "insert into users " "(user_id,user_name,password,org_name,create_time) " "values(?,?,?,?,?)" << "pg" << "postgresql" << "123" << "default" << trantor::Date::now() >> [TEST_CTX](const Result &r) { MANDATE(r.insertId() == 1ULL); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - DbClient streaming-type interface(0) what():", e.base().what()); }; /// 1.2 insert,blocking *clientPtr << "insert into users " "(user_id,user_name,password,org_name,create_time) " "values(?,?,?,?,?)" << "pg1" << "postgresql1" << "123" << "default" << trantor::Date::now() << Mode::Blocking >> [TEST_CTX](const Result &r) { MANDATE(r.insertId() == 2ULL); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - DbClient streaming-type interface(1) what():", e.base().what()); }; *clientPtr << "select * from users where user_id=?;" << "pg1" << Mode::Blocking >> [TEST_CTX](const Result &r) { MANDATE(r.size() == 1); MANDATE(r[0]["user_id"].as() == "pg1"); using namespace drogon_model::sqlite3; Users user(r[0]); MANDATE(user.getValueOfUserId() == "pg1"); // LOG_INFO << "user:" << user.toJson().toStyledString(); MANDATE(trantor::Date::now().secondsSinceEpoch() - user.getValueOfCreateTime().secondsSinceEpoch() <= 1); } >> [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - DbClient streaming-type interface(2) what():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", 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():", e.base().what()); }; /// Test asynchronous method /// 2.1 insert clientPtr->execSqlAsync( "insert into users " "(user_id,user_name,password,org_name,create_time) " "values(?,?,?,?,?)", [TEST_CTX](const Result &r) { MANDATE(r.insertId() == 1ULL); }, [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - DbClient asynchronous interface(0) what():", e.base().what()); }, "pg", "postgresql", "123", "default", trantor::Date::now()); /// 2.2 insert clientPtr->execSqlAsync( "insert into users " "(user_id,user_name,password,org_name,create_time) " "values(?,?,?,?,?)", [TEST_CTX](const Result &r) { MANDATE(r.affectedRows() == 1UL); }, [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - DbClient asynchronous interface(1) what():", e.base().what()); }, "pg1", "postgresql1", "123", "default", trantor::Date::now()); /// 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():", 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():", 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():", 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():", 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():", 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():", 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():", e.base().what()); }); /// Test synchronous method /// 3.1 insert try { auto r = clientPtr->execSqlSync( "insert into users " "(user_id,user_name,password,org_name,create_time) " "values(?,?,?,?,?)", "pg", "postgresql", "123", "default", trantor::Date::now()); MANDATE(r.insertId() == 1ULL); } catch (const DrogonDbException &e) { FAULT("sqlite3 - DbClient asynchronous interface(0) what():", e.base().what()); } /// 3.2 insert,(string_view) try { drogon::string_view sv("pg1"); drogon::string_view sv1("postgresql1"); drogon::string_view sv2("123"); auto r = clientPtr->execSqlSync( "insert into users " "(user_id,user_name,password,org_name,create_time) " "values(?,?,?,?,?)", sv, (const drogon::string_view &)sv1, std::move(sv2), drogon::string_view("default"), trantor::Date::now()); MANDATE(r.affectedRows() == 1UL); } catch (const DrogonDbException &e) { FAULT("sqlite3 - DbClient asynchronous interface(1) what():", 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():", 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():", 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,create_time) " "values(?,?,?,?,?) ", "pg", "postgresql", "123", "default", trantor::Date::now()); try { auto r = f.get(); MANDATE(r.insertId() == 1ULL); } catch (const DrogonDbException &e) { FAULT("sqlite3 - DbClient future interface(0) what():", e.base().what()); } /// 4.2 insert f = clientPtr->execSqlAsyncFuture( "insert into users (user_id,user_name,password,org_name,create_time) " "values(?,?,?,?,?)", "pg1", "postgresql1", "123", "default", trantor::Date::now()); try { auto r = f.get(); MANDATE(r.affectedRows() == 1UL); } catch (const DrogonDbException &e) { FAULT("sqlite3 - DbClient future interface(1) what():", 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():", 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():", 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():", 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():", 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,create_time) " "values(?,?,?,?,?)", "pg", "postgresql", "123", "default", trantor::Date::now()); MANDATE(r.insertId() == 1ULL); } catch (const DrogonDbException &e) { FAULT("sqlite3 - Row throwing exceptions(0) what():", 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():", 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():", e.base().what()); } /// Test ORM mapper TODO /// 5.1 insert, noneblocking using namespace drogon_model::sqlite3; Mapper mapper(clientPtr); Users user; user.setUserId("pg"); user.setUserName("postgres"); user.setPassword("123"); user.setOrgName("default"); user.setCreateTime(trantor::Date::now()); mapper.insert( user, [TEST_CTX](Users ret) { MANDATE(ret.getPrimaryKey() == 1UL); }, [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - ORM mapper asynchronous interface(0) what():", 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():", e.base().what()); }); /// 5.3 select where in mapper.findBy( Criteria(Users::Cols::_id, CompareOperator::In, std::vector{2, 200}), [TEST_CTX](std::vector users) { MANDATE(users.size() == 1UL); }, [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - ORM mapper asynchronous interface(2) what():", e.base().what()); }); /// 5.3.5 count mapper.count( 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():", e.base().what()); }); /// 5.3.6 custom where query mapper.findBy( Criteria("password is not null"_sql), [TEST_CTX](std::vector users) { MANDATE(users.size() == 2); }, [TEST_CTX](const DrogonDbException &e) { FAULT("sqlite3 - ORM mapper asynchronous interface(4) what():", 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():", 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():", 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():", e.base().what()); } /// 7.3 ORM CoroMapper try { auto mapper = CoroMapper(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():", e.base().what()); } try { auto mapper = CoroMapper(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():", e.base().what()); } try { auto mapper = CoroMapper(clientPtr); auto n = co_await mapper.deleteByPrimaryKey(1); MANDATE(n == 1); } catch (const DrogonDbException &e) { FAULT("sqlite3 - CoroMapper coroutine interface(2) what():", 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, true); #endif #if USE_SQLITE3 sqlite3Client = DbClient::newSqlite3Client("filename=:memory:", 1); #endif const int testStatus = test::run(argc, argv); return testStatus; }