1 module mysql.row; 2 3 4 import std.algorithm; 5 import std.datetime; 6 import std.traits; 7 import std.typecons; 8 9 import mysql.exception; 10 import mysql.type; 11 12 13 template isWritableDataMember(T, string Member) { 14 static if (is(TypeTuple!(__traits(getMember, T, Member)))) { 15 enum isWritableDataMember = false; 16 } else static if (!is(typeof(__traits(getMember, T, Member)))) { 17 enum isWritableDataMember = false; 18 } else static if (is(typeof(__traits(getMember, T, Member)) == void)) { 19 enum isWritableDataMember = false; 20 } else static if (isSomeFunction!(typeof(__traits(getMember, T, Member)))) { 21 enum isWritableDataMember = false; 22 } else static if (!is(typeof((){ T x = void; __traits(getMember, x, Member) = __traits(getMember, x, Member); }()))) { 23 enum isWritableDataMember = false; 24 } else static if ((__traits(getProtection, __traits(getMember, T, Member)) != "public") && (__traits(getProtection, __traits(getMember, T, Member)) != "export")) { 25 enum isWritableDataMember = false; 26 } else { 27 enum isWritableDataMember = true; 28 } 29 } 30 31 32 enum Strict { 33 yes = 0, 34 no, 35 } 36 37 38 struct MySQLRow { 39 package void header(MySQLHeader header) { 40 index_ = null; 41 names_.length = header.length; 42 foreach (index, column; header) { 43 names_[index] = column.name; 44 index_[column.name] = index; 45 } 46 } 47 48 package void set(size_t index, MySQLValue x) { 49 values_[index] = x; 50 } 51 52 package void nullify(size_t index) { 53 values_[index].nullify(); 54 } 55 56 package @property length(size_t x) { 57 values_.length = x; 58 } 59 60 @property length() const { 61 return values_.length; 62 } 63 64 @property const(string)[] columns() const { 65 return names_; 66 } 67 68 @property MySQLValue opDispatch(string key)() const { 69 return opIndex(key); 70 } 71 72 MySQLValue opIndex(string key) const { 73 if (auto pindex = key in index_) 74 return values_[*pindex]; 75 throw new MySQLErrorException("Column '" ~ key ~ "' was not found in this result set"); 76 } 77 78 MySQLValue opIndex(size_t index) const { 79 return values_[index]; 80 } 81 82 const(MySQLValue)* opBinaryRight(string op)(string key) const if (op == "in") { 83 if (auto pindex = key in index_) 84 return &values_[*pindex]; 85 return null; 86 } 87 88 int opApply(int delegate(const ref MySQLValue value) del) const { 89 foreach (ref v; values_) 90 if (auto ret = del(v)) 91 return ret; 92 return 0; 93 } 94 95 int opApply(int delegate(ref size_t, const ref MySQLValue) del) const { 96 foreach (ref size_t i, ref v; values_) 97 if (auto ret = del(i, v)) 98 return ret; 99 return 0; 100 } 101 102 int opApply(int delegate(const ref string, const ref MySQLValue) del) const { 103 foreach (size_t i, ref v; values_) 104 if (auto ret = del(names_[i], v)) 105 return ret; 106 return 0; 107 } 108 109 string toString() const { 110 import std.conv; 111 return to!string(values_); 112 } 113 114 string[] toStringArray(size_t start = 0, size_t end = ~cast(size_t)0) const { 115 end = min(end, values_.length); 116 start = min(start, values_.length); 117 if (start > end) 118 swap(start, end); 119 120 string[] result; 121 result.reserve(end - start); 122 foreach(i; start..end) 123 result ~= values_[i].toString; 124 return result; 125 } 126 127 void toStruct(T, Strict strict = Strict.yes)(ref T x) if(is(Unqual!T == struct)) { 128 static if (isTuple!(Unqual!T)) { 129 foreach(i, ref f; x.field) { 130 static if (strict == Strict.yes) { 131 f = this[i].get!(Unqual!(typeof(f))); 132 } else { 133 if (!this[i].isNull) 134 f = this[i].get!(Unqual!(typeof(f))); 135 } 136 } 137 } else { 138 structurize!(T, strict, null)(x); 139 } 140 } 141 142 T toStruct(T, Strict strict = Strict.yes)() if (is(Unqual!T == struct)) { 143 T result; 144 toStruct!(T, strict)(result); 145 return result; 146 } 147 148 private: 149 void structurize(T, Strict strict = Strict.yes, string path = null)(ref T result) { 150 foreach(member; __traits(allMembers, T)) { 151 static if (isWritableDataMember!(T, member)) { 152 enum pathMember = path ~ member; 153 alias MemberType = typeof(__traits(getMember, result, member)); 154 155 static if (is(Unqual!MemberType == struct) && !is(Unqual!MemberType == Date) && !is(Unqual!MemberType == DateTime) && !is(Unqual!MemberType == SysTime) && !is(Unqual!MemberType == Duration)) { 156 enum pathNew = pathMember ~ "."; 157 structurize!(MemberType, strict, pathNew)(__traits(getMember, result, member)); 158 } else { 159 static if (strict == Strict.yes) { 160 __traits(getMember, result, member) = this[pathMember].get!(Unqual!MemberType); 161 } else { 162 auto pvalue = pathMember in this; 163 if (pvalue && !pvalue.isNull) 164 __traits(getMember, result, member) = pvalue.get!(Unqual!MemberType); 165 } 166 } 167 } 168 } 169 } 170 171 MySQLValue[] values_; 172 string[] names_; 173 size_t[string] index_; 174 }