1 /** 2 * HibernateD - Object-Relation Mapping for D programming language, with interface similar to Hibernate. 3 * 4 * Hibernate documentation can be found here: 5 * $(LINK http://hibernate.org/docs)$(BR) 6 * 7 * Source file hibernated/tests.d. 8 * 9 * This module contains unit tests for functional testing on real DB. 10 * 11 * Copyright: Copyright 2013 12 * License: $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 13 * Author: Vadim Lopatin 14 */ 15 module hibernated.tests; 16 17 import std.algorithm; 18 import std.conv; 19 import std.stdio; 20 import std.datetime; 21 import std.typecons; 22 import std.exception; 23 import std.variant; 24 25 import hibernated.core; 26 27 version(unittest) { 28 29 //@Entity 30 @Table("users") // to override table name - "users" instead of default "user" 31 class User { 32 33 //@Generated 34 long id; 35 36 string name; 37 38 // property column 39 private long _flags; 40 @Null // override NotNull which is inferred from long type 41 @property void flags(long v) { _flags = v; } 42 @property ref long flags() { return _flags; } 43 44 // getter/setter property 45 string comment; 46 // @Column -- not mandatory, will be deduced 47 @Null // override default nullability of string with @Null (instead of using String) 48 @Column(null, 1024) // override default length, autogenerate column name) 49 string getComment() { return comment; } 50 void setComment(string v) { comment = v; } 51 52 //@ManyToOne -- not mandatory, will be deduced 53 //@JoinColumn("customer_fk") 54 Customer customer; 55 56 @ManyToMany 57 LazyCollection!Role roles; 58 59 override string toString() { 60 return "id=" ~ to!string(id) ~ ", name=" ~ name ~ ", flags=" ~ to!string(flags) ~ ", comment=" ~ comment ~ ", customerId=" ~ (customer is null ? "NULL" : customer.toString()); 61 } 62 63 } 64 65 66 //@Entity 67 @Table("customers") // to override table name - "customers" instead of default "customer" 68 class Customer { 69 //@Generated 70 int id; 71 // @Column -- not mandatory, will be deduced 72 string name; 73 74 // deduced as @Embedded automatically 75 Address address; 76 77 //@ManyToOne -- not mandatory, will be deduced 78 //@JoinColumn("account_type_fk") 79 Lazy!AccountType accountType; 80 81 // @OneToMany("customer") 82 // LazyCollection!User users; 83 84 //@OneToMany("customer") -- not mandatory, will be deduced 85 private User[] _users; 86 @property User[] users() { return _users; } 87 @property void users(User[] value) { _users = value; } 88 89 this() { 90 address = new Address(); 91 } 92 override string toString() { 93 return "id=" ~ to!string(id) ~ ", name=" ~ name ~ ", address=" ~ address.toString(); 94 } 95 } 96 97 static assert(isEmbeddedObjectMember!(Customer, "address")); 98 99 @Embeddable 100 class Address { 101 hibernated.type.String zip; 102 hibernated.type.String city; 103 hibernated.type.String streetAddress; 104 @Transient // mark field with @Transient to avoid creating column for it 105 string someNonPersistentField; 106 107 override string toString() { 108 return " zip=" ~ zip ~ ", city=" ~ city ~ ", streetAddress=" ~ streetAddress; 109 } 110 } 111 112 @Entity // need to have at least one annotation to import automatically from module 113 class AccountType { 114 //@Generated 115 int id; 116 string name; 117 } 118 119 //@Entity 120 class Role { 121 //@Generated 122 int id; 123 string name; 124 @ManyToMany 125 LazyCollection!User users; 126 } 127 128 //@Entity 129 //@Table("t1") 130 class T1 { 131 //@Id 132 //@Generated 133 int id; 134 135 //@NotNull 136 @UniqueKey 137 string name; 138 139 // property column 140 private long _flags; 141 // @Column -- not mandatory, will be deduced 142 @property long flags() { return _flags; } 143 @property void flags(long v) { _flags = v; } 144 145 // getter/setter property 146 private string comment; 147 // @Column -- not mandatory, will be deduced 148 @Null 149 string getComment() { return comment; } 150 void setComment(string v) { comment = v; } 151 152 153 override string toString() { 154 return "id=" ~ to!string(id) ~ ", name=" ~ name ~ ", flags=" ~ to!string(flags) ~ ", comment=" ~ comment; 155 } 156 } 157 158 @Entity 159 static class GeneratorTest { 160 //@Generator("std.uuid.randomUUID().toString()") 161 @Generator(UUID_GENERATOR) 162 string id; 163 string name; 164 } 165 166 @Entity 167 static class TypeTest { 168 //@Generated 169 int id; 170 string string_field; 171 hibernated.type.String nullable_string_field; 172 byte byte_field; 173 short short_field; 174 int int_field; 175 long long_field; 176 ubyte ubyte_field; 177 ushort ushort_field; 178 ulong ulong_field; 179 DateTime datetime_field; 180 Date date_field; 181 TimeOfDay time_field; 182 Byte nullable_byte_field; 183 Short nullable_short_field; 184 Int nullable_int_field; 185 Long nullable_long_field; 186 Ubyte nullable_ubyte_field; 187 Ushort nullable_ushort_field; 188 Ulong nullable_ulong_field; 189 NullableDateTime nullable_datetime_field; 190 NullableDate nullable_date_field; 191 NullableTimeOfDay nullable_time_field; 192 float float_field; 193 double double_field; 194 Float nullable_float_field; 195 Double nullable_double_field; 196 byte[] byte_array_field; 197 ubyte[] ubyte_array_field; 198 } 199 200 import ddbc.drivers.mysqlddbc; 201 import ddbc.drivers.pgsqlddbc; 202 import ddbc.drivers.sqliteddbc; 203 import ddbc.common; 204 import hibernated.dialects.mysqldialect; 205 import hibernated.dialects.sqlitedialect; 206 import hibernated.dialects.pgsqldialect; 207 208 209 string[] UNIT_TEST_DROP_TABLES_SCRIPT = 210 [ 211 "DROP TABLE IF EXISTS role_users", 212 "DROP TABLE IF EXISTS account_type", 213 "DROP TABLE IF EXISTS users", 214 "DROP TABLE IF EXISTS customers", 215 "DROP TABLE IF EXISTS person", 216 "DROP TABLE IF EXISTS person_info", 217 "DROP TABLE IF EXISTS person_info2", 218 "DROP TABLE IF EXISTS role", 219 "DROP TABLE IF EXISTS generator_test", 220 ]; 221 string[] UNIT_TEST_CREATE_TABLES_SCRIPT = 222 [ 223 "CREATE TABLE IF NOT EXISTS role (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL)", 224 "CREATE TABLE IF NOT EXISTS account_type (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL)", 225 "CREATE TABLE IF NOT EXISTS users (id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, flags INT, comment TEXT, customer_fk BIGINT NULL)", 226 "CREATE TABLE IF NOT EXISTS customers (id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, zip varchar(20), city varchar(100), street_address varchar(255), account_type_fk int)", 227 "CREATE TABLE IF NOT EXISTS person_info (id int not null primary key AUTO_INCREMENT, flags bigint)", 228 "CREATE TABLE IF NOT EXISTS person (id int not null primary key AUTO_INCREMENT, first_name varchar(255) not null, last_name varchar(255) not null, more_info_fk int)", 229 "CREATE TABLE IF NOT EXISTS person_info2 (id int not null primary key AUTO_INCREMENT, flags bigint, person_info_fk int)", 230 "CREATE TABLE IF NOT EXISTS role_users (role_fk int not null, user_fk int not null, primary key (role_fk, user_fk), unique index(user_fk, role_fk))", 231 "CREATE TABLE IF NOT EXISTS generator_test (id varchar(64) not null primary key, name varchar(255) not null)", 232 ]; 233 string[] UNIT_TEST_FILL_TABLES_SCRIPT = 234 [ 235 "INSERT INTO role (name) VALUES ('admin')", 236 "INSERT INTO role (name) VALUES ('viewer')", 237 "INSERT INTO role (name) VALUES ('editor')", 238 "INSERT INTO account_type (name) VALUES ('Type1')", 239 "INSERT INTO account_type (name) VALUES ('Type2')", 240 "INSERT INTO customers (name, zip, account_type_fk) VALUES ('customer 1', '12345', 1)", 241 "INSERT INTO customers (name, zip) VALUES ('customer 2', '54321')", 242 "INSERT INTO customers (name, street_address, account_type_fk) VALUES ('customer 3', 'Baker Street, 24', 2)", 243 "INSERT INTO users (name, flags, comment, customer_fk) VALUES ('user 1', 11, 'comments for user 1', 1)", 244 "INSERT INTO users (name, flags, comment, customer_fk) VALUES ('user 2', 22, 'this user belongs to customer 1', 1)", 245 "INSERT INTO users (name, flags, comment, customer_fk) VALUES ('user 3', NULL, 'this user belongs to customer 2', 2)", 246 "INSERT INTO users (name, flags, comment, customer_fk) VALUES ('user 4', 44, NULL, 3)", 247 "INSERT INTO users (name, flags, comment, customer_fk) VALUES ('test user 5', 55, 'this user belongs to customer 3, too', 3)", 248 "INSERT INTO users (name, flags, comment, customer_fk) VALUES ('test user 6', 66, 'for checking of Nullable!long reading', null)", 249 "INSERT INTO person_info (id, flags) VALUES (3, 123)", 250 "INSERT INTO person_info (id, flags) VALUES (4, 234)", 251 "INSERT INTO person_info (id, flags) VALUES (5, 345)", 252 "INSERT INTO person_info2 (id, flags, person_info_fk) VALUES (10, 1, 3)", 253 "INSERT INTO person_info2 (id, flags, person_info_fk) VALUES (11, 2, 4)", 254 "INSERT INTO person (first_name, last_name, more_info_fk) VALUES ('Andrei', 'Alexandrescu', 3)", 255 "INSERT INTO person (first_name, last_name, more_info_fk) VALUES ('Walter', 'Bright', 4)", 256 "INSERT INTO person (first_name, last_name, more_info_fk) VALUES ('John', 'Smith', 5)", 257 "INSERT INTO role_users (role_fk, user_fk) VALUES (1, 1)", 258 "INSERT INTO role_users (role_fk, user_fk) VALUES (2, 1)", 259 "INSERT INTO role_users (role_fk, user_fk) VALUES (2, 2)", 260 "INSERT INTO role_users (role_fk, user_fk) VALUES (2, 3)", 261 "INSERT INTO role_users (role_fk, user_fk) VALUES (3, 2)", 262 "INSERT INTO role_users (role_fk, user_fk) VALUES (3, 3)", 263 "INSERT INTO role_users (role_fk, user_fk) VALUES (3, 5)", 264 ]; 265 266 void recreateTestSchema(bool dropTables, bool createTables, bool fillTables) { 267 DataSource connectionPool = getUnitTestDataSource(); 268 if (connectionPool is null) 269 return; // DB tests disabled 270 Connection conn = connectionPool.getConnection(); 271 scope(exit) conn.close(); 272 if (dropTables) 273 unitTestExecuteBatch(conn, UNIT_TEST_DROP_TABLES_SCRIPT); 274 if (createTables) 275 unitTestExecuteBatch(conn, UNIT_TEST_CREATE_TABLES_SCRIPT); 276 if (fillTables) 277 unitTestExecuteBatch(conn, UNIT_TEST_FILL_TABLES_SCRIPT); 278 } 279 280 immutable bool DB_TESTS_ENABLED = SQLITE_TESTS_ENABLED || MYSQL_TESTS_ENABLED || PGSQL_TESTS_ENABLED; 281 282 283 package DataSource _unitTestConnectionPool; 284 /// will return null if DB tests are disabled 285 DataSource getUnitTestDataSource() { 286 if (_unitTestConnectionPool is null) { 287 static if (SQLITE_TESTS_ENABLED) { 288 pragma(msg, "Will use SQLite for HibernateD unit tests"); 289 _unitTestConnectionPool = createUnitTestSQLITEDataSource(); 290 } else if (MYSQL_TESTS_ENABLED) { 291 pragma(msg, "Will use MySQL for HibernateD unit tests"); 292 _unitTestConnectionPool = createUnitTestMySQLDataSource(); 293 } else if (PGSQL_TESTS_ENABLED) { 294 pragma(msg, "Will use PGSQL for HibernateD unit tests"); 295 _unitTestConnectionPool = createUnitTestPGSQLDataSource(); 296 } 297 } 298 return _unitTestConnectionPool; 299 } 300 Dialect getUnitTestDialect() { 301 302 static if (SQLITE_TESTS_ENABLED) { 303 return new SQLiteDialect(); 304 } else if (MYSQL_TESTS_ENABLED) { 305 return new MySQLDialect(); 306 } else if (PGSQL_TESTS_ENABLED) { 307 return new PGSQLDialect(); 308 } else { 309 return null; // disabled 310 } 311 } 312 313 void closeUnitTestDataSource() { 314 // if (!_unitTestConnectionPool is null) { 315 // _unitTestConnectionPool.close(); 316 // _unitTestConnectionPool = null; 317 // } 318 } 319 } 320 321 322 unittest { 323 324 // Checking generated metadata 325 EntityMetaData schema = new SchemaInfoImpl!(User, Customer, AccountType, T1, TypeTest, Address, Role); 326 327 //writeln("metadata test 1"); 328 assert(schema["TypeTest"].length==29); 329 assert(schema.getEntityCount() == 7); 330 assert(schema["User"]["name"].columnName == "name"); 331 assert(schema["User"][0].columnName == "id"); 332 assert(schema["User"][2].propertyName == "flags"); 333 assert(schema["User"]["id"].generated == true); 334 assert(schema["User"]["id"].key == true); 335 assert(schema["User"]["name"].key == false); 336 assert(schema["Customer"]["id"].generated == true); 337 assert(schema["Customer"]["id"].key == true); 338 assert(schema["Customer"]["address"].embedded == true); 339 assert(schema["Customer"]["address"].referencedEntity !is null); 340 assert(schema["Customer"]["address"].referencedEntity["streetAddress"].columnName == "street_address"); 341 assert(schema["User"]["customer"].columnName !is null); 342 343 assert(!schema["User"].embeddable); // test if @Embeddable is working 344 assert(schema["Address"].embeddable); // test if @Embeddable is working 345 assert(schema["Address"].length == 3); // test if @Transient is working 346 347 assert(schema["Customer"]["users"].relation == RelationType.OneToMany); 348 assert(schema["User"]["customer"].relation == RelationType.ManyToOne); 349 assert(schema["User"]["roles"].relation == RelationType.ManyToMany); 350 assert(schema["User"]["roles"].joinTable !is null); 351 assert(schema["User"]["roles"].joinTable.tableName == "role_users"); 352 assert(schema["User"]["roles"].joinTable.column1 == "user_fk"); 353 assert(schema["User"]["roles"].joinTable.column2 == "role_fk"); 354 assert(schema["Role"]["users"].joinTable.tableName == "role_users"); 355 assert(schema["Role"]["users"].joinTable.column1 == "role_fk"); 356 assert(schema["Role"]["users"].joinTable.column2 == "user_fk"); 357 358 assert(schema["Customer"]["users"].collection); 359 360 assert(schema["User"]["id"].readFunc !is null); 361 362 assert(schema["User"]["comment"].length == 1024); 363 static assert(isGetterFunction!(__traits(getMember, User, "getComment"), "getComment")); 364 static assert(isGetterFunction!(__traits(getMember, T1, "getComment"), "getComment")); 365 static assert(hasMemberAnnotation!(User, "getComment", Null)); 366 static assert(hasMemberAnnotation!(T1, "getComment", Null)); 367 static assert(!isMainMemberForProperty!(User, "comment")); 368 static assert(isMainMemberForProperty!(User, "getComment")); 369 static assert(isMainMemberForProperty!(Customer, "users")); 370 371 assert(schema["T1"]["comment"].nullable); 372 assert(schema["User"]["comment"].nullable); 373 374 assert(schema["TypeTest"]["id"].key); 375 assert(schema["TypeTest"]["id"].key); 376 assert(!schema["TypeTest"]["string_field"].nullable); 377 assert(schema["TypeTest"]["nullable_string_field"].nullable); 378 assert(!schema["TypeTest"]["byte_field"].nullable); 379 assert(!schema["TypeTest"]["short_field"].nullable); 380 assert(!schema["TypeTest"]["int_field"].nullable); 381 assert(!schema["TypeTest"]["long_field"].nullable); 382 assert(!schema["TypeTest"]["ubyte_field"].nullable); 383 assert(!schema["TypeTest"]["ushort_field"].nullable); 384 assert(!schema["TypeTest"]["ulong_field"].nullable); 385 assert(!schema["TypeTest"]["datetime_field"].nullable); 386 assert(!schema["TypeTest"]["date_field"].nullable); 387 assert(!schema["TypeTest"]["time_field"].nullable); 388 assert(schema["TypeTest"]["nullable_byte_field"].nullable); 389 assert(schema["TypeTest"]["nullable_short_field"].nullable); 390 assert(schema["TypeTest"]["nullable_int_field"].nullable); 391 assert(schema["TypeTest"]["nullable_long_field"].nullable); 392 assert(schema["TypeTest"]["nullable_ubyte_field"].nullable); 393 assert(schema["TypeTest"]["nullable_ushort_field"].nullable); 394 assert(schema["TypeTest"]["nullable_ulong_field"].nullable); 395 assert(schema["TypeTest"]["nullable_datetime_field"].nullable); 396 assert(schema["TypeTest"]["nullable_date_field"].nullable); 397 assert(schema["TypeTest"]["nullable_time_field"].nullable); 398 assert(!schema["TypeTest"]["float_field"].nullable); 399 assert(!schema["TypeTest"]["double_field"].nullable); 400 assert(schema["TypeTest"]["nullable_float_field"].nullable); 401 assert(schema["TypeTest"]["nullable_double_field"].nullable); 402 assert(schema["TypeTest"]["byte_array_field"].nullable); 403 assert(schema["TypeTest"]["ubyte_array_field"].nullable); 404 405 auto e2 = schema.createEntity("User"); 406 assert(e2 !is null); 407 User e2user = cast(User)e2; 408 assert(e2user !is null); 409 410 411 412 413 // TODO: 414 // e2user.customer = new Customer(); 415 // e2user.customer.id = 25; 416 // e2user.customer.name = "cust25"; 417 // Variant v = schema.getPropertyValue(e2user, "customer"); 418 // assert(v.get!Customer().name == "cust25"); 419 // e2user.customer = null; 420 // //assert(schema.getPropertyValue(e2user, "customer").to!Object is null); //Variant(cast(Customer)null)); 421 // Customer c42 = new Customer(); 422 // c42.id = 42; 423 // c42.name = "customer 42"; 424 // schema.setPropertyValue(e2user, "customer", Variant(c42)); 425 // assert(e2user.customer.id == 42); 426 // //assert(schema.getPropertyValue(e2user, "customer") == 42); 427 428 Object e1 = schema.findEntity("User").createEntity(); 429 assert(e1 !is null); 430 User e1user = cast(User)e1; 431 assert(e1user !is null); 432 e1user.id = 25; 433 434 435 436 } 437 438 unittest { 439 if (DB_TESTS_ENABLED) { 440 recreateTestSchema(true, false, false); 441 442 443 //writeln("metadata test 2"); 444 445 // Checking generated metadata 446 EntityMetaData schema = new SchemaInfoImpl!(User, Customer, AccountType, T1, TypeTest, Address, Role, GeneratorTest, Person, MoreInfo, EvenMoreInfo); 447 Dialect dialect = getUnitTestDialect(); 448 449 DBInfo db = new DBInfo(dialect, schema); 450 string[] createTables = db.getCreateTableSQL(); 451 // foreach(t; createTables) 452 // writeln(t); 453 string[] createIndexes = db.getCreateIndexSQL(); 454 // foreach(t; createIndexes) 455 // writeln(t); 456 static if (SQLITE_TESTS_ENABLED) { 457 assert(db["users"].getCreateTableSQL() == "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, flags INT NULL, comment TEXT NULL, customer_fk INT NULL)"); 458 assert(db["customers"].getCreateTableSQL() == "CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT NOT NULL, zip TEXT NULL, city TEXT NULL, street_address TEXT NULL, account_type_fk INT NULL)"); 459 assert(db["account_type"].getCreateTableSQL() == "CREATE TABLE account_type (id INTEGER PRIMARY KEY, name TEXT NOT NULL)"); 460 assert(db["t1"].getCreateTableSQL() == "CREATE TABLE t1 (id INTEGER PRIMARY KEY, name TEXT NOT NULL, flags INT NOT NULL, comment TEXT NULL)"); 461 assert(db["role"].getCreateTableSQL() == "CREATE TABLE role (id INTEGER PRIMARY KEY, name TEXT NOT NULL)"); 462 assert(db["generator_test"].getCreateTableSQL() == "CREATE TABLE generator_test (id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL)"); 463 assert(db["role_users"].getCreateTableSQL() == "CREATE TABLE role_users (role_fk INT NOT NULL, user_fk INT NOT NULL, PRIMARY KEY (role_fk, user_fk), UNIQUE (user_fk, role_fk))"); 464 } else static if (MYSQL_TESTS_ENABLED) { 465 assert(db["users"].getCreateTableSQL() == "CREATE TABLE users (id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, flags BIGINT NULL, comment VARCHAR(1024) NULL, customer_fk INT NULL)"); 466 assert(db["customers"].getCreateTableSQL() == "CREATE TABLE customers (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, zip VARCHAR(255) NULL, city VARCHAR(255) NULL, street_address VARCHAR(255) NULL, account_type_fk INT NULL)"); 467 assert(db["account_type"].getCreateTableSQL() == "CREATE TABLE account_type (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL)"); 468 assert(db["t1"].getCreateTableSQL() == "CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, flags BIGINT NOT NULL, comment VARCHAR(255) NULL)"); 469 assert(db["role"].getCreateTableSQL() == "CREATE TABLE role (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL)"); 470 assert(db["generator_test"].getCreateTableSQL() == "CREATE TABLE generator_test (id VARCHAR(255) NOT NULL PRIMARY KEY, name VARCHAR(255) NOT NULL)"); 471 assert(db["role_users"].getCreateTableSQL() == "CREATE TABLE role_users (role_fk INT NOT NULL, user_fk BIGINT NOT NULL, PRIMARY KEY (role_fk, user_fk), UNIQUE INDEX role_users_reverse_index (user_fk, role_fk))"); 472 } else static if (PGSQL_TESTS_ENABLED) { 473 } 474 475 476 477 DataSource ds = getUnitTestDataSource(); 478 if (ds is null) 479 return; // DB tests disabled 480 SessionFactory factory = new SessionFactoryImpl(schema, dialect, ds); 481 db = factory.getDBMetaData(); 482 { 483 Connection conn = ds.getConnection(); 484 scope(exit) conn.close(); 485 db.updateDBSchema(conn, true, true); 486 recreateTestSchema(false, false, true); 487 } 488 489 490 491 492 scope(exit) factory.close(); 493 { 494 Session sess = factory.openSession(); 495 scope(exit) sess.close(); 496 497 User u1 = sess.load!User(1); 498 //writeln("Loaded value: " ~ u1.toString); 499 assert(u1.id == 1); 500 assert(u1.name == "user 1"); 501 assert(u1.customer.name == "customer 1"); 502 assert(u1.customer.accountType() !is null); 503 assert(u1.customer.accountType().name == "Type1"); 504 Role[] u1roles = u1.roles; 505 assert(u1roles.length == 2); 506 507 User u2 = sess.load!User(2); 508 assert(u2.name == "user 2"); 509 assert(u2.flags == 22); // NULL is loaded as 0 if property cannot hold nulls 510 511 User u3 = sess.get!User(3); 512 assert(u3.name == "user 3"); 513 assert(u3.flags == 0); // NULL is loaded as 0 if property cannot hold nulls 514 assert(u3.getComment() !is null); 515 assert(u3.customer.name == "customer 2"); 516 assert(u3.customer.accountType() is null); 517 518 User u4 = new User(); 519 sess.load(u4, 4); 520 assert(u4.name == "user 4"); 521 assert(u4.getComment() is null); 522 523 User u5 = new User(); 524 u5.id = 5; 525 sess.refresh(u5); 526 assert(u5.name == "test user 5"); 527 //assert(u5.customer !is null); 528 529 u5 = sess.load!User(5); 530 assert(u5.name == "test user 5"); 531 assert(u5.customer !is null); 532 assert(u5.customer.id == 3); 533 assert(u5.customer.name == "customer 3"); 534 assert(u5.customer.accountType() !is null); 535 assert(u5.customer.accountType().name == "Type2"); 536 537 User u6 = sess.load!User(6); 538 assert(u6.name == "test user 6"); 539 assert(u6.customer is null); 540 541 // 542 //writeln("loading customer 3"); 543 // testing @Embedded property 544 Customer c3 = sess.load!Customer(3); 545 assert(c3.address.zip is null); 546 assert(c3.address.streetAddress == "Baker Street, 24"); 547 c3.address.streetAddress = "Baker Street, 24/2"; 548 c3.address.zip = "55555"; 549 550 User[] c3users = c3.users; 551 //writeln(" *** customer has " ~ to!string(c3users.length) ~ " users"); 552 assert(c3users.length == 2); 553 assert(c3users[0].customer == c3); 554 assert(c3users[1].customer == c3); 555 556 //writeln("updating customer 3"); 557 sess.update(c3); 558 Customer c3_reloaded = sess.load!Customer(3); 559 assert(c3.address.streetAddress == "Baker Street, 24/2"); 560 assert(c3.address.zip == "55555"); 561 562 } 563 { 564 Session sess = factory.openSession(); 565 scope(exit) sess.close(); 566 567 568 // check Session.save() when id is filled 569 Customer c4 = new Customer(); 570 c4.id = 4; 571 c4.name = "Customer_4"; 572 sess.save(c4); 573 574 Customer c4_check = sess.load!Customer(4); 575 assert(c4.id == c4_check.id); 576 assert(c4.name == c4_check.name); 577 578 sess.remove(c4); 579 580 c4 = sess.get!Customer(4); 581 assert (c4 is null); 582 583 Customer c5 = new Customer(); 584 c5.name = "Customer_5"; 585 sess.save(c5); 586 587 // Testing generator function (uuid) 588 GeneratorTest g1 = new GeneratorTest(); 589 g1.name = "row 1"; 590 assert(g1.id is null); 591 sess.save(g1); 592 assert(g1.id !is null); 593 594 595 assertThrown!MappingException(sess.createQuery("SELECT id, name, blabla FROM User ORDER BY name")); 596 assertThrown!QuerySyntaxException(sess.createQuery("SELECT id: name FROM User ORDER BY name")); 597 598 // test multiple row query 599 Query q = sess.createQuery("FROM User ORDER BY name"); 600 User[] list = q.list!User(); 601 assert(list.length == 6); 602 assert(list[0].name == "test user 5"); 603 assert(list[1].name == "test user 6"); 604 assert(list[2].name == "user 1"); 605 // writeln("Read " ~ to!string(list.length) ~ " rows from User"); 606 // foreach(row; list) { 607 // writeln(row.toString()); 608 // } 609 Variant[][] rows = q.listRows(); 610 assert(rows.length == 6); 611 // foreach(row; rows) { 612 // writeln(row); 613 // } 614 assertThrown!HibernatedException(q.uniqueResult!User()); 615 assertThrown!HibernatedException(q.uniqueRow()); 616 617 } 618 { 619 Session sess = factory.openSession(); 620 scope(exit) sess.close(); 621 622 // test single row select 623 Query q = sess.createQuery("FROM User AS u WHERE id = :Id and (u.name like '%test%' or flags=44)"); 624 assertThrown!HibernatedException(q.list!User()); // cannot execute w/o all parameters set 625 q.setParameter("Id", Variant(6)); 626 User[] list = q.list!User(); 627 assert(list.length == 1); 628 assert(list[0].name == "test user 6"); 629 // writeln("Read " ~ to!string(list.length) ~ " rows from User"); 630 // foreach(row; list) { 631 // writeln(row.toString()); 632 // } 633 User uu = q.uniqueResult!User(); 634 assert(uu.name == "test user 6"); 635 Variant[] row = q.uniqueRow(); 636 assert(row[0] == 6L); 637 assert(row[1] == "test user 6"); 638 639 // test empty SELECT result 640 q.setParameter("Id", Variant(7)); 641 row = q.uniqueRow(); 642 assert(row is null); 643 uu = q.uniqueResult!User(); 644 assert(uu is null); 645 646 q = sess.createQuery("SELECT c.name, c.address.zip FROM Customer AS c WHERE id = :Id").setParameter("Id", Variant(1)); 647 row = q.uniqueRow(); 648 assert(row !is null); 649 assert(row[0] == "customer 1"); // name 650 assert(row[1] == "12345"); // address.zip 651 652 653 } 654 { 655 // prepare data 656 Session sess = factory.openSession(); 657 scope(exit) sess.close(); 658 659 Role r10 = new Role(); 660 r10.name = "role10"; 661 Role r11 = new Role(); 662 r11.name = "role11"; 663 Customer c10 = new Customer(); 664 c10.name = "Customer 10"; 665 User u10 = new User(); 666 u10.name = "Alex"; 667 u10.customer = c10; 668 u10.roles = [r10, r11]; 669 sess.save(r10); 670 sess.save(r11); 671 sess.save(c10); 672 sess.save(u10); 673 assert(c10.id != 0); 674 assert(u10.id != 0); 675 assert(r10.id != 0); 676 assert(r11.id != 0); 677 } 678 { 679 // check data in separate session 680 Session sess = factory.openSession(); 681 scope(exit) sess.close(); 682 User u10 = sess.createQuery("FROM User WHERE name=:Name").setParameter("Name", "Alex").uniqueResult!User(); 683 assert(u10.roles.length == 2); 684 assert(u10.roles[0].name == "role10" || u10.roles.get()[0].name == "role11"); 685 assert(u10.roles[1].name == "role10" || u10.roles.get()[1].name == "role11"); 686 assert(u10.customer.name == "Customer 10"); 687 assert(u10.customer.users.length == 1); 688 assert(u10.customer.users[0] == u10); 689 assert(u10.roles[0].users.length == 1); 690 assert(u10.roles[0].users[0] == u10); 691 // removing one role from user 692 u10.roles.get().remove(0); 693 sess.update(u10); 694 } 695 { 696 // check that only one role left 697 Session sess = factory.openSession(); 698 scope(exit) sess.close(); 699 User u10 = sess.createQuery("FROM User WHERE name=:Name").setParameter("Name", "Alex").uniqueResult!User(); 700 assert(u10.roles.length == 1); 701 assert(u10.roles[0].name == "role10" || u10.roles.get()[0].name == "role11"); 702 // remove user 703 sess.remove(u10); 704 } 705 { 706 // check that user is removed 707 Session sess = factory.openSession(); 708 scope(exit) sess.close(); 709 User u10 = sess.createQuery("FROM User WHERE name=:Name").setParameter("Name", "Alex").uniqueResult!User(); 710 assert(u10 is null); 711 } 712 } 713 } 714 715 716 version (unittest) { 717 // for testing of Embeddable 718 @Embeddable 719 class EMName { 720 string firstName; 721 string lastName; 722 } 723 724 //@Entity 725 class EMUser { 726 //@Id @Generated 727 //@Column 728 int id; 729 730 // deduced as @Embedded automatically 731 EMName userName; 732 } 733 734 // for testing of Embeddable 735 //@Entity 736 class Person { 737 //@Id 738 int id; 739 740 // @Column @NotNull 741 string firstName; 742 // @Column @NotNull 743 string lastName; 744 745 @NotNull 746 @OneToOne 747 @JoinColumn("more_info_fk") 748 MoreInfo moreInfo; 749 } 750 751 752 //@Entity 753 @Table("person_info") 754 class MoreInfo { 755 //@Id @Generated 756 int id; 757 // @Column 758 long flags; 759 @OneToOne("moreInfo") 760 Person person; 761 @OneToOne("personInfo") 762 EvenMoreInfo evenMore; 763 } 764 765 //@Entity 766 @Table("person_info2") 767 class EvenMoreInfo { 768 //@Id @Generated 769 int id; 770 //@Column 771 long flags; 772 @OneToOne 773 @JoinColumn("person_info_fk") 774 MoreInfo personInfo; 775 } 776 777 } 778 779 780 unittest { 781 static assert(hasAnnotation!(EMName, Embeddable)); 782 static assert(isEmbeddedObjectMember!(EMUser, "userName")); 783 static assert(!hasMemberAnnotation!(EMUser, "userName", OneToOne)); 784 static assert(getPropertyEmbeddedEntityName!(EMUser, "userName") == "EMName"); 785 static assert(getPropertyEmbeddedClassName!(EMUser, "userName") == "hibernated.tests.EMName"); 786 //pragma(msg, getEmbeddedPropertyDef!(EMUser, "userName")()); 787 788 // Checking generated metadata 789 EntityMetaData schema = new SchemaInfoImpl!(EMName, EMUser); 790 791 static assert(hasMemberAnnotation!(Person, "moreInfo", OneToOne)); 792 static assert(getPropertyReferencedEntityName!(Person, "moreInfo") == "MoreInfo"); 793 static assert(getPropertyReferencedClassName!(Person, "moreInfo") == "hibernated.tests.MoreInfo"); 794 //pragma(msg, getOneToOnePropertyDef!(Person, "moreInfo")); 795 //pragma(msg, getOneToOnePropertyDef!(MoreInfo, "person")); 796 //pragma(msg, "running getOneToOneReferencedPropertyName"); 797 //pragma(msg, getOneToOneReferencedPropertyName!(MoreInfo, "person")); 798 static assert(getJoinColumnName!(Person, "moreInfo") == "more_info_fk"); 799 static assert(getOneToOneReferencedPropertyName!(MoreInfo, "person") == "moreInfo"); 800 static assert(getOneToOneReferencedPropertyName!(Person, "moreInfo") is null); 801 802 //pragma(msg, "done getOneToOneReferencedPropertyName"); 803 804 // Checking generated metadata 805 //EntityMetaData schema = new SchemaInfoImpl!(Person, MoreInfo); 806 // foreach(e; schema["Person"]) { 807 // writeln("property: " ~ e.propertyName); 808 // } 809 schema = new SchemaInfoImpl!(hibernated.tests); //Person, MoreInfo, EvenMoreInfo, 810 811 { 812 813 int[Variant] map0; 814 map0[Variant(1)] = 3; 815 assert(map0[Variant(1)] == 3); 816 map0[Variant(1)]++; 817 assert(map0[Variant(1)] == 4); 818 819 //writeln("map test"); 820 PropertyLoadMap map = new PropertyLoadMap(); 821 Person ppp1 = new Person(); 822 Person ppp2 = new Person(); 823 Person ppp3 = new Person(); 824 //writeln("adding first"); 825 map.add(schema["Person"]["moreInfo"], Variant(1), ppp1); 826 //writeln("adding second"); 827 auto prop1 = schema["Person"]["moreInfo"]; 828 auto prop2 = schema["Person"]["moreInfo"]; 829 map.add(prop1, Variant(2), ppp2); 830 map.add(prop2, Variant(2), ppp3); 831 map.add(prop2, Variant(2), ppp3); 832 map.add(prop2, Variant(2), ppp3); 833 map.add(prop2, Variant(2), ppp3); 834 assert(prop1 == prop2); 835 assert(prop1.opHash() == prop2.opHash()); 836 //writeln("checking length"); 837 assert(Variant(3) == Variant(3L)); 838 assert(map.length == 1); 839 assert(map.map.length == 1); 840 assert(map.keys.length == 1); 841 assert(map.map.values.length == 1); 842 //writeln("length of moreInfo is " ~ to!string(map[prop1].length)); 843 auto m = map[prop1]; 844 assert(m == map[prop2]); 845 assert(m.map.length == 2); 846 Variant v1 = 1; 847 Variant v2 = 2; 848 //writeln("length for id 1 " ~ to!string(m[Variant(1)].length)); 849 //writeln("length for id 2 " ~ to!string(m[Variant(2)].length)); 850 assert(m.length == 2); 851 assert(m[Variant(1)].length == 1); 852 assert(m[Variant(2)].length == 2); 853 } 854 855 if (DB_TESTS_ENABLED) { 856 //recreateTestSchema(); 857 858 //writeln("metadata test 2"); 859 import hibernated.dialects.mysqldialect; 860 861 // Checking generated metadata 862 Dialect dialect = getUnitTestDialect(); 863 DataSource ds = getUnitTestDataSource(); 864 if (ds is null) 865 return; // DB tests disabled 866 SessionFactory factory = new SessionFactoryImpl(schema, dialect, ds); 867 scope(exit) factory.close(); 868 { 869 Session sess = factory.openSession(); 870 scope(exit) sess.close(); 871 872 auto p1 = sess.get!Person(1); 873 assert(p1.firstName == "Andrei"); 874 875 876 // all non-null oneToOne relations 877 auto q = sess.createQuery("FROM Person WHERE id=:Id").setParameter("Id", Variant(1)); 878 Person p2 = q.uniqueResult!Person(); 879 assert(p2.firstName == "Andrei"); 880 assert(p2.moreInfo !is null); 881 assert(p2.moreInfo.person !is null); 882 assert(p2.moreInfo.person == p2); 883 assert(p2.moreInfo.flags == 123); 884 assert(p2.moreInfo.evenMore !is null); 885 assert(p2.moreInfo.evenMore.flags == 1); 886 assert(p2.moreInfo.evenMore.personInfo !is null); 887 assert(p2.moreInfo.evenMore.personInfo == p2.moreInfo); 888 889 890 // null oneToOne relation 891 q = sess.createQuery("FROM Person WHERE id=:Id").setParameter("Id", Variant(3)); 892 p2 = q.uniqueResult!Person(); 893 assert(p2.firstName == "John"); 894 assert(p2.moreInfo !is null); 895 assert(p2.moreInfo.person !is null); 896 assert(p2.moreInfo.person == p2); 897 assert(p2.moreInfo.flags == 345); 898 assert(p2.moreInfo.evenMore is null); 899 900 } 901 902 } 903 } 904 905