-
-
Save patrickkh7788/2b62f721f5a2608c0761f089f0832efb to your computer and use it in GitHub Desktop.
optimized ORM queries http://dpaste.dzfl.pl/cd375ac594cf
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
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