Merge branch 'development' of ssh://git.fifthgrid.com:3022/blockstorage/repertory into development
This commit is contained in:
commit
8c548bad92
13300
3rd_party/sqlite/include/sqlite3.h
vendored
Normal file
13300
3rd_party/sqlite/include/sqlite3.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
252720
3rd_party/sqlite/src/sqlite3.c
vendored
Normal file
252720
3rd_party/sqlite/src/sqlite3.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
297
cmake/modules/FindSodium.cmake
Normal file
297
cmake/modules/FindSodium.cmake
Normal file
@ -0,0 +1,297 @@
|
||||
# Written in 2016 by Henrik Steffen Gaßmann <henrik@gassmann.onl>
|
||||
#
|
||||
# To the extent possible under law, the author(s) have dedicated all
|
||||
# copyright and related and neighboring rights to this software to the
|
||||
# public domain worldwide. This software is distributed without any warranty.
|
||||
#
|
||||
# You should have received a copy of the CC0 Public Domain Dedication
|
||||
# along with this software. If not, see
|
||||
#
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
#
|
||||
########################################################################
|
||||
# Tries to find the local libsodium installation.
|
||||
#
|
||||
# On Windows the sodium_DIR environment variable is used as a default
|
||||
# hint which can be overridden by setting the corresponding cmake variable.
|
||||
#
|
||||
# Once done the following variables will be defined:
|
||||
#
|
||||
# sodium_FOUND
|
||||
# sodium_INCLUDE_DIR
|
||||
# sodium_LIBRARY_DEBUG
|
||||
# sodium_LIBRARY_RELEASE
|
||||
#
|
||||
#
|
||||
# Furthermore an imported "sodium" target is created.
|
||||
#
|
||||
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU"
|
||||
OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(_GCC_COMPATIBLE 1)
|
||||
endif()
|
||||
|
||||
# static library option
|
||||
if (NOT DEFINED sodium_USE_STATIC_LIBS)
|
||||
option(sodium_USE_STATIC_LIBS "enable to statically link against sodium" OFF)
|
||||
endif()
|
||||
if(NOT (sodium_USE_STATIC_LIBS EQUAL sodium_USE_STATIC_LIBS_LAST))
|
||||
unset(sodium_LIBRARY CACHE)
|
||||
unset(sodium_LIBRARY_DEBUG CACHE)
|
||||
unset(sodium_LIBRARY_RELEASE CACHE)
|
||||
unset(sodium_DLL_DEBUG CACHE)
|
||||
unset(sodium_DLL_RELEASE CACHE)
|
||||
set(sodium_USE_STATIC_LIBS_LAST ${sodium_USE_STATIC_LIBS} CACHE INTERNAL "internal change tracking variable")
|
||||
endif()
|
||||
|
||||
|
||||
########################################################################
|
||||
# UNIX
|
||||
if (UNIX)
|
||||
# import pkg-config
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(sodium_PKG QUIET libsodium)
|
||||
endif()
|
||||
|
||||
if(sodium_USE_STATIC_LIBS)
|
||||
foreach(_libname ${sodium_PKG_STATIC_LIBRARIES})
|
||||
if (NOT _libname MATCHES "^lib.*\\.a$") # ignore strings already ending with .a
|
||||
list(INSERT sodium_PKG_STATIC_LIBRARIES 0 "lib${_libname}.a")
|
||||
endif()
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES sodium_PKG_STATIC_LIBRARIES)
|
||||
|
||||
# if pkgconfig for libsodium doesn't provide
|
||||
# static lib info, then override PKG_STATIC here..
|
||||
if (NOT sodium_PKG_STATIC_FOUND)
|
||||
set(sodium_PKG_STATIC_LIBRARIES libsodium.a)
|
||||
endif()
|
||||
|
||||
set(XPREFIX sodium_PKG_STATIC)
|
||||
else()
|
||||
if (NOT sodium_PKG_FOUND)
|
||||
set(sodium_PKG_LIBRARIES sodium)
|
||||
endif()
|
||||
|
||||
set(XPREFIX sodium_PKG)
|
||||
endif()
|
||||
|
||||
find_path(sodium_INCLUDE_DIR sodium.h
|
||||
HINTS ${${XPREFIX}_INCLUDE_DIRS}
|
||||
)
|
||||
find_library(sodium_LIBRARY_DEBUG NAMES ${${XPREFIX}_LIBRARIES}
|
||||
HINTS ${${XPREFIX}_LIBRARY_DIRS}
|
||||
)
|
||||
find_library(sodium_LIBRARY_RELEASE NAMES ${${XPREFIX}_LIBRARIES}
|
||||
HINTS ${${XPREFIX}_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
|
||||
########################################################################
|
||||
# Windows
|
||||
elseif (WIN32)
|
||||
set(sodium_DIR "$ENV{sodium_DIR}" CACHE FILEPATH "sodium install directory")
|
||||
mark_as_advanced(sodium_DIR)
|
||||
|
||||
find_path(sodium_INCLUDE_DIR sodium.h
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
# detect target architecture
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/arch.cpp" [=[
|
||||
#if defined _M_IX86
|
||||
#error ARCH_VALUE x86_32
|
||||
#elif defined _M_X64
|
||||
#error ARCH_VALUE x86_64
|
||||
#endif
|
||||
#error ARCH_VALUE unknown
|
||||
]=])
|
||||
try_compile(_UNUSED_VAR "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/arch.cpp"
|
||||
OUTPUT_VARIABLE _COMPILATION_LOG
|
||||
)
|
||||
string(REGEX REPLACE ".*ARCH_VALUE ([a-zA-Z0-9_]+).*" "\\1" _TARGET_ARCH "${_COMPILATION_LOG}")
|
||||
|
||||
# construct library path
|
||||
if (_TARGET_ARCH STREQUAL "x86_32")
|
||||
string(APPEND _PLATFORM_PATH "Win32")
|
||||
elseif(_TARGET_ARCH STREQUAL "x86_64")
|
||||
string(APPEND _PLATFORM_PATH "x64")
|
||||
else()
|
||||
message(FATAL_ERROR "the ${_TARGET_ARCH} architecture is not supported by Findsodium.cmake.")
|
||||
endif()
|
||||
string(APPEND _PLATFORM_PATH "/$$CONFIG$$")
|
||||
|
||||
if (MSVC_VERSION LESS 1900)
|
||||
math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 60")
|
||||
else()
|
||||
math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 50")
|
||||
endif()
|
||||
string(APPEND _PLATFORM_PATH "/v${_VS_VERSION}")
|
||||
|
||||
if (sodium_USE_STATIC_LIBS)
|
||||
string(APPEND _PLATFORM_PATH "/static")
|
||||
else()
|
||||
string(APPEND _PLATFORM_PATH "/dynamic")
|
||||
endif()
|
||||
|
||||
string(REPLACE "$$CONFIG$$" "Debug" _DEBUG_PATH_SUFFIX "${_PLATFORM_PATH}")
|
||||
string(REPLACE "$$CONFIG$$" "Release" _RELEASE_PATH_SUFFIX "${_PLATFORM_PATH}")
|
||||
|
||||
find_library(sodium_LIBRARY_DEBUG libsodium.lib
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}
|
||||
)
|
||||
find_library(sodium_LIBRARY_RELEASE libsodium.lib
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}
|
||||
)
|
||||
if (NOT sodium_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES_BCK ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll")
|
||||
find_library(sodium_DLL_DEBUG libsodium
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}
|
||||
)
|
||||
find_library(sodium_DLL_RELEASE libsodium
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}
|
||||
)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_BCK})
|
||||
endif()
|
||||
|
||||
elseif(_GCC_COMPATIBLE)
|
||||
if (sodium_USE_STATIC_LIBS)
|
||||
find_library(sodium_LIBRARY_DEBUG libsodium.a
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
find_library(sodium_LIBRARY_RELEASE libsodium.a
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
else()
|
||||
find_library(sodium_LIBRARY_DEBUG libsodium.dll.a
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
find_library(sodium_LIBRARY_RELEASE libsodium.dll.a
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
file(GLOB _DLL
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${sodium_DIR}/bin"
|
||||
"${sodium_DIR}/bin/libsodium*.dll"
|
||||
)
|
||||
find_library(sodium_DLL_DEBUG ${_DLL} libsodium
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES bin
|
||||
)
|
||||
find_library(sodium_DLL_RELEASE ${_DLL} libsodium
|
||||
HINTS ${sodium_DIR}
|
||||
PATH_SUFFIXES bin
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "this platform is not supported by FindSodium.cmake")
|
||||
endif()
|
||||
|
||||
|
||||
########################################################################
|
||||
# unsupported
|
||||
else()
|
||||
message(FATAL_ERROR "this platform is not supported by FindSodium.cmake")
|
||||
endif()
|
||||
|
||||
|
||||
########################################################################
|
||||
# common stuff
|
||||
|
||||
# extract sodium version
|
||||
if (sodium_INCLUDE_DIR)
|
||||
set(_VERSION_HEADER "${_INCLUDE_DIR}/sodium/version.h")
|
||||
if (EXISTS _VERSION_HEADER)
|
||||
file(READ "${_VERSION_HEADER}" _VERSION_HEADER_CONTENT)
|
||||
string(REGEX REPLACE ".*#[ \t]*define[ \t]*SODIUM_VERSION_STRING[ \t]*\"([^\n]*)\".*" "\\1"
|
||||
sodium_VERSION "${_VERSION_HEADER_CONTENT}")
|
||||
set(sodium_VERSION "${sodium_VERSION}" PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# communicate results
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
Sodium # The name must be either uppercase or match the filename case.
|
||||
REQUIRED_VARS
|
||||
sodium_LIBRARY_RELEASE
|
||||
sodium_LIBRARY_DEBUG
|
||||
sodium_INCLUDE_DIR
|
||||
VERSION_VAR
|
||||
sodium_VERSION
|
||||
)
|
||||
|
||||
if(Sodium_FOUND)
|
||||
set(sodium_LIBRARIES
|
||||
optimized ${sodium_LIBRARY_RELEASE} debug ${sodium_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# mark file paths as advanced
|
||||
mark_as_advanced(sodium_INCLUDE_DIR)
|
||||
mark_as_advanced(sodium_LIBRARY_DEBUG)
|
||||
mark_as_advanced(sodium_LIBRARY_RELEASE)
|
||||
if (WIN32)
|
||||
mark_as_advanced(sodium_DLL_DEBUG)
|
||||
mark_as_advanced(sodium_DLL_RELEASE)
|
||||
endif()
|
||||
|
||||
# create imported target
|
||||
if(sodium_USE_STATIC_LIBS)
|
||||
set(_LIB_TYPE STATIC)
|
||||
else()
|
||||
set(_LIB_TYPE SHARED)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET sodium)
|
||||
add_library(sodium ${_LIB_TYPE} IMPORTED)
|
||||
endif()
|
||||
|
||||
set_target_properties(sodium PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${sodium_INCLUDE_DIR}"
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
)
|
||||
|
||||
if (sodium_USE_STATIC_LIBS)
|
||||
set_target_properties(sodium PROPERTIES
|
||||
INTERFACE_COMPILE_DEFINITIONS "SODIUM_STATIC"
|
||||
IMPORTED_LOCATION "${sodium_LIBRARY_RELEASE}"
|
||||
IMPORTED_LOCATION_DEBUG "${sodium_LIBRARY_DEBUG}"
|
||||
)
|
||||
else()
|
||||
if (UNIX)
|
||||
set_target_properties(sodium PROPERTIES
|
||||
IMPORTED_LOCATION "${sodium_LIBRARY_RELEASE}"
|
||||
IMPORTED_LOCATION_DEBUG "${sodium_LIBRARY_DEBUG}"
|
||||
)
|
||||
elseif (WIN32)
|
||||
set_target_properties(sodium PROPERTIES
|
||||
IMPORTED_IMPLIB "${sodium_LIBRARY_RELEASE}"
|
||||
IMPORTED_IMPLIB_DEBUG "${sodium_LIBRARY_DEBUG}"
|
||||
)
|
||||
if (NOT (sodium_DLL_DEBUG MATCHES ".*-NOTFOUND"))
|
||||
set_target_properties(sodium PROPERTIES
|
||||
IMPORTED_LOCATION_DEBUG "${sodium_DLL_DEBUG}"
|
||||
)
|
||||
endif()
|
||||
if (NOT (sodium_DLL_RELEASE MATCHES ".*-NOTFOUND"))
|
||||
set_target_properties(sodium PROPERTIES
|
||||
IMPORTED_LOCATION_RELWITHDEBINFO "${sodium_DLL_RELEASE}"
|
||||
IMPORTED_LOCATION_MINSIZEREL "${sodium_DLL_RELEASE}"
|
||||
IMPORTED_LOCATION_RELEASE "${sodium_DLL_RELEASE}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
49
include/comm/curl/requests/http_post.hpp
Normal file
49
include/comm/curl/requests/http_post.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDE_COMM_CURL_CURL_REQUESTS_HTTP_POST_HPP_
|
||||
#define INCLUDE_COMM_CURL_CURL_REQUESTS_HTTP_POST_HPP_
|
||||
|
||||
#include "comm/curl/requests/http_request_base.hpp"
|
||||
|
||||
namespace repertory::curl::requests {
|
||||
struct http_post final : http_request_base {
|
||||
http_post() = default;
|
||||
http_post(const http_post &) = default;
|
||||
http_post(http_post &&) = default;
|
||||
auto operator=(const http_post &) -> http_post & = default;
|
||||
auto operator=(http_post &&) -> http_post & = default;
|
||||
|
||||
~http_post() override;
|
||||
|
||||
std::optional<nlohmann::json> json;
|
||||
|
||||
[[nodiscard]] auto set_method(CURL *curl,
|
||||
stop_type & /*stop_requested*/) const
|
||||
-> bool override;
|
||||
|
||||
private:
|
||||
mutable curl_slist *headers{nullptr};
|
||||
mutable std::optional<std::string> json_str;
|
||||
};
|
||||
} // namespace repertory::curl::requests
|
||||
|
||||
#endif // INCLUDE_COMM_CURL_CURL_REQUESTS_HTTP_POST_HPP_
|
246
include/database/db_common.hpp
Normal file
246
include/database/db_common.hpp
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDE_DATABASE_DB_COMMON_HPP_
|
||||
#define INCLUDE_DATABASE_DB_COMMON_HPP_
|
||||
|
||||
#include "utils/error_utils.hpp"
|
||||
|
||||
namespace repertory::db {
|
||||
using db_types_t = std::variant<std::int64_t, std::string>;
|
||||
|
||||
struct sqlite3_deleter {
|
||||
void operator()(sqlite3 *db3) {
|
||||
if (db3 != nullptr) {
|
||||
sqlite3_close_v2(db3);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using db3_t = std::unique_ptr<sqlite3, sqlite3_deleter>;
|
||||
|
||||
struct sqlite3_statement_deleter {
|
||||
void operator()(sqlite3_stmt *stmt) {
|
||||
if (stmt != nullptr) {
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using db3_stmt_t = std::unique_ptr<sqlite3_stmt, sqlite3_statement_deleter>;
|
||||
|
||||
struct comp_data_t final {
|
||||
std::string column_name;
|
||||
std::string op_type;
|
||||
db_types_t value;
|
||||
};
|
||||
|
||||
class db_column final {
|
||||
public:
|
||||
db_column() noexcept = default;
|
||||
db_column(const db_column &) = default;
|
||||
db_column(db_column &&column) noexcept = default;
|
||||
~db_column() = default;
|
||||
|
||||
auto operator=(const db_column &) -> db_column & = default;
|
||||
auto operator=(db_column &&) -> db_column & = default;
|
||||
|
||||
db_column(std::int32_t index, std::string name, db_types_t value) noexcept
|
||||
: index_(index), name_(std::move(name)), value_(std::move(value)) {}
|
||||
|
||||
private:
|
||||
std::int32_t index_{};
|
||||
std::string name_;
|
||||
db_types_t value_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto get_index() const -> std::int32_t { return index_; }
|
||||
|
||||
[[nodiscard]] auto get_name() const -> std::string { return name_; }
|
||||
|
||||
template <typename data_type>
|
||||
[[nodiscard]] auto get_value() const -> data_type {
|
||||
return std::visit(
|
||||
overloaded{
|
||||
[](const data_type &value) -> data_type { return value; },
|
||||
[](auto &&) -> data_type {
|
||||
throw std::runtime_error("data type not supported");
|
||||
},
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_value_as_json() const -> nlohmann::json {
|
||||
return std::visit(
|
||||
overloaded{
|
||||
[this](std::int64_t value) -> auto {
|
||||
return nlohmann::json({{name_, value}});
|
||||
},
|
||||
[](auto &&value) -> auto { return nlohmann::json::parse(value); },
|
||||
},
|
||||
value_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename context_t> class db_row final {
|
||||
public:
|
||||
db_row(std::shared_ptr<context_t> context) {
|
||||
auto column_count = sqlite3_column_count(context->stmt.get());
|
||||
for (std::int32_t col = 0; col < column_count; col++) {
|
||||
std::string name{sqlite3_column_name(context->stmt.get(), col)};
|
||||
auto column_type = sqlite3_column_type(context->stmt.get(), col);
|
||||
|
||||
db_types_t value;
|
||||
switch (column_type) {
|
||||
case SQLITE_INTEGER: {
|
||||
value = sqlite3_column_int64(context->stmt.get(), col);
|
||||
} break;
|
||||
|
||||
case SQLITE_TEXT: {
|
||||
const auto *text = reinterpret_cast<const char *>(
|
||||
sqlite3_column_text(context->stmt.get(), col));
|
||||
value = std::string(text == nullptr ? "" : text);
|
||||
} break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("column type not implemented|" + name + '|' +
|
||||
std::to_string(column_type));
|
||||
}
|
||||
|
||||
columns_[name] = db_column{col, name, value};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, db_column> columns_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto get_columns() const -> std::vector<db_column> {
|
||||
std::vector<db_column> ret;
|
||||
for (const auto &item : columns_) {
|
||||
ret.push_back(item.second);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_column(std::int32_t index) const -> db_column {
|
||||
auto iter = std::find_if(columns_.begin(), columns_.end(),
|
||||
[&index](auto &&col) -> bool {
|
||||
return col.second.get_index() == index;
|
||||
});
|
||||
if (iter == columns_.end()) {
|
||||
throw std::out_of_range("");
|
||||
}
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_column(std::string name) const -> db_column {
|
||||
return columns_.at(name);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename context_t> struct db_result final {
|
||||
db_result(std::shared_ptr<context_t> context, std::int32_t res)
|
||||
: context_(std::move(context)), res_(res) {
|
||||
constexpr const auto *function_name =
|
||||
static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
if (res == SQLITE_OK) {
|
||||
set_res(sqlite3_step(context_->stmt.get()), function_name);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<context_t> context_;
|
||||
mutable std::int32_t res_;
|
||||
|
||||
private:
|
||||
void set_res(std::int32_t res, std::string function) const {
|
||||
if (res != SQLITE_OK && res != SQLITE_DONE && res != SQLITE_ROW) {
|
||||
utils::error::raise_error(function, "failed to step|" +
|
||||
std::to_string(res) + '|' +
|
||||
sqlite3_errstr(res));
|
||||
}
|
||||
res_ = res;
|
||||
}
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto ok() const -> bool {
|
||||
return res_ == SQLITE_DONE || res_ == SQLITE_ROW;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_error() const -> std::int32_t { return res_; }
|
||||
|
||||
[[nodiscard]] auto get_error_str() const -> std::string {
|
||||
return sqlite3_errstr(res_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_row(std::optional<db_row<context_t>> &row) const
|
||||
-> bool {
|
||||
constexpr const auto *function_name =
|
||||
static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
row.reset();
|
||||
if (has_row()) {
|
||||
row = db_row{context_};
|
||||
set_res(sqlite3_step(context_->stmt.get()), function_name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto has_row() const -> bool { return res_ == SQLITE_ROW; }
|
||||
|
||||
void next_row() const {
|
||||
constexpr const auto *function_name =
|
||||
static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
if (has_row()) {
|
||||
set_res(sqlite3_step(context_->stmt.get()), function_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline void set_journal_mode(sqlite3 &db3) {
|
||||
sqlite3_exec(&db3, "PRAGMA journal_mode = WAL;", nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline auto execute_sql(sqlite3 &db3, const std::string &sql,
|
||||
std::string &err) -> bool {
|
||||
char *err_msg{nullptr};
|
||||
auto res = sqlite3_exec(&db3, sql.c_str(), nullptr, nullptr, &err_msg);
|
||||
if (err_msg != nullptr) {
|
||||
err = err_msg;
|
||||
sqlite3_free(err_msg);
|
||||
err_msg = nullptr;
|
||||
}
|
||||
if (res != SQLITE_OK) {
|
||||
err = "failed to execute sql|" + sql + "|" + std::to_string(res) + '|' +
|
||||
(err.empty() ? sqlite3_errstr(res) : err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace repertory::db
|
||||
|
||||
#endif // INCLUDE_DATABASE_DB_COMMON_HPP_
|
69
include/database/db_insert.hpp
Normal file
69
include/database/db_insert.hpp
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDE_DATABASE_DB_INSERT_HPP_
|
||||
#define INCLUDE_DATABASE_DB_INSERT_HPP_
|
||||
|
||||
#include "database/db_common.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
|
||||
namespace repertory::db {
|
||||
class db_insert final {
|
||||
public:
|
||||
struct context final {
|
||||
context(sqlite3 &db3_, std::string table_name_)
|
||||
: db3(db3_), table_name(std::move(table_name_)) {}
|
||||
|
||||
sqlite3 &db3;
|
||||
std::string table_name;
|
||||
|
||||
bool or_replace{false};
|
||||
std::map<std::string, db_types_t> values{};
|
||||
db3_stmt_t stmt{nullptr};
|
||||
};
|
||||
|
||||
using row = db_row<context>;
|
||||
|
||||
public:
|
||||
db_insert(sqlite3 &db3, std::string table_name)
|
||||
: context_(std::make_shared<context>(db3, table_name)) {}
|
||||
|
||||
db_insert(std::shared_ptr<context> ctx) : context_(std::move(ctx)) {}
|
||||
|
||||
private:
|
||||
std::shared_ptr<context> context_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto or_replace() -> db_insert & {
|
||||
context_->or_replace = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto column_value(std::string column_name, db_types_t value)
|
||||
-> db_insert &;
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
};
|
||||
} // namespace repertory::db
|
||||
|
||||
#endif // INCLUDE_DATABASE_DB_INSERT_HPP_
|
125
include/database/db_select.hpp
Normal file
125
include/database/db_select.hpp
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDE_DATABASE_DB_SELECT_HPP_
|
||||
#define INCLUDE_DATABASE_DB_SELECT_HPP_
|
||||
|
||||
#include "database/db_common.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
|
||||
namespace repertory::db {
|
||||
class db_select final {
|
||||
public:
|
||||
struct context final {
|
||||
context(sqlite3 &db3_, std::string table_name_)
|
||||
: db3(db3_), table_name(std::move(table_name_)) {}
|
||||
|
||||
sqlite3 &db3;
|
||||
std::string table_name;
|
||||
|
||||
std::vector<comp_data_t> ands{};
|
||||
std::vector<std::string> columns{};
|
||||
std::map<std::string, std::string> count_columns{};
|
||||
bool delete_query{false};
|
||||
std::optional<std::int32_t> limit;
|
||||
std::optional<std::pair<std::string, bool>> order_by;
|
||||
db3_stmt_t stmt{nullptr};
|
||||
};
|
||||
|
||||
using row = db_row<context>;
|
||||
|
||||
public:
|
||||
db_select(sqlite3 &db3, std::string table_name)
|
||||
: context_(std::make_shared<context>(db3, table_name)) {}
|
||||
|
||||
db_select(std::shared_ptr<context> ctx) : context_(std::move(ctx)) {}
|
||||
|
||||
public:
|
||||
struct db_where final {
|
||||
db_where(std::shared_ptr<context> ctx, std::string column_name)
|
||||
: context_(std::move(ctx)), column_name_(std::move(column_name)) {}
|
||||
|
||||
public:
|
||||
struct db_where_next final {
|
||||
db_where_next(std::shared_ptr<context> ctx) : context_(std::move(ctx)) {}
|
||||
|
||||
private:
|
||||
std::shared_ptr<context> context_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto and_where(std::string column_name) const -> db_where {
|
||||
return db_where{context_, column_name};
|
||||
}
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string {
|
||||
return db_select{context_}.dump();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context> {
|
||||
return db_select{context_}.go();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto limit(std::int32_t value) const -> db_select {
|
||||
return db_select{context_}.limit(value);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto order_by(std::string column_name, bool ascending) const
|
||||
-> db_select {
|
||||
return db_select{context_}.order_by(column_name, ascending);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<context> context_;
|
||||
std::string column_name_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto equals(db_types_t value) const -> db_where_next {
|
||||
context_->ands.emplace_back(comp_data_t{column_name_, "=", value});
|
||||
return db_where_next{context_};
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<context> context_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto column(std::string column_name) -> db_select &;
|
||||
|
||||
[[nodiscard]] auto count(std::string column_name, std::string as_column_name)
|
||||
-> db_select &;
|
||||
|
||||
[[nodiscard]] auto delete_query() -> db_select &;
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
|
||||
[[nodiscard]] auto limit(std::int32_t value) -> db_select &;
|
||||
|
||||
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
|
||||
-> db_select &;
|
||||
|
||||
[[nodiscard]] auto where(std::string column_name) const -> db_where;
|
||||
};
|
||||
} // namespace repertory::db
|
||||
|
||||
#endif // INCLUDE_DATABASE_DB_SELECT_HPP_
|
84
include/providers/meta_db.hpp
Normal file
84
include/providers/meta_db.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDE_PROVIDERS_META_DB_HPP_
|
||||
#define INCLUDE_PROVIDERS_META_DB_HPP_
|
||||
|
||||
#include "database/db_common.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class app_config;
|
||||
|
||||
class meta_db final {
|
||||
public:
|
||||
meta_db(const app_config &cfg);
|
||||
~meta_db();
|
||||
|
||||
meta_db(const meta_db &) = delete;
|
||||
meta_db(meta_db &&) = delete;
|
||||
auto operator=(const meta_db &) -> meta_db & = delete;
|
||||
auto operator=(meta_db &&) -> meta_db & = delete;
|
||||
|
||||
private:
|
||||
db::db3_t db_;
|
||||
constexpr static const auto table_name = "meta";
|
||||
|
||||
private:
|
||||
[[nodiscard]] auto update_item_meta(const std::string &api_path,
|
||||
api_meta_map meta) -> api_error;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto get_api_path(const std::string &source_path,
|
||||
std::string &api_path) -> api_error;
|
||||
|
||||
[[nodiscard]] auto get_api_path_list() -> std::vector<std::string>;
|
||||
|
||||
[[nodiscard]] auto get_item_meta(const std::string &api_path,
|
||||
api_meta_map &meta) -> api_error;
|
||||
|
||||
[[nodiscard]] auto get_item_meta(const std::string &api_path,
|
||||
const std::string &key,
|
||||
std::string &value) const -> api_error;
|
||||
|
||||
[[nodiscard]] auto get_pinned_files() const -> std::vector<std::string>;
|
||||
|
||||
[[nodiscard]] auto get_total_item_count() const -> std::uint64_t;
|
||||
|
||||
void remove_api_path(const std::string &api_path);
|
||||
|
||||
[[nodiscard]] auto remove_item_meta(const std::string &api_path,
|
||||
const std::string &key) -> api_error;
|
||||
|
||||
[[nodiscard]] auto rename_item_meta(const std::string &from_api_path,
|
||||
const std::string &to_api_path)
|
||||
-> api_error;
|
||||
|
||||
[[nodiscard]] auto set_item_meta(const std::string &api_path,
|
||||
const std::string &key,
|
||||
const std::string &value) -> api_error;
|
||||
|
||||
[[nodiscard]] auto set_item_meta(const std::string &api_path,
|
||||
const api_meta_map &meta) -> api_error;
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // INCLUDE_PROVIDERS_META_DB_HPP_
|
79
scripts/make_common.sh
Executable file
79
scripts/make_common.sh
Executable file
@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
|
||||
BUILD_TYPE=$1
|
||||
BUILD_CLEAN=$2
|
||||
IS_MINGW=$3
|
||||
|
||||
if [ "${BUILD_TYPE}" == "" ]; then
|
||||
BUILD_TYPE=Release
|
||||
fi
|
||||
|
||||
if [ "${IS_MINGW}" == "1" ]; then
|
||||
BUILD_ROOT=build2
|
||||
else
|
||||
BUILD_ROOT=build
|
||||
fi
|
||||
|
||||
BUILD_FOLDER=$(echo "${BUILD_TYPE}" | tr '[:upper:]' '[:lower:]')
|
||||
if [ "${BUILD_FOLDER}" == "release" ]; then
|
||||
BUILD_TYPE=Release
|
||||
fi
|
||||
|
||||
NUM_JOBS=${MY_NUM_JOBS}
|
||||
if [[ -z "${NUM_JOBS}" ]]; then
|
||||
NUM_JOBS=$(getconf _NPROCESSORS_ONLN 2> /dev/null || getconf NPROCESSORS_ONLN 2> /dev/null || echo 1)
|
||||
if [ "${NUM_JOBS}" -gt "2" ]; then
|
||||
NUM_JOBS=$(expr ${NUM_JOBS} - 2)
|
||||
elif [ "${NUM_JOBS}" -gt "1" ]; then
|
||||
NUM_JOBS=$(expr ${NUM_JOBS} - 1)
|
||||
fi
|
||||
fi
|
||||
echo "Job count: ${NUM_JOBS}"
|
||||
|
||||
pushd "$(dirname "$0")"
|
||||
mkdir -p ../${BUILD_ROOT}/${BUILD_FOLDER}
|
||||
|
||||
pushd ../${BUILD_ROOT}/${BUILD_FOLDER}
|
||||
|
||||
if [ "${IS_MINGW}" == "1" ]; then
|
||||
TOOLCHAIN=$(realpath /cmake_toolchain.cmake)
|
||||
CMAKE_ADDITIONAL_OPTS=-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN}
|
||||
fi
|
||||
|
||||
if [ "${IS_MINGW}" == "1" ]; then
|
||||
EXE_EXT=.exe
|
||||
fi
|
||||
|
||||
cmake ../.. ${CMAKE_ADDITIONAL_OPTS} \
|
||||
-G"Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DREPERTORY_ENABLE_S3=ON \
|
||||
-DREPERTORY_ENABLE_S3_TESTING=ON || exit 1
|
||||
|
||||
pushd ..
|
||||
ln -sf ${BUILD_FOLDER}/compile_commands.json .
|
||||
ln -sf ${BUILD_FOLDER}/repertory${EXE_EXT} .
|
||||
ln -sf ${BUILD_FOLDER}/unittests${EXE_EXT} .
|
||||
if [ "${IS_MINGW}" == "1" ]; then
|
||||
ln -sf ${BUILD_FOLDER}/winfsp-x64.dll .
|
||||
fi
|
||||
popd
|
||||
|
||||
if [ "${BUILD_CLEAN}" == "clean" ]; then
|
||||
make clean
|
||||
fi
|
||||
|
||||
make -j${NUM_JOBS} || exit 1
|
||||
popd
|
||||
|
||||
pushd ../${BUILD_ROOT}
|
||||
ln -sf ${BUILD_FOLDER}/compile_commands.json .
|
||||
ln -sf ${BUILD_FOLDER}/repertory${EXE_EXT} .
|
||||
ln -sf ${BUILD_FOLDER}/unittests${EXE_EXT} .
|
||||
if [ "${IS_MINGW}" == "1" ]; then
|
||||
ln -sf ${BUILD_FOLDER}/winfsp-x64.dll .
|
||||
fi
|
||||
popd
|
||||
|
||||
ln -sf ../3rd_party/cacert.pem ../${BUILD_ROOT}/cacert.pem
|
||||
popd
|
28
scripts/make_win32.sh
Executable file
28
scripts/make_win32.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
NUM_JOBS=${MY_NUM_JOBS}
|
||||
if [[ -z "${NUM_JOBS}" ]]; then
|
||||
NUM_JOBS=$(getconf _NPROCESSORS_ONLN 2> /dev/null || getconf NPROCESSORS_ONLN 2> /dev/null || echo 1)
|
||||
if [ "${NUM_JOBS}" -gt "2" ]; then
|
||||
NUM_JOBS=$(expr ${NUM_JOBS} - 2)
|
||||
elif [ "${NUM_JOBS}" -gt "1" ]; then
|
||||
NUM_JOBS=$(expr ${NUM_JOBS} - 1)
|
||||
fi
|
||||
fi
|
||||
|
||||
BUILD_TYPE=$1
|
||||
BUILD_CLEAN=$2
|
||||
|
||||
SOURCE_DIR=$(dirname "$0")/..
|
||||
SOURCE_DIR=$(realpath ${SOURCE_DIR})
|
||||
|
||||
NAME=mingw64
|
||||
BUILD_ARCH=64_bit
|
||||
|
||||
docker stop repertory_${NAME}
|
||||
docker rm repertory_${NAME}
|
||||
docker build --build-arg NUM_JOBS=${MY_NUM_JOBS} -t repertory:${NAME} - < ${SOURCE_DIR}/docker/${BUILD_ARCH}/${NAME} &&
|
||||
docker run -td -u $(id -u):$(id -g) --name repertory_${NAME} -w ${SOURCE_DIR} -v ${SOURCE_DIR}:${SOURCE_DIR}:rw,z repertory:${NAME} &&
|
||||
docker exec repertory_${NAME} /bin/bash -c "${SOURCE_DIR}/scripts/make_common.sh ${BUILD_TYPE} \"${BUILD_CLEAN}\" 1"
|
||||
docker stop repertory_${NAME}
|
||||
docker rm repertory_${NAME}
|
88
src/comm/curl/requests/http_post.cpp
Normal file
88
src/comm/curl/requests/http_post.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
<<<<<<< HEAD:include/utils/rocksdb_utils.hpp
|
||||
/*
|
||||
Copyright <2018-2023> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDE_UTILS_ROCKSDB_UTILS_HPP_
|
||||
#define INCLUDE_UTILS_ROCKSDB_UTILS_HPP_
|
||||
|
||||
namespace repertory {
|
||||
class app_config;
|
||||
|
||||
namespace utils::db {
|
||||
void create_rocksdb(const app_config &config, const std::string &name,
|
||||
std::unique_ptr<rocksdb::DB> &db);
|
||||
|
||||
void create_rocksdb(
|
||||
const app_config &config, const std::string &name,
|
||||
const std::vector<rocksdb::ColumnFamilyDescriptor> &families,
|
||||
std::vector<rocksdb::ColumnFamilyHandle *> &handles,
|
||||
std::unique_ptr<rocksdb::DB> &db);
|
||||
} // namespace utils::db
|
||||
} // namespace repertory
|
||||
|
||||
#endif // INCLUDE_UTILS_ROCKSDB_UTILS_HPP_
|
||||
=======
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "comm/curl/requests/http_post.hpp"
|
||||
|
||||
namespace repertory::curl::requests {
|
||||
http_post::~http_post() {
|
||||
if (headers != nullptr) {
|
||||
curl_slist_free_all(headers);
|
||||
}
|
||||
}
|
||||
|
||||
auto http_post::set_method(CURL *curl, stop_type & /*stop_requested*/) const
|
||||
-> bool {
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
|
||||
if (json.has_value()) {
|
||||
headers = curl_slist_append(headers, "content-type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
json_str = json->dump();
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_str->c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace repertory::curl::requests
|
||||
>>>>>>> 9b453327a81e182a9ec87ef1aae13169516436e0:src/comm/curl/requests/http_post.cpp
|
98
src/database/db_insert.cpp
Normal file
98
src/database/db_insert.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "database/db_insert.hpp"
|
||||
|
||||
namespace repertory::db {
|
||||
auto db_insert::column_value(std::string column_name, db_types_t value)
|
||||
-> db_insert & {
|
||||
context_->values[column_name] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_insert::dump() const -> std::string {
|
||||
std::stringstream query;
|
||||
query << "INSERT ";
|
||||
if (context_->or_replace) {
|
||||
query << "OR REPLACE ";
|
||||
}
|
||||
query << "INTO \"" << context_->table_name << "\" (";
|
||||
|
||||
for (std::int32_t idx = 0;
|
||||
idx < static_cast<std::int32_t>(context_->values.size()); idx++) {
|
||||
if (idx > 0) {
|
||||
query << ", ";
|
||||
}
|
||||
query << '"' << std::next(context_->values.begin(), idx)->first << '"';
|
||||
}
|
||||
|
||||
query << ") VALUES (";
|
||||
for (std::int32_t idx = 0;
|
||||
idx < static_cast<std::int32_t>(context_->values.size()); idx++) {
|
||||
if (idx > 0) {
|
||||
query << ", ";
|
||||
}
|
||||
query << "?" << (idx + 1);
|
||||
}
|
||||
query << ");";
|
||||
|
||||
return query.str();
|
||||
}
|
||||
|
||||
auto db_insert::go() const -> db_result<context> {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
sqlite3_stmt *stmt_ptr{nullptr};
|
||||
auto query_str = dump();
|
||||
auto res = sqlite3_prepare_v2(&context_->db3, query_str.c_str(), -1,
|
||||
&stmt_ptr, nullptr);
|
||||
if (res != SQLITE_OK) {
|
||||
utils::error::raise_error(function_name, "failed to prepare|" +
|
||||
std::to_string(res) + '|' +
|
||||
sqlite3_errstr(res));
|
||||
return {context_, res};
|
||||
}
|
||||
context_->stmt.reset(stmt_ptr);
|
||||
|
||||
for (std::int32_t idx = 0;
|
||||
idx < static_cast<std::int32_t>(context_->values.size()); idx++) {
|
||||
res = std::visit(
|
||||
overloaded{
|
||||
[this, &idx](std::int64_t data) -> std::int32_t {
|
||||
return sqlite3_bind_int64(context_->stmt.get(), idx + 1, data);
|
||||
},
|
||||
[this, &idx](const std::string &data) -> std::int32_t {
|
||||
return sqlite3_bind_text(context_->stmt.get(), idx + 1,
|
||||
data.c_str(), -1, nullptr);
|
||||
},
|
||||
},
|
||||
std::next(context_->values.begin(), idx)->second);
|
||||
if (res != SQLITE_OK) {
|
||||
utils::error::raise_error(function_name, "failed to bind|" +
|
||||
std::to_string(res) + '|' +
|
||||
sqlite3_errstr(res));
|
||||
return {context_, res};
|
||||
}
|
||||
}
|
||||
|
||||
return {context_, res};
|
||||
}
|
||||
} // namespace repertory::db
|
175
src/database/db_select.cpp
Normal file
175
src/database/db_select.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "database/db_select.hpp"
|
||||
|
||||
namespace repertory::db {
|
||||
|
||||
auto db_select::column(std::string column_name) -> db_select & {
|
||||
if (context_->delete_query) {
|
||||
throw std::runtime_error("columns may not be specified for delete");
|
||||
}
|
||||
|
||||
context_->columns.push_back(column_name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_select::count(std::string column_name, std::string as_column_name)
|
||||
-> db_select & {
|
||||
context_->count_columns[column_name] = as_column_name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_select::delete_query() -> db_select & {
|
||||
if (not context_->columns.empty()) {
|
||||
throw std::runtime_error("columns must be empty for delete");
|
||||
}
|
||||
|
||||
context_->delete_query = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_select::dump() const -> std::string {
|
||||
std::stringstream query;
|
||||
query << (context_->delete_query ? "DELETE " : "SELECT ");
|
||||
if (not context_->delete_query) {
|
||||
bool has_column{false};
|
||||
if (context_->columns.empty()) {
|
||||
if (context_->count_columns.empty()) {
|
||||
query << "*";
|
||||
has_column = true;
|
||||
}
|
||||
} else {
|
||||
has_column = not context_->columns.empty();
|
||||
for (std::size_t idx = 0U; idx < context_->columns.size(); idx++) {
|
||||
if (idx > 0U) {
|
||||
query << ", ";
|
||||
}
|
||||
query << context_->columns.at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::int32_t idx = 0U;
|
||||
idx < static_cast<std::int32_t>(context_->count_columns.size());
|
||||
idx++) {
|
||||
if (has_column || idx > 0) {
|
||||
query << ", ";
|
||||
}
|
||||
query << "COUNT(\"";
|
||||
auto &count_column = *std::next(context_->count_columns.begin(), idx);
|
||||
query << count_column.first << "\") AS \"" << count_column.second << '"';
|
||||
}
|
||||
}
|
||||
query << " FROM \"" << context_->table_name << "\"";
|
||||
|
||||
if (not context_->ands.empty()) {
|
||||
query << " WHERE (";
|
||||
for (std::int32_t idx = 0;
|
||||
idx < static_cast<std::int32_t>(context_->ands.size()); idx++) {
|
||||
if (idx > 0) {
|
||||
query << " AND ";
|
||||
}
|
||||
|
||||
auto &item = context_->ands.at(static_cast<std::size_t>(idx));
|
||||
query << '"' << item.column_name << '"' << item.op_type << "?"
|
||||
<< (idx + 1);
|
||||
}
|
||||
query << ")";
|
||||
}
|
||||
|
||||
if (not context_->delete_query) {
|
||||
if (context_->order_by.has_value()) {
|
||||
query << " ORDER BY \"" << context_->order_by.value().first << "\" ";
|
||||
query << (context_->order_by.value().second ? "ASC" : "DESC");
|
||||
}
|
||||
|
||||
if (context_->limit.has_value()) {
|
||||
query << " LIMIT " << context_->limit.value();
|
||||
}
|
||||
}
|
||||
|
||||
query << ';';
|
||||
|
||||
return query.str();
|
||||
}
|
||||
|
||||
auto db_select::go() const -> db_result<context> {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
sqlite3_stmt *stmt_ptr{nullptr};
|
||||
auto query_str = dump();
|
||||
auto res = sqlite3_prepare_v2(&context_->db3, query_str.c_str(), -1,
|
||||
&stmt_ptr, nullptr);
|
||||
if (res != SQLITE_OK) {
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to prepare|" + std::to_string(res) + '|' +
|
||||
sqlite3_errstr(res) + '|' + query_str);
|
||||
return {context_, res};
|
||||
}
|
||||
context_->stmt.reset(stmt_ptr);
|
||||
|
||||
for (std::int32_t idx = 0;
|
||||
idx < static_cast<std::int32_t>(context_->ands.size()); idx++) {
|
||||
res = std::visit(
|
||||
overloaded{
|
||||
[this, &idx](std::int64_t data) -> std::int32_t {
|
||||
return sqlite3_bind_int64(context_->stmt.get(), idx + 1, data);
|
||||
},
|
||||
[this, &idx](const std::string &data) -> std::int32_t {
|
||||
return sqlite3_bind_text(context_->stmt.get(), idx + 1,
|
||||
data.c_str(), -1, nullptr);
|
||||
},
|
||||
},
|
||||
context_->ands.at(static_cast<std::size_t>(idx)).value);
|
||||
if (res != SQLITE_OK) {
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to bind|" + std::to_string(res) + '|' +
|
||||
sqlite3_errstr(res) + '|' + query_str);
|
||||
return {context_, res};
|
||||
}
|
||||
}
|
||||
|
||||
return {context_, res};
|
||||
}
|
||||
|
||||
auto db_select::limit(std::int32_t value) -> db_select & {
|
||||
if (context_->delete_query) {
|
||||
throw std::runtime_error("limit may not be specified for delete");
|
||||
}
|
||||
|
||||
context_->limit = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_select::order_by(std::string column_name, bool ascending)
|
||||
-> db_select & {
|
||||
if (context_->delete_query) {
|
||||
throw std::runtime_error("order_by may not be specified for delete");
|
||||
}
|
||||
|
||||
context_->order_by = {column_name, ascending};
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_select::where(std::string column_name) const -> db_where {
|
||||
return db_where{context_, column_name};
|
||||
}
|
||||
} // namespace repertory::db
|
315
src/providers/meta_db.cpp
Normal file
315
src/providers/meta_db.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "providers/meta_db.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "database/db_common.hpp"
|
||||
#include "database/db_insert.hpp"
|
||||
#include "database/db_select.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
meta_db::meta_db(const app_config &cfg) {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
auto db_path = utils::path::combine(cfg.get_data_directory(), {"meta.db3"});
|
||||
|
||||
sqlite3 *db3{nullptr};
|
||||
auto res =
|
||||
sqlite3_open_v2(db_path.c_str(), &db3,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr);
|
||||
if (res != SQLITE_OK) {
|
||||
utils::error::raise_error(function_name, "failed to open db|" + db_path +
|
||||
'|' + std::to_string(res) +
|
||||
'|' + sqlite3_errstr(res));
|
||||
return;
|
||||
}
|
||||
db_.reset(db3);
|
||||
|
||||
const auto *create = "CREATE TABLE IF NOT EXISTS "
|
||||
"meta "
|
||||
"("
|
||||
"api_path TEXT PRIMARY KEY ASC, "
|
||||
"data TEXT, "
|
||||
"directory INTEGER, "
|
||||
"pinned INTEGER, "
|
||||
"source_path TEXT"
|
||||
");";
|
||||
std::string err;
|
||||
if (not db::execute_sql(*db_, create, err)) {
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to create db|" + db_path + '|' + err);
|
||||
db_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
db::set_journal_mode(*db_);
|
||||
}
|
||||
|
||||
meta_db::~meta_db() { db_.reset(); }
|
||||
|
||||
auto meta_db::get_api_path(const std::string &source_path,
|
||||
std::string &api_path) -> api_error {
|
||||
auto result = db::db_select{*db_, table_name}
|
||||
.column("api_path")
|
||||
.where("source_path")
|
||||
.equals(source_path)
|
||||
.limit(1)
|
||||
.go();
|
||||
|
||||
std::optional<db::db_select::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
api_path = row->get_column("api_path").get_value<std::string>();
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
|
||||
auto meta_db::get_api_path_list() -> std::vector<std::string> {
|
||||
std::vector<std::string> ret{};
|
||||
|
||||
auto result = db::db_select{*db_, table_name}.column("api_path").go();
|
||||
while (result.has_row()) {
|
||||
std::optional<db::db_select::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
ret.push_back(row->get_column("api_path").get_value<std::string>());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto meta_db::get_item_meta(const std::string &api_path, api_meta_map &meta)
|
||||
-> api_error {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
auto result = db::db_select{*db_, table_name}
|
||||
.column("*")
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.limit(1)
|
||||
.go();
|
||||
if (not result.has_row()) {
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
|
||||
try {
|
||||
std::optional<db::db_select::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
meta = json::parse(row->get_column("data").get_value<std::string>())
|
||||
.get<api_meta_map>();
|
||||
meta[META_DIRECTORY] = utils::string::from_bool(
|
||||
row->get_column("directory").get_value<std::int64_t>() == 1);
|
||||
meta[META_PINNED] = utils::string::from_bool(
|
||||
row->get_column("pinned").get_value<std::int64_t>() == 1);
|
||||
meta[META_SOURCE] =
|
||||
row->get_column("source_path").get_value<std::string>();
|
||||
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
return api_error::item_not_found;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_api_path_error(function_name, api_path, e,
|
||||
"failed to get item meta");
|
||||
}
|
||||
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
auto meta_db::get_item_meta(const std::string &api_path, const std::string &key,
|
||||
std::string &value) const -> api_error {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
auto result = db::db_select{*db_, table_name}
|
||||
.column("*")
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.limit(1)
|
||||
.go();
|
||||
if (not result.has_row()) {
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
|
||||
try {
|
||||
std::optional<db::db_select::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
value =
|
||||
key == META_SOURCE
|
||||
? row->get_column("source_path").get_value<std::string>()
|
||||
: key == META_PINNED
|
||||
? utils::string::from_bool(
|
||||
row->get_column("pinned").get_value<std::int64_t>() == 1)
|
||||
: key == META_DIRECTORY
|
||||
? utils::string::from_bool(
|
||||
row->get_column("directory").get_value<std::int64_t>() == 1)
|
||||
: json::parse(
|
||||
row->get_column("data").get_value<std::string>())[key]
|
||||
.get<std::string>();
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
return api_error::item_not_found;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_api_path_error(function_name, api_path, e,
|
||||
"failed to get item meta");
|
||||
}
|
||||
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
auto meta_db::get_pinned_files() const -> std::vector<std::string> {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
std::vector<std::string> ret{};
|
||||
|
||||
try {
|
||||
auto result = db::db_select{*db_, table_name}
|
||||
.column("api_path")
|
||||
.where("pinned")
|
||||
.equals(1)
|
||||
.go();
|
||||
while (result.has_row()) {
|
||||
std::optional<db::db_select::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
ret.emplace_back(row->get_column("api_path").get_value<std::string>());
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_error(function_name, e, "failed to get pinned files");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto meta_db::get_total_item_count() const -> std::uint64_t {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
std::uint64_t ret{};
|
||||
|
||||
try {
|
||||
auto result =
|
||||
db::db_select{*db_, table_name}.count("api_path", "count").go();
|
||||
|
||||
std::optional<db::db_select::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
ret = static_cast<std::uint64_t>(
|
||||
row->get_column("count").get_value<std::int64_t>());
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_error(function_name, e,
|
||||
"failed to get total item count");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void meta_db::remove_api_path(const std::string &api_path) {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
auto result = db::db_select{*db_, table_name}
|
||||
.delete_query()
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
if (not result.ok()) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, api_path, result.get_error(), "failed to remove meta");
|
||||
}
|
||||
}
|
||||
|
||||
auto meta_db::remove_item_meta(const std::string &api_path,
|
||||
const std::string &key) -> api_error {
|
||||
api_meta_map meta{};
|
||||
auto res = get_item_meta(api_path, meta);
|
||||
if (res != api_error::success) {
|
||||
return res;
|
||||
}
|
||||
|
||||
meta.erase(key);
|
||||
return update_item_meta(api_path, meta);
|
||||
}
|
||||
|
||||
auto meta_db::rename_item_meta(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> api_error {
|
||||
api_meta_map meta{};
|
||||
auto res = get_item_meta(from_api_path, meta);
|
||||
if (res != api_error::success) {
|
||||
return res;
|
||||
}
|
||||
remove_api_path(from_api_path);
|
||||
|
||||
return update_item_meta(to_api_path, meta);
|
||||
}
|
||||
|
||||
auto meta_db::set_item_meta(const std::string &api_path, const std::string &key,
|
||||
const std::string &value) -> api_error {
|
||||
return set_item_meta(api_path, {{key, value}});
|
||||
}
|
||||
|
||||
auto meta_db::set_item_meta(const std::string &api_path,
|
||||
const api_meta_map &meta) -> api_error {
|
||||
api_meta_map existing_meta{};
|
||||
if (get_item_meta(api_path, existing_meta) != api_error::success) {
|
||||
// TODO handle error
|
||||
}
|
||||
|
||||
for (const auto &item : meta) {
|
||||
existing_meta[item.first] = item.second;
|
||||
}
|
||||
|
||||
return update_item_meta(api_path, existing_meta);
|
||||
}
|
||||
|
||||
auto meta_db::update_item_meta(const std::string &api_path, api_meta_map meta)
|
||||
-> api_error {
|
||||
constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__);
|
||||
|
||||
auto directory = utils::string::to_bool(meta[META_DIRECTORY]);
|
||||
auto pinned = utils::string::to_bool(meta[META_PINNED]);
|
||||
auto source_path = meta[META_SOURCE];
|
||||
|
||||
meta.erase(META_DIRECTORY);
|
||||
meta.erase(META_PINNED);
|
||||
meta.erase(META_SOURCE);
|
||||
|
||||
auto result = db::db_insert{*db_, table_name}
|
||||
.or_replace()
|
||||
.column_value("api_path", api_path)
|
||||
.column_value("data", nlohmann::json(meta).dump())
|
||||
.column_value("directory", directory ? 1 : 0)
|
||||
.column_value("pinned", pinned ? 1 : 0)
|
||||
.column_value("source_path", source_path)
|
||||
.go();
|
||||
if (not result.ok()) {
|
||||
utils::error::raise_api_path_error(function_name, api_path,
|
||||
result.get_error(),
|
||||
"failed to update item meta");
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
return api_error::success;
|
||||
}
|
||||
} // namespace repertory
|
124
tests/database_test.cpp
Normal file
124
tests/database_test.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "database/db_common.hpp"
|
||||
#include "database/db_insert.hpp"
|
||||
#include "database/db_select.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(database, db_insert) {
|
||||
console_consumer consumer1;
|
||||
event_system::instance().start();
|
||||
{
|
||||
db::db3_t db3;
|
||||
{
|
||||
sqlite3 *db3_ptr{nullptr};
|
||||
auto res = sqlite3_open_v2(
|
||||
utils::path::absolute(
|
||||
utils::path::combine(get_test_dir(), {"test.db3"}))
|
||||
.c_str(),
|
||||
&db3_ptr, SQLITE_OPEN_READWRITE, nullptr);
|
||||
ASSERT_EQ(SQLITE_OK, res);
|
||||
ASSERT_TRUE(db3_ptr != nullptr);
|
||||
|
||||
db3.reset(db3_ptr);
|
||||
}
|
||||
|
||||
auto query = db::db_insert{*db3.get(), "table"}
|
||||
.column_value("column1", "test9")
|
||||
.column_value("column2", "test9");
|
||||
auto query_str = query.dump();
|
||||
std::cout << query_str << std::endl;
|
||||
EXPECT_STREQ(
|
||||
R"(INSERT INTO "table" ("column1", "column2") VALUES (?1, ?2);)",
|
||||
query_str.c_str());
|
||||
|
||||
query = db::db_insert{*db3.get(), "table"}
|
||||
.or_replace()
|
||||
.column_value("column1", "test1")
|
||||
.column_value("column2", "test2");
|
||||
query_str = query.dump();
|
||||
std::cout << query_str << std::endl;
|
||||
EXPECT_STREQ(
|
||||
R"(INSERT OR REPLACE INTO "table" ("column1", "column2") VALUES (?1, ?2);)",
|
||||
query_str.c_str());
|
||||
|
||||
auto res = query.go();
|
||||
EXPECT_TRUE(res.ok());
|
||||
EXPECT_FALSE(res.has_row());
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(database, db_select) {
|
||||
console_consumer consumer1;
|
||||
event_system::instance().start();
|
||||
{
|
||||
db::db3_t db3;
|
||||
{
|
||||
sqlite3 *db3_ptr{nullptr};
|
||||
auto res = sqlite3_open_v2(
|
||||
utils::path::combine(get_test_dir(), {"test.db3"}).c_str(), &db3_ptr,
|
||||
SQLITE_OPEN_READWRITE, nullptr);
|
||||
ASSERT_EQ(SQLITE_OK, res);
|
||||
ASSERT_TRUE(db3_ptr != nullptr);
|
||||
|
||||
db3.reset(db3_ptr);
|
||||
}
|
||||
|
||||
auto query = db::db_select{*db3.get(), "table"}
|
||||
.where("column1")
|
||||
.equals("test1")
|
||||
.and_where("column2")
|
||||
.equals("test2");
|
||||
auto query_str = query.dump();
|
||||
std::cout << query_str << std::endl;
|
||||
EXPECT_STREQ(
|
||||
R"(SELECT * FROM "table" WHERE ("column1"=?1 AND "column2"=?2);)",
|
||||
query_str.c_str());
|
||||
auto res = query.go();
|
||||
|
||||
EXPECT_TRUE(res.ok());
|
||||
EXPECT_TRUE(res.has_row());
|
||||
std::size_t row_count{};
|
||||
while (res.has_row()) {
|
||||
std::optional<db::db_select::row> row;
|
||||
EXPECT_TRUE(res.get_row(row));
|
||||
EXPECT_TRUE(row.has_value());
|
||||
if (row.has_value()) {
|
||||
for (const auto &column : row.value().get_columns()) {
|
||||
std::cout << column.get_index() << ':';
|
||||
std::cout << column.get_name() << ':';
|
||||
std::cout << column.get_value<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
++row_count;
|
||||
}
|
||||
EXPECT_EQ(std::size_t(1U), row_count);
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
} // namespace repertory
|
Loading…
x
Reference in New Issue
Block a user