From 00c327f57efdf5216ff49b695d6bf850f1a6409d Mon Sep 17 00:00:00 2001 From: MoonlightSentinel Date: Fri, 7 May 2021 21:33:40 +0200 Subject: [PATCH] database_generation: Don't assign to functions, ... in populateFromDbRow Using `tupleof` instead of `__traits(allMembers, ...)` skips over all nested declarations that are not actual fields. --- database.d | 52 +++++++++++++++++++++++++++++++++++++++++++ database_generation.d | 28 ++++++++++++++++++----- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/database.d b/database.d index 99d0257..51e49ab 100644 --- a/database.d +++ b/database.d @@ -1468,5 +1468,57 @@ struct varchar(size_t max) { alias asString this; } +version (unittest) +{ + /// Unittest utility that returns a predefined set of values + package (arsd) final class PredefinedResultSet : ResultSet + { + string[] fields; + Row[] rows; + size_t current; + this(string[] fields, Row[] rows) + { + this.fields = fields; + this.rows = rows; + foreach (ref row; rows) + row.resultSet = this; + } + int getFieldIndex(const string field) const + { + foreach (const idx, const val; fields) + if (val == field) + return cast(int) idx; + + assert(false, "No field with name: " ~ field); + } + + string[] fieldNames() + { + return fields; + } + + @property bool empty() const + { + return current == rows.length; + } + + Row front() @property + { + assert(!empty); + return rows[current]; + } + + void popFront() + { + assert(!empty); + current++; + } + + size_t length() @property + { + return rows.length - current; + } + } +} diff --git a/database_generation.d b/database_generation.d index 30b8abf..6c4470e 100644 --- a/database_generation.d +++ b/database_generation.d @@ -378,11 +378,9 @@ auto find(alias T)(Database db, int id) { private void populateFromDbRow(T)(ref T t, Row record) { foreach(field, value; record) { sw: switch(field) { - static foreach(memberName; __traits(allMembers, T)) { - case memberName: - static if(is(typeof(__traits(getMember, T, memberName)))) { - populateFromDbVal(__traits(getMember, t, memberName), value); - } + static foreach(const idx, alias mem; T.tupleof) { + case __traits(identifier, mem): + populateFromDbVal(t.tupleof[idx], value); break sw; } default: @@ -414,6 +412,26 @@ private void populateFromDbVal(V)(ref V val, string value) { } } +unittest +{ + static struct SomeStruct + { + int a; + void foo() {} + int b; + } + + auto rs = new PredefinedResultSet( + [ "a", "b" ], + [ Row([ "1", "2" ]) ] + ); + + SomeStruct s; + populateFromDbRow(s, rs.front); + + assert(s.a == 1); + assert(s.b == 2); +} /++ Gets all the children of that type. Specifically, it looks in T for a ForeignKey referencing B and queries on that.