Data row returned from database servers.
DBRow
may be instantiated with any number of arguments. It subtypes base type which
depends on that number:
Number of arguments | Base type |
0 | Variant[]
It is default dynamic row, which can handle arbitrary number of columns and any of their types.
|
1 | Specs itself, more precisely Specs[0]
struct S { int i, float f }
DBRow!int rowInt;
DBRow!S rowS;
DBRow!(Tuple!(string, bool)) rowTuple;
DBRow!(int[10]) rowSA;
DBRow!(bool[]) rowDA;
|
>= 2 | Tuple!Specs
DBRow!(int, string) row1; // two arguments
DBRow!(int, "i") row2; // two arguments
|
If there is only one argument, the semantics depend on its type:
Type | Semantics |
base type, such as int | Row contains only one column of that type |
struct | Row columns are mapped to fields of the struct in the same order |
Tuple | Row columns are mapped to tuple fields in the same order |
static array | Row columns are mapped to array items, they share the same type |
dynamic array | Same as static array, except that column count may change during runtime |
Note:
String types are treated as base types.
There is an exception for RDBMSes which are capable of returning arrays and/or composite types. If such a
database server returns array or composite in one column it may be mapped to
DBRow
as if it was many columns.
For example:
struct S { string field1; int field2; }
DBRow!S row;
In this case row may handle result that either:
- has two columns convertible to respectively, string and int
- has one column with composite type compatible with S
DBRow's instantiated with dynamic array (and thus default Variant[]) provide additional bracket syntax
for accessing fields:
auto value = row["columnName"];
There are cases when result contains duplicate column names. Normally column name inside brackets refers
to the first column of that name. To access other columns with that name, use additional index parameter:
auto value = row["columnName", 1]; // second column named "columnName"
auto value = row["columnName", 0]; // first column named "columnName"
auto value = row["columnName"]; // same as above
Examples:
Default untyped (dynamic) DBRow:
DBRow!() row1;
DBRow!(Variant[]) row2;
assert(is(typeof(row1.base == row2.base)));
auto cmd = new PGCommand(conn, "SElECT typname, typlen FROM pg_type");
auto result = cmd.executeQuery;
foreach (i, row; result)
{
writeln(i, " - ", row["typname"], ", ", row["typlen"]);
}
result.close;
DBRow with only one field:
DBRow!int row;
row = 10;
row += 1;
assert(row == 11);
DBRow!Variant untypedRow;
untypedRow = 10;
DBRow with more than one field:
struct S { int i; string s; }
alias Tuple!(int, "i", string, "s") TS;
// all three rows are compatible
DBRow!S row1;
DBRow!TS row2;
DBRow!(int, "i", string, "s") row3;
row1.i = row2.i = row3.i = 10;
row1.s = row2.s = row3.s = "abc";
// these two rows are also compatible
DBRow!(int, int) row4;
DBRow!(int[2]) row5;
row4[0] = row5[0] = 10;
row4[1] = row5[1] = 20;
Advanced example:
enum Axis { x, y, z }
struct SubRow1 { string s; int[] nums; int num; }
alias Tuple!(int, "num", string, "s") SubRow2;
struct Row { SubRow1 left; SubRow2[] right; Axis axis; string text; }
auto cmd = new PGCommand(conn, "SELECT ROW('text', ARRAY[1, 2, 3], 100),
ARRAY[ROW(1, 'str'), ROW(2, 'aab')], 'x', 'anotherText'");
auto row = cmd.executeRow!Row;
assert(row.left.s == "text");
assert(row.left.nums == [1, 2, 3]);
assert(row.left.num == 100);
assert(row.right[0].num == 1 && row.right[0].s == "str");
assert(row.right[1].num == 2 && row.right[1].s == "aab");
assert(row.axis == Axis.x);
assert(row.s == "anotherText");
- void
checkReceivedFieldCount
(int fieldCount);
- Checks if received field count matches field count of this row type.
This is used internally by clients and it applies only to DBRow types, which have static number of fields.