mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-28 23:27:45 +00:00
add migration functionality to dbm
This commit is contained in:
parent
19e325dcba
commit
ee924160be
6 changed files with 237 additions and 10 deletions
|
@ -602,3 +602,8 @@ CREATE TABLE `charamonsternote` (
|
|||
`UPDATE_DATE` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY(`CharacterId`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
CREATE TABLE `__Migration` (
|
||||
`MigrationName` VARCHAR(250) NOT NULL,
|
||||
PRIMARY KEY (`MigrationName`)
|
||||
) ENGINE=InnoDB;
|
||||
|
|
|
@ -141,3 +141,15 @@ void Util::valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t&
|
|||
outVal = 1 << bitIndex;
|
||||
}
|
||||
|
||||
|
||||
std::string Util::fmtUtcTime( const std::string& fmt )
|
||||
{
|
||||
auto t = std::time( nullptr );
|
||||
auto tm = std::gmtime( &t );
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
ss << std::put_time( tm, fmt.c_str() );
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace Sapphire::Common::Util
|
|||
|
||||
std::string toLowerCopy( const std::string& inStr );
|
||||
|
||||
std::string fmtUtcTime( const std::string& fmt );
|
||||
|
||||
uint64_t getTimeMs();
|
||||
|
||||
/*!
|
||||
|
|
|
@ -4,6 +4,15 @@
|
|||
#include <fstream>
|
||||
#include <streambuf>
|
||||
#include <sstream>
|
||||
#include <Logging/Logger.h>
|
||||
#include <experimental/filesystem>
|
||||
|
||||
#include <common/Util/Util.h>
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::Common;
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
DbManager::DbManager( const std::string& host, const std::string& database, const std::string& user, const std::string& pw, uint16_t port ) :
|
||||
m_host( host ),
|
||||
|
@ -107,9 +116,14 @@ bool DbManager::performAction()
|
|||
case Mode::LIQUIDATE:
|
||||
result = modeLiquidate();
|
||||
break;
|
||||
case Mode::UPDATE:
|
||||
case Mode::MIGRATE:
|
||||
result = modeMigrate();
|
||||
break;
|
||||
case Mode::CHECK:
|
||||
result = modeCheck();
|
||||
break;
|
||||
case Mode::ADD_MIGRATION:
|
||||
result = modeAddMigration();
|
||||
break;
|
||||
case Mode::CLEAN_CHARS:
|
||||
break;
|
||||
|
@ -195,8 +209,8 @@ bool DbManager::modeInit()
|
|||
content.erase( 0, pos + delimiter.length() );
|
||||
}
|
||||
|
||||
std::cout << "======================================================" << std::endl;
|
||||
std::cout << "Inserting default values..." << std::endl;
|
||||
Logger::info( "======================================================" );
|
||||
Logger::info( "Inserting default values..." );
|
||||
|
||||
|
||||
std::ifstream t1( m_iFile );
|
||||
|
@ -273,7 +287,7 @@ bool DbManager::modeLiquidate()
|
|||
|
||||
while( resultSet->next() )
|
||||
{
|
||||
std::cout << "DROP TABLE `" + resultSet->getString( 1 ) + "`;" << "\n";
|
||||
Logger::info( "DROP TABLE `{}`;", resultSet->getString( 1 ) );
|
||||
if( !execute( "DROP TABLE `" + resultSet->getString( 1 ) + "`;" ) )
|
||||
return false;
|
||||
}
|
||||
|
@ -297,4 +311,157 @@ void DbManager::setSchemaFile( const std::string& sFile )
|
|||
m_sFile = sFile;
|
||||
}
|
||||
|
||||
void DbManager::setMigratioName( const std::string& name )
|
||||
{
|
||||
m_migrationName = name;
|
||||
}
|
||||
|
||||
bool DbManager::modeCheck()
|
||||
{
|
||||
if( !selectSchema() )
|
||||
return false;
|
||||
|
||||
std::string query = "SELECT MigrationName FROM __Migration;";
|
||||
|
||||
std::vector< std::string > appliedMigrations;
|
||||
|
||||
try
|
||||
{
|
||||
auto stmt = m_pConnection->createStatement();
|
||||
auto resultSet = stmt->executeQuery( query );
|
||||
|
||||
while( resultSet->next() )
|
||||
{
|
||||
appliedMigrations.emplace_back( resultSet->getString( 1 ) );
|
||||
}
|
||||
}
|
||||
catch( std::runtime_error& e )
|
||||
{
|
||||
m_lastError = e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t missing = 0;
|
||||
for( auto& entry : fs::directory_iterator( "sql/migrations" ) )
|
||||
{
|
||||
auto& path = entry.path();
|
||||
|
||||
// just in case...
|
||||
if( path.extension() != ".sql" )
|
||||
continue;
|
||||
|
||||
if( std::find( appliedMigrations.begin(), appliedMigrations.end(), path.filename().string() ) == appliedMigrations.end() )
|
||||
{
|
||||
Logger::info( "Missing migration: {}", path.filename().string() );
|
||||
missing++;
|
||||
}
|
||||
}
|
||||
|
||||
if( missing > 0 )
|
||||
{
|
||||
Logger::warn( "Database is missing {} migrations.", missing );
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info( "All available migrations have been applied." );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbManager::modeMigrate()
|
||||
{
|
||||
if( !selectSchema() )
|
||||
return false;
|
||||
|
||||
std::string query = "SELECT MigrationName FROM __Migration;";
|
||||
|
||||
std::vector< std::string > appliedMigrations;
|
||||
|
||||
try
|
||||
{
|
||||
auto stmt = m_pConnection->createStatement();
|
||||
auto resultSet = stmt->executeQuery( query );
|
||||
|
||||
while( resultSet->next() )
|
||||
{
|
||||
appliedMigrations.emplace_back( resultSet->getString( 1 ) );
|
||||
}
|
||||
}
|
||||
catch( std::runtime_error& e )
|
||||
{
|
||||
m_lastError = e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
for( auto& entry : fs::directory_iterator( "sql/migrations" ) )
|
||||
{
|
||||
auto& path = entry.path();
|
||||
|
||||
// just in case...
|
||||
if( path.extension() != ".sql" )
|
||||
continue;
|
||||
|
||||
if( std::find( appliedMigrations.begin(), appliedMigrations.end(), path.filename().string() ) == appliedMigrations.end() )
|
||||
{
|
||||
Logger::info( "Applying migration: {}", path.filename().string() );
|
||||
|
||||
std::ifstream mFile( path.string() );
|
||||
if( !mFile.is_open() )
|
||||
{
|
||||
m_lastError = "File " + path.string() + " does not exist!";
|
||||
return false;
|
||||
}
|
||||
std::string sql( ( std::istreambuf_iterator< char >( mFile ) ),
|
||||
( std::istreambuf_iterator< char >( ) ) );
|
||||
|
||||
try
|
||||
{
|
||||
auto stmt = m_pConnection->createStatement();
|
||||
stmt->executeQuery( sql );
|
||||
}
|
||||
catch( std::runtime_error& e )
|
||||
{
|
||||
m_lastError = e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
// insert into migrations table
|
||||
if( !execute( fmt::format( "INSERT INTO __Migration (`MigrationName`) VALUES ('{}');", path.filename().string() ) ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbManager::modeAddMigration()
|
||||
{
|
||||
if( !selectSchema() )
|
||||
return false;
|
||||
|
||||
fs::create_directories( "sql/migrations" );
|
||||
|
||||
auto filename = fmt::format( "{}_{}.sql", Util::fmtUtcTime( "%Y%m%d%H%M%S" ), m_migrationName );
|
||||
|
||||
if( filename.size() > 250 )
|
||||
{
|
||||
Logger::error( "Migration name '{}' is longer than 250 characters, please shorten its name.", filename );
|
||||
return false;
|
||||
}
|
||||
|
||||
auto path = fmt::format( "sql/migrations/{}", filename );
|
||||
|
||||
std::ofstream mFile( path );
|
||||
|
||||
mFile << fmt::format( "-- Migration generated at {}", Util::fmtUtcTime( "%Y/%m/%d %H:%M:%S" ) ) << std::endl;
|
||||
mFile << fmt::format( "-- {}", filename ) << std::endl << std::endl;
|
||||
|
||||
mFile.close();
|
||||
|
||||
Logger::info( "New migration created: {}", path );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,9 +13,10 @@ enum class Mode
|
|||
{
|
||||
INIT,
|
||||
LIQUIDATE,
|
||||
UPDATE,
|
||||
MIGRATE,
|
||||
CHECK,
|
||||
CLEAN_CHARS
|
||||
CLEAN_CHARS,
|
||||
ADD_MIGRATION,
|
||||
};
|
||||
|
||||
class DbManager
|
||||
|
@ -37,6 +38,12 @@ class DbManager
|
|||
|
||||
bool modeLiquidate();
|
||||
|
||||
bool modeCheck();
|
||||
|
||||
bool modeMigrate();
|
||||
|
||||
bool modeAddMigration();
|
||||
|
||||
virtual ~DbManager();
|
||||
|
||||
const std::string& getLastError();
|
||||
|
@ -49,6 +56,8 @@ class DbManager
|
|||
|
||||
void setForceMode( bool mode );
|
||||
|
||||
void setMigratioName( const std::string& name );
|
||||
|
||||
private:
|
||||
std::string m_host;
|
||||
std::string m_database;
|
||||
|
@ -61,6 +70,8 @@ class DbManager
|
|||
std::string m_iFile;
|
||||
std::string m_sFile;
|
||||
bool m_force;
|
||||
|
||||
std::string m_migrationName;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
#include <common/Logging/Logger.h>
|
||||
#include <experimental/filesystem>
|
||||
#include <MySqlConnector.h>
|
||||
#include <common/Util/CrashHandler.h>
|
||||
#include <common/Config/ConfigMgr.h>
|
||||
|
||||
Sapphire::Common::Util::CrashHandler crashHandler;
|
||||
|
||||
namespace filesys = std::experimental::filesystem;
|
||||
|
||||
|
@ -77,13 +80,14 @@ std::string delChar( std::string &str, char del )
|
|||
|
||||
void printUsage()
|
||||
{
|
||||
Logger::info( " Usage: sapphire_dbm " );
|
||||
Logger::info( " Usage: dbm " );
|
||||
Logger::info( "\t --mode" );
|
||||
Logger::info( "\t\t initialize -> Creates DB if not present and inserts default tables/data" );
|
||||
Logger::info( "\t\t check -> Checks if Sapphire DB-Version matches your DB-Version" );
|
||||
Logger::info( "\t\t update -> Updates your DB-Version to Sapphire DB-Version" );
|
||||
Logger::info( "\t\t migrate -> Updates your DB-Version to Sapphire DB-Version" );
|
||||
Logger::info( "\t\t clearchars -> Removes all character data from DB. Accounts will stay untouched" );
|
||||
Logger::info( "\t\t liquidate -> Removes all tables and deletes the DB" );
|
||||
Logger::info( "\t\t add-migration -> Creates a new migration with the assoicated up/down sql files" );
|
||||
Logger::info( "\t --user <mysqlUserName>" );
|
||||
Logger::info( "\t --pass <mysqlPassword> ( default empty )" );
|
||||
Logger::info( "\t --host <mysqlHost> ( default 127.0.0.1 )" );
|
||||
|
@ -91,6 +95,7 @@ void printUsage()
|
|||
Logger::info( "\t --database <mysqlDatabase>" );
|
||||
Logger::info( "\t --sfile <path/to/schemafile> ( default sql/schema/schema.sql )" );
|
||||
Logger::info( "\t --force ( skips user input / auto Yes )" );
|
||||
Logger::info( "\t --name <migration name>" );
|
||||
}
|
||||
|
||||
int main( int32_t argc, char* argv[] )
|
||||
|
@ -109,8 +114,21 @@ int main( int32_t argc, char* argv[] )
|
|||
std::string sFile;
|
||||
std::string iFile;
|
||||
|
||||
std::string migrationName;
|
||||
|
||||
bool force = false;
|
||||
|
||||
// load config first so it can still be overridden if required
|
||||
Common::ConfigMgr configMgr;
|
||||
Common::Config::GlobalConfig globalConfig;
|
||||
if( configMgr.loadGlobalConfig( globalConfig ) )
|
||||
{
|
||||
host = globalConfig.database.host;
|
||||
database = globalConfig.database.database;
|
||||
user = globalConfig.database.user;
|
||||
pass = globalConfig.database.password;
|
||||
}
|
||||
|
||||
std::vector< std::string > args( argv + 1, argv + argc );
|
||||
for( uint32_t i = 0; i + 1 < args.size(); i += 2 )
|
||||
{
|
||||
|
@ -137,6 +155,8 @@ int main( int32_t argc, char* argv[] )
|
|||
iFile = val;
|
||||
else if( arg == "force" )
|
||||
force = true;
|
||||
else if( arg == "name" )
|
||||
migrationName = val;
|
||||
}
|
||||
|
||||
if( host.empty() )
|
||||
|
@ -155,6 +175,12 @@ int main( int32_t argc, char* argv[] )
|
|||
dbm.setInsertFile( iFile );
|
||||
dbm.setSchemaFile( sFile );
|
||||
}
|
||||
|
||||
if( !migrationName.empty() )
|
||||
{
|
||||
dbm.setMigratioName( migrationName );
|
||||
}
|
||||
|
||||
if( force )
|
||||
dbm.setForceMode( true );
|
||||
//initialize|check|update|clearchars|liquidate
|
||||
|
@ -166,9 +192,9 @@ int main( int32_t argc, char* argv[] )
|
|||
{
|
||||
dbm.setMode( Mode::CHECK );
|
||||
}
|
||||
else if( mode.find( "update" ) != std::string::npos )
|
||||
else if( mode.find( "migrate" ) != std::string::npos )
|
||||
{
|
||||
dbm.setMode( Mode::UPDATE );
|
||||
dbm.setMode( Mode::MIGRATE );
|
||||
}
|
||||
else if( mode.find( "clearchars" ) != std::string::npos )
|
||||
{
|
||||
|
@ -178,6 +204,10 @@ int main( int32_t argc, char* argv[] )
|
|||
{
|
||||
dbm.setMode( Mode::LIQUIDATE );
|
||||
}
|
||||
else if( mode.find( "add-migration" ) != std::string::npos )
|
||||
{
|
||||
dbm.setMode( Mode::ADD_MIGRATION );
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::fatal( "Not a valid mode: {0} !", mode );
|
||||
|
|
Loading…
Add table
Reference in a new issue