Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more request examples #192

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif()

add_executable(ozo_request request.cpp)
target_link_libraries(ozo_request ozo)
add_executable(ozo_request_coroutine request_coroutine.cpp)
target_link_libraries(ozo_request_coroutine ozo)

# enable a bunch of warnings and make them errors
target_compile_options(ozo_request PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror)
target_compile_options(ozo_request_coroutine PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror)

# ignore specific errors for clang
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
target_compile_options(ozo_request PRIVATE -Wno-ignored-optimization-argument)
target_compile_options(ozo_request_coroutine PRIVATE -Wno-ignored-optimization-argument)
endif()

add_executable(ozo_retry_request retry_request.cpp)
Expand Down Expand Up @@ -48,3 +48,25 @@ target_compile_options(ozo_connection_pool PRIVATE -Wall -Wextra -Wsign-compare
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
target_compile_options(ozo_connection_pool PRIVATE -Wno-ignored-optimization-argument)
endif()

add_executable(ozo_request_future request_future.cpp)
target_link_libraries(ozo_request_future ozo)

# enable a bunch of warnings and make them errors
target_compile_options(ozo_request_future PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror)

# ignore specific errors for clang
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
target_compile_options(ozo_request_future PRIVATE -Wno-ignored-optimization-argument)
endif()

add_executable(ozo_request_callback request_callback.cpp)
target_link_libraries(ozo_request_callback ozo)

# enable a bunch of warnings and make them errors
target_compile_options(ozo_request_callback PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror)

# ignore specific errors for clang
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
target_compile_options(ozo_request_callback PRIVATE -Wno-ignored-optimization-argument)
endif()
69 changes: 69 additions & 0 deletions examples/request_callback.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <ozo/connection_info.h>
#include <ozo/request.h>
#include <ozo/shortcuts.h>

#include <boost/asio/io_service.hpp>

#include <iostream>

namespace asio = boost::asio;

int main(int argc, char **argv) {
std::cout << "OZO request example" << std::endl;

if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <connection string>\n";
return 1;
}

// Ozo perform all IO using Boost.Asio, so first thing we need to do is setup asio::io_context
asio::io_context io;

// To make a request we need to make a ConnectionSource. It knows how to connect to database using
// connection string. See https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING
// how to make a connection string.
auto conn_info = ozo::connection_info(argv[1]);

// Request result is always set of rows. Client should take care of output object lifetime.
const auto result = std::make_shared<ozo::rows_of<int>>();

// All IO is asynchronous, therefore we have a choice here, what should be our CompletionToken.
// We use callback function that will be called after operation is finished.
const auto callback = [result] (ozo::error_code ec, auto connection) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callback may be a functional object with the result stored as std::unique_ptr. Ozo now works fine with non-copyable callbacks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// When request is completed we check is there an error. This example should not produce any errors
// if there are no problems with target database, network or permissions for given user in connection
// string.
if (ec) {
std::cout << "Request failed with error: " << ec.message();
// Here we should check if the connection is in null state to avoid UB.
if (!ozo::is_null_recursive(connection)) {
// Let's check libpq native error message and if so - print it out
if (auto msg = ozo::error_message(connection); !msg.empty()) {
std::cout << ", error message: " << msg;
}
// Sometimes libpq native error message is not enough, so let's check
// the additional error context from OZO
if (auto ctx = ozo::get_error_context(connection); !ctx.empty()) {
std::cout << ", error context: " << ctx;
}
}
std::cout << std::endl;
return;
}

// Just print request result
std::cout << "Selected:" << std::endl;
for (auto value : *result) {
std::cout << std::get<0>(value) << std::endl;
}
};

// This allows to use _SQL literals
using namespace ozo::literals;
using namespace std::chrono_literals;
ozo::request(conn_info[io], "SELECT 1"_SQL, 1s, ozo::into(*result), callback);

io.run();

return 0;
}
File renamed without changes.
69 changes: 69 additions & 0 deletions examples/request_future.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <ozo/connection_info.h>
#include <ozo/request.h>
#include <ozo/shortcuts.h>

#include <boost/asio/io_service.hpp>
#include <boost/asio/use_future.hpp>

#include <iostream>
#include <thread>

namespace asio = boost::asio;

int main(int argc, char **argv) {
std::cout << "OZO request example" << std::endl;

if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <connection string>\n";
return 1;
}

// Ozo perform all IO using Boost.Asio, so first thing we need to do is setup asio::io_context
asio::io_context io;

// To make a request we need to make a ConnectionSource. It knows how to connect to database using
// connection string. See https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING
// how to make a connection string.
auto conn_info = ozo::connection_info(argv[1]);

// All IO is asynchronous, therefore we have a choice here, what should be our CompletionToken.
// We use boost::asio::use_future. To make this example more real all asynchronous operation will be performed
// in a separate thread. Work guard will help to keep io_context running until we decide to stop it.
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> guard = boost::asio::make_work_guard(io);
std::thread worker([&io] {
io.run();
});

// Request result is always set of rows. Client should take care of output object lifetime.
ozo::rows_of<int> result;

// This allows to use _SQL literals
using namespace ozo::literals;
using namespace std::chrono_literals;
auto connection = ozo::request(conn_info[io], "SELECT 1"_SQL, 1s, ozo::into(result), asio::use_future);

// When request is completed we check is there an exception. This example should not produce any errors
// if there are no problems with target database, network or permissions for given user in connection
// string.
try {
// Here we wait until asynchronous operation in a different thread is finished. If any error is occured
// an exception will be thrown. Unfortunately without any additional context, only static error code message.
connection.get();

// Just print request result
std::cout << "Selected:" << std::endl;
for (auto value : result) {
std::cout << std::get<0>(value) << std::endl;
}
} catch (const std::exception& error) {
std::cout << "Request failed with error: " << error.what();
}

// Reset work guard to release io and make it able to stop.
guard.reset();

// Make sure thread is finished.
worker.join();

return 0;
}
28 changes: 16 additions & 12 deletions scripts/run_example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ scripts/build.sh pg docker clang release

docker-compose up -d ozo_postgres

docker-compose run \
--rm \
--user "$(id -u):$(id -g)" \
ozo_build_with_pg_tests \
bash \
-exc '/code/scripts/wait_postgres.sh; ${BASE_BUILD_DIR}/clang_release/examples/ozo_request "host=${POSTGRES_HOST} user=${POSTGRES_USER} dbname=${POSTGRES_DB} password=${POSTGRES_PASSWORD}"'
function run_example {
BINARY="\${BASE_BUILD_DIR}/clang_release/examples/${1:?}"
CONN_INFO='"host=${POSTGRES_HOST:?} user=${POSTGRES_USER:?} dbname=${POSTGRES_DB:?} password=${POSTGRES_PASSWORD:?}"'
docker-compose run \
--rm \
--user "$(id -u):$(id -g)" \
ozo_build_with_pg_tests \
bash \
-exc "/code/scripts/wait_postgres.sh; ${BINARY:?} ${CONN_INFO:?} ${CONN_INFO:?}"
}

docker-compose run \
--rm \
--user "$(id -u):$(id -g)" \
ozo_build_with_pg_tests \
bash \
-exc '/code/scripts/wait_postgres.sh; ${BASE_BUILD_DIR}/clang_release/examples/ozo_connection_pool "host=${POSTGRES_HOST} user=${POSTGRES_USER} dbname=${POSTGRES_DB} password=${POSTGRES_PASSWORD}"'
run_example ozo_request_coroutine
run_example ozo_connection_pool
run_example ozo_retry_request
run_example ozo_role_based_request
run_example ozo_request_future
run_example ozo_request_callback

docker-compose stop ozo_postgres
docker-compose rm -f ozo_postgres
2 changes: 1 addition & 1 deletion tests/external_project/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ cmake_minimum_required(VERSION 3.12)
project(my_ozo_using_project)

find_package(ozo REQUIRED)
add_executable(my_app ../../examples/request.cpp)
add_executable(my_app ../../examples/request_coroutine.cpp)
target_link_libraries(my_app PRIVATE yandex::ozo)