tv_rename/sqlitepp.hpp

264 lines
8.4 KiB
C++

#ifndef SQLITEPP
#define SQLITEPP
#include <iostream>
#include <unordered_map>
#include <vector>
#ifndef WIN32
#include <sqlite3.h>
#else
#include "sqlite-amalgamation/sqlite3.h"
#include <codecvt>
#include <shlobj.h>
std::string _w_2_8( const std::wstring &wstring ) {
std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > wconv;
return wconv.to_bytes( wstring );
}
std::wstring _8_2_w( const std::string &utf8 ) {
std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > wconv;
return wconv.from_bytes( utf8 );
}
#endif
// TODO maybe split this into hpp/cpp
namespace SQLite {
constexpr size_t OPEN_READONLY = 0x00000001;
constexpr size_t OPEN_READWRITE = 0x00000002;
constexpr size_t OPEN_CREATE = 0x00000004;
constexpr size_t OPEN_URI = 0x00000040;
constexpr size_t OPEN_MEMORY = 0x00000080;
constexpr size_t OPEN_NOMUTEX = 0x00008000;
constexpr size_t OPEN_FULLMUTEX = 0x00010000;
constexpr size_t OPEN_SHAREDCACHE = 0x00020000;
constexpr size_t OPEN_PRIVATECACHE = 0x00040000;
class Database {
public:
Database() {}
Database( const std::string &file, size_t options ) {
open( file, options );
}
#ifdef WIN32
Database( const std::wstring &file, size_t options ) {
open( file, options );
}
#endif
~Database() {
close();
}
void open( const std::string &file, size_t options ) {
if ( sqlite3_open_v2( file.c_str(), &db, options, nullptr ) ) {
throw std::runtime_error( "Could not open database " + file );
}
}
#ifdef WIN32
void open( const std::wstring &file, size_t options ) {
if ( sqlite3_open_v2( _w_2_8( file ).c_str(), &db, options,
nullptr ) ) {
throw std::runtime_error( "Could not open database " +
_w_2_8( file ) );
}
}
#endif
// execute command without output
void exec( const std::string &command ) {
char *errMsg = nullptr;
int rc = sqlite3_exec( db, command.c_str(), nullptr, nullptr, &errMsg );
if ( rc )
throw std::runtime_error( "\"" + command +
"\" resulted in an error:\n" + errMsg );
sqlite3_free( errMsg );
}
#ifdef WIN32
void exec( const std::wstring &command ) {
char *errMsg = nullptr;
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), nullptr, nullptr,
&errMsg );
if ( rc )
throw std::runtime_error( "\"" + _w_2_8( command ) +
"\" resulted in an error:\n" + errMsg );
sqlite3_free( errMsg );
}
#endif
// execute command that should only output 1 result
void exec( const std::string &command, std::string &output ) {
char *errMsg = nullptr;
int rc = sqlite3_exec( db, command.c_str(), insert_val_s,
static_cast< void * >( &output ), &errMsg );
if ( rc )
throw std::runtime_error( "\"" + command +
"\" resulted in an error:\n" + errMsg );
sqlite3_free( errMsg );
}
#ifdef WIN32
void exec( const std::wstring &command, std::wstring &output ) {
char *errMsg = nullptr;
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_val_ws,
static_cast< void * >( &output ), &errMsg );
if ( rc )
throw std::runtime_error( "\"" + _w_2_8( command ) +
"\" resulted in an error:\n" + errMsg );
sqlite3_free( errMsg );
}
#endif
// didn't work with set for some reason, so only vector is allowed
void exec( const std::string &command,
std::vector< std::unordered_map< std::string, std::string > >
&object ) {
char *errMsg = nullptr;
int rc = sqlite3_exec( db, command.c_str(), insert_col_val,
static_cast< void * >( &object ), &errMsg );
if ( rc )
throw std::runtime_error( "\"" + command +
"\" resulted in an error:\n" + errMsg );
sqlite3_free( errMsg );
}
#ifdef WIN32
// didn't work with set for some reason, so only vector is allowed
void exec( const std::wstring &command,
std::vector< std::unordered_map< std::wstring, std::wstring > >
&object ) {
char *errMsg = nullptr;
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_col_val_w,
static_cast< void * >( &object ), &errMsg );
if ( rc )
throw std::runtime_error( "\"" + _w_2_8( command ) +
"\" resulted in an error:\n" + errMsg );
sqlite3_free( errMsg );
}
#endif
// execute command with output and store output in object (store only
// values) object can by any container as long as it's template is
// 'std::string'
template < typename V > void exec( const std::string &command, V &object ) {
char *errMsg = nullptr;
int rc = sqlite3_exec( db, command.c_str(), insert_val< V >,
static_cast< void * >( &object ), &errMsg );
if ( rc )
throw std::runtime_error( "\"" + command +
"\" resulted in an error:\n" + errMsg );
sqlite3_free( errMsg );
}
#ifdef WIN32
template < typename V >
void exec( const std::wstring &command, V &object ) {
char *errMsg = nullptr;
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_val_w< V >,
static_cast< void * >( &object ), &errMsg );
if ( rc )
throw std::runtime_error( "\"" + _w_2_8( command ) +
"\" resulted in an error:\n" + errMsg );
sqlite3_free( errMsg );
}
#endif
void close() {
sqlite3_close( db );
}
int64_t lastRowID() {
return sqlite3_last_insert_rowid( db );
}
private:
sqlite3 *db;
static int insert_col_val( void *d, int argc, char **argv,
char **azColName ) {
auto &data = *static_cast<
std::vector< std::unordered_map< std::string, std::string > > * >(
d );
std::unordered_map< std::string, std::string > buffer;
for ( int i = 0; i < argc; i++ ) {
// insert all columns and values into 'data'
buffer[azColName[i]] = argv[i] ? argv[i] : "";
}
data.insert( data.end(), std::move( buffer ) );
return 0;
}
#ifdef WIN32
static int insert_col_val_w( void *d, int argc, char **argv,
char **azColName ) {
auto &data = *static_cast<
std::vector< std::unordered_map< std::wstring, std::wstring > > * >(
d );
std::unordered_map< std::wstring, std::wstring > buffer;
for ( int i = 0; i < argc; i++ ) {
// insert all columns and values into 'data'
buffer[_8_2_w( azColName[i] )] = argv[i] ? _8_2_w( argv[i] ) : L"";
}
data.insert( data.end(), std::move( buffer ) );
return 0;
}
#endif
static int insert_val_s( void *d, int argc, char **argv,
char ** /*UNUSED*/ ) {
if ( argc > 0 )
*static_cast< std::string * >( d ) = argv[0] ? argv[0] : "";
return 0;
}
#ifdef WIN32
static int insert_val_ws( void *d, int argc, char **argv,
char ** /*UNUSED*/ ) {
if ( argc > 0 ) {
*static_cast< std::wstring * >( d ) =
argv[0] ? _8_2_w( argv[0] ) : L"";
}
return 0;
}
#endif
template < typename V >
static int insert_val( void *d, int argc, char **argv,
char ** /*UNUSED*/ ) {
auto &data = *static_cast< V * >( d );
for ( int i = 0; i < argc; i++ ) {
// insert all values into 'data'
data.insert( data.end(), argv[i] ? argv[i] : "" );
}
return 0;
}
#ifdef WIN32
template < typename V >
static int insert_val_w( void *d, int argc, char **argv,
char ** /*UNUSED*/ ) {
auto &data = *static_cast< V * >( d );
for ( int i = 0; i < argc; i++ ) {
// insert all values into 'data'
data.insert( data.end(), argv[i] ? _8_2_w( argv[i] ) : L"" );
}
return 0;
}
#endif
};
} // namespace SQLite
#endif