Created
April 29, 2017 14:25
-
-
Save trevorsibanda/94312f87ff5e98aeb4a5357565d5f981 to your computer and use it in GitHub Desktop.
C++ define sql tables as classes. typesafe.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//g++ db.cpp -o db.exe 2>&1 | more | |
#include<algorithm> | |
#include <string> | |
#include <vector> | |
#include<iostream> | |
#include <typeinfo> | |
#include <map> | |
using namespace std; | |
typedef enum{AutoInc, PrimaryKey, NotNull, Unique} ColumnOption; | |
class Expression{ | |
public: | |
Expression():rep(""){} | |
Expression(std::string _rep):rep(_rep){} | |
template <typename T> | |
Expression operator ==(const T& v ); | |
Expression operator ==(const Expression& expr); | |
Expression operator and(const Expression& expr){ | |
return Expression(this->compose() + " AND " + expr.compose()); | |
} | |
const std::string compose()const{ return this->rep; }; | |
std::string rep; | |
}; | |
typedef std::vector<Expression> vExpression; | |
class UntypedColumn{ | |
public: | |
UntypedColumn(string _name, std::vector<ColumnOption> _opts): name(_name),options(_opts){ | |
} | |
string name; | |
std::vector<ColumnOption> options; | |
}; | |
template <class T> | |
class TypedColumn: public UntypedColumn, public Expression{ | |
public: | |
TypedColumn(string _name, vector<ColumnOption> opts): UntypedColumn(_name, opts){} | |
const std::string type(){T ptrT; return typeid(ptrT).name();} | |
T getValue()const{ return T(); } | |
string valueToSQLLiteral(T v){ | |
return string("'sqlLiteral'"); | |
} | |
UntypedColumn* untyped(){ | |
return new UntypedColumn(this->name, this->options); | |
} | |
Expression operator >(const T& val){ | |
return Expression(this->name + " > " + this->valueToSQLLiteral(val)); | |
} | |
Expression operator -(const T& val){ | |
return Expression(this->name + " - " + this->valueToSQLLiteral(val)); | |
} | |
Expression operator +(const T& val){ | |
return Expression(this->name + " + " + this->valueToSQLLiteral(val)); | |
} | |
Expression operator <(const T& val){ | |
return Expression(this->name + " < " + this->valueToSQLLiteral(val)); | |
} | |
Expression operator <(const Expression& e){ | |
return Expression(this->name + " < (" + e.compose() + ") "); | |
} | |
Expression operator and(const Expression& e){ | |
return Expression(this->compose() + " AND " + e.compose()); | |
} | |
}; | |
template <> | |
std::string TypedColumn<int>::valueToSQLLiteral(int v){ | |
return std::to_string(v); | |
} | |
template <> | |
std::string TypedColumn<std::string>::valueToSQLLiteral(std::string v){ | |
return "'"+v+"'"; | |
} | |
template <class T> | |
class Column: public TypedColumn<T>{ | |
public: | |
Column(string _name, vector<ColumnOption> opts):TypedColumn<T>(_name, opts){ | |
} | |
}; | |
template <typename T> | |
class SchemaBuilder{ | |
public: | |
SchemaBuilder(T* _table):table(_table){ | |
} | |
virtual ~SchemaBuilder(){ | |
} | |
std::string create_statements(){ | |
std::string s = "CREATE TABLE " + table->name + "("; | |
auto type_map = this->table->type_map(); | |
int c=0, size = this->table->columns.size(); | |
for(auto untypedCol: this->table->columns){ | |
std::string ti = type_map[untypedCol->name]; | |
c += 1; | |
s += (untypedCol->name + " " + this->typeToSQLType(ti) + this->column_options(untypedCol->options) + (c == size ? "": ", ")); | |
} | |
s += " ); \n"; | |
return s; | |
} | |
std::string column_options(const std::vector<ColumnOption> opts){ | |
std::string s; | |
for(auto opt: opts) | |
switch(opt){ | |
case PrimaryKey: s += " PRIMARY KEY"; break; | |
case AutoInc: s += " AUTO_INCREMENT "; break; | |
case NotNull: s += " NOT NULL "; break; | |
case Unique: s += " UNIQUE "; break; | |
} | |
return s; | |
} | |
std::string typeToSQLType(const std::string ti){ | |
std::string s; | |
int i; | |
long l; | |
float f; | |
char c; | |
char* cPtr; | |
if(ti == typeid(int(0)).name()) | |
return "INT"; | |
if(ti == typeid(string("")).name()) | |
return "TEXT"; | |
if(ti == typeid(char(0)).name()) | |
return "CHAR"; | |
if(ti == typeid(new char(0)).name()) | |
return "VARCHAR(255)"; | |
if(ti == typeid(float(0.00)).name()) | |
return "FLOAT"; | |
else | |
return "BLOB"; | |
} | |
T* table; | |
}; | |
template <typename Type> | |
class Table{ | |
public: | |
Table(string _name, string schema):name(_name),_schema(this){} | |
virtual ~Table(){ | |
//for(auto c: this->columns){ | |
// delete c; | |
//} | |
} | |
template <typename T> | |
Column<T>* column(string name, vector<ColumnOption> options){ | |
Column<T>* col = new Column<T>(name, options); | |
std::cout<<"\n"<<typeid(col).name()<<endl; | |
columns.push_back(col->untyped()); | |
//colTypeMap.insert(std::make_pair(col->name, col->type())); | |
register_column(col); | |
return col; | |
} | |
const SchemaBuilder<Table<Type>> schema() const{ | |
return this->_schema; | |
} | |
const std::map<std::string, std::string> type_map()const{ | |
return this->colTypeMap; | |
} | |
Type projection_(Type row, Table t); | |
std::vector<UntypedColumn*> columns; | |
std::string name; | |
private: | |
std::map<std::string, std::string> colTypeMap; | |
template <typename T> | |
void register_column(Column<T>* col){ | |
colTypeMap[col->name] = col->type(); | |
} | |
SchemaBuilder<Table<Type>> _schema; | |
}; | |
template <typename T> | |
class TableQuery{ | |
public: | |
TableQuery():table(new T()){ | |
}; | |
virtual ~TableQuery(){ | |
delete this->table; | |
} | |
string result()const{}; | |
void where(Expression e){ | |
map(); | |
std::cout<<" WHERE "<<e.compose()<<endl; | |
} | |
void map(){ | |
string s = "SELECT "; | |
for(auto vcol : table->columns){ | |
//std::cout<<vcol->type().name()<<endl; | |
//Column<void*>* col = boost::any_cast<Column<void*>>(vcol); | |
s += vcol->name + " , "; | |
} | |
s += " 1 FROM "; | |
std::cout<<s; | |
} | |
void filter(Expression e){ | |
} | |
T* table; | |
}; | |
//template <typename T> | |
//Column<T>* column(string name, vector<ColumnOption> options){ return new Column<T>(name, options);} | |
class User { | |
public: | |
int id; | |
string name; | |
float amount; | |
}; | |
class UsersTable: public Table<User>{ | |
public: | |
UsersTable():Table("users", ""){ | |
id = column<int>("id", {AutoInc, PrimaryKey}); | |
name = column<string>("name", vector<ColumnOption>()); | |
amount = column<float>("amount", {}); | |
} | |
~UsersTable(){} | |
const Column<int>* id; | |
const Column<string>* name; | |
const Column<float>* amount; | |
User projection_(User row, UsersTable t){ | |
User u; | |
u.id = t.id->getValue(); | |
u.name = t.name->getValue(); | |
return u; | |
} | |
}; | |
int main(){ | |
TableQuery<UsersTable>* tq = new TableQuery<UsersTable>(); | |
UsersTable* ut = tq->table; | |
//tq->map(); | |
auto name = *(ut->name); | |
auto id = *(ut->id); | |
tq->where(id < 90 and id < (id + 10) and (name - string("trevor"))); | |
auto cs = ut->schema();//.create_statements(); | |
std::cout<<std::endl<<cs.create_statements(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment