Skip to content

Commit

Permalink
Merge pull request #5 from jgaa/actions
Browse files Browse the repository at this point in the history
Add example
  • Loading branch information
jgaa committed Mar 12, 2024
2 parents 5e798dd + 51a2d61 commit 52d32ca
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 1 deletion.
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake)

option(MYSQLPOOL_WITH_TESTS "Enable Tests" ON)
option(MYSQLPOOL_WITH_INTGRATION_TESTS "Enable Integretion Tests" OFF)
option(MYSQLPOOL_WITH_EXAMPLES "Compile examples" ON)

set(MYSQLPOOL_LOGGER "clog" CACHE STRING "Log system to use. One of 'clog', 'internal', 'logfault', 'boost' or 'none'")
set(MYSQLPOOL_LOG_LEVEL_STR "info" CACHE STRING "Minimum log level to enable")
Expand Down Expand Up @@ -101,14 +102,17 @@ find_package(Boost ${USE_BOOST_VERSION} REQUIRED COMPONENTS
context
chrono
json
program_options
${BOOST_LOG_DEP}
)

add_library(boost INTERFACE IMPORTED)
set_property(TARGET boost PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR})


if (MYSQLPOOL_WITH_EXAMPLES)
add_subdirectory(examples/simple)
endif()

if (MYSQLPOOL_WITH_TESTS)
enable_testing()
Expand Down
1 change: 1 addition & 0 deletions config.h.template
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
#define DEFAULT_MYSQLPOOL_DATABASE "${DEFAULT_MYSQLPOOL_DATABASE}"
#define DEFAULT_MYSQLPOOL_HOST "${DEFAULT_MYSQLPOOL_HOST}"
#define DEFAULT_MYSQLPOOL_PORT "${DEFAULT_MYSQLPOOL_PORT}"
#define MYSQLPOOL_VERSION "${MYSQLPOOL_VERSION}"
21 changes: 21 additions & 0 deletions examples/simple/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

project(simple_sql_app
DESCRIPTION "Simple example on how to use mysqlpool-cpp"
LANGUAGES CXX
)

add_executable(${PROJECT_NAME} main.cpp fun_with_sql.cpp)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
target_link_libraries(${PROJECT_NAME} mysqlpool)

target_include_directories(${PROJECT_NAME} PRIVATE
$<BUILD_INTERFACE:${Boost_INCLUDE_DIR}>
$<BUILD_INTERFACE:${MYSQLPOOL_ROOT}/include>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/generated-include>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/external-projects/installed/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$Boost_INCLUDE_DIR
)

121 changes: 121 additions & 0 deletions examples/simple/fun_with_sql.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@

#include <boost/asio.hpp>

#include "mysqlpool/logging.h"
#include "mysqlpool/mysqlpool.h"
#include "mysqlpool/conf.h"
#include "mysqlpool/config.h"

using namespace std;
namespace mp = jgaa::mysqlpool;



boost::asio::awaitable<void> ping_the_db_server(mp::Mysqlpool& pool) {

// Lets get an actual connection to the database
// hande is a Handle to a Connection.
// It will automatically release the connection when it goes out of scope.
auto handle = co_await pool.getConnection();

// When we obtain a handle, we can use the native boost.mysql methods.
// Let's try it and ping the server.
// If the server is not available, the async_ping will throw an exception.

cout << "Pinging the server..." << endl;
co_await handle.connection().async_ping(boost::asio::use_awaitable);
}

boost::asio::awaitable<void> get_db_version_using_boost_mysql(mp::Mysqlpool& pool) {

// Lets get an actual connection to the database
auto handle = co_await pool.getConnection();

// hande is a Handle to a Connection.
// It will automatically release the connection when it goes out of scope.

// Now, let's see what version the database server uses, by sending a query: 'SELECT @@version'
// This time we will use proper error handling.
// Please see the boost.mysql documentation for more information.

boost::mysql::results res;
boost::mysql::diagnostics diag;
const auto [ec] = co_await handle.connection().async_execute("SELECT @@version", res, diag, mp::tuple_awaitable);
if (ec) {
MYSQLPOOL_LOG_ERROR_("Error: " << ec.message()
<< ", diag client: " << diag.client_message()
<< ", diag server: " << diag.server_message());
co_return;
}
if (res.has_value() && !res.rows().empty()) {
const auto db_version = res.rows()[0][0].as_string();
cout << "Database version: " << db_version << endl;
}

co_return;
}


boost::asio::awaitable<void> get_db_version(mp::Mysqlpool& pool) {

// Now, lets do the same as above, but with less code.
// Note that we leave most of the error-handling to Mysqlpool.
// We also let Mysqlpool handle the connection, and release it before exec() returns.
// If there is a problem, Mysqlpool will retry if appropriate.
// If not, it will throw an exception.

const auto res = co_await pool.exec("SELECT @@version");

// if pool.exec() returned, we know that the result is not empty.
assert(!res.empty());

// We still have to check that the db server sent us something.
if (!res.rows().empty()) {
const auto db_version = res.rows()[0][0].as_string();
cout << "Database version: " << db_version << endl;
}

co_return;
}

// Entry point from main()
void run_examples(const mp::DbConfig& config){


// Create an io_context, which is the heart of the boost.asio library.
// It will manage all asynchronous operations.
boost::asio::io_context ctx;

// Create an instance of Mysqlool
// It will connect to the database and keep a pool of connections.
mp::Mysqlpool pool(ctx, config);

// Start a coroutine context, and work in it until we are done.
auto res = boost::asio::co_spawn(ctx, [&]() -> boost::asio::awaitable<void> {
// Initialzie the connection pool.
// It will connect to the database and keep a pool of connections.
co_await pool.init();

// Run trough the examples
co_await ping_the_db_server(pool);
co_await get_db_version_using_boost_mysql(pool);
co_await get_db_version(pool);

// Gracefully shut down the connection-pool.
co_await pool.close();

}, boost::asio::use_future);

// Let the main thread run the boost.asio event loop.
ctx.run();

try {
// Now, let's deal with exceptions from the coroutines, if any
res.get();
} catch (const exception& ex) {
MYSQLPOOL_LOG_ERROR_("Caught exception from coroutine: " << ex.what());
}

MYSQLPOOL_LOG_INFO_("Example run is done: ");
}

125 changes: 125 additions & 0 deletions examples/simple/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@

#include <iostream>
#include <filesystem>
#include <boost/program_options.hpp>
#include <boost/asio.hpp>

#include "mysqlpool/logging.h"
#include "mysqlpool/mysqlpool.h"
#include "mysqlpool/conf.h"
#include "mysqlpool/config.h"

#ifdef _MSC_VER
# include <stdlib.h>
// Use _putenv_s when compiled with Microsoft's compiler
// Thank you Microsoft!
# define setenv(key, value, ignore) _putenv_s(key, value)
#endif

using namespace std;
namespace mp = jgaa::mysqlpool;

extern void run_examples(const mp::DbConfig& config);

int main(int argc, char* argv[]) {
// Don't make the app crash with an uincaught exception if Linux can't deal with your locale setting!
// In stead, switch to the "C" locale which hopefully works.
try {
locale loc("");
} catch (const std::exception&) {
cout << "Locales in Linux are fundamentally broken. Never worked. Never will. Overriding the current mess with LC_ALL=C" << endl;
setenv("LC_ALL", "C", 1);
}

std::string log_level = "info";
mp::DbConfig config;

const auto appname = filesystem::path(argv[0]).stem().string();

namespace po = boost::program_options;
po::options_description general("Options");
general.add_options()
("help,h", "Print help and exit")
("version,v", "Print version and exit")
("log-to-console,C",
po::value(&log_level)->default_value(log_level),
"Log-level to the console; one of 'info', 'debug', 'trace'. Empty string to disable.")
;
po::options_description db_opts("Database options");
db_opts.add_options()
("db-user",
po::value(&config.username),
"Mysql user to use when logging into the mysql server")
("db-passwd",
po::value(&config.password),
"Mysql password to use when logging into the mysql server")
("db-name",
po::value(&config.database)->default_value(config.database),
"Database to use")
("db-host",
po::value(&config.host)->default_value(config.host),
"Hostname or IP address for the database server")
("db-port",
po::value(&config.port)->default_value(config.port),
"Port number for the database server")
("db-min-connections",
po::value(&config.min_connections)->default_value(config.min_connections),
"Max concurrent connections to the database server")
("db-max-connections",
po::value(&config.max_connections)->default_value(config.max_connections),
"Max concurrent connections to the database server")
("db-retry-connect",
po::value(&config.retry_connect)->default_value(config.retry_connect),
"Retry connect to the database-server # times on startup. Useful when using containers, where nextappd may be running before the database is ready.")
("db-retry-delay",
po::value(&config.retry_connect_delay_ms)->default_value(config.retry_connect_delay_ms),
"Milliseconds to wait between connection retries")
;

po::options_description cmdline_options;
cmdline_options.add(general).add(db_opts);
po::variables_map vm;
try {
po::store(po::command_line_parser(argc, argv).options(cmdline_options).run(), vm);
po::notify(vm);
} catch (const std::exception& ex) {
cerr << appname
<< " Failed to parse command-line arguments: " << ex.what() << endl;
return -1;
}

if (vm.count("help")) {
std::cout <<appname << " [options]";
std::cout << cmdline_options << std::endl;
return -2;
}

if (vm.count("version")) {
std::cout << appname << endl
<< "Using C++ standard " << __cplusplus << endl
<< "Boost " << BOOST_LIB_VERSION << endl
<< "Platform " << BOOST_PLATFORM << endl
<< "Compiler " << BOOST_COMPILER << endl
<< "Build date " <<__DATE__ << endl
<< "Mysqlpool " << MYSQLPOOL_VERSION << endl;
return -3;
}

// Set up logging
// In this example we use this macro to use whatever log framework
// mysqlpool is configured to use.
// In your app, you will typically choose what log framework to use
// and configure it in your app.
MYSQLPOOL_TEST_LOGGING_SETUP(log_level);

MYSQLPOOL_LOG_INFO_(appname << " starting up.");

try {
run_examples(config);
} catch (const exception& ex) {
MYSQLPOOL_LOG_ERROR_("Caught exception: " << ex.what());
return -5;
}

MYSQLPOOL_LOG_INFO_(appname << " is done!");
}
1 change: 1 addition & 0 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"boost-log",
"boost-mysql",
"boost-uuid",
"boost-program-options",
"zlib",
"openssl",
"gtest"
Expand Down

0 comments on commit 52d32ca

Please sign in to comment.