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