Skip to content

Instantly share code, notes, and snippets.

@trevorsibanda
Created April 29, 2017 14:25
Show Gist options
  • Save trevorsibanda/94312f87ff5e98aeb4a5357565d5f981 to your computer and use it in GitHub Desktop.
Save trevorsibanda/94312f87ff5e98aeb4a5357565d5f981 to your computer and use it in GitHub Desktop.
C++ define sql tables as classes. typesafe.
//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