Project

General

Profile

Bug #1128 ยป DboTest.C

Saif Rehman, 01/13/2012 07:58 AM

 
/*
* Copyright (C) 2009 Emweb bvba, Kessel-Lo, Belgium.
*
* See the LICENSE file for terms of use.
*/
#ifdef WTDBO

#include <boost/test/unit_test.hpp>

#include <Wt/Dbo/Dbo>
#include <Wt/Dbo/backend/Postgres>
#include <Wt/Dbo/backend/Sqlite3>
#include <Wt/Dbo/backend/Firebird>
#include <Wt/Dbo/FixedSqlConnectionPool>
#include <Wt/WDate>
#include <Wt/WDateTime>
#include <Wt/WTime>
#include <Wt/Dbo/WtSqlTraits>
#include <Wt/Dbo/ptr_tuple>
#include <Wt/Dbo/QueryModel>
#include <Wt/WLogger>
#include <Wt/Dbo/Query>
#include <boost/tuple/tuple.hpp>
#include <boost/thread.hpp>
#include <boost/unordered_map.hpp>

//Post directives
class Configuration;
class ConfigurationBool;
class ConfigurationDouble;
class ConfigurationFloat;
class ConfigurationInt;
class ConfigurationString;

//Configuration Keys structure
struct ConfigurationKeys
{
std::string Name;
std::string Application;

ConfigurationKeys();
ConfigurationKeys(std::string Name, std::string Application);

bool operator< (const ConfigurationKeys& other) const;
bool operator== (const ConfigurationKeys& other) const;
};

//Overloaded operator<< for Configuration Keys structure
std::ostream& operator<< (std::ostream& o, const ConfigurationKeys& c);

namespace Wt
{
namespace Dbo
{
//Overloaded Wt::Dbo::field() for Configuration Keys structure
template<class Action>
void field(Action& action, ConfigurationKeys& Keys, const std::string& name, int size = -1)
{
field(action, Keys.Name, "Name", 255);
field(action, Keys.Application, "Application", 255);
}

//Overloaded dbo_traits for Configuration DBO
template<>
struct dbo_traits<::Configuration> : public dbo_default_traits
{
typedef ConfigurationKeys IdType;
static IdType invalidId();
static const char *surrogateIdField();
};
//Overloaded dbo_traits for ConfigurationBool DBO
template<>
struct dbo_traits<ConfigurationBool> : public dbo_default_traits
{
static const char *surrogateIdField();
};
//Overloaded dbo_traits for ConfigurationDouble DBO
template<>
struct dbo_traits<ConfigurationDouble> : public dbo_default_traits
{
static const char *surrogateIdField();
};
//Overloaded dbo_traits for ConfigurationFloat DBO
template<>
struct dbo_traits<ConfigurationFloat> : public dbo_default_traits
{
static const char *surrogateIdField();
};
//Overloaded dbo_traits for ConfigurationInt DBO
template<>
struct dbo_traits<ConfigurationInt> : public dbo_default_traits
{
static const char *surrogateIdField();
};
//Overloaded dbo_traits for ConfigurationString DBO
template<>
struct dbo_traits<ConfigurationString> : public dbo_default_traits
{
static const char *surrogateIdField();
};
}
};

//Configuration DBO class
class Configuration
{
public:
enum ValueTypes
{
Bool = 0,
Double = 1,
Float = 2,
Int = 3,
String = 4,
};

//hasMany relations
Wt::Dbo::collection< Wt::Dbo::ptr<ConfigurationBool> > ConfigurationBoolDbo;
Wt::Dbo::collection< Wt::Dbo::ptr<ConfigurationDouble> > ConfigurationDoubleDbo;
Wt::Dbo::collection< Wt::Dbo::ptr<ConfigurationFloat> > ConfigurationFloatDbo;
Wt::Dbo::collection< Wt::Dbo::ptr<ConfigurationInt> > ConfigurationIntDbo;
Wt::Dbo::collection< Wt::Dbo::ptr<ConfigurationString> > ConfigurationStringDbo;

//Fields
ConfigurationKeys Id;
std::string Title;
ValueTypes Type;
boost::optional<std::string> Details;

//Persistence Method
template<class Action>
void persist(Action& a)
{
Wt::Dbo::id(a, Id, "Id");
Wt::Dbo::field(a, Title, "Title");
Wt::Dbo::field(a, Type, "Type");
Wt::Dbo::field(a, Details, "Details");
Wt::Dbo::hasMany(a, ConfigurationBoolDbo, Wt::Dbo::ManyToOne, "Configuration");
Wt::Dbo::hasMany(a, ConfigurationDoubleDbo, Wt::Dbo::ManyToOne, "Configuration");
Wt::Dbo::hasMany(a, ConfigurationFloatDbo, Wt::Dbo::ManyToOne, "Configuration");
Wt::Dbo::hasMany(a, ConfigurationIntDbo, Wt::Dbo::ManyToOne, "Configuration");
Wt::Dbo::hasMany(a, ConfigurationStringDbo, Wt::Dbo::ManyToOne, "Configuration");
}
};

//ConfigurationBool DBO Class
class ConfigurationBool
{
public:
//belongsTo
Wt::Dbo::ptr<Configuration> ConfigurationDbo;
bool Value;

template<class Action>void persist(Action& a)
{
Wt::Dbo::field(a, Value, "Value");
Wt::Dbo::belongsTo(a, ConfigurationDbo, "Configuration", Wt::Dbo::OnUpdateCascade | Wt::Dbo::OnDeleteCascade);
}
};

//ConfigurationDouble DBO Class
class ConfigurationDouble
{
public:
//belongsTo
Wt::Dbo::ptr<Configuration> ConfigurationDbo;
double Value;

template<class Action>void persist(Action& a)
{
Wt::Dbo::field(a, Value, "Value");
Wt::Dbo::belongsTo(a, ConfigurationDbo, "Configuration", Wt::Dbo::OnUpdateCascade | Wt::Dbo::OnDeleteCascade);
}
};

//ConfigurationFloat DBO Class
class ConfigurationFloat
{
public:
//belongsTo
Wt::Dbo::ptr<Configuration> ConfigurationDbo;
float Value;

template<class Action>void persist(Action& a)
{
Wt::Dbo::field(a, Value, "Value");
Wt::Dbo::belongsTo(a, ConfigurationDbo, "Configuration", Wt::Dbo::OnUpdateCascade | Wt::Dbo::OnDeleteCascade);
}
};

//ConfigurationInt DBO Class
class ConfigurationInt
{
public:
//belongsTo
Wt::Dbo::ptr<Configuration> ConfigurationDbo;
int Value;

template<class Action>void persist(Action& a)
{
Wt::Dbo::field(a, Value, "Value");
Wt::Dbo::belongsTo(a, ConfigurationDbo, "Configuration", Wt::Dbo::OnUpdateCascade | Wt::Dbo::OnDeleteCascade);
}
};

//ConfigurationString DBO Class
class ConfigurationString
{
public:
//belongsTo
Wt::Dbo::ptr<Configuration> ConfigurationDbo;
boost::optional<std::string> Value;

template<class Action>void persist(Action& a)
{
Wt::Dbo::field(a, Value, "Value");
Wt::Dbo::belongsTo(a, ConfigurationDbo, "Configuration", Wt::Dbo::OnUpdateCascade | Wt::Dbo::OnDeleteCascade);
}
};

//Configuration Keys
ConfigurationKeys::ConfigurationKeys()
: Name(std::string()), Application(std::string())
{ }
ConfigurationKeys::ConfigurationKeys(std::string Name, std::string Application)
: Name(Name), Application(Application)
{ }
bool ConfigurationKeys::operator== (const ConfigurationKeys& other) const
{
return Name == other.Name && Application == other.Application;
}
bool ConfigurationKeys::operator< (const ConfigurationKeys& other) const
{
if(Application < other.Application)
{
return true;
}
else if(Name == other.Name)
{
return Name < other.Name;
}
else
{
return false;
}
}
std::ostream& operator<< (std::ostream& o, const ConfigurationKeys& c)
{
return o << "(" << c.Name << ", " << c.Application << ")";
}

//Overloaded dbo_trait for Configuration DBO
Wt::Dbo::dbo_traits<Configuration>::IdType Wt::Dbo::dbo_traits<Configuration>::invalidId()
{
return Wt::Dbo::dbo_traits<Configuration>::IdType();
}
const char* Wt::Dbo::dbo_traits<Configuration>::surrogateIdField()
{
return 0;
}

//Remove ID field from Configuration related DBOs
const char* Wt::Dbo::dbo_traits<ConfigurationBool>::surrogateIdField()
{
return 0;
}
const char* Wt::Dbo::dbo_traits<ConfigurationDouble>::surrogateIdField()
{
return 0;
}
const char* Wt::Dbo::dbo_traits<ConfigurationFloat>::surrogateIdField()
{
return 0;
}
const char* Wt::Dbo::dbo_traits<ConfigurationInt>::surrogateIdField()
{
return 0;
}
const char* Wt::Dbo::dbo_traits<ConfigurationString>::surrogateIdField()
{
return 0;
}

class Configurations;
//SQL Connection
Wt::Dbo::FixedSqlConnectionPool *SQLPool;
//Global Configurations
Configurations *Config;

class Configurations
{
public:
typedef boost::unordered_map< const std::string, boost::unordered_map< const std::string, Wt::Dbo::ptr<ConfigurationBool> > > ConfigurationBoolMaps;
typedef boost::unordered_map< const std::string, boost::unordered_map< const std::string, Wt::Dbo::ptr<ConfigurationDouble> > > ConfigurationDoubleMaps;
typedef boost::unordered_map< const std::string, boost::unordered_map< const std::string, Wt::Dbo::ptr<ConfigurationFloat> > > ConfigurationFloatMaps;
typedef boost::unordered_map< const std::string, boost::unordered_map< const std::string, Wt::Dbo::ptr<ConfigurationInt> > > ConfigurationIntMaps;
typedef boost::unordered_map< const std::string, boost::unordered_map< const std::string, Wt::Dbo::ptr<ConfigurationString> > > ConfigurationStringMaps;
typedef boost::tuple< Wt::Dbo::ptr<Configuration>, Wt::Dbo::ptr<ConfigurationBool> > ConfigurationBoolTuples;
typedef boost::tuple< Wt::Dbo::ptr<Configuration>, Wt::Dbo::ptr<ConfigurationDouble> > ConfigurationDoubleTuples;
typedef boost::tuple< Wt::Dbo::ptr<Configuration>, Wt::Dbo::ptr<ConfigurationFloat> > ConfigurationFloatTuples;
typedef boost::tuple< Wt::Dbo::ptr<Configuration>, Wt::Dbo::ptr<ConfigurationInt> > ConfigurationIntTuples;
typedef boost::tuple< Wt::Dbo::ptr<Configuration>, Wt::Dbo::ptr<ConfigurationString> > ConfigurationStringTuples;
Configurations();
void Install();
void Uninstall();
void FetchAll();

template<typename Source> bool GetBool(const std::string& Name, const std::string& Application, Source Default);
bool GetBool(const std::string& Name, const std::string& Application, bool Default = false);
template<typename Source> double GetDouble(const std::string& Name, const std::string& Application, Source Default);
double GetDouble(const std::string& Name, const std::string& Application, double Default = 0);
template<typename Source> float GetFloat(const std::string& Name, const std::string& Application, Source Default);
float GetFloat(const std::string& Name, const std::string& Application, float Default = 0);
template<typename Source> int GetInt(const std::string& Name, const std::string& Application, Source Default);
int GetInt(const std::string& Name, const std::string& Application, int Default = 0);
template<typename Source> std::string GetStr(const std::string& Name, const std::string& Application, Source Default);
std::string GetStr(const std::string& Name, const std::string& Application, std::string Default = "");

long long GetLoadDurationinMS() const;
int GetConfigurationsCount() const;

protected:
ConfigurationBoolMaps ConfigurationBoolMap;
ConfigurationDoubleMaps ConfigurationDoubleMap;
ConfigurationFloatMaps ConfigurationFloatMap;
ConfigurationIntMaps ConfigurationIntMap;
ConfigurationStringMaps ConfigurationStringMap;
boost::posix_time::time_duration LoadDuration;
int ConfigurationsCount;

private:
mutable boost::shared_mutex mutex;

Wt::Dbo::Session Session;
Wt::Dbo::Query<ConfigurationBoolTuples> FetchBoolQuery;
Wt::Dbo::Query<ConfigurationDoubleTuples> FetchDoubleQuery;
Wt::Dbo::Query<ConfigurationFloatTuples> FetchFloatQuery;
Wt::Dbo::Query<ConfigurationIntTuples> FetchIntQuery;
Wt::Dbo::Query<ConfigurationStringTuples> FetchStringQuery;
};

#define READ_LOCK boost::shared_lock<boost::shared_mutex> lock(mutex)
#define WRITE_LOCK boost::lock_guard<boost::shared_mutex> lock(mutex)

Configurations::Configurations()
{
ConfigurationsCount = 0;
LoadDuration = boost::posix_time::time_duration(0, 0, 0);
Session.setConnectionPool(*SQLPool);

//Map DBOs
Session.mapClass<Configuration>("configuration");
Session.mapClass<ConfigurationBool>("configurationbool");
Session.mapClass<ConfigurationDouble>("configurationdouble");
Session.mapClass<ConfigurationFloat>("configurationfloat");
Session.mapClass<ConfigurationInt>("configurationint");
Session.mapClass<ConfigurationString>("configurationstring");

//Define the query to fetch and join all rows
FetchBoolQuery = Session.query<ConfigurationBoolTuples>(std::string("SELECT")
+ " \"configuration\", \"configurationbool\""
+ " FROM \"configuration\""
+ " LEFT JOIN \"configurationbool\" ON \"configuration\".\"Name\" = \"configurationbool\".\"Name\" AND \"configuration\".\"Application\" = \"configurationbool\".\"Application\" "
+ " WHERE \"configuration\".\"Type\" = 0");

FetchDoubleQuery = Session.query<ConfigurationDoubleTuples>(std::string("SELECT")
+ " \"configuration\", \"configurationdouble\""
+ " FROM \"configuration\""
+ " LEFT JOIN \"configurationdouble\" ON \"configuration\".\"Name\" = \"configurationdouble\".\"Name\" AND \"configuration\".\"Application\" = \"configurationdouble\".\"Application\" "
+ " WHERE \"configuration\".\"Type\" = 1");

FetchFloatQuery = Session.query<ConfigurationFloatTuples>(std::string("SELECT")
+ " \"configuration\", \"configurationfloat\""
+ " FROM \"configuration\""
+ " LEFT JOIN \"configurationfloat\" ON \"configuration\".\"Name\" = \"configurationfloat\".\"Name\" AND \"configuration\".\"Application\" = \"configurationfloat\".\"Application\" "
+ " WHERE \"configuration\".\"Type\" = 2");

FetchIntQuery = Session.query<ConfigurationIntTuples>(std::string("SELECT")
+ " \"configuration\", \"configurationint\""
+ " FROM \"configuration\""
+ " LEFT JOIN \"configurationint\" ON \"configuration\".\"Name\" = \"configurationint\".\"Name\" AND \"configuration\".\"Application\" = \"configurationint\".\"Application\" "
+ " WHERE \"configuration\".\"Type\" = 3");

FetchStringQuery = Session.query<ConfigurationStringTuples>(std::string("SELECT")
+ " \"configuration\", \"configurationstring\""
+ " FROM \"configuration\""
+ " LEFT JOIN \"configurationstring\" ON \"configuration\".\"Name\" = \"configurationstring\".\"Name\" AND \"configuration\".\"Application\" = \"configurationstring\".\"Application\" "
+ " WHERE \"configuration\".\"Type\" = 4");
}

void Configurations::Install()
{
Session.createTables();
Wt::Dbo::Transaction transaction(Session);

//BaseURL
Wt::Dbo::ptr<Configuration> BaseUrl = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationString> BaseUrlVal = Session.add(new ConfigurationString());
BaseUrl.modify()->Id.Name = "BaseURL";
BaseUrl.modify()->Id.Application = "Server";
BaseUrl.modify()->Title = "Base URL of the website";
BaseUrl.modify()->Type = Configuration::String;
BaseUrl.modify()->Details = "This is the base URL that the user can see when browsing. For example, http://www.mywebsite.com/wt .\nThis field may be left empty.";
BaseUrlVal.modify()->Value = "";
BaseUrl.modify()->ConfigurationStringDbo.insert(BaseUrlVal);

//DosPuzzle
Wt::Dbo::ptr<Configuration> DosPuzzle = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationBool> DosPuzzleVal = Session.add(new ConfigurationBool());
DosPuzzle.modify()->Id.Name = "DosPuzzle";
DosPuzzle.modify()->Id.Application = "Server";
DosPuzzle.modify()->Title = "Denial-of-Service protection puzzle";
DosPuzzle.modify()->Type = Configuration::Bool;
DosPuzzle.modify()->Details = "When enabled the server adds a puzzle to validate Ajax sessions in the first Ajax request. This is a simple measure which avoids Denial-of-Service attacks on Ajax sessions.\n\nDefault value: Off";
DosPuzzleVal.modify()->Value = false;
DosPuzzle.modify()->ConfigurationBoolDbo.insert(DosPuzzleVal);

//JavascriptDebug
Wt::Dbo::ptr<Configuration> JavascriptDebug = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationInt> JavascriptDebugVal = Session.add(new ConfigurationInt());
JavascriptDebug.modify()->Id.Name = "JavascriptDebug";
JavascriptDebug.modify()->Id.Application = "Server";
JavascriptDebug.modify()->Title = "Debug javascript mode";
JavascriptDebug.modify()->Type = Configuration::Int;
JavascriptDebug.modify()->Details = "Enable this only if you are a developer and to debug javascript.\n\nPossible values:\n1 = (Off)JavaScript errors are caught and a simple error message is printed to indicate that something is terribly wrong(default, recommended)\n2 = (On)JavaScript errors are caught but also a stack trace is printed, useful for diagnosing a problem in production\n3 = (On)JavaScript errors are not caught but the browser built-in debug options are used";
JavascriptDebugVal.modify()->Value = 1;
JavascriptDebug.modify()->ConfigurationIntDbo.insert(JavascriptDebugVal);

//MaxRequestSize
Wt::Dbo::ptr<Configuration> MaxRequestSize = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationInt> MaxRequestSizeVal = Session.add(new ConfigurationInt());
MaxRequestSize.modify()->Id.Name = "MaxRequestSize";
MaxRequestSize.modify()->Id.Application = "Server";
MaxRequestSize.modify()->Title = "Max request size";
MaxRequestSize.modify()->Type = Configuration::Int;
MaxRequestSize.modify()->Details = "Maximum request size in kilobytes. This has to be increased to allow uploading larger sized files.";
MaxRequestSizeVal.modify()->Value = 128;
MaxRequestSize.modify()->ConfigurationIntDbo.insert(MaxRequestSizeVal);

//ReverseProxy
Wt::Dbo::ptr<Configuration> ReverseProxy = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationBool> ReverseProxyVal = Session.add(new ConfigurationBool());
ReverseProxy.modify()->Id.Name = "ReverseProxy";
ReverseProxy.modify()->Id.Application = "Server";
ReverseProxy.modify()->Title = "Behind reverse proxy";
ReverseProxy.modify()->Type = Configuration::Bool;
ReverseProxy.modify()->Details = "Enable this if the server is behind a reverse proxy. If you do not know what this means then disable it.\n\nDefault Value: Off";
ReverseProxyVal.modify()->Value = false;
ReverseProxy.modify()->ConfigurationBoolDbo.insert(ReverseProxyVal);

//SessionTimeout
Wt::Dbo::ptr<Configuration> SessionTimeout = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationInt> SessionTimeoutVal = Session.add(new ConfigurationInt());
SessionTimeout.modify()->Id.Name = "SessionTimeout";
SessionTimeout.modify()->Id.Application = "Server";
SessionTimeout.modify()->Title = "Session timeout delay";
SessionTimeout.modify()->Type = Configuration::Int;
SessionTimeout.modify()->Details = "Session timeout delay in seconds. When a session remains inactive for this amount of time, it will be cleaned up.\nRecommended value: 600 (1 minute)";
SessionTimeoutVal.modify()->Value = 600;
SessionTimeout.modify()->ConfigurationIntDbo.insert(SessionTimeoutVal);

//SessionTracking
Wt::Dbo::ptr<Configuration> SessionTracking = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationInt> SessionTrackingVal = Session.add(new ConfigurationInt());
SessionTracking.modify()->Id.Name = "SessionTracking";
SessionTracking.modify()->Id.Application = "Server";
SessionTracking.modify()->Title = "Session tracking strategy";
SessionTracking.modify()->Type = Configuration::Int;
SessionTracking.modify()->Details = "Possible values:\n1 = Cookies are used if available, otherwise URL rewriting for tracking session(default)\n2 = Only URL rewriting for tracking session";
SessionTrackingVal.modify()->Value = 1;
SessionTracking.modify()->ConfigurationIntDbo.insert(SessionTrackingVal);

//LogDebugLevel
Wt::Dbo::ptr<Configuration> LogDebugLevel = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationBool> LogDebugLevelVal = Session.add(new ConfigurationBool());
LogDebugLevel.modify()->Id.Name = "LogDebugLevel";
LogDebugLevel.modify()->Id.Application = "Logging";
LogDebugLevel.modify()->Title = "Log debugging messages";
LogDebugLevel.modify()->Type = Configuration::Bool;
LogDebugLevel.modify()->Details = "When enabled debugging events/messages will be included in the log file. These notices only gives information for developers and might not be meaningful to end users.\n\nRecommended Value: Off";
LogDebugLevelVal.modify()->Value = false;
LogDebugLevel.modify()->ConfigurationBoolDbo.insert(LogDebugLevelVal);

//LogDirectory
Wt::Dbo::ptr<Configuration> LogDirectory = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationString> LogDirectoryVal = Session.add(new ConfigurationString());
LogDirectory.modify()->Id.Name = "LogDirectory";
LogDirectory.modify()->Id.Application = "Logging";
LogDirectory.modify()->Title = "Logging file directory";
LogDirectory.modify()->Type = Configuration::String;
LogDirectory.modify()->Details = "Location to where the file in which logs will be created is. Can be a full path or even a relative path.\n\nWhen this is left empty, no log file will be created but disabling file logging is highly not recommended.\nDefault Value: ./logs";
LogDirectoryVal.modify()->Value = "./logs";
LogDirectory.modify()->ConfigurationStringDbo.insert(LogDirectoryVal);

//LogErrorLevel
Wt::Dbo::ptr<Configuration> LogErrorLevel = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationBool> LogErrorLevelVal = Session.add(new ConfigurationBool());
LogErrorLevel.modify()->Id.Name = "LogErrorLevel";
LogErrorLevel.modify()->Id.Application = "Logging";
LogErrorLevel.modify()->Title = "Log error messages";
LogErrorLevel.modify()->Type = Configuration::Bool;
LogErrorLevel.modify()->Details = "When enabled errors will be included in the log file. \n\nRecommended Value: On";
LogErrorLevelVal.modify()->Value = true;
LogErrorLevel.modify()->ConfigurationBoolDbo.insert(LogErrorLevelVal);

//LogInfoLevel
Wt::Dbo::ptr<Configuration> LogInfoLevel = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationBool> LogInfoLevelVal = Session.add(new ConfigurationBool());
LogInfoLevel.modify()->Id.Name = "LogInfoLevel";
LogInfoLevel.modify()->Id.Application = "Logging";
LogInfoLevel.modify()->Title = "Log informational notices";
LogInfoLevel.modify()->Type = Configuration::Bool;
LogInfoLevel.modify()->Details = "When enabled informational notices will be included in the log file. These notices only gives information rather than reporting a warning or an error.";
LogInfoLevelVal.modify()->Value = false;
LogInfoLevel.modify()->ConfigurationBoolDbo.insert(LogInfoLevelVal);

//LogSecureLevel
Wt::Dbo::ptr<Configuration> LogSecureLevel = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationBool> LogSecureLevelVal = Session.add(new ConfigurationBool());
LogSecureLevel.modify()->Id.Name = "LogSecureLevel";
LogSecureLevel.modify()->Id.Application = "Logging";
LogSecureLevel.modify()->Title = "Log security events";
LogSecureLevel.modify()->Type = Configuration::Bool;
LogSecureLevel.modify()->Details = "When enabled security related messages will be included in the log file.\n\nRecommended Value: On";
LogSecureLevelVal.modify()->Value = true;
LogSecureLevel.modify()->ConfigurationBoolDbo.insert(LogInfoLevelVal);

//LogWarnLevel
Wt::Dbo::ptr<Configuration> LogWarnLevel = Session.add(new Configuration());
Wt::Dbo::ptr<ConfigurationBool> LogWarnLevelVal = Session.add(new ConfigurationBool());
LogWarnLevel.modify()->Id.Name = "LogWarnLevel";
LogWarnLevel.modify()->Id.Application = "Logging";
LogWarnLevel.modify()->Title = "Log warnings";
LogWarnLevel.modify()->Type = Configuration::Bool;
LogWarnLevel.modify()->Details = "When enabled warnings will be included in the log file. These warnings indicate that there was something could have caused an error and should be considered.\n\nRecommended Value: On";
LogWarnLevelVal.modify()->Value = true;
LogWarnLevel.modify()->ConfigurationBoolDbo.insert(LogWarnLevelVal);

try
{
transaction.commit();
}
catch(Wt::Dbo::Exception& e)
{
throw e;
}
}

void Configurations::Uninstall()
{
try
{
Session.dropTables();
}
catch(Wt::Dbo::Exception& e)
{
throw e;
}
}

void Configurations::FetchAll()
{
WRITE_LOCK;
//Time at start
boost::posix_time::ptime PTStart = boost::posix_time::microsec_clock::local_time();

Wt::Dbo::Transaction transaction(Session);
try
{
ConfigurationsCount = 0;
typedef Wt::Dbo::collection< ConfigurationBoolTuples > BoolCollections;
typedef Wt::Dbo::collection< ConfigurationDoubleTuples > DoubleCollections;
typedef Wt::Dbo::collection< ConfigurationFloatTuples > FloatCollections;
typedef Wt::Dbo::collection< ConfigurationIntTuples > IntCollections;
typedef Wt::Dbo::collection< ConfigurationStringTuples > StringCollections;
BoolCollections BoolCollection;
DoubleCollections DoubleCollection;
FloatCollections FloatCollection;
IntCollections IntCollection;
StringCollections StringCollection;

//Fetch em all
Wt::Dbo::Transaction transaction(Session);
BoolCollection = FetchBoolQuery.resultList();
for(BoolCollections::const_iterator itr = BoolCollection.begin();
itr != BoolCollection.end();
itr++, ConfigurationsCount++)
{
std::cerr << itr->get<0>()->Id.Name << std::endl;
ConfigurationBoolMap[itr->get<0>()->Id.Application][itr->get<0>()->Id.Name] = itr->get<1>();
}

DoubleCollection = FetchDoubleQuery.resultList();
for(DoubleCollections::const_iterator itr = DoubleCollection.begin();
itr != DoubleCollection.end();
itr++, ConfigurationsCount++)
{
std::cerr << itr->get<0>()->Id.Name << std::endl;
ConfigurationDoubleMap[itr->get<0>()->Id.Application][itr->get<0>()->Id.Name] = itr->get<1>();
}

FloatCollection = FetchFloatQuery.resultList();
for(FloatCollections::const_iterator itr = FloatCollection.begin();
itr != FloatCollection.end();
itr++, ConfigurationsCount++)
{
std::cerr << itr->get<0>()->Id.Name << std::endl;
ConfigurationFloatMap[itr->get<0>()->Id.Application][itr->get<0>()->Id.Name] = itr->get<1>();
}

IntCollection = FetchIntQuery.resultList();
for(IntCollections::const_iterator itr = IntCollection.begin();
itr != IntCollection.end();
itr++, ConfigurationsCount++)
{
std::cerr << itr->get<0>()->Id.Name << std::endl;
ConfigurationIntMap[itr->get<0>()->Id.Application][itr->get<0>()->Id.Name] = itr->get<1>();
}

StringCollection = FetchStringQuery.resultList();
for(StringCollections::const_iterator itr = StringCollection.begin();
itr != StringCollection.end();
itr++, ConfigurationsCount++)
{
std::cerr << itr->get<0>()->Id.Name << std::endl;
ConfigurationStringMap[itr->get<0>()->Id.Application][itr->get<0>()->Id.Name] = itr->get<1>();
}
transaction.commit();
}
catch(Wt::Dbo::Exception& e)
{
throw e;
}

//Time at end
boost::posix_time::ptime PTEnd = boost::posix_time::microsec_clock::local_time();
LoadDuration = boost::posix_time::time_duration(PTEnd - PTStart);
}

//Boolean getter
template<>
bool Configurations::GetBool<bool>(const std::string& Name, const std::string& Application, bool Default)
{
READ_LOCK;
return ConfigurationBoolMap[Application][Name] ? ConfigurationBoolMap[Application][Name]->Value : Default;
}

//Double getter
template<>
double Configurations::GetDouble<double>(const std::string& Name, const std::string& Application, double Default)
{
READ_LOCK;
return ConfigurationDoubleMap[Application][Name] ? ConfigurationDoubleMap[Application][Name]->Value : Default;
}

//Float getter
template<>
float Configurations::GetFloat<float>(const std::string& Name, const std::string& Application, float Default)
{
READ_LOCK;
return ConfigurationFloatMap[Application][Name] ? ConfigurationFloatMap[Application][Name]->Value : Default;
}

//Integer getter
template<>
int Configurations::GetInt<int>(const std::string& Name, const std::string& Application, int Default)
{
READ_LOCK;
return ConfigurationIntMap[Application][Name] ? ConfigurationIntMap[Application][Name]->Value : Default;
}

//String getter
template<>
std::string Configurations::GetStr<std::string>(const std::string& Name, const std::string& Application, std::string Default)
{
READ_LOCK;
if(!ConfigurationStringMap[Application][Name])
{
return Default;
}
if(!ConfigurationStringMap[Application][Name]->Value.is_initialized())
{
return "";
}
return *ConfigurationStringMap[Application][Name]->Value;
}

//Boolean alternative source getters
template<>
bool Configurations::GetBool<double>(const std::string& Name, const std::string& Application, double Default)
{
READ_LOCK;
return GetDouble<double>(Name, Application, Default) > 0;
}

template<>
bool Configurations::GetBool<float>(const std::string& Name, const std::string& Application, float Default)
{
READ_LOCK;
return GetFloat<float>(Name, Application, Default) > 0;
}

template<>
bool Configurations::GetBool<int>(const std::string& Name, const std::string& Application, int Default)
{
READ_LOCK;
return GetInt<int>(Name, Application, Default) > 0;
}

template<>
bool Configurations::GetBool<std::string>(const std::string& Name, const std::string& Application, std::string Default)
{
READ_LOCK;
return ConfigurationStringMap[Application][Name];
}

bool Configurations::GetBool(const std::string& Name, const std::string& Application, bool Default)
{
READ_LOCK;
return GetBool<bool>(Name, Application, Default);
}

//Double alternative source getters
template<>
double Configurations::GetDouble<int>(const std::string& Name, const std::string& Application, int Default)
{
READ_LOCK;
return (double)GetInt<int>(Name, Application, Default);
}

double Configurations::GetDouble(const std::string& Name, const std::string& Application, double Default)
{
READ_LOCK;
return GetDouble<double>(Name, Application, Default);
}

//Float alternative source getters
template<>
float Configurations::GetFloat<double>(const std::string& Name, const std::string& Application, double Default)
{
READ_LOCK;
return (float)GetDouble<double>(Name, Application, Default);
}

template<>
float Configurations::GetFloat<int>(const std::string& Name, const std::string& Application, int Default)
{
READ_LOCK;
return (float)GetInt<int>(Name, Application, Default);
}

float Configurations::GetFloat(const std::string& Name, const std::string& Application, float Default)
{
READ_LOCK;
return GetFloat<float>(Name, Application, Default);
}

//Integer alternative source getters
template<>
int Configurations::GetInt<bool>(const std::string& Name, const std::string& Application, bool Default)
{
READ_LOCK;
return GetBool<bool>(Name, Application, Default) ? 1 : 0;
}

int Configurations::GetInt(const std::string& Name, const std::string& Application, int Default)
{
READ_LOCK;
return GetInt<int>(Name, Application, Default);
}

//String alternative source getters
template<>
std::string Configurations::GetStr<double>(const std::string& Name, const std::string& Application, double Default)
{
READ_LOCK;
std::ostringstream ss;
ss << GetDouble<double>(Name, Application, Default);
return ss.str();
}

template<>
std::string Configurations::GetStr<float>(const std::string& Name, const std::string& Application, float Default)
{
READ_LOCK;
std::ostringstream ss;
ss << GetFloat<float>(Name, Application, Default);
return ss.str();
}

template<>
std::string Configurations::GetStr<int>(const std::string& Name, const std::string& Application, int Default)
{
READ_LOCK;
std::ostringstream ss;
ss << GetInt<int>(Name, Application, Default);
return ss.str();
}

std::string Configurations::GetStr(const std::string& Name, const std::string& Application, std::string Default)
{
READ_LOCK;
return GetStr<std::string>(Name, Application, Default);
}

long long Configurations::GetLoadDurationinMS() const
{
READ_LOCK;
return LoadDuration.total_milliseconds();
}

int Configurations::GetConfigurationsCount() const
{
READ_LOCK;
return ConfigurationsCount;
}

BOOST_AUTO_TEST_CASE( dbo_test1 )
{
//Loading Start Time
boost::posix_time::ptime PTStart = boost::posix_time::microsec_clock::local_time();

//Create starting logger
Wt::WLogger StartLogger;
StartLogger.configure("* -debug");
StartLogger.addField("datetime", false);
StartLogger.addField("type", false);
StartLogger.addField("message", true);

StartLogger.entry("info");
StartLogger.entry("info") << Wt::WLogger::timestamp << Wt::WLogger::sep
<< '[' << "notice" << ']' << Wt::WLogger::sep << "Starting up server!";

/* *************************************************************************
* ************************ Initialize Database **************************
* *************************************************************************/
//Start SQL Connection
try
{
//Wt::Dbo::SqlConnection *SQLConnection = new Wt::Dbo::backend::MySQL("wt", "root", "root", "127.0.0.1");
Wt::Dbo::SqlConnection *SQLConnection = new Wt::Dbo::backend::Sqlite3(":memory:");
SQLConnection->setProperty("show-queries", "true");
SQLPool = new Wt::Dbo::FixedSqlConnectionPool(SQLConnection, 1);
}
catch(Wt::Dbo::Exception& e)
{
StartLogger.entry("fatal") << Wt::WLogger::timestamp << Wt::WLogger::sep
<< '[' << "fatal error" << ']' << Wt::WLogger::sep << e.what();
exit(EXIT_FAILURE);
}
catch(std::exception &e)
{
StartLogger.entry("fatal") << Wt::WLogger::timestamp << Wt::WLogger::sep
<< '[' << "fatal error" << ']' << Wt::WLogger::sep << e.what();
exit(EXIT_FAILURE);
}

/* *************************************************************************
* ************************ Load Configurations **************************
* *************************************************************************/
Config = new Configurations;
try
{
//Config->Uninstall();
Config->Install();
Config->FetchAll();
}
catch(Wt::Dbo::Exception& e)
{
std::cerr << e.what(); //test
}

StartLogger.entry("info") << Wt::WLogger::timestamp << Wt::WLogger::sep
<< '[' << "notice" << ']' << Wt::WLogger::sep << Config->GetConfigurationsCount() << " Configurations Loaded in " << Config->GetLoadDurationinMS() << " Ms";

//Deallocate
delete Config;
delete SQLPool; //Also deletes SQLConnection
}

#endif
    (1-1/1)