Skip to content

Instantly share code, notes, and snippets.

@MartinNowak
Created February 26, 2016 20:04
Show Gist options
  • Save MartinNowak/b99f6205db47703b0635 to your computer and use it in GitHub Desktop.
Save MartinNowak/b99f6205db47703b0635 to your computer and use it in GitHub Desktop.
optimized ORM queries http://dpaste.dzfl.pl/cd375ac594cf
import std.stdio, std.variant;
//==============================================================================
// registry for query field names
template registerQuery(T, string file, size_t line)
{
__gshared string[] fields;
}
template registerQueryField(T, string field, string file, size_t line)
{
static immutable size_t index;
shared static this()
{
// collect all fields in an array
index = registerQuery!(T, file, line).fields.length;
registerQuery!(T, file, line).fields ~= field;
}
// "return" index
alias registerQueryField = index;
}
//==============================================================================
class DB
{
// each query is a unique type, hence the file and line arguments
auto get(T, string file=__FILE__, size_t line=__LINE__)()
{
return Query!(T, file, line)(this);
}
}
struct Query(T, string file, size_t line)
{
alias QueryRow = Row!(T, file, line);
QueryRow first()
{
if (_where.length)
writefln("SELECT %-(%s, %) FROM %s WHERE %s;", usedFields, T.stringof, _where);
else
writefln("SELECT %-(%s, %) FROM %s;", usedFields, T.stringof);
// db code here
auto data = new Variant[](usedFields.length);
data[0] = "Martin";
data[1] = cast(ubyte)31;
// return row
return QueryRow(data);
}
private:
// returns all registered fields
@property string[] usedFields()
{
return registerQuery!(T, file, line).fields;
}
alias Type = T;
DB db;
string _where;
}
struct Row(T, string file, size_t line)
{
Variant[] row;
auto opDispatch(string name)()
{
// get the column index for this query and field name
alias columnIndex = registerQueryField!(T, name, file, line);
// get the field type of T.name
alias FieldType = typeof(__traits(getMember, Person.init, name));
writefln("get column %s as type %s", columnIndex, FieldType.stringof);
return row[columnIndex].get!FieldType();
}
}
//==============================================================================
Query where(alias pred, Query)(Query query)
{
string result;
auto p = Where!(Query.Type)(&result);
pred(p); // record predicate
query._where ~= result;
return query;
}
struct Where(T)
{
auto opDispatch(string name)()
{
alias FieldType = typeof(__traits(getMember, Person.init, name));
return WhereField!(T, FieldType, name)(_result);
}
private:
string* _result;
}
struct WhereField(T, FieldType, string name)
{
void opEquals(T)(T arg)
{
import std.string;
*_result ~= "%s = %s".format(name, arg);
}
// can't use opCmp
void lt(T)(T arg)
{
import std.string;
*_result ~= "%s < %s".format(name, arg);
}
void gt(T)(T arg)
{
import std.string;
*_result ~= "%s > %s".format(name, arg);
}
private:
string* _result;
}
//==============================================================================
struct Person { string name; ubyte age; uint birthday; }
void main()
{
auto db = new DB();
auto p = db.get!Person.first;
writefln("name %s age %s", p.name, p.age);
auto p2 = db.get!Person.where!(p => p.name == "Martin").first;
writefln("name %s age %s", p2.name, p2.age);
auto p3 = db.get!Person.where!(p => p.age.gt(21)).first;
writefln("name %s age %s", p3.name, p3.age);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment