1 /** 2 DDBC - D DataBase Connector - abstraction layer for RDBMS access, with interface similar to JDBC. 3 4 Source file ddbc/drivers/pgsqlddbc.d. 5 DDBC library attempts to provide implementation independent interface to different databases. 6 7 Set of supported RDBMSs can be extended by writing Drivers for particular DBs. 8 9 JDBC documentation can be found here: 10 $(LINK http://docs.oracle.com/javase/1.5.0/docs/api/java/sql/package-summary.html)$(BR) 11 12 This module contains implementation POD utilities. 13 ---- 14 import ddbc; 15 import std.stdio; 16 17 // prepare database connectivity 18 auto conn = createConnection("sqlite:ddbctest.sqlite"); 19 scope(exit) conn.close(); 20 Statement stmt = conn.createStatement(); 21 scope(exit) stmt.close(); 22 // fill database with test data 23 stmt.executeUpdate("DROP TABLE IF EXISTS user"); 24 stmt.executeUpdate("CREATE TABLE user (id INTEGER PRIMARY KEY, name VARCHAR(255) NOT NULL, flags int null)"); 25 stmt.executeUpdate(`INSERT INTO user (id, name, flags) VALUES (1, "John", 5), (2, "Andrei", 2), (3, "Walter", 2), (4, "Rikki", 3), (5, "Iain", 0), (6, "Robert", 1)`); 26 27 // our POD object 28 struct User { 29 long id; 30 string name; 31 int flags; 32 } 33 34 writeln("reading all user table rows"); 35 foreach(e; stmt.select!User) { 36 writeln("id:", e.id, " name:", e.name, " flags:", e.flags); 37 } 38 39 writeln("reading user table rows with where and order by"); 40 foreach(e; stmt.select!User.where("id < 6").orderBy("name desc")) { 41 writeln("id:", e.id, " name:", e.name, " flags:", e.flags); 42 } 43 ---- 44 45 Copyright: Copyright 2013 46 License: $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 47 Author: Vadim Lopatin 48 */ 49 module ddbc.pods; 50 51 import std.algorithm; 52 import std.traits; 53 import std.typecons; 54 import std.conv; 55 import std.datetime; 56 import std..string; 57 import std.variant; 58 59 static import std.ascii; 60 61 import ddbc.core; 62 63 alias Nullable!byte Byte; 64 alias Nullable!ubyte Ubyte; 65 alias Nullable!short Short; 66 alias Nullable!ushort Ushort; 67 alias Nullable!int Int; 68 alias Nullable!uint Uint; 69 alias Nullable!long Long; 70 alias Nullable!ulong Ulong; 71 alias Nullable!float Float; 72 alias Nullable!double Double; 73 alias Nullable!SysTime NullableSysTime; 74 alias Nullable!DateTime NullableDateTime; 75 alias Nullable!Date NullableDate; 76 alias Nullable!TimeOfDay NullableTimeOfDay; 77 78 /// Wrapper around string, to distinguish between Null and NotNull fields: string is NotNull, String is Null -- same interface as in Nullable 79 // Looks ugly, but I tried `typedef string String`, but it is deprecated; `alias string String` cannot be distinguished from just string. How to define String better? 80 struct String 81 { 82 string _value; 83 84 /** 85 Returns $(D true) if and only if $(D this) is in the null state. 86 */ 87 @property bool isNull() const pure nothrow @safe 88 { 89 return _value is null; 90 } 91 92 /** 93 Forces $(D this) to the null state. 94 */ 95 void nullify() 96 { 97 _value = null; 98 } 99 100 alias _value this; 101 } 102 103 enum PropertyMemberType : int { 104 BOOL_TYPE, // bool 105 BYTE_TYPE, // byte 106 SHORT_TYPE, // short 107 INT_TYPE, // int 108 LONG_TYPE, // long 109 UBYTE_TYPE, // ubyte 110 USHORT_TYPE, // ushort 111 UINT_TYPE, // uint 112 ULONG_TYPE, // ulong 113 NULLABLE_BYTE_TYPE, // Nullable!byte 114 NULLABLE_SHORT_TYPE, // Nullable!short 115 NULLABLE_INT_TYPE, // Nullable!int 116 NULLABLE_LONG_TYPE, // Nullable!long 117 NULLABLE_UBYTE_TYPE, // Nullable!ubyte 118 NULLABLE_USHORT_TYPE,// Nullable!ushort 119 NULLABLE_UINT_TYPE, // Nullable!uint 120 NULLABLE_ULONG_TYPE, // Nullable!ulong 121 FLOAT_TYPE, // float 122 DOUBLE_TYPE, // double 123 NULLABLE_FLOAT_TYPE, // Nullable!float 124 NULLABLE_DOUBLE_TYPE,// Nullable!double 125 STRING_TYPE, // string 126 NULLABLE_STRING_TYPE, // nullable string - String struct 127 SYSTIME_TYPE, 128 DATETIME_TYPE, // std.datetime.DateTime 129 DATE_TYPE, // std.datetime.Date 130 TIME_TYPE, // std.datetime.TimeOfDay 131 NULLABLE_SYSTIME_TYPE, 132 NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 133 NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 134 NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 135 BYTE_ARRAY_TYPE, // byte[] 136 UBYTE_ARRAY_TYPE, // ubyte[] 137 } 138 139 /// converts camel case MyEntityName to my_entity_name 140 string camelCaseToUnderscoreDelimited(immutable string s) { 141 string res; 142 bool lastLower = false; 143 static import std.ascii; 144 145 foreach(ch; s) { 146 if (ch >= 'A' && ch <= 'Z') { 147 if (lastLower) { 148 lastLower = false; 149 res ~= "_"; 150 } 151 res ~= std.ascii.toLower(ch); 152 } else if (ch >= 'a' && ch <= 'z') { 153 lastLower = true; 154 res ~= ch; 155 } else { 156 res ~= ch; 157 } 158 } 159 return res; 160 } 161 162 unittest { 163 static assert(camelCaseToUnderscoreDelimited("User") == "user"); 164 static assert(camelCaseToUnderscoreDelimited("MegaTableName") == "mega_table_name"); 165 } 166 167 168 template isSupportedSimpleType(T, string m) { 169 alias typeof(__traits(getMember, T, m)) ti; 170 static if (is(ti == function)) { 171 static if (is(ReturnType!(ti) == bool)) { 172 enum bool isSupportedSimpleType = true; 173 } else static if (is(ReturnType!(ti) == byte)) { 174 enum bool isSupportedSimpleType = true; 175 } else static if (is(ReturnType!(ti) == short)) { 176 enum bool isSupportedSimpleType = true; 177 } else static if (is(ReturnType!(ti) == int)) { 178 enum bool isSupportedSimpleType = true; 179 } else static if (is(ReturnType!(ti) == long)) { 180 enum bool isSupportedSimpleType = true; 181 } else static if (is(ReturnType!(ti) == ubyte)) { 182 enum bool isSupportedSimpleType = true; 183 } else static if (is(ReturnType!(ti) == ushort)) { 184 enum bool isSupportedSimpleType = true; 185 } else static if (is(ReturnType!(ti) == uint)) { 186 enum bool isSupportedSimpleType = true; 187 } else static if (is(ReturnType!(ti) == ulong)) { 188 enum bool isSupportedSimpleType = true; 189 } else static if (is(ReturnType!(ti) == float)) { 190 enum bool isSupportedSimpleType = true; 191 } else static if (is(ReturnType!(ti) == double)) { 192 enum bool isSupportedSimpleType = true; 193 } else static if (is(ReturnType!(ti) == Nullable!byte)) { 194 enum bool isSupportedSimpleType = true; 195 } else static if (is(ReturnType!(ti) == Nullable!short)) { 196 enum bool isSupportedSimpleType = true; 197 } else static if (is(ReturnType!(ti) == Nullable!int)) { 198 enum bool isSupportedSimpleType = true; 199 } else static if (is(ReturnType!(ti) == Nullable!long)) { 200 enum bool isSupportedSimpleType = true; 201 } else static if (is(ReturnType!(ti) == Nullable!ubyte)) { 202 enum bool isSupportedSimpleType = true; 203 } else static if (is(ReturnType!(ti) == Nullable!ushort)) { 204 enum bool isSupportedSimpleType = true; 205 } else static if (is(ReturnType!(ti) == Nullable!uint)) { 206 enum bool isSupportedSimpleType = true; 207 } else static if (is(ReturnType!(ti) == Nullable!ulong)) { 208 enum bool isSupportedSimpleType = true; 209 } else static if (is(ReturnType!(ti) == Nullable!float)) { 210 enum bool isSupportedSimpleType = true; 211 } else static if (is(ReturnType!(ti) == Nullable!double)) { 212 enum bool isSupportedSimpleType = true; 213 } else static if (is(ReturnType!(ti) == string)) { 214 enum bool isSupportedSimpleType = true; 215 } else static if (is(ReturnType!(ti) == String)) { 216 enum bool isSupportedSimpleType = true; 217 } else static if (is(ReturnType!(ti) == SysTime)) { 218 enum bool isSupportedSimpleType = true; 219 } else static if (is(ReturnType!(ti) == DateTime)) { 220 enum bool isSupportedSimpleType = true; 221 } else static if (is(ReturnType!(ti) == Date)) { 222 enum bool isSupportedSimpleType = true; 223 } else static if (is(ReturnType!(ti) == TimeOfDay)) { 224 enum bool isSupportedSimpleType = true; 225 } else static if (is(ReturnType!(ti) == Nullable!SysTime)) { 226 enum bool isSupportedSimpleType = true; 227 } else static if (is(ReturnType!(ti) == Nullable!DateTime)) { 228 enum bool isSupportedSimpleType = true; 229 } else static if (is(ReturnType!(ti) == Nullable!Date)) { 230 enum bool isSupportedSimpleType = true; 231 } else static if (is(ReturnType!(ti) == Nullable!TimeOfDay)) { 232 enum bool isSupportedSimpleType = true; 233 } else static if (is(ReturnType!(ti) == byte[])) { 234 enum bool isSupportedSimpleType = true; 235 } else static if (is(ReturnType!(ti) == ubyte[])) { 236 enum bool isSupportedSimpleType = true; 237 } else static if (true) { 238 enum bool isSupportedSimpleType = false; 239 } 240 } else static if (is(ti == bool)) { 241 enum bool isSupportedSimpleType = true; 242 } else static if (is(ti == byte)) { 243 enum bool isSupportedSimpleType = true; 244 } else static if (is(ti == short)) { 245 enum bool isSupportedSimpleType = true; 246 } else static if (is(ti == int)) { 247 enum bool isSupportedSimpleType = true; 248 } else static if (is(ti == long)) { 249 enum bool isSupportedSimpleType = true; 250 } else static if (is(ti == ubyte)) { 251 enum bool isSupportedSimpleType = true; 252 } else static if (is(ti == ushort)) { 253 enum bool isSupportedSimpleType = true; 254 } else static if (is(ti == uint)) { 255 enum bool isSupportedSimpleType = true; 256 } else static if (is(ti == ulong)) { 257 enum bool isSupportedSimpleType = true; 258 } else static if (is(ti == float)) { 259 enum bool isSupportedSimpleType = true; 260 } else static if (is(ti == double)) { 261 enum bool isSupportedSimpleType = true; 262 } else static if (is(ti == Nullable!byte)) { 263 enum bool isSupportedSimpleType = true; 264 } else static if (is(ti == Nullable!short)) { 265 enum bool isSupportedSimpleType = true; 266 } else static if (is(ti == Nullable!int)) { 267 enum bool isSupportedSimpleType = true; 268 } else static if (is(ti == Nullable!long)) { 269 enum bool isSupportedSimpleType = true; 270 } else static if (is(ti == Nullable!ubyte)) { 271 enum bool isSupportedSimpleType = true; 272 } else static if (is(ti == Nullable!ushort)) { 273 enum bool isSupportedSimpleType = true; 274 } else static if (is(ti == Nullable!uint)) { 275 enum bool isSupportedSimpleType = true; 276 } else static if (is(ti == Nullable!ulong)) { 277 enum bool isSupportedSimpleType = true; 278 } else static if (is(ti == Nullable!float)) { 279 enum bool isSupportedSimpleType = true; 280 } else static if (is(ti == Nullable!double)) { 281 enum bool isSupportedSimpleType = true; 282 } else static if (is(ti == string)) { 283 enum bool isSupportedSimpleType = true; 284 } else static if (is(ti == String)) { 285 enum bool isSupportedSimpleType = true; 286 } else static if (is(ti == SysTime)) { 287 enum bool isSupportedSimpleType = true; 288 } else static if (is(ti == DateTime)) { 289 enum bool isSupportedSimpleType = true; 290 } else static if (is(ti == Date)) { 291 enum bool isSupportedSimpleType = true; 292 } else static if (is(ti == TimeOfDay)) { 293 enum bool isSupportedSimpleType = true; 294 } else static if (is(ti == Nullable!SysTime)) { 295 enum bool isSupportedSimpleType = true; 296 } else static if (is(ti == Nullable!DateTime)) { 297 enum bool isSupportedSimpleType = true; 298 } else static if (is(ti == Nullable!Date)) { 299 enum bool isSupportedSimpleType = true; 300 } else static if (is(ti == Nullable!TimeOfDay)) { 301 enum bool isSupportedSimpleType = true; 302 } else static if (is(ti == byte[])) { 303 enum bool isSupportedSimpleType = true; 304 } else static if (is(ti == ubyte[])) { 305 enum bool isSupportedSimpleType = true; 306 } else static if (true) { 307 enum bool isSupportedSimpleType = false; 308 } 309 } 310 311 PropertyMemberType getPropertyType(ti)() { 312 //pragma(msg, T.stringof); 313 //alias typeof(T) ti; 314 static if (is(ti == bool)) { 315 return PropertyMemberType.BOOL_TYPE; 316 } else static if (is(ti == byte)) { 317 return PropertyMemberType.BYTE_TYPE; 318 } else static if (is(ti == short)) { 319 return PropertyMemberType.SHORT_TYPE; 320 } else static if (is(ti == int)) { 321 return PropertyMemberType.INT_TYPE; 322 } else static if (is(ti == long)) { 323 return PropertyMemberType.LONG_TYPE; 324 } else static if (is(ti == ubyte)) { 325 return PropertyMemberType.UBYTE_TYPE; 326 } else static if (is(ti == ushort)) { 327 return PropertyMemberType.USHORT_TYPE; 328 } else static if (is(ti == uint)) { 329 return PropertyMemberType.UINT_TYPE; 330 } else static if (is(ti == ulong)) { 331 return PropertyMemberType.ULONG_TYPE; 332 } else static if (is(ti == float)) { 333 return PropertyMemberType.FLOAT_TYPE; 334 } else static if (is(ti == double)) { 335 return PropertyMemberType.DOUBLE_TYPE; 336 } else static if (is(ti == Nullable!byte)) { 337 return PropertyMemberType.NULLABLE_BYTE_TYPE; 338 } else static if (is(ti == Nullable!short)) { 339 return PropertyMemberType.NULLABLE_SHORT_TYPE; 340 } else static if (is(ti == Nullable!int)) { 341 return PropertyMemberType.NULLABLE_INT_TYPE; 342 } else static if (is(ti == Nullable!long)) { 343 return PropertyMemberType.NULLABLE_LONG_TYPE; 344 } else static if (is(ti == Nullable!ubyte)) { 345 return PropertyMemberType.NULLABLE_UBYTE_TYPE; 346 } else static if (is(ti == Nullable!ushort)) { 347 return PropertyMemberType.NULLABLE_USHORT_TYPE; 348 } else static if (is(ti == Nullable!uint)) { 349 return PropertyMemberType.NULLABLE_UINT_TYPE; 350 } else static if (is(ti == Nullable!ulong)) { 351 return PropertyMemberType.NULLABLE_ULONG_TYPE; 352 } else static if (is(ti == Nullable!float)) { 353 return PropertyMemberType.NULLABLE_FLOAT_TYPE; 354 } else static if (is(ti == Nullable!double)) { 355 return PropertyMemberType.NULLABLE_DOUBLE_TYPE; 356 } else static if (is(ti == string)) { 357 return PropertyMemberType.STRING_TYPE; 358 } else static if (is(ti == String)) { 359 return PropertyMemberType.NULLABLE_STRING_TYPE; 360 } else static if (is(ti == SysTime)) { 361 return PropertyMemberType.SYSTIME_TYPE; 362 } else static if (is(ti == DateTime)) { 363 return PropertyMemberType.DATETIME_TYPE; 364 } else static if (is(ti == Date)) { 365 return PropertyMemberType.DATE_TYPE; 366 } else static if (is(ti == TimeOfDay)) { 367 return PropertyMemberType.TIME_TYPE; 368 } else static if (is(ti == Nullable!SysTime)) { 369 return PropertyMemberType.NULLABLE_SYSTIME_TYPE; 370 } else static if (is(ti == Nullable!DateTime)) { 371 return PropertyMemberType.NULLABLE_DATETIME_TYPE; 372 } else static if (is(ti == Nullable!Date)) { 373 return PropertyMemberType.NULLABLE_DATE_TYPE; 374 } else static if (is(ti == Nullable!TimeOfDay)) { 375 return PropertyMemberType.NULLABLE_TIME_TYPE; 376 } else static if (is(ti == byte[])) { 377 return PropertyMemberType.BYTE_ARRAY_TYPE; 378 } else static if (is(ti == ubyte[])) { 379 return PropertyMemberType.UBYTE_ARRAY_TYPE; 380 } else static if (true) { 381 static assert (false, "has unsupported type " ~ ti.stringof); 382 } 383 } 384 385 PropertyMemberType getPropertyMemberType(T, string m)() { 386 alias typeof(__traits(getMember, T, m)) ti; 387 static if (is(ti == bool)) { 388 return PropertyMemberType.BOOL_TYPE; 389 } else static if (is(ti == byte)) { 390 return PropertyMemberType.BYTE_TYPE; 391 } else static if (is(ti == short)) { 392 return PropertyMemberType.SHORT_TYPE; 393 } else static if (is(ti == int)) { 394 return PropertyMemberType.INT_TYPE; 395 } else static if (is(ti == long)) { 396 return PropertyMemberType.LONG_TYPE; 397 } else static if (is(ti == ubyte)) { 398 return PropertyMemberType.UBYTE_TYPE; 399 } else static if (is(ti == ushort)) { 400 return PropertyMemberType.USHORT_TYPE; 401 } else static if (is(ti == uint)) { 402 return PropertyMemberType.UINT_TYPE; 403 } else static if (is(ti == ulong)) { 404 return PropertyMemberType.ULONG_TYPE; 405 } else static if (is(ti == float)) { 406 return PropertyMemberType.FLOAT_TYPE; 407 } else static if (is(ti == double)) { 408 return PropertyMemberType.DOUBLE_TYPE; 409 } else static if (is(ti == Nullable!byte)) { 410 return PropertyMemberType.NULLABLE_BYTE_TYPE; 411 } else static if (is(ti == Nullable!short)) { 412 return PropertyMemberType.NULLABLE_SHORT_TYPE; 413 } else static if (is(ti == Nullable!int)) { 414 return PropertyMemberType.NULLABLE_INT_TYPE; 415 } else static if (is(ti == Nullable!long)) { 416 return PropertyMemberType.NULLABLE_LONG_TYPE; 417 } else static if (is(ti == Nullable!ubyte)) { 418 return PropertyMemberType.NULLABLE_UBYTE_TYPE; 419 } else static if (is(ti == Nullable!ushort)) { 420 return PropertyMemberType.NULLABLE_USHORT_TYPE; 421 } else static if (is(ti == Nullable!uint)) { 422 return PropertyMemberType.NULLABLE_UINT_TYPE; 423 } else static if (is(ti == Nullable!ulong)) { 424 return PropertyMemberType.NULLABLE_ULONG_TYPE; 425 } else static if (is(ti == Nullable!float)) { 426 return PropertyMemberType.NULLABLE_FLOAT_TYPE; 427 } else static if (is(ti == Nullable!double)) { 428 return PropertyMemberType.NULLABLE_DOUBLE_TYPE; 429 } else static if (is(ti == string)) { 430 return PropertyMemberType.STRING_TYPE; 431 } else static if (is(ti == String)) { 432 return PropertyMemberType.NULLABLE_STRING_TYPE; 433 } else static if (is(ti == SysTime)) { 434 return PropertyMemberType.SYSTIME_TYPE; 435 } else static if (is(ti == DateTime)) { 436 return PropertyMemberType.DATETIME_TYPE; 437 } else static if (is(ti == Date)) { 438 return PropertyMemberType.DATE_TYPE; 439 } else static if (is(ti == TimeOfDay)) { 440 return PropertyMemberType.TIME_TYPE; 441 } else static if (is(ti == Nullable!SysTime)) { 442 return PropertyMemberType.NULLABLE_SYSTIME_TYPE; 443 } else static if (is(ti == Nullable!DateTime)) { 444 return PropertyMemberType.NULLABLE_DATETIME_TYPE; 445 } else static if (is(ti == Nullable!Date)) { 446 return PropertyMemberType.NULLABLE_DATE_TYPE; 447 } else static if (is(ti == Nullable!TimeOfDay)) { 448 return PropertyMemberType.NULLABLE_TIME_TYPE; 449 } else static if (is(ti == byte[])) { 450 return PropertyMemberType.BYTE_ARRAY_TYPE; 451 } else static if (is(ti == ubyte[])) { 452 return PropertyMemberType.UBYTE_ARRAY_TYPE; 453 } else static if (true) { 454 static assert (false, "Member " ~ m ~ " of class " ~ T.stringof ~ " has unsupported type " ~ ti.stringof); 455 } 456 } 457 458 string getPropertyReadCode(T, string m)() { 459 return "entity." ~ m; 460 } 461 462 string getPropertyReadCode(alias T)() { 463 return "entity." ~ T.stringof; 464 } 465 466 static immutable bool[] ColumnTypeCanHoldNulls = 467 [ 468 false, //BOOL_TYPE // bool 469 false, //BYTE_TYPE, // byte 470 false, //SHORT_TYPE, // short 471 false, //INT_TYPE, // int 472 false, //LONG_TYPE, // long 473 false, //UBYTE_TYPE, // ubyte 474 false, //USHORT_TYPE, // ushort 475 false, //UINT_TYPE, // uint 476 false, //ULONG_TYPE, // ulong 477 true, //NULLABLE_BYTE_TYPE, // Nullable!byte 478 true, //NULLABLE_SHORT_TYPE, // Nullable!short 479 true, //NULLABLE_INT_TYPE, // Nullable!int 480 true, //NULLABLE_LONG_TYPE, // Nullable!long 481 true, //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 482 true, //NULLABLE_USHORT_TYPE,// Nullable!ushort 483 true, //NULLABLE_UINT_TYPE, // Nullable!uint 484 true, //NULLABLE_ULONG_TYPE, // Nullable!ulong 485 false,//FLOAT_TYPE, // float 486 false,//DOUBLE_TYPE, // double 487 true, //NULLABLE_FLOAT_TYPE, // Nullable!float 488 true, //NULLABLE_DOUBLE_TYPE,// Nullable!double 489 false, //STRING_TYPE // string -- treat as @NotNull by default 490 true, //NULLABLE_STRING_TYPE // String 491 false, //SYSTIME_TYPE 492 false, //DATETIME_TYPE, // std.datetime.DateTime 493 false, //DATE_TYPE, // std.datetime.Date 494 false, //TIME_TYPE, // std.datetime.TimeOfDay 495 true, //NULLABLE_SYSTIME_TYPE 496 true, //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 497 true, //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 498 true, //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 499 true, //BYTE_ARRAY_TYPE, // byte[] 500 true, //UBYTE_ARRAY_TYPE, // ubyte[] 501 ]; 502 503 bool isColumnTypeNullableByDefault(T, string m)() { 504 return ColumnTypeCanHoldNulls[getPropertyMemberType!(T,m)]; 505 } 506 507 static immutable string[] ColumnTypeKeyIsSetCode = 508 [ 509 "(%s != 0)", //BOOL_TYPE // bool 510 "(%s != 0)", //BYTE_TYPE, // byte 511 "(%s != 0)", //SHORT_TYPE, // short 512 "(%s != 0)", //INT_TYPE, // int 513 "(%s != 0)", //LONG_TYPE, // long 514 "(%s != 0)", //UBYTE_TYPE, // ubyte 515 "(%s != 0)", //USHORT_TYPE, // ushort 516 "(%s != 0)", //UINT_TYPE, // uint 517 "(%s != 0)", //ULONG_TYPE, // ulong 518 "(!%s.isNull)", //NULLABLE_BYTE_TYPE, // Nullable!byte 519 "(!%s.isNull)", //NULLABLE_SHORT_TYPE, // Nullable!short 520 "(!%s.isNull)", //NULLABLE_INT_TYPE, // Nullable!int 521 "(!%s.isNull)", //NULLABLE_LONG_TYPE, // Nullable!long 522 "(!%s.isNull)", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 523 "(!%s.isNull)", //NULLABLE_USHORT_TYPE,// Nullable!ushort 524 "(!%s.isNull)", //NULLABLE_UINT_TYPE, // Nullable!uint 525 "(!%s.isNull)", //NULLABLE_ULONG_TYPE, // Nullable!ulong 526 "(%s != 0)",//FLOAT_TYPE, // float 527 "(%s != 0)",//DOUBLE_TYPE, // double 528 "(!%s.isNull)", //NULLABLE_FLOAT_TYPE, // Nullable!float 529 "(!%s.isNull)", //NULLABLE_DOUBLE_TYPE,// Nullable!double 530 "(%s !is null)", //STRING_TYPE // string 531 "(%s !is null)", //NULLABLE_STRING_TYPE // String 532 "(%s != SysTime())", //SYSTIME_TYPE, // std.datetime.systime : SysTime 533 "(%s != DateTime())", //DATETIME_TYPE, // std.datetime.DateTime 534 "(%s != Date())", //DATE_TYPE, // std.datetime.Date 535 "(%s != TimeOfDay())", //TIME_TYPE, // std.datetime.TimeOfDay 536 "(!%s.isNull)", //NULLABLE_SYSTIME_TYPE, // Nullable!std.datetime.systime.SysTime 537 "(!%s.isNull)", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 538 "(!%s.isNull)", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 539 "(!%s.isNull)", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 540 "(%s !is null)", //BYTE_ARRAY_TYPE, // byte[] 541 "(%s !is null)", //UBYTE_ARRAY_TYPE, // ubyte[] 542 ]; 543 544 string getColumnTypeKeyIsSetCode(T, string m)() { 545 return substituteParam(ColumnTypeKeyIsSetCode[getPropertyMemberType!(T,m)()], getPropertyReadCode!(T,m)()); 546 } 547 548 static immutable string[] ColumnTypeIsNullCode = 549 [ 550 "(false)", //BOOL_TYPE // bool 551 "(false)", //BYTE_TYPE, // byte 552 "(false)", //SHORT_TYPE, // short 553 "(false)", //INT_TYPE, // int 554 "(false)", //LONG_TYPE, // long 555 "(false)", //UBYTE_TYPE, // ubyte 556 "(false)", //USHORT_TYPE, // ushort 557 "(false)", //UINT_TYPE, // uint 558 "(false)", //ULONG_TYPE, // ulong 559 "(%s.isNull)", //NULLABLE_BYTE_TYPE, // Nullable!byte 560 "(%s.isNull)", //NULLABLE_SHORT_TYPE, // Nullable!short 561 "(%s.isNull)", //NULLABLE_INT_TYPE, // Nullable!int 562 "(%s.isNull)", //NULLABLE_LONG_TYPE, // Nullable!long 563 "(%s.isNull)", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 564 "(%s.isNull)", //NULLABLE_USHORT_TYPE,// Nullable!ushort 565 "(%s.isNull)", //NULLABLE_UINT_TYPE, // Nullable!uint 566 "(%s.isNull)", //NULLABLE_ULONG_TYPE, // Nullable!ulong 567 "(false)",//FLOAT_TYPE, // float 568 "(false)",//DOUBLE_TYPE, // double 569 "(%s.isNull)", //NULLABLE_FLOAT_TYPE, // Nullable!float 570 "(%s.isNull)", //NULLABLE_DOUBLE_TYPE,// Nullable!double 571 "(%s is null)", //STRING_TYPE // string 572 "(%s is null)", //NULLABLE_STRING_TYPE // String 573 "(false)", //SYSTIME_TYPE 574 "(false)", //DATETIME_TYPE, // std.datetime.DateTime 575 "(false)", //DATE_TYPE, // std.datetime.Date 576 "(false)", //TIME_TYPE, // std.datetime.TimeOfDay 577 "(%s.isNull)", //NULLABLE_SYSTIME_TYPE 578 "(%s.isNull)", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 579 "(%s.isNull)", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 580 "(%s.isNull)", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 581 "(%s is null)", //BYTE_ARRAY_TYPE, // byte[] 582 "(%s is null)", //UBYTE_ARRAY_TYPE, // ubyte[] 583 ]; 584 585 string getColumnTypeIsNullCode(T, string m)() { 586 return substituteParam(ColumnTypeIsNullCode[getPropertyMemberType!(T,m)()], getPropertyReadCode!(T,m)()); 587 } 588 589 static immutable string[] ColumnTypeSetNullCode = 590 [ 591 "bool nv;", // BOOL_TYPE // bool 592 "byte nv = 0;", //BYTE_TYPE, // byte 593 "short nv = 0;", //SHORT_TYPE, // short 594 "int nv = 0;", //INT_TYPE, // int 595 "long nv = 0;", //LONG_TYPE, // long 596 "ubyte nv = 0;", //UBYTE_TYPE, // ubyte 597 "ushort nv = 0;", //USHORT_TYPE, // ushort 598 "uint nv = 0;", //UINT_TYPE, // uint 599 "ulong nv = 0;", //ULONG_TYPE, // ulong 600 "Nullable!byte nv;", //NULLABLE_BYTE_TYPE, // Nullable!byte 601 "Nullable!short nv;", //NULLABLE_SHORT_TYPE, // Nullable!short 602 "Nullable!int nv;", //NULLABLE_INT_TYPE, // Nullable!int 603 "Nullable!long nv;", //NULLABLE_LONG_TYPE, // Nullable!long 604 "Nullable!ubyte nv;", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 605 "Nullable!ushort nv;", //NULLABLE_USHORT_TYPE,// Nullable!ushort 606 "Nullable!uint nv;", //NULLABLE_UINT_TYPE, // Nullable!uint 607 "Nullable!ulong nv;", //NULLABLE_ULONG_TYPE, // Nullable!ulong 608 "float nv = 0;",//FLOAT_TYPE, // float 609 "double nv = 0;",//DOUBLE_TYPE, // double 610 "Nullable!float nv;", //NULLABLE_FLOAT_TYPE, // Nullable!float 611 "Nullable!double nv;", //NULLABLE_DOUBLE_TYPE,// Nullable!double 612 "string nv;", //STRING_TYPE // string 613 "string nv;", //NULLABLE_STRING_TYPE // String 614 "SysTime nv;", //SYSTIME_TYPE 615 "DateTime nv;", //DATETIME_TYPE, // std.datetime.DateTime 616 "Date nv;", //DATE_TYPE, // std.datetime.Date 617 "TimeOfDay nv;", //TIME_TYPE, // std.datetime.TimeOfDay 618 "Nullable!SysTime nv;", //NULLABLE_SYSTIME_TYPE 619 "Nullable!DateTime nv;", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 620 "Nullable!Date nv;", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 621 "Nullable!TimeOfDay nv;", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 622 "byte[] nv = null;", //BYTE_ARRAY_TYPE, // byte[] 623 "ubyte[] nv = null;", //UBYTE_ARRAY_TYPE, // ubyte[] 624 ]; 625 626 static immutable string[] ColumnTypePropertyToVariant = 627 [ 628 "Variant(%s)", //BOOL_TYPE // bool 629 "Variant(%s)", //BYTE_TYPE, // byte 630 "Variant(%s)", //SHORT_TYPE, // short 631 "Variant(%s)", //INT_TYPE, // int 632 "Variant(%s)", //LONG_TYPE, // long 633 "Variant(%s)", //UBYTE_TYPE, // ubyte 634 "Variant(%s)", //USHORT_TYPE, // ushort 635 "Variant(%s)", //UINT_TYPE, // uint 636 "Variant(%s)", //ULONG_TYPE, // ulong 637 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_BYTE_TYPE, // Nullable!byte 638 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_SHORT_TYPE, // Nullable!short 639 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_INT_TYPE, // Nullable!int 640 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_LONG_TYPE, // Nullable!long 641 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 642 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_USHORT_TYPE,// Nullable!ushort 643 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_UINT_TYPE, // Nullable!uint 644 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_ULONG_TYPE, // Nullable!ulong 645 "Variant(%s)",//FLOAT_TYPE, // float 646 "Variant(%s)",//DOUBLE_TYPE, // double 647 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_FLOAT_TYPE, // Nullable!float 648 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_DOUBLE_TYPE,// Nullable!double 649 "Variant(%s)", //STRING_TYPE // string 650 "Variant(%s)", //NULLABLE_STRING_TYPE // String 651 "Variant(%s)", //SYSTIME_TYPE 652 "Variant(%s)", //DATETIME_TYPE, // std.datetime.DateTime 653 "Variant(%s)", //DATE_TYPE, // std.datetime.Date 654 "Variant(%s)", //TIME_TYPE, // std.datetime.TimeOfDay 655 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_SYSTIME_TYPE 656 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 657 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 658 "(%s.isNull ? Variant(null) : Variant(%s.get()))", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 659 "Variant(%s)", //BYTE_ARRAY_TYPE, // byte[] 660 "Variant(%s)", //UBYTE_ARRAY_TYPE, // ubyte[] 661 ]; 662 663 static immutable string[] ColumnTypeDatasetReaderCode = 664 [ 665 "r.getBoolean(index)", //BOOL_TYPE, // bool 666 "r.getByte(index)", //BYTE_TYPE, // byte 667 "r.getShort(index)", //SHORT_TYPE, // short 668 "r.getInt(index)", //INT_TYPE, // int 669 "r.getLong(index)", //LONG_TYPE, // long 670 "r.getUbyte(index)", //UBYTE_TYPE, // ubyte 671 "r.getUshort(index)", //USHORT_TYPE, // ushort 672 "r.getUint(index)", //UINT_TYPE, // uint 673 "r.getUlong(index)", //ULONG_TYPE, // ulong 674 "Nullable!byte(r.getByte(index))", //NULLABLE_BYTE_TYPE, // Nullable!byte 675 "Nullable!short(r.getShort(index))", //NULLABLE_SHORT_TYPE, // Nullable!short 676 "Nullable!int(r.getInt(index))", //NULLABLE_INT_TYPE, // Nullable!int 677 "Nullable!long(r.getLong(index))", //NULLABLE_LONG_TYPE, // Nullable!long 678 "Nullable!ubyte(r.getUbyte(index))", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 679 "Nullable!ushort(r.getUshort(index))", //NULLABLE_USHORT_TYPE,// Nullable!ushort 680 "Nullable!uint(r.getUint(index))", //NULLABLE_UINT_TYPE, // Nullable!uint 681 "Nullable!ulong(r.getUlong(index))", //NULLABLE_ULONG_TYPE, // Nullable!ulong 682 "r.getFloat(index)",//FLOAT_TYPE, // float 683 "r.getDouble(index)",//DOUBLE_TYPE, // double 684 "Nullable!float(r.getFloat(index))", //NULLABLE_FLOAT_TYPE, // Nullable!float 685 "Nullable!double(r.getDouble(index))", //NULLABLE_DOUBLE_TYPE,// Nullable!double 686 "r.getString(index)", //STRING_TYPE // string 687 "r.getString(index)", //NULLABLE_STRING_TYPE // String 688 "r.getSysTime(index)", //SYSTIME_TYPE 689 "r.getDateTime(index)", //DATETIME_TYPE, // std.datetime.DateTime 690 "r.getDate(index)", //DATE_TYPE, // std.datetime.Date 691 "r.getTime(index)", //TIME_TYPE, // std.datetime.TimeOfDay 692 "Nullable!SysTime(r.getSysTime(index))", //NULLABLE_SYSTIME_TYPE 693 "Nullable!DateTime(r.getDateTime(index))", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 694 "Nullable!Date(r.getDate(index))", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 695 "Nullable!TimeOfDay(r.getTime(index))", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 696 "r.getBytes(index)", //BYTE_ARRAY_TYPE, // byte[] 697 "r.getUbytes(index)", //UBYTE_ARRAY_TYPE, // ubyte[] 698 ]; 699 700 string getColumnTypeDatasetReadCode(T, string m)() { 701 return ColumnTypeDatasetReaderCode[getPropertyMemberType!(T,m)()]; 702 } 703 704 string getVarTypeDatasetReadCode(T)() { 705 return ColumnTypeDatasetReaderCode[getPropertyType!T]; 706 } 707 708 string getPropertyWriteCode(T, string m)() { 709 //immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 710 immutable string nullValueCode = ColumnTypeSetNullCode[getPropertyMemberType!(T,m)()]; 711 immutable string datasetReader = "(!r.isNull(index) ? " ~ getColumnTypeDatasetReadCode!(T, m)() ~ " : nv)"; 712 return nullValueCode ~ "entity." ~ m ~ " = " ~ datasetReader ~ ";"; 713 } 714 715 string getPropertyWriteCode(T)() { 716 //immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 717 immutable string nullValueCode = ColumnTypeSetNullCode[getPropertyType!T]; 718 immutable string datasetReader = "(!r.isNull(index) ? " ~ getVarTypeDatasetReadCode!T ~ " : nv)"; 719 return nullValueCode ~ "a = " ~ datasetReader ~ ";"; 720 } 721 722 /// returns array of field names 723 string[] getColumnNamesForType(T)() if (__traits(isPOD, T)) { 724 string[] res; 725 foreach(m; FieldNameTuple!T) { 726 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 727 // skip non-public members 728 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 729 static if (isSupportedSimpleType!(T, m)) { 730 res ~= m; 731 } 732 } 733 } 734 } 735 return res; 736 } 737 738 string getColumnReadCode(T, string m)() { 739 return "{" ~ getPropertyWriteCode!(T,m)() ~ "index++;}\n"; 740 } 741 742 string getAllColumnsReadCode(T)() { 743 string res = "int index = 1;\n"; 744 foreach(m; FieldNameTuple!T) { 745 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 746 // skip non-public members 747 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 748 static if (isSupportedSimpleType!(T, m)) { 749 res ~= getColumnReadCode!(T, m); 750 } 751 } 752 } 753 } 754 return res; 755 } 756 757 string getAllColumnsReadCode(T, fieldList...)() { 758 string res = "int index = 1;\n"; 759 foreach(m; fieldList) { 760 res ~= getColumnReadCode!(T, m); 761 } 762 return res; 763 } 764 765 unittest { 766 struct User1 { 767 long id; 768 string name; 769 int flags; 770 } 771 //pragma(msg, "nullValueCode = " ~ ColumnTypeSetNullCode[getPropertyMemberType!(User, "id")()]); 772 //pragma(msg, "datasetReader = " ~ getColumnTypeDatasetReadCode!(User, "id")()); 773 //pragma(msg, "getPropertyWriteCode: " ~ getPropertyWriteCode!(User, "id")); 774 //pragma(msg, "getAllColumnsReadCode:\n" ~ getAllColumnsReadCode!(User)); 775 //static assert(getPropertyWriteCode!(User, "id") == "long nv = 0;entity.id = (!r.isNull(index) ? r.getLong(index) : nv);"); 776 } 777 778 unittest { 779 struct User1 { 780 long id; 781 string name; 782 int flags; 783 } 784 static assert(getPropertyMemberType!(User1, "id")() == PropertyMemberType.LONG_TYPE); 785 static assert(getPropertyMemberType!(User1, "name")() == PropertyMemberType.STRING_TYPE); 786 //pragma(msg, "getPropertyMemberType unit test passed"); 787 } 788 789 790 791 /// returns table name for struct type 792 string getTableNameForType(T)() if (__traits(isPOD, T)) { 793 return camelCaseToUnderscoreDelimited(T.stringof); 794 } 795 796 unittest { 797 struct User1 { 798 long id; 799 string name; 800 int flags; 801 } 802 static assert(getTableNameForType!User1() == "user1"); 803 } 804 805 /// returns "SELECT <field list> FROM <table name>" 806 string generateSelectSQL(T)() { 807 return "SELECT " ~ join(getColumnNamesForType!(T)(), ",") ~ " FROM " ~ getTableNameForType!(T)(); 808 } 809 810 unittest { 811 struct User1 { 812 long id; 813 string name; 814 int flags; 815 } 816 static assert(generateSelectSQL!User1() == "SELECT id,name,flags FROM user1"); 817 } 818 819 string joinFieldList(fieldList...)() { 820 string res; 821 foreach(f; fieldList) { 822 if (res.length) 823 res ~= ","; 824 res ~= f; 825 } 826 return res; 827 } 828 829 /// returns "SELECT <field list> FROM <table name>" 830 string generateSelectSQL(T, fieldList...)() { 831 string res = "SELECT "; 832 res ~= joinFieldList!fieldList; 833 res ~= " FROM " ~ getTableNameForType!(T)(); 834 return res; 835 } 836 837 unittest { 838 //pragma(msg, "column names: " ~ join(getColumnNamesForType!(User)(), ",")); 839 //pragma(msg, "select SQL: " ~ generateSelectSQL!(User)()); 840 } 841 842 /// returns "SELECT <field list> FROM <table name>" 843 string generateSelectForGetSQL(T)() { 844 string res = generateSelectSQL!T(); 845 res ~= " WHERE id="; 846 return res; 847 } 848 849 string generateSelectForGetSQLWithFilter(T)() { 850 string res = generateSelectSQL!T(); 851 res ~= " WHERE "; 852 return res; 853 } 854 855 T get(T)(Statement stmt, long id) { 856 T entity; 857 static immutable getSQL = generateSelectForGetSQL!T(); 858 ResultSet r; 859 r = stmt.executeQuery(getSQL ~ to!string(id)); 860 r.next(); 861 mixin(getAllColumnsReadCode!T()); 862 return entity; 863 } 864 865 T get(T)(Statement stmt, string filter) { 866 T entity; 867 static immutable getSQL = generateSelectForGetSQLWithFilter!T(); 868 ResultSet r; 869 r = stmt.executeQuery(getSQL ~ filter); 870 r.next(); 871 mixin(getAllColumnsReadCode!T()); 872 return entity; 873 } 874 875 string getColumnTypeDatasetReadCodeByName(T, string m)() { 876 PropertyMemberType pmt = getPropertyMemberType!(T,m)(); 877 final switch(pmt) with (PropertyMemberType) { 878 case BOOL_TYPE: 879 return `r.getBoolean("` ~ m ~ `")`; 880 case BYTE_TYPE: 881 return `r.getByte("` ~ m ~ `")`; 882 case SHORT_TYPE: 883 return `r.getShort("` ~ m ~ `")`; 884 case INT_TYPE: 885 return `r.getInt("` ~ m ~ `")`; 886 case LONG_TYPE: 887 return `r.getLong("` ~ m ~ `")`; 888 case UBYTE_TYPE: 889 return `r.getUbyte("` ~ m ~ `")`; 890 case USHORT_TYPE: 891 return `r.getUshort("` ~ m ~ `")`; 892 case UINT_TYPE: 893 return `r.getUint("` ~ m ~ `")`; 894 case ULONG_TYPE: 895 return `r.getUlong("` ~ m ~ `")`; 896 case FLOAT_TYPE: 897 return `r.getFloat("` ~ m ~ `")`; 898 case DOUBLE_TYPE: 899 return `r.getDouble("` ~ m ~ `")`; 900 case STRING_TYPE: 901 return `r.getString("` ~ m ~ `")`; 902 case DATE_TYPE: 903 return `r.getDate("` ~ m ~ `")`; 904 case TIME_TYPE: 905 return `r.getTime("` ~ m ~ `")`; 906 case SYSTIME_TYPE: 907 return `r.getSysTime("` ~ m ~ `")`; 908 case DATETIME_TYPE: 909 return `r.getDateTime("` ~ m ~ `")`; 910 case BYTE_ARRAY_TYPE: 911 return `r.getBytes("` ~ m ~ `")`; 912 case UBYTE_ARRAY_TYPE: 913 return `r.getUbytes("` ~ m ~ `")`; 914 case NULLABLE_BYTE_TYPE: 915 return `Nullable!byte(r.getByte("` ~ m ~ `"))`; 916 case NULLABLE_SHORT_TYPE: 917 return `Nullable!short(r.getShort("` ~ m ~ `"))`; 918 case NULLABLE_INT_TYPE: 919 return `Nullable!int(r.getInt("` ~ m ~ `"))`; 920 case NULLABLE_LONG_TYPE: 921 return `Nullable!long(r.getLong("` ~ m ~ `"))`; 922 case NULLABLE_UBYTE_TYPE: 923 return `Nullable!ubyte(r.getUbyte("` ~ m ~ `"))`; 924 case NULLABLE_USHORT_TYPE: 925 return `Nullable!ushort(r.getUshort("` ~ m ~ `"))`; 926 case NULLABLE_UINT_TYPE: 927 return `Nullable!uint(r.getUint("` ~ m ~ `"))`; 928 case NULLABLE_ULONG_TYPE: 929 return `Nullable!ulong(r.getUlong("` ~ m ~ `"))`; 930 case NULLABLE_FLOAT_TYPE: 931 return `Nullable!float(r.getFloat("` ~ m ~ `"))`; 932 case NULLABLE_DOUBLE_TYPE: 933 return `Nullable!double(r.getDouble("` ~ m ~ `"))`; 934 case NULLABLE_STRING_TYPE: 935 return `r.getString("` ~ m ~ `")`; 936 case NULLABLE_DATE_TYPE: 937 return `Nullable!Date(r.getDate("` ~ m ~ `"))`; 938 case NULLABLE_TIME_TYPE: 939 return `Nullable!Time(r.getTime("` ~ m ~ `"))`; 940 case NULLABLE_SYSTIME_TYPE: 941 return `Nullable!SysTime(r.getSysTime("` ~ m ~ `"))`; 942 case NULLABLE_DATETIME_TYPE: 943 return `Nullable!DateTime(r.getDateTime("` ~ m ~ `"))`; 944 } 945 } 946 947 string getPropertyWriteCodeByName(T, string m)() { 948 immutable string nullValueCode = ColumnTypeSetNullCode[getPropertyMemberType!(T,m)()]; 949 immutable string propertyWriter = nullValueCode ~ "entity." ~ m ~ " = " ~ getColumnTypeDatasetReadCodeByName!(T, m)() ~ ";\n"; 950 return propertyWriter ~ "if (r.wasNull) entity." ~ m ~ " = nv;"; 951 } 952 953 string getColumnReadCodeByName(T, string m)() { 954 return "{" ~ getPropertyWriteCodeByName!(T,m)() ~ "}\n"; 955 } 956 957 string getAllColumnsReadCodeByName(T)() { 958 string res; 959 foreach(m; FieldNameTuple!T) { 960 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 961 // skip non-public members 962 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 963 static if (isSupportedSimpleType!(T, m)) { 964 res ~= getColumnReadCodeByName!(T, m); 965 } 966 } 967 } 968 } 969 return res; 970 } 971 972 /** 973 * Extract a row from the result set as the specified type. 974 * Requires that next has already been checked. 975 * Can be used for example to extract rows from executing a PreparedStatement. 976 */ 977 T get(T)(ResultSet r) { 978 T entity; 979 mixin(getAllColumnsReadCodeByName!T()); 980 return entity; 981 } 982 983 /// range for select query 984 struct select(T, fieldList...) if (__traits(isPOD, T)) { 985 T entity; 986 private Statement stmt; 987 private ResultSet r; 988 static immutable selectSQL = generateSelectSQL!(T, fieldList)(); 989 string whereCondSQL; 990 string orderBySQL; 991 this(Statement stmt) { 992 this.stmt = stmt; 993 } 994 ref select where(string whereCond) { 995 whereCondSQL = " WHERE " ~ whereCond; 996 return this; 997 } 998 ref select orderBy(string order) { 999 orderBySQL = " ORDER BY " ~ order; 1000 return this; 1001 } 1002 ref T front() { 1003 return entity; 1004 } 1005 void popFront() { 1006 } 1007 @property bool empty() { 1008 if (!r) 1009 r = stmt.executeQuery(selectSQL ~ whereCondSQL ~ orderBySQL); 1010 if (!r.next()) 1011 return true; 1012 mixin(getAllColumnsReadCode!(T, fieldList)); 1013 return false; 1014 } 1015 ~this() { 1016 if (r) 1017 r.close(); 1018 } 1019 } 1020 1021 /// returns "INSERT INTO <table name> (<field list>) VALUES (value list) 1022 string generateInsertSQL(T)() { 1023 string res = "INSERT INTO " ~ getTableNameForType!(T)(); 1024 string []values; 1025 foreach(m; FieldNameTuple!T) { 1026 if (m != "id") { 1027 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 1028 // skip non-public members 1029 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 1030 values ~= m; 1031 } 1032 } 1033 } 1034 } 1035 res ~= "(" ~ join(values, ",") ~ ")"; 1036 res ~= " VALUES "; 1037 return res; 1038 } 1039 1040 string addFieldValue(T)(string m) { 1041 string tmp = `{Variant v = o.`~m~`;`; 1042 tmp ~= `static if (isColumnTypeNullableByDefault!(T, "`~m~`")()) {`; 1043 tmp ~= ` if(o.`~m~`.isNull) {`; 1044 tmp ~= ` values ~= "NULL";`; 1045 tmp ~= ` } else {`; 1046 tmp ~= ` values ~= "'" ~ to!string(o.` ~ m ~ `) ~ "'";`; 1047 tmp ~= `}} else {`; 1048 tmp ~= ` values ~= "'" ~ to!string(o.` ~ m ~ `) ~ "'";`; 1049 tmp ~= `}}`; 1050 return tmp; 1051 // return `values ~= "'" ~ to!string(o.` ~ m ~ `) ~ "'";`; 1052 } 1053 1054 bool insert(T)(Statement stmt, ref T o) if (__traits(isPOD, T)) { 1055 auto insertSQL = generateInsertSQL!(T)(); 1056 string []values; 1057 foreach(m; FieldNameTuple!T) { 1058 if (m != "id") { 1059 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 1060 // skip non-public members 1061 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 1062 // pragma(msg,addFieldValue!(T)(m)); 1063 mixin(addFieldValue!(T)(m)); 1064 } 1065 } 1066 } 1067 } 1068 insertSQL ~= "(" ~ join(values, ",") ~ ")"; 1069 Variant insertId; 1070 stmt.executeUpdate(insertSQL, insertId); 1071 o.id = insertId.get!long; 1072 return true; 1073 } 1074 1075 /// returns "UPDATE <table name> SET field1=value1 WHERE id=id 1076 string generateUpdateSQL(T)() { 1077 string res = "UPDATE " ~ getTableNameForType!(T)(); 1078 string []values; 1079 foreach(m; FieldNameTuple!T) { 1080 if (m != "id") { 1081 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 1082 // skip non-public members 1083 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 1084 values ~= m; 1085 } 1086 } 1087 } 1088 } 1089 res ~= " SET "; 1090 return res; 1091 } 1092 1093 string addUpdateValue(T)(string m) { 1094 return `values ~= "` ~ m ~ `=\"" ~ to!string(o.` ~ m ~ `) ~ "\"";`; 1095 } 1096 1097 bool update(T)(Statement stmt, ref T o) if (__traits(isPOD, T)) { 1098 auto updateSQL = generateUpdateSQL!(T)(); 1099 string []values; 1100 foreach(m; FieldNameTuple!T) { 1101 if (m != "id") { 1102 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 1103 // skip non-public members 1104 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 1105 1106 // static if(typeof(__traits(getMember, T, m)) == function) { 1107 // pragma(msg, "Ignoring function: "~m~"()"); 1108 // } 1109 1110 // static if(is(__traits(getMember, T, m) == function)) { 1111 // pragma(msg, "Ignoring function: "~m~"()"); 1112 // } else { 1113 // pragma(msg, addUpdateValue!(T)(m)); 1114 // //mixin(addUpdateValue!(T)(m)); 1115 // } 1116 1117 static if (__traits(getOverloads, T, m).length > 0) { 1118 // even if the struct/class doesn't have and override (such as opAssign) the compiler 1119 // can potentially add one. See: https://dlang.org/library/std/traits/has_elaborate_assign.html 1120 pragma(msg, "Ignoring 'override "~m~"()'"); 1121 } else { 1122 pragma(msg, addUpdateValue!(T)(m)); 1123 mixin(addUpdateValue!(T)(m)); 1124 } 1125 } 1126 } 1127 } 1128 } 1129 updateSQL ~= join(values, ","); 1130 updateSQL ~= mixin(`" WHERE id="~ to!string(o.id) ~ ";"`); 1131 Variant updateId; 1132 stmt.executeUpdate(updateSQL, updateId); 1133 return true; 1134 } 1135 1136 /// returns "DELETE FROM <table name> WHERE id=id 1137 string generateDeleteSQL(T)() { 1138 string res = "DELETE FROM " ~ getTableNameForType!(T)(); 1139 return res; 1140 } 1141 1142 bool remove(T)(Statement stmt, ref T o) if (__traits(isPOD, T)) { 1143 auto deleteSQL = generateDeleteSQL!(T)(); 1144 deleteSQL ~= mixin(`" WHERE id="~ to!string(o.id) ~ ";"`); 1145 Variant deleteId; 1146 stmt.executeUpdate(deleteSQL, deleteId); 1147 return true; 1148 } 1149 1150 template isSupportedSimpleTypeRef(M) { 1151 alias typeof(M) ti; 1152 static if (!__traits(isRef, M)) { 1153 enum bool isSupportedSimpleTypeRef = false; 1154 } else static if (is(ti == bool)) { 1155 enum bool isSupportedSimpleType = true; 1156 } else static if (is(ti == byte)) { 1157 enum bool isSupportedSimpleType = true; 1158 } else static if (is(ti == short)) { 1159 enum bool isSupportedSimpleType = true; 1160 } else static if (is(ti == int)) { 1161 enum bool isSupportedSimpleType = true; 1162 } else static if (is(ti == long)) { 1163 enum bool isSupportedSimpleType = true; 1164 } else static if (is(ti == ubyte)) { 1165 enum bool isSupportedSimpleType = true; 1166 } else static if (is(ti == ushort)) { 1167 enum bool isSupportedSimpleType = true; 1168 } else static if (is(ti == uint)) { 1169 enum bool isSupportedSimpleType = true; 1170 } else static if (is(ti == ulong)) { 1171 enum bool isSupportedSimpleType = true; 1172 } else static if (is(ti == float)) { 1173 enum bool isSupportedSimpleType = true; 1174 } else static if (is(ti == double)) { 1175 enum bool isSupportedSimpleType = true; 1176 } else static if (is(ti == Nullable!byte)) { 1177 enum bool isSupportedSimpleType = true; 1178 } else static if (is(ti == Nullable!short)) { 1179 enum bool isSupportedSimpleType = true; 1180 } else static if (is(ti == Nullable!int)) { 1181 enum bool isSupportedSimpleType = true; 1182 } else static if (is(ti == Nullable!long)) { 1183 enum bool isSupportedSimpleType = true; 1184 } else static if (is(ti == Nullable!ubyte)) { 1185 enum bool isSupportedSimpleType = true; 1186 } else static if (is(ti == Nullable!ushort)) { 1187 enum bool isSupportedSimpleType = true; 1188 } else static if (is(ti == Nullable!uint)) { 1189 enum bool isSupportedSimpleType = true; 1190 } else static if (is(ti == Nullable!ulong)) { 1191 enum bool isSupportedSimpleType = true; 1192 } else static if (is(ti == Nullable!float)) { 1193 enum bool isSupportedSimpleType = true; 1194 } else static if (is(ti == Nullable!double)) { 1195 enum bool isSupportedSimpleType = true; 1196 } else static if (is(ti == string)) { 1197 enum bool isSupportedSimpleType = true; 1198 } else static if (is(ti == String)) { 1199 enum bool isSupportedSimpleType = true; 1200 } else static if (is(ti == SysTime)) { 1201 enum bool isSupportedSimpleType = true; 1202 } else static if (is(ti == DateTime)) { 1203 enum bool isSupportedSimpleType = true; 1204 } else static if (is(ti == Date)) { 1205 enum bool isSupportedSimpleType = true; 1206 } else static if (is(ti == TimeOfDay)) { 1207 enum bool isSupportedSimpleType = true; 1208 } else static if (is(ti == Nullable!SysTime)) { 1209 enum bool isSupportedSimpleType = true; 1210 } else static if (is(ti == Nullable!DateTime)) { 1211 enum bool isSupportedSimpleType = true; 1212 } else static if (is(ti == Nullable!Date)) { 1213 enum bool isSupportedSimpleType = true; 1214 } else static if (is(ti == Nullable!TimeOfDay)) { 1215 enum bool isSupportedSimpleType = true; 1216 } else static if (is(ti == byte[])) { 1217 enum bool isSupportedSimpleType = true; 1218 } else static if (is(ti == ubyte[])) { 1219 enum bool isSupportedSimpleType = true; 1220 } else static if (true) { 1221 enum bool isSupportedSimpleType = false; 1222 } 1223 } 1224 1225 // TODO: use better way to count parameters 1226 int paramCount(destList...)() { 1227 int res = 0; 1228 foreach(p; destList) { 1229 res++; 1230 } 1231 return res; 1232 } 1233 1234 bool isSupportedSimpleTypeRefList(destList...)() { 1235 foreach(p; destList) { 1236 static if (!isSupportedSimpleTypeRef!p) { 1237 return false; 1238 } 1239 } 1240 return true; 1241 } 1242 1243 struct select(Args...) {//if (isSupportedSimpleTypeRefList!Args()) 1244 private Statement stmt; 1245 private ResultSet r; 1246 private void delegate() _copyFunction; 1247 private int rowIndex; 1248 1249 this(Args...)(Statement stmt, string sql, ref Args args) { 1250 this.stmt = stmt; 1251 selectSQL = sql; 1252 _copyFunction = delegate() { 1253 foreach(i, ref a; args) { 1254 int index = i + 1; 1255 mixin(getPropertyWriteCode!(typeof(a))); 1256 } 1257 }; 1258 } 1259 1260 string selectSQL; 1261 string whereCondSQL; 1262 string orderBySQL; 1263 ref select where(string whereCond) { 1264 whereCondSQL = " WHERE " ~ whereCond; 1265 return this; 1266 } 1267 ref select orderBy(string order) { 1268 orderBySQL = " ORDER BY " ~ order; 1269 return this; 1270 } 1271 int front() { 1272 return rowIndex; 1273 } 1274 void popFront() { 1275 rowIndex++; 1276 } 1277 @property bool empty() { 1278 if (!r) 1279 r = stmt.executeQuery(selectSQL ~ whereCondSQL ~ orderBySQL); 1280 if (!r.next()) 1281 return true; 1282 _copyFunction(); 1283 return false; 1284 } 1285 ~this() { 1286 if (r) 1287 r.close(); 1288 } 1289 1290 }