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/metadata.d. 8 * 9 * This module contains implementation of Annotations parsing and ORM model metadata holder classes. 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.metadata; 16 17 import std.ascii; 18 import std.conv; 19 import std.datetime; 20 import std.exception; 21 //import std.stdio : writeln; 22 import std.string; 23 import std.traits; 24 import std.typecons; 25 import std.typetuple; 26 import std.variant; 27 import std.uuid; 28 29 import ddbc.core; 30 import ddbc.common; 31 32 import hibernated.annotations; 33 import hibernated.core; 34 import hibernated.type; 35 import hibernated.session; 36 import hibernated.dialect; 37 import hibernated.dialects.mysqldialect; 38 39 // For backwards compatibily 40 // 'enforceEx' will be removed with 2.089 41 static if(__VERSION__ < 2080) { 42 alias enforceHelper = enforceEx; 43 } else { 44 alias enforceHelper = enforce; 45 } 46 47 // For backwards compatibily (since D 2.101, logger is no longer in std.experimental) 48 static if (__traits(compiles, (){ import std.logger; } )) { 49 import std.logger : trace, warning; 50 } else { 51 import std.experimental.logger : trace, warning; 52 } 53 54 abstract class EntityMetaData { 55 56 @property size_t length(); 57 const(EntityInfo) opIndex(int index) const; 58 const(EntityInfo) opIndex(string entityName) const; 59 const(PropertyInfo) opIndex(string entityName, string propertyName) const; 60 61 public string getEntityName(TypeInfo_Class type) const { 62 return getClassMap()[type].name; 63 } 64 65 public string getEntityNameForClass(T)() const { 66 return getClassMap()[T.classinfo].name; 67 } 68 69 int opApply(int delegate(ref const EntityInfo) dg) const; 70 71 72 public const(EntityInfo[]) getEntities() const; 73 public const(EntityInfo[string]) getEntityMap() const; 74 public const(EntityInfo[TypeInfo_Class]) getClassMap() const; 75 public const(EntityInfo) findEntity(string entityName) const; 76 public const(EntityInfo) findEntity(TypeInfo_Class entityClass) const; 77 public const(EntityInfo) findEntityForObject(Object obj) const; 78 public const(EntityInfo) getEntity(int entityIndex) const; 79 public int getEntityCount() const; 80 /// Entity factory 81 public Object createEntity(string entityName) const; 82 /// Fills all properties of entity instance from dataset 83 public int readAllColumns(Object obj, DataSetReader r, int startColumn) const; 84 /// Puts all properties of entity instance to dataset 85 public int writeAllColumns(Object obj, DataSetWriter w, int startColumn, bool exceptKey = false) const; 86 87 public string generateFindAllForEntity(Dialect dialect, string entityName) const; 88 89 public int getFieldCount(const EntityInfo ei, bool exceptKey) const; 90 91 public string getAllFieldList(Dialect dialect, const EntityInfo ei, bool exceptKey = false) const; 92 public string getAllFieldList(Dialect dialect, string entityName, bool exceptKey = false) const; 93 94 public string generateFindByPkForEntity(Dialect dialect, const EntityInfo ei) const; 95 public string generateFindByPkForEntity(Dialect dialect, string entityName) const; 96 97 public string generateInsertAllFieldsForEntity(Dialect dialect, const EntityInfo ei) const; 98 public string generateInsertAllFieldsForEntity(Dialect dialect, string entityName) const; 99 public string generateInsertNoKeyForEntity(Dialect dialect, const EntityInfo ei) const; 100 public string generateUpdateForEntity(Dialect dialect, const EntityInfo ei) const; 101 102 public Variant getPropertyValue(Object obj, string propertyName) const; 103 public void setPropertyValue(Object obj, string propertyName, Variant value) const; 104 } 105 106 enum RelationType { 107 None, 108 Embedded, 109 OneToOne, 110 OneToMany, 111 ManyToOne, 112 ManyToMany, 113 } 114 115 /// Metadata of entity property 116 class PropertyInfo { 117 public: 118 /// reads simple property value from data set to object 119 alias ReaderFunc = void function(Object, DataSetReader, int index); 120 /// writes simple property value to data set from object 121 alias WriterFunc = void function(Object, DataSetWriter, int index); 122 /// copy property from second passed object to first 123 alias CopyFunc = void function(Object, Object); 124 /// returns simple property as Variant 125 alias GetVariantFunc = Variant function(Object); 126 /// sets simple property from Variant 127 alias SetVariantFunc = void function(Object, Variant value); 128 /// returns true if property value of object is not null 129 alias IsNullFunc = bool function(Object); 130 /// returns true if key property of object is set (similar to IsNullFunc but returns true if non-nullable number is 0. 131 alias KeyIsSetFunc = bool function(Object); 132 /// returns OneToOne, ManyToOne or Embedded property as Object 133 alias GetObjectFunc = Object function(Object); 134 /// sets OneToOne, ManyToOne or Embedded property as Object 135 alias SetObjectFunc = void function(Object, Object); 136 /// sets lazy loader delegate for OneToOne, or ManyToOne property if it's Lazy! template instance 137 alias SetObjectDelegateFunc = void function(Object, Object delegate()); 138 /// sets lazy loader delegate for OneToMany, or ManyToMany property if it's LazyCollection! template instance 139 alias SetCollectionDelegateFunc = void function(Object, Object[] delegate()); 140 /// returns OneToMany or ManyToMany property value as object array 141 alias GetCollectionFunc = Object[] function(Object); 142 /// sets OneToMany or ManyToMany property value from object array 143 alias SetCollectionFunc = void function(Object, Object[]); 144 /// returns true if Lazy! or LazyCollection! property is loaded (no loader delegate set). 145 alias IsLoadedFunc = bool function(Object); 146 /// returns new generated primary key for property 147 alias GeneratorFunc = Variant function(Connection conn, const PropertyInfo prop); 148 149 package EntityInfo _entity; 150 @property const(EntityInfo) entity() const { return _entity; } 151 @property const(EntityMetaData) metadata() const { return _entity._metadata; } 152 153 immutable string propertyName; 154 immutable string columnName; 155 immutable Type columnType; 156 immutable int length; 157 immutable bool key; 158 immutable bool generated; 159 immutable bool nullable; 160 immutable string uniqueIndex; 161 immutable RelationType relation; 162 immutable bool lazyLoad; 163 immutable bool collection; 164 165 immutable string referencedEntityName; // for @Embedded, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany holds name of entity 166 package EntityInfo _referencedEntity; // for @Embedded, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany holds entity info reference, filled in runtime 167 @property const(EntityInfo) referencedEntity() const { return _referencedEntity; } 168 169 immutable string referencedPropertyName; // for @OneToOne, @OneToMany, @ManyToOne 170 package PropertyInfo _referencedProperty; 171 @property const(PropertyInfo) referencedProperty() const { return _referencedProperty; } 172 173 package int _columnOffset; // offset from first column of this entity in selects 174 @property int columnOffset() const { return _columnOffset; } // offset from first column of this entity in selects 175 176 package JoinTableInfo _joinTable; 177 @property const (JoinTableInfo) joinTable() const { return _joinTable; } 178 179 immutable ReaderFunc readFunc; 180 immutable WriterFunc writeFunc; 181 immutable GetVariantFunc getFunc; 182 immutable SetVariantFunc setFunc; 183 immutable KeyIsSetFunc keyIsSetFunc; 184 immutable IsNullFunc isNullFunc; 185 immutable GetObjectFunc getObjectFunc; 186 immutable SetObjectFunc setObjectFunc; 187 immutable CopyFunc copyFieldFunc; 188 immutable GetCollectionFunc getCollectionFunc; 189 immutable SetCollectionFunc setCollectionFunc; 190 immutable SetObjectDelegateFunc setObjectDelegateFunc; 191 immutable SetCollectionDelegateFunc setCollectionDelegateFunc; 192 immutable IsLoadedFunc isLoadedFunc; 193 immutable GeneratorFunc generatorFunc; 194 195 @property bool simple() const { return relation == RelationType.None; }; 196 @property bool embedded() const { return relation == RelationType.Embedded; }; 197 @property bool oneToOne() const { return relation == RelationType.OneToOne; }; 198 @property bool oneToMany() const { return relation == RelationType.OneToMany; }; 199 @property bool manyToOne() const { return relation == RelationType.ManyToOne; }; 200 @property bool manyToMany() const { return relation == RelationType.ManyToMany; }; 201 202 this(string propertyName, string columnName, Type columnType, int length, bool key, bool generated, bool nullable, string uniqueIndex, RelationType relation, string referencedEntityName, string referencedPropertyName, ReaderFunc reader, WriterFunc writer, GetVariantFunc getFunc, SetVariantFunc setFunc, KeyIsSetFunc keyIsSetFunc, IsNullFunc isNullFunc, 203 CopyFunc copyFieldFunc, 204 GeneratorFunc generatorFunc = null, 205 GetObjectFunc getObjectFunc = null, 206 SetObjectFunc setObjectFunc = null, 207 GetCollectionFunc getCollectionFunc = null, 208 SetCollectionFunc setCollectionFunc = null, 209 SetObjectDelegateFunc setObjectDelegateFunc = null, 210 SetCollectionDelegateFunc setCollectionDelegateFunc = null, 211 IsLoadedFunc isLoadedFunc = null, 212 bool lazyLoad = false, bool collection = false, 213 JoinTableInfo joinTable = null) { 214 this.propertyName = propertyName; 215 this.columnName = columnName; 216 this.columnType = cast(immutable Type)columnType; 217 this.length = length; 218 this.key = key; 219 this.generated = generated; 220 this.nullable = nullable; 221 this.relation = relation; 222 this.referencedEntityName =referencedEntityName; 223 this.referencedPropertyName = referencedPropertyName; 224 this.readFunc = reader; 225 this.writeFunc = writer; 226 this.getFunc = getFunc; 227 this.setFunc = setFunc; 228 this.keyIsSetFunc = keyIsSetFunc; 229 this.isNullFunc = isNullFunc; 230 this.getObjectFunc = getObjectFunc; 231 this.setObjectFunc = setObjectFunc; 232 this.copyFieldFunc = copyFieldFunc; 233 this.generatorFunc = generatorFunc; 234 this.lazyLoad = lazyLoad; 235 this.collection = collection; 236 this.setObjectDelegateFunc = setObjectDelegateFunc; 237 this.setCollectionDelegateFunc = setCollectionDelegateFunc; 238 this.getCollectionFunc = getCollectionFunc; 239 this.setCollectionFunc = setCollectionFunc; 240 this.isLoadedFunc = isLoadedFunc; 241 this._joinTable = joinTable; 242 this.uniqueIndex = uniqueIndex; 243 } 244 245 package void updateJoinTable() { 246 assert(relation == RelationType.ManyToMany); 247 assert(_joinTable !is null); 248 _joinTable.setEntities(entity, referencedEntity); 249 } 250 251 hash_t opHash() const { 252 return (cast(hash_t)(cast(void*)this)) * 31; 253 } 254 255 bool opEquals(ref const PropertyInfo s) const { 256 return this == s; 257 } 258 259 int opCmp(ref const PropertyInfo s) const { 260 return this == s ? 0 : (opHash() > s.opHash() ? 1 : -1); 261 } 262 263 Variant[] getCollectionIds(Object obj) const { 264 assert(oneToMany || manyToMany); 265 Variant[] res; 266 Object[] list = getCollectionFunc(obj); 267 if (list is null) 268 return res; 269 foreach(item; list) { 270 res ~= referencedEntity.getKey(item); 271 } 272 return res; 273 } 274 } 275 276 /// Metadata of single entity 277 class EntityInfo { 278 279 package EntityMetaData _metadata; 280 @property const(EntityMetaData) metadata() const { return _metadata; } 281 282 immutable string name; 283 immutable string tableName; 284 private PropertyInfo[] _properties; 285 @property const(PropertyInfo[]) properties() const { return _properties; } 286 package PropertyInfo [string] _propertyMap; 287 immutable TypeInfo_Class classInfo; 288 private int _keyIndex; 289 @property int keyIndex() const { return _keyIndex; } 290 private PropertyInfo _keyProperty; 291 @property const(PropertyInfo) keyProperty() const { return _keyProperty; } 292 293 immutable bool embeddable; 294 295 296 int opApply(int delegate(ref const PropertyInfo) dg) const { 297 int result = 0; 298 for (int i = 0; i < _properties.length; i++) { 299 result = dg(_properties[i]); 300 if (result) break; 301 } 302 return result; 303 } 304 305 public this(string name, string tableName, bool embeddable, PropertyInfo [] properties, TypeInfo_Class classInfo) { 306 this.name = name; 307 this.tableName = tableName; 308 this.embeddable = embeddable; 309 this._properties = properties; 310 this.classInfo = cast(immutable TypeInfo_Class)classInfo; 311 PropertyInfo[string] map; 312 foreach(i, p; properties) { 313 p._entity = this; 314 map[p.propertyName] = p; 315 if (p.key) { 316 _keyIndex = cast(int)i; 317 _keyProperty = p; 318 } 319 } 320 this._propertyMap = map; 321 enforceHelper!MappingException(keyProperty !is null || embeddable, "No key specified for non-embeddable entity " ~ name); 322 } 323 /// returns key value as Variant from entity instance 324 Variant getKey(Object obj) const { return keyProperty.getFunc(obj); } 325 /// returns key value as Variant from data set 326 Variant getKey(DataSetReader r, int startColumn) const { return r.getVariant(startColumn + keyProperty.columnOffset); } 327 /// sets key value from Variant 328 void setKey(Object obj, Variant value) const { keyProperty.setFunc(obj, value); } 329 /// returns property info for key property 330 const(PropertyInfo) getKeyProperty() const { return keyProperty; } 331 /// checks if primary key is set (for non-nullable member types like int or long, 0 is considered as non-set) 332 bool isKeySet(Object obj) const { return keyProperty.keyIsSetFunc(obj); } 333 /// checks if primary key is set (for non-nullable member types like int or long, 0 is considered as non-set) 334 bool isKeyNull(DataSetReader r, int startColumn) const { return r.isNull(startColumn + keyProperty.columnOffset); } 335 /// checks if property value is null 336 bool isNull(Object obj) const { return keyProperty.isNullFunc(obj); } 337 /// returns property value as Variant 338 Variant getPropertyValue(Object obj, string propertyName) const { return findProperty(propertyName).getFunc(obj); } 339 /// sets property value from Variant 340 void setPropertyValue(Object obj, string propertyName, Variant value) const { return findProperty(propertyName).setFunc(obj, value); } 341 /// returns all properties as array 342 const (PropertyInfo[]) getProperties() const { return properties; } 343 /// returns map of property name to property metadata 344 const (PropertyInfo[string]) getPropertyMap() const { return _propertyMap; } 345 /// returns number of properties 346 ulong getPropertyCount() const { return properties.length; } 347 /// returns number of properties 348 ulong getPropertyCountExceptKey() const { return properties.length - 1; } 349 350 @property size_t length() const { return properties.length; } 351 352 const(PropertyInfo) opIndex(int index) const { 353 return properties[index]; 354 } 355 356 const(PropertyInfo) opIndex(string propertyName) const { 357 return findProperty(propertyName); 358 } 359 360 /// returns property by index 361 const(PropertyInfo) getProperty(int propertyIndex) const { return properties[propertyIndex]; } 362 /// returns property by name, throws exception if not found 363 const(PropertyInfo) findProperty(string propertyName) const { try { return _propertyMap[propertyName]; } catch (Throwable e) { throw new MappingException("No property " ~ propertyName ~ " found in entity " ~ name); } } 364 /// create instance of entity object (using default constructor) 365 Object createEntity() const { return Object.factory(classInfo.name); } 366 367 void copyAllProperties(Object to, Object from) const { 368 foreach(pi; this) 369 pi.copyFieldFunc(to, from); 370 } 371 } 372 373 class JoinTableInfo { 374 package string _tableName; 375 @property string tableName() const { return _tableName; } 376 package string _column1; 377 @property string column1() const { return _column1; } 378 package string _column2; 379 @property string column2() const { return _column2; } 380 package EntityInfo _thisEntity; 381 @property const (EntityInfo) thisEntity() const { return _thisEntity; } 382 package EntityInfo _otherEntity; 383 @property const (EntityInfo) otherEntity() const { return _otherEntity; } 384 this(string tableName, string column1, string column2) { 385 this._tableName = tableName; 386 this._column1 = column1; 387 this._column2 = column2; 388 } 389 /// set entities, and replace missing parameters with default generated values 390 package void setEntities(const EntityInfo thisEntity, const EntityInfo otherEntity) { 391 assert(thisEntity !is null); 392 assert(otherEntity !is null); 393 this._thisEntity = cast(EntityInfo)thisEntity; 394 this._otherEntity = cast(EntityInfo)otherEntity; 395 // table name is constructed from names of two entities delimited with underscore, sorted in alphabetical order, with appended suffix 's': entity1_entity2s 396 // (to get same table name on two sides) 397 string entity1 = camelCaseToUnderscoreDelimited(thisEntity.name < otherEntity.name ? thisEntity.name : otherEntity.name); 398 string entity2 = camelCaseToUnderscoreDelimited(thisEntity.name < otherEntity.name ? otherEntity.name : thisEntity.name); 399 _tableName = _tableName !is null ? _tableName : entity1 ~ "_" ~ entity2 ~ "s"; 400 // columns are entity name (CamelCase to camel_case 401 _column1 = _column1 !is null ? _column1 : camelCaseToUnderscoreDelimited(thisEntity.name) ~ "_fk"; 402 _column2 = _column2 !is null ? _column2 : camelCaseToUnderscoreDelimited(otherEntity.name) ~ "_fk"; 403 } 404 static string generateJoinTableCode(string table, string column1, string column2) { 405 return "new JoinTableInfo(" ~ quoteString(table) ~ ", " ~ quoteString(column1) ~ ", " ~ quoteString(column2) ~ ")"; 406 } 407 408 string getInsertSQL(const Dialect dialect) const { 409 return "INSERT INTO " ~ dialect.quoteIfNeeded(_tableName) ~ "(" ~ dialect.quoteIfNeeded(_column1) ~ ", " ~ dialect.quoteIfNeeded(column2) ~ ") VALUES "; 410 } 411 412 string getOtherKeySelectSQL(const Dialect dialect, string thisKeySQL) const { 413 return "SELECT " ~ dialect.quoteIfNeeded(column2) ~ " FROM " ~ dialect.quoteIfNeeded(_tableName) ~ " WHERE " ~ dialect.quoteIfNeeded(_column1) ~ "=" ~ thisKeySQL; 414 } 415 416 string getInsertSQL(const Dialect dialect, string thisKeySQL, string[] otherKeysSQL) const { 417 string list; 418 foreach(otherKeySQL; otherKeysSQL) { 419 if (list.length > 0) 420 list ~= ", "; 421 list ~= "(" ~ thisKeySQL ~ ", " ~ otherKeySQL ~ ")"; 422 } 423 return getInsertSQL(dialect) ~ list; 424 } 425 426 string getDeleteSQL(const Dialect dialect, string thisKeySQL, string[] otherKeysSQL) const { 427 string sql = "DELETE FROM " ~ dialect.quoteIfNeeded(_tableName) ~ " WHERE " ~ dialect.quoteIfNeeded(_column1) ~ "=" ~ thisKeySQL ~ " AND " ~ dialect.quoteIfNeeded(_column2) ~ " IN "; 428 string list; 429 foreach(otherKeySQL; otherKeysSQL) { 430 if (list.length > 0) 431 list ~= ", "; 432 list ~= otherKeySQL; 433 } 434 return sql ~ "(" ~ list ~ ")"; 435 } 436 } 437 438 string quoteString(string s) { 439 return s is null ? "null" : "\"" ~ s ~ "\""; 440 } 441 442 string quoteBool(bool b) { 443 return b ? "true" : "false"; 444 } 445 446 string capitalizeFieldName(immutable string name) { 447 if (name[0] == '_') 448 return toUpper(name[1..2]) ~ name[2..$]; 449 else 450 return toUpper(name[0..1]) ~ name[1..$]; 451 } 452 453 /// lowercases first letter 454 string classNameToPropertyName(immutable string name) { 455 return toLower(name[0..1]) ~ name[1..$]; 456 } 457 458 string getterNameToFieldName(immutable string name) { 459 if (name[0..3] == "get") 460 return toLower(name[3..4]) ~ name[4..$]; 461 if (name[0..2] == "is") 462 return toLower(name[2..3]) ~ name[3..$]; 463 return "_" ~ name; 464 } 465 466 string getterNameToSetterName(immutable string name) { 467 if (name[0..3] == "get") 468 return "set" ~ name[3..$]; // e.g. getValue() -> setValue() 469 if (name[0..2] == "is") 470 return "set" ~ toUpper(name[0..1]) ~ name[1..$]; // e.g. isDefault()->setIsDefault() 471 return "_" ~ name; 472 } 473 474 /// converts camel case MyEntityName to my_entity_name 475 string camelCaseToUnderscoreDelimited(immutable string s) { 476 string res; 477 bool lastLower = false; 478 foreach(ch; s) { 479 if (ch >= 'A' && ch <= 'Z') { 480 if (lastLower) { 481 lastLower = false; 482 res ~= "_"; 483 } 484 res ~= std.ascii.toLower(ch); 485 } else if (ch >= 'a' && ch <= 'z') { 486 lastLower = true; 487 res ~= ch; 488 } else { 489 res ~= ch; 490 } 491 } 492 return res; 493 } 494 495 unittest { 496 static assert(camelCaseToUnderscoreDelimited("User") == "user"); 497 static assert(camelCaseToUnderscoreDelimited("MegaTableName") == "mega_table_name"); 498 } 499 500 /// returns true if class member has at least one known property level annotation (@Column, @Id, @Generated) 501 template hasHibernatedPropertyAnnotation(T, string m) { 502 enum bool hasHibernatedPropertyAnnotation = hasOneOfMemberAnnotations!(T, m, Id, Column, OneToOne, ManyToOne, ManyToMany, OneToMany, Generated, Generator); 503 } 504 505 bool hasHibernatedClassOrPropertyAnnotation(T)() { 506 static if (hasOneOfAnnotations!(T, Entity, Embeddable, Table)) { 507 return true; 508 } else { 509 auto hasAnnotation = false; 510 foreach (m; __traits(allMembers, T)) { 511 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 512 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 513 static if (hasHibernatedPropertyAnnotation!(T, m)) { 514 hasAnnotation = true; 515 break; 516 } 517 } 518 } 519 } 520 return hasAnnotation; 521 } 522 } 523 524 bool hasAnyKeyPropertyAnnotation(T)() { 525 auto hasAny = false; 526 foreach (m; __traits(allMembers, T)) { 527 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 528 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 529 static if (hasOneOfMemberAnnotations!(T, m, Id, Generated, Generator)) 530 hasAny = true; 531 break; 532 } 533 } 534 } 535 return hasAny; 536 } 537 538 /// returns true if class has one of specified anotations 539 bool hasOneOfAnnotations(T : Object, A...)() { 540 auto hasOne = false; 541 foreach(a; A) { 542 static if (hasAnnotation!(T, a)) { 543 hasOne = true; 544 break; 545 } 546 } 547 return hasOne; 548 } 549 550 /// returns true if class member has one of specified anotations 551 bool hasOneOfMemberAnnotations(T : Object, string m, A...)() { 552 bool res = false; 553 foreach(a; A) { 554 static if (hasMemberAnnotation!(T, m, a)) { 555 res = true; 556 break; 557 } 558 } 559 return res; 560 } 561 562 /// returns true if class has specified anotations 563 bool hasAnnotation(T, A)() { 564 bool res = false; 565 foreach(a; __traits(getAttributes, T)) { 566 static if (is(typeof(a) == A) || a.stringof == A.stringof) { 567 res = true; 568 break; 569 } 570 } 571 return res; 572 } 573 574 bool isGetterFunction(alias overload, string methodName)() { 575 //pragma(msg, "isGetterFunction " ~ methodName ~ " " ~ typeof(overload).stringof); 576 static if (is(typeof(overload) == function)) { 577 //pragma(msg, "is function " ~ methodName ~ " " ~ typeof(overload).stringof); 578 static if (ParameterTypeTuple!(overload).length == 0) { 579 //pragma(msg, "no params " ~ methodName ~ " " ~ typeof(overload).stringof); 580 static if (functionAttributes!overload & FunctionAttribute.property) { 581 //pragma(msg, "is property"); 582 //writeln("is property or starts with get or is"); 583 return true; 584 } else if (methodName.startsWith("get") || methodName.startsWith("get")) { 585 //pragma(msg, "is getter"); 586 //writeln("is property or starts with get or is"); 587 return true; 588 } else { 589 return false; 590 } 591 } else { 592 return false; 593 } 594 } else { 595 return false; 596 } 597 } 598 599 /// returns true if class member has specified anotations 600 bool hasMemberAnnotation(T, string m, A)() { 601 bool res = false; 602 static if (is(typeof(__traits(getMember, T, m)) == function)) { 603 // function: check overloads 604 Louter: 605 foreach(overload; MemberFunctionsTuple!(T, m)) { 606 static if (isGetterFunction!(overload, m)) { 607 foreach(a; __traits(getAttributes, overload)) { 608 static if (is(typeof(a) == A) || a.stringof == A.stringof) { 609 res = true; 610 break Louter; 611 } 612 } 613 } 614 } 615 } else { 616 foreach(a; __traits(getAttributes, __traits(getMember,T,m))) { 617 static if (is(typeof(a) == A) || a.stringof == A.stringof) { 618 res = true; 619 break; 620 } 621 } 622 } 623 return res; 624 } 625 626 /// returns entity name for class type 627 string getEntityName(T : Object)() { 628 // foreach (a; __traits(getAttributes, T)) { 629 // static if (is(typeof(a) == Entity)) { 630 // return a.name; 631 // } 632 // static if (a.stringof == Entity.stringof) { 633 // return T.stringof; 634 // } 635 // } 636 return T.stringof; 637 } 638 639 /// returns table name for class type 640 string getTableName(T : Object)() { 641 string name = camelCaseToUnderscoreDelimited(T.stringof); 642 foreach (a; __traits(getAttributes, T)) { 643 static if (is(typeof(a) == Table)) { 644 name = a.name; 645 break; 646 } 647 } 648 return name; 649 } 650 651 string applyDefault(string s, string defaultValue) { 652 return s != null && s.length > 0 ? s : defaultValue; 653 } 654 655 string getColumnName(T, string m)() { 656 immutable string defValue = camelCaseToUnderscoreDelimited(getPropertyName!(T,m)); 657 string name = defValue; 658 static if (is(typeof(__traits(getMember, T, m)) == function)) { 659 // function: check overloads 660 Louter: 661 foreach(overload; MemberFunctionsTuple!(T, m)) { 662 static if (isGetterFunction!(overload, m)) { 663 foreach(a; __traits(getAttributes, overload)) { 664 static if (is(typeof(a) == Column)) { 665 name = applyDefault(a.name, defValue); 666 break Louter; 667 } 668 } 669 } 670 } 671 } else { 672 foreach(a; __traits(getAttributes, __traits(getMember,T,m))) { 673 static if (is(typeof(a) == Column)) { 674 name = applyDefault(a.name, defValue); 675 break; 676 } 677 } 678 } 679 return name; 680 } 681 682 string getGeneratorCode(T, string m)() { 683 string code = null; 684 foreach (a; __traits(getAttributes, __traits(getMember,T,m))) { 685 static if (is(typeof(a) == Generator)) { 686 static assert(a.code != null && a.code != "", "@Generator doesn't have code specified"); 687 code = a.code; 688 break; 689 } 690 static if (a.stringof == Generator.stringof) { 691 static assert(false, "@Generator doesn't have code specified"); 692 } 693 } 694 return code; 695 } 696 697 string getJoinColumnName(T, string m)() { 698 string name = null; 699 immutable string defValue = camelCaseToUnderscoreDelimited(getPropertyName!(T,m)()) ~ "_fk"; 700 static if (is(typeof(__traits(getMember, T, m)) == function)) { 701 // function: check overloads 702 Louter: 703 foreach(overload; MemberFunctionsTuple!(T, m)) { 704 static if (isGetterFunction!(overload, m)) { 705 foreach(a; __traits(getAttributes, overload)) { 706 static if (is(typeof(a) == JoinColumn)) { 707 name = applyDefault(a.name, defValue); 708 break Louter; 709 } else static if (a.stringof == JoinColumn.stringof) { 710 name = defValue; 711 break Louter; 712 } 713 } 714 } 715 } 716 } else { 717 foreach(a; __traits(getAttributes, __traits(getMember,T,m))) { 718 static if (is(typeof(a) == JoinColumn)) { 719 name = applyDefault(a.name, defValue); 720 break; 721 } else static if (a.stringof == JoinColumn.stringof) { 722 name = defValue; 723 break; 724 } 725 } 726 } 727 return name; 728 } 729 730 string getUniqueIndexName(T, string m)() { 731 string name = null; 732 immutable string defValue = camelCaseToUnderscoreDelimited(getEntityName!T) ~ "_" ~ camelCaseToUnderscoreDelimited(getPropertyName!(T,m)()) ~ "_index"; 733 static if (is(typeof(__traits(getMember, T, m)) == function)) { 734 // function: check overloads 735 Louter: 736 foreach(overload; MemberFunctionsTuple!(T, m)) { 737 static if (isGetterFunction!(overload, m)) { 738 foreach(a; __traits(getAttributes, overload)) { 739 static if (is(typeof(a) == UniqueKey)) { 740 name = applyDefault(a.name, defValue); 741 break Louter; 742 } else static if (a.stringof == UniqueKey.stringof) { 743 name = defValue; 744 break Louter; 745 } 746 } 747 } 748 } 749 } else { 750 foreach(a; __traits(getAttributes, __traits(getMember,T,m))) { 751 static if (is(typeof(a) == UniqueKey)) { 752 name = applyDefault(a.name, defValue); 753 break; 754 } else static if (a.stringof == UniqueKey.stringof) { 755 name = defValue; 756 break; 757 } 758 } 759 } 760 return name; 761 } 762 763 string getJoinTableName(T, string m)() { 764 string name = null; 765 static if (is(typeof(__traits(getMember, T, m)) == function)) { 766 // function: check overloads 767 Louter: 768 foreach(overload; MemberFunctionsTuple!(T, m)) { 769 static if (isGetterFunction!(overload, m)) { 770 foreach(a; __traits(getAttributes, overload)) { 771 static if (is(typeof(a) == JoinTable)) { 772 name = emptyStringToNull(a.joinTableName); 773 break Louter; 774 } 775 } 776 } 777 } 778 } else { 779 foreach(a; __traits(getAttributes, __traits(getMember,T,m))) { 780 static if (is(typeof(a) == JoinTable)) { 781 name = emptyStringToNull(a.joinTableName); 782 break; 783 } 784 } 785 } 786 return name; 787 } 788 789 string getJoinTableColumn1(T, string m)() { 790 string column = null; 791 foreach (a; __traits(getAttributes, __traits(getMember,T,m))) { 792 static if (is(typeof(a) == JoinTable)) { 793 column = emptyStringToNull(a.joinColumn1); 794 break; 795 } 796 } 797 return column; 798 } 799 800 string getJoinTableColumn2(T, string m)() { 801 string column = null; 802 foreach (a; __traits(getAttributes, __traits(getMember,T,m))) { 803 static if (is(typeof(a) == JoinTable)) { 804 column = emptyStringToNull(a.joinColumn2); 805 break; 806 } 807 } 808 return column; 809 } 810 811 string emptyStringToNull(string s) { 812 return (s is null || s.length == 0) ? null : s; 813 } 814 815 string getOneToOneReferencedPropertyName(T, string m)() { 816 string propertyName = null; 817 foreach (a; __traits(getAttributes, __traits(getMember,T,m))) { 818 static if (is(typeof(a) == OneToOne)) { 819 propertyName = emptyStringToNull(a.name); 820 break; 821 } 822 static if (a.stringof == OneToOne.stringof) { 823 propertyName = null; 824 break; 825 } 826 } 827 return propertyName; 828 } 829 830 /** 831 T is class/entity 832 m is member of T eg T.m; m is a collection/array. The ElementType of the collection/array has a ref to T. 833 Try to figure out the field name in the type of m which is of type T. 834 When m has a attribute of OneToMany with a name, the atribute.name is used. 835 */ 836 string getOneToManyReferencedPropertyName(T, string m)() { 837 // first check there is a attribute @OneToMany with a non null name, if so use it! 838 foreach( a; __traits( getAttributes, __traits( getMember, T, m ) ) ) { 839 static if( is( typeof(a) == OneToMany ) && a.name != null && a.name.length != 0 ) { 840 return a.name; 841 } 842 } 843 // No attrib or no name, try to deduce the field name from the type of T's field m 844 alias memberFieldType = typeof(__traits(getMember, T, m)); 845 static if( is( memberFieldType == LazyCollection!TAL, TAL )) 846 { 847 alias refererType = TAL; 848 } 849 else 850 { 851 import std.range : ElementType; 852 alias refererType = ElementType!memberFieldType; 853 } 854 // test T has single occurance in refererType 855 static if (__VERSION__ < 2074) { 856 import std.traits : FieldTypeTuple, Filter; // Filter used to be in std.traits 857 } else { 858 import std.traits : FieldTypeTuple; 859 import std.meta : Filter; 860 } 861 alias refererFields = FieldTypeTuple!refererType; 862 enum bool isSameType(U) = is( T == U ) || is ( Lazy!T == U ); 863 alias refererFieldsofTypeT = Filter!( isSameType, refererFields ); 864 // assert there is exactly one field with type T in refererFields 865 // when there is more than one use explicit attributes for each field eg: OneToMany( "field name first referer" ).. OneToMany( "field name second referer" ).. 866 static assert( refererFieldsofTypeT.length == 1, "auto deduction of OneToMany referencedPropertyName for " ~ T.stringof ~ "." ~ m ~ " failed: ElementType of " ~ refererType.stringof ~ "[] has " ~ refererFieldsofTypeT.length.stringof ~ " of fields " ~ T.stringof ~ ". (Use explicit OneToMany( fieldname in " ~ refererType.stringof ~ " ) annotations for multiple referers.)" ); 867 string res = null; 868 foreach( mf; __traits( allMembers, refererType ) ) { 869 static if( is( typeof(__traits(getMember, refererType, mf)) == T ) ) { 870 res = mf; 871 break; 872 } 873 } 874 return res; 875 } 876 877 int getColumnLength(T, string m)() { 878 auto length = 0; 879 static if (is(typeof(__traits(getMember, T, m)) == function)) { 880 // function: check overloads 881 Louter: 882 foreach(overload; MemberFunctionsTuple!(T, m)) { 883 static if (isGetterFunction!(overload, m)) { 884 foreach(a; __traits(getAttributes, overload)) { 885 static if (is(typeof(a) == Column)) { 886 length = a.length; 887 break Louter; 888 } 889 } 890 } 891 } 892 } else { 893 foreach(a; __traits(getAttributes, __traits(getMember,T,m))) { 894 static if (is(typeof(a) == Column)) { 895 length = a.length; 896 break; 897 } 898 } 899 } 900 return length; 901 } 902 903 string getPropertyName(T, string m)() { 904 alias ti = typeof(__traits(getMember, T, m)); 905 906 static if (is(ti == function)) { 907 return getterNameToFieldName(m); 908 } else 909 return m; 910 } 911 912 enum PropertyMemberKind : int { 913 FIELD_MEMBER, // int field; 914 GETTER_MEMBER, // getField() + setField() or isField() and setField() 915 PROPERTY_MEMBER, // @property T field() { ... } + @property xxx field(T value) { ... } 916 LAZY_MEMBER, // Lazy!Object field; 917 UNSUPPORTED_MEMBER,// 918 } 919 920 bool hasPercentSign(immutable string str) { 921 foreach(ch; str) { 922 if (ch == '%') 923 return true; 924 } 925 return false; 926 } 927 928 int percentSignCount(immutable string str) { 929 string res; 930 foreach(ch; str) { 931 if (ch == '%') 932 res ~= "%"; 933 } 934 return cast(int)res.length; 935 } 936 937 string substituteParam(immutable string fmt, immutable string value) { 938 if (hasPercentSign(fmt)) 939 return format(fmt, value); 940 else 941 return fmt; 942 } 943 944 //string substituteIntParam(immutable string fmt, immutable int value) { 945 // int percentPos = -1; 946 // for (int i=0; i<fmt.length; i++) { 947 // if (fmt[i] == '%') { 948 // percentPos = i; 949 // } 950 // 951 // } 952 // if (percentPos < 0) 953 // return fmt; 954 // return fmt[0 .. percentPos] ~ "1024" ~ fmt[percentPos + 2 .. $]; //to!string(value) 955 //// string res; 956 //// bool skipNext = false; 957 //// 958 //// foreach(ch; fmt) { 959 //// if (ch == '%') { 960 //// res ~= "1024"; //to!string(value); 961 //// skipNext = true; 962 //// } else if (!skipNext) { 963 //// res ~= ch; 964 //// skipNext = false; 965 //// } 966 //// } 967 //// return res; 968 // // following code causes error in DMD 969 //// if (hasPercentSign(fmt)) 970 //// return format(fmt, value); 971 //// else 972 //// return fmt; 973 //} 974 975 string substituteParamTwice(immutable string fmt, immutable string value) { 976 immutable int paramCount = cast(int)percentSignCount(fmt); 977 if (paramCount == 1) 978 return format(fmt, value); 979 else if (paramCount == 2) 980 return format(fmt, value, value); 981 else 982 return fmt; 983 } 984 985 static immutable string[] PropertyMemberKind_ReadCode = 986 [ 987 "entity.%s", 988 "entity.%s()", 989 "entity.%s", 990 "entity.%s()", 991 "dummy" 992 ]; 993 994 PropertyMemberKind getPropertyMemberKind(T : Object, string m)() { 995 auto memberKind = PropertyMemberKind.UNSUPPORTED_MEMBER; 996 alias ti = typeof(__traits(getMember, T, m)); 997 998 static if (is(ti == function)) { 999 // interate through all overloads 1000 //return checkGetterOverload!(T, m); 1001 foreach(overload; MemberFunctionsTuple!(T, m)) { 1002 static if (ParameterTypeTuple!(overload).length == 0) { 1003 static if (functionAttributes!overload & FunctionAttribute.property) { 1004 memberKind = PropertyMemberKind.PROPERTY_MEMBER; 1005 break; 1006 } 1007 else static if (m.startsWith("get") || m.startsWith("is")) { 1008 memberKind = PropertyMemberKind.GETTER_MEMBER; 1009 break; 1010 } 1011 } 1012 } 1013 } else { 1014 static if (isLazyInstance!(ti)) { 1015 memberKind = PropertyMemberKind.LAZY_MEMBER; 1016 } else { 1017 memberKind = PropertyMemberKind.FIELD_MEMBER; 1018 } 1019 } 1020 return memberKind; 1021 } 1022 1023 string getPropertyEmbeddedEntityName(T : Object, string m)() { 1024 alias ti = typeof(__traits(getMember, T, m)); 1025 1026 static if (is(ti == function)) { 1027 static if (isImplicitlyConvertible!(ReturnType!(ti), Object)) { 1028 static assert(hasAnnotation!(ReturnType!(ti), Embeddable), "@Embedded property class should have @Embeddable annotation"); 1029 return getEntityName!(ReturnType!(ti)); 1030 } else 1031 static assert(false, "@Embedded property can be only class with @Embeddable annotation"); 1032 } else { 1033 static if (isImplicitlyConvertible!(ti, Object)) { 1034 static assert(hasAnnotation!(ti, Embeddable), "@Embedded property class should have @Embeddable annotation"); 1035 return getEntityName!ti; 1036 } else 1037 static assert(false, "@Embedded property can be only class with @Embeddable annotation"); 1038 } 1039 } 1040 1041 template isLazyInstance(T) { 1042 static if (is(T x == Lazy!Args, Args...)) 1043 enum bool isLazyInstance = true; 1044 else 1045 enum bool isLazyInstance = false; 1046 } 1047 1048 template isLazyCollectionInstance(T) { 1049 static if (is(T x == LazyCollection!Args, Args...)) 1050 enum bool isLazyCollectionInstance = true; 1051 else 1052 enum bool isLazyCollectionInstance = false; 1053 } 1054 1055 template isLazyMember(T : Object, string m) { 1056 static if (is(typeof(__traits(getMember, T, m)) x == Lazy!Args, Args...)) 1057 enum bool isLazyMember = true; 1058 else 1059 enum bool isLazyMember = false; 1060 } 1061 1062 template isLazyCollectionMember(T : Object, string m) { 1063 static if (is(typeof(__traits(getMember, T, m)) x == LazyCollection!Args, Args...)) 1064 enum bool isLazyCollectionMember = true; 1065 else 1066 enum bool isLazyCollectionMember = false; 1067 } 1068 1069 template isObject(T) { 1070 enum bool isObject = (__traits(compiles, isImplicitlyConvertible!(T, Object)) && isImplicitlyConvertible!(T, Object)); 1071 } 1072 1073 /// member is field or function or property with SomeClass type 1074 template isObjectMember(T : Object, string m) { 1075 alias ti = typeof(__traits(getMember, T, m)); 1076 1077 static if (is(ti == function)) { 1078 enum bool isObjectMember = isImplicitlyConvertible!(ReturnType!(ti), Object); 1079 } else { 1080 enum bool isObjectMember = isImplicitlyConvertible!(ti, Object); 1081 } 1082 } 1083 1084 template hasPublicMember(T : Object, string m) { 1085 //pragma(msg, "hasPublicMember "~ T.stringof ~ ", " ~ m); 1086 static if (__traits(hasMember, T, m)) { 1087 enum bool hasPublicMember = __traits(compiles, __traits(getMember, T, m));//(__traits(getProtection, __traits(getMember, T, m)) == "public"); 1088 } else { 1089 enum bool hasPublicMember = false; 1090 } 1091 } 1092 1093 //unittest { 1094 // class Foo { 1095 // int id; 1096 // void x(); 1097 // } 1098 // static assert(hasPublicMember!(Foo, "id")); 1099 // static assert(hasPublicMember!(Foo, "x")); 1100 // static assert(!hasPublicMember!(Foo, "zzz")); 1101 // 1102 //} 1103 1104 /// returns true if it's object field of Embeddable object type 1105 template isEmbeddedObjectMember(T : Object, string m) { 1106 static if (isObjectMember!(T, m)) { 1107 alias typeof(__traits(getMember, T, m)) ti; 1108 enum bool isEmbeddedObjectMember = hasAnnotation!(getReferencedInstanceType!ti, Embeddable); 1109 } else { 1110 enum bool isEmbeddedObjectMember = false; 1111 } 1112 } 1113 1114 template hasPublicField(T : Object, string m) { 1115 static if (hasPublicMember!(T, m)) { 1116 enum bool hasPublicField = !is(typeof(__traits(getMember, T, m)) == function) && !is(typeof(__traits(getMember, T, m)) == delegate); 1117 } else { 1118 enum bool hasPublicField = false; 1119 } 1120 } 1121 1122 template hasPublicFieldWithAnnotation(T : Object, string m) { 1123 static if (hasPublicField!(T, m)) { 1124 enum bool hasPublicFieldWithAnnotation = hasHibernatedPropertyAnnotation!(T, m); 1125 } else { 1126 enum bool hasPublicFieldWithAnnotation = false; 1127 } 1128 } 1129 1130 /// returns true if one of overloads of member m of class T is property setter with specified value type 1131 bool hasWritePropretyForType(T: Object, string m, ParamType)() { 1132 auto hasProperty = false; 1133 foreach(overload; MemberFunctionsTuple!(T, m)) { 1134 static if (ParameterTypeTuple!(overload).length == 1) { 1135 static if (functionAttributes!overload & FunctionAttribute.property) { 1136 hasProperty = is(ParameterTypeTuple!(overload)[0] == ParamType); 1137 break; 1138 } 1139 } 1140 } 1141 return hasProperty; 1142 } 1143 1144 /// returns true if member m of class T has both property getter and setter of the same type 1145 bool isReadWriteProperty(T: Object, string m)() { 1146 bool res = false; 1147 foreach(overload; MemberFunctionsTuple!(T, m)) { 1148 static if (ParameterTypeTuple!(overload).length == 0) { 1149 static if (functionAttributes!overload & FunctionAttribute.property) { 1150 res = hasWritePropretyForType!(T, m, ReturnType!overload); 1151 break; 1152 } 1153 } 1154 } 1155 return res; 1156 } 1157 1158 /// check that member m exists in class T, and it's function with single parameter of type ti 1159 template isValidSetter(T : Object, string m, ParamType) { 1160 // it's public member 1161 static if (hasPublicMember!(T, m)) { 1162 // it's function with single parameter of proper type 1163 enum bool isValidSetter = is(typeof(__traits(getMember, T, m)) == function) && 1164 ParameterTypeTuple!(typeof(__traits(getMember, T, m))).length == 1 && 1165 is(ParameterTypeTuple!(typeof(__traits(getMember, T, m)))[0] == ParamType); 1166 } else { 1167 enum bool isValidSetter = false; 1168 } 1169 } 1170 1171 template isValidGetter(T : Object, string m) { 1172 // it's public member with get or is prefix 1173 static if ((m.startsWith("get") || m.startsWith("is")) && hasPublicMember!(T, m)) { 1174 alias ti = typeof(__traits(getMember, T, m)); 1175 alias rti = ReturnType!ti; 1176 1177 // it's function 1178 static if (is(typeof(__traits(getMember, T, m)) == function)) { 1179 // function has no parameters 1180 static if (ParameterTypeTuple!(typeof(__traits(getMember, T, m))).length == 0) { 1181 // has paired setter function of the same type 1182 static if (isValidSetter!(T, getterNameToSetterName(m), rti)) { 1183 enum bool isValidGetter = true; 1184 } else { 1185 enum bool isValidGetter = false; 1186 } 1187 } 1188 } else { 1189 enum bool isValidGetter = false; 1190 } 1191 } else { 1192 enum bool isValidGetter = false; 1193 } 1194 } 1195 1196 template isValidGetterWithAnnotation(T : Object, string m) { 1197 // it's public member with get or is prefix 1198 static if (isValidGetter!(T, m)) { 1199 enum bool isValidGetterWithAnnotation = hasHibernatedPropertyAnnotation!(T,m); 1200 } else { 1201 enum bool isValidGetterWithAnnotation = false; 1202 } 1203 } 1204 1205 bool isMainMemberForProperty(T : Object, string m)() { 1206 // skip non-public members 1207 static if (hasPublicMember!(T, m)) { 1208 alias ti = typeof(__traits(getMember, T, m)); 1209 1210 immutable bool thisMemberHasAnnotation = hasHibernatedPropertyAnnotation!(T,m); 1211 static if (is(ti == function)) { 1212 // function or property 1213 static if (functionAttributes!ti & FunctionAttribute.property) { 1214 // property 1215 return isReadWriteProprety!(T, m); 1216 } else { 1217 // getter function 1218 // should have corresponding setter 1219 static if (isValidGetter!(T,m)) { 1220 // if any field with matching name is found, only one of them may have annotation 1221 immutable bool annotatedField = hasPublicFieldWithAnnotation!(T, getterNameToFieldName(m)) || hasPublicFieldWithAnnotation!(T, "_" ~ getterNameToFieldName(m)); 1222 static assert(!annotatedField || !thisMemberHasAnnotation, "Both getter and corresponding field have annotations. Annotate only one of them."); 1223 return !annotatedField; 1224 } else { 1225 // non-conventional name for getter or no setter 1226 return false; 1227 } 1228 } 1229 } else { 1230 // field 1231 //capitalizeFieldName 1232 immutable string gname = capitalizeFieldName(m); 1233 immutable bool hasAnnotadedGetter = isValidGetterWithAnnotation!(T, "get" ~ gname) || isValidGetterWithAnnotation!(T, "is" ~ gname); 1234 immutable bool hasGetter = isValidGetter!(T, "get" ~ gname) || isValidGetter!(T, "is" ~ gname); 1235 static assert (!thisMemberHasAnnotation || !hasAnnotadedGetter, "Both getter and corresponding field have annotations. Annotate only one of them."); 1236 return !hasAnnotadedGetter && (thisMemberHasAnnotation || !hasGetter); 1237 } 1238 } else { 1239 // member is not public 1240 return false; 1241 } 1242 } 1243 1244 /// member is field or function or property returing SomeClass[] or LazyCollection!SomeClass 1245 template isCollectionMember(T : Object, string m) { 1246 alias ti = typeof(__traits(getMember, T, m)); 1247 1248 static if (is(ti == function)) { 1249 static if (is(ReturnType!(typeof(__traits(getMember, T, m))) x == LazyCollection!Args, Args...)) 1250 enum bool isCollectionMember = true; 1251 else { 1252 //pragma(msg, typeof(__traits(getMember, T, m).init[0])); 1253 alias rti = ReturnType!ti; 1254 static if (isArray!rti && isImplicitlyConvertible!(typeof(rti.init[0]), Object)) 1255 enum bool isCollectionMember = true; 1256 else 1257 enum bool isCollectionMember = false; 1258 } 1259 } else { 1260 static if (is(typeof(__traits(getMember, T, m)) x == LazyCollection!Args, Args...)) 1261 enum bool isCollectionMember = true; 1262 else { 1263 //pragma(msg, typeof(__traits(getMember, T, m).init[0])); 1264 static if (isArray!(ti) && isImplicitlyConvertible!(typeof(__traits(getMember, T, m).init[0]), Object)) 1265 enum bool isCollectionMember = true; 1266 else 1267 enum bool isCollectionMember = false; 1268 } 1269 } 1270 } 1271 1272 unittest { 1273 class Foo { 1274 bool dummy; 1275 } 1276 struct Bar { 1277 bool dummy; 1278 } 1279 class MemberTest { 1280 bool simple; 1281 bool getSimple() { return simple; } 1282 int someInt; 1283 Long someLong; 1284 bool[] simples; 1285 bool[] getSimples() { return simples; } 1286 @property bool[] simpless() { return simples; } 1287 Foo foo; 1288 Foo getFoo() { return foo; } 1289 @property Foo fooo() { return foo; } 1290 Foo[] foos; 1291 Foo[] getFoos() { return foos; } 1292 @property Foo[] fooos() { return foos; } 1293 LazyCollection!Foo lfoos; 1294 ref LazyCollection!Foo lgetFoos() { return lfoos; } 1295 @property ref LazyCollection!Foo lfooos() { return lfoos; } 1296 } 1297 static assert(getColumnName!(MemberTest, "simple") == "simple"); 1298 static assert(getColumnName!(MemberTest, "getSimple") == "simple"); 1299 static assert(isObject!Foo); 1300 static assert(!isObject!Bar); 1301 static assert(!isObjectMember!(MemberTest, "simple")); 1302 static assert(!isObjectMember!(MemberTest, "simples")); 1303 static assert(!isObjectMember!(MemberTest, "getSimples")); 1304 static assert(!isObjectMember!(MemberTest, "simpless")); 1305 static assert(!isCollectionMember!(MemberTest, "simples")); 1306 static assert(!isCollectionMember!(MemberTest, "getSimples")); 1307 static assert(!isCollectionMember!(MemberTest, "simpless")); 1308 static assert(isObjectMember!(MemberTest, "foo")); 1309 static assert(isObjectMember!(MemberTest, "getFoo")); 1310 static assert(isObjectMember!(MemberTest, "fooo")); 1311 static assert(!isCollectionMember!(MemberTest, "simple")); 1312 static assert(!isCollectionMember!(MemberTest, "foo")); 1313 static assert(!isCollectionMember!(MemberTest, "getFoo")); 1314 static assert(!isCollectionMember!(MemberTest, "fooo")); 1315 static assert(isCollectionMember!(MemberTest, "foos")); 1316 static assert(isCollectionMember!(MemberTest, "getFoos")); 1317 static assert(isCollectionMember!(MemberTest, "fooos")); 1318 static assert(isCollectionMember!(MemberTest, "lfoos")); 1319 static assert(isCollectionMember!(MemberTest, "lgetFoos")); 1320 static assert(isCollectionMember!(MemberTest, "lfooos")); 1321 static assert(isSupportedSimpleType!(MemberTest, "simple")); 1322 static assert(!isSupportedSimpleType!(MemberTest, "foo")); 1323 static assert(isSupportedSimpleType!(MemberTest, "someInt")); 1324 static assert(isSupportedSimpleType!(MemberTest, "someLong")); 1325 } 1326 1327 template getLazyInstanceType(T) { 1328 static if (is(T x == Lazy!Args, Args...)) 1329 alias getLazyInstanceType = Args[0]; 1330 else { 1331 static assert(false, "Not a Lazy! instance"); 1332 } 1333 } 1334 1335 template getLazyCollectionInstanceType(T) { 1336 static if (is(T x == LazyCollection!Args, Args...)) 1337 alias getLazyInstanceType = Args[0]; 1338 else { 1339 static assert(false, "Not a LazyCollection! instance"); 1340 } 1341 } 1342 1343 template getReferencedInstanceType(T) { 1344 //pragma(msg, T.stringof); 1345 static if (is(T == delegate)) { 1346 //pragma(msg, "is delegate"); 1347 static if (isImplicitlyConvertible!(ReturnType!(T), Object)) { 1348 alias getReferencedInstanceType = ReturnType!(T); 1349 } else 1350 static assert(false, "@OneToOne, @ManyToOne, @OneToMany, @ManyToMany property can be only class or Lazy!class"); 1351 } else static if (is(T == function)) { 1352 //pragma(msg, "is function"); 1353 static if (isImplicitlyConvertible!(ReturnType!(T), Object)) { 1354 alias getReferencedInstanceType = ReturnType!(T); 1355 } else { 1356 static if (is(ReturnType!(T) x == Lazy!Args, Args...)) 1357 alias getReferencedInstanceType = Args[0]; 1358 else 1359 static assert(false, "Type cannot be used as relation " ~ T.stringof); 1360 } 1361 } else { 1362 //pragma(msg, "is not function"); 1363 static if (is(T x == LazyCollection!Args, Args...)) { 1364 alias getReferencedInstanceType = Args[0]; 1365 } else { 1366 static if (is(T x == Lazy!Args, Args...)) { 1367 alias getReferencedInstanceType = Args[0]; 1368 } else { 1369 static if (isArray!(T)) { 1370 static if (isImplicitlyConvertible!(typeof(T.init[0]), Object)) { 1371 //pragma(msg, "isImplicitlyConvertible!(T, Object)"); 1372 alias getReferencedInstanceType = typeof(T.init[0]); 1373 } else { 1374 static assert(false, "Type cannot be used as relation " ~ T.stringof); 1375 } 1376 } else static if (isImplicitlyConvertible!(T, Object)) { 1377 //pragma(msg, "isImplicitlyConvertible!(T, Object)"); 1378 alias getReferencedInstanceType = T; 1379 } else static if (isImplicitlyConvertible!(T, Object[])) { 1380 //pragma(msg, "isImplicitlyConvertible!(T, Object)"); 1381 alias getReferencedInstanceType = T; 1382 } else { 1383 static assert(false, "Type cannot be used as relation " ~ T.stringof); 1384 } 1385 } 1386 } 1387 } 1388 } 1389 1390 string getPropertyReferencedEntityName(T : Object, string m)() { 1391 alias ti = typeof(__traits(getMember, T, m)); 1392 return getEntityName!(getReferencedInstanceType!ti); 1393 } 1394 1395 string getPropertyEmbeddedClassName(T : Object, string m)() { 1396 alias ti = typeof(__traits(getMember, T, m)); 1397 1398 static if (is(ti == function)) { 1399 static if (isImplicitlyConvertible!(ReturnType!(ti), Object)) { 1400 static assert(hasAnnotation!(ReturnType!(ti), Embeddable), "@Embedded property class should have @Embeddable annotation"); 1401 return fullyQualifiedName!(ReturnType!(ti)); 1402 } else 1403 static assert(false, "@Embedded property can be only class with @Embeddable annotation"); 1404 } else { 1405 static if (isImplicitlyConvertible!(ti, Object)) { 1406 static assert(hasAnnotation!(ti, Embeddable), "@Embedded property class should have @Embeddable annotation"); 1407 return fullyQualifiedName!ti; 1408 } else 1409 static assert(false, "@Embedded property can be only class with @Embeddable annotation"); 1410 } 1411 } 1412 1413 string getPropertyReferencedClassName(T : Object, string m)() { 1414 alias ti = typeof(__traits(getMember, T, m)); 1415 return fullyQualifiedName!(getReferencedInstanceType!ti); 1416 } 1417 1418 1419 1420 1421 1422 enum PropertyMemberType : int { 1423 BOOL_TYPE, // bool 1424 BYTE_TYPE, // byte 1425 SHORT_TYPE, // short 1426 INT_TYPE, // int 1427 LONG_TYPE, // long 1428 UBYTE_TYPE, // ubyte 1429 USHORT_TYPE, // ushort 1430 UINT_TYPE, // uint 1431 ULONG_TYPE, // ulong 1432 NULLABLE_BYTE_TYPE, // Nullable!byte 1433 NULLABLE_SHORT_TYPE, // Nullable!short 1434 NULLABLE_INT_TYPE, // Nullable!int 1435 NULLABLE_LONG_TYPE, // Nullable!long 1436 NULLABLE_UBYTE_TYPE, // Nullable!ubyte 1437 NULLABLE_USHORT_TYPE,// Nullable!ushort 1438 NULLABLE_UINT_TYPE, // Nullable!uint 1439 NULLABLE_ULONG_TYPE, // Nullable!ulong 1440 FLOAT_TYPE, // float 1441 DOUBLE_TYPE, // double 1442 NULLABLE_FLOAT_TYPE, // Nullable!float 1443 NULLABLE_DOUBLE_TYPE,// Nullable!double 1444 STRING_TYPE, // string 1445 NULLABLE_STRING_TYPE, // nullable string - String struct 1446 DATETIME_TYPE, // std.datetime.DateTime 1447 DATE_TYPE, // std.datetime.Date 1448 TIME_TYPE, // std.datetime.TimeOfDay 1449 NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 1450 NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 1451 NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 1452 BYTE_ARRAY_TYPE, // byte[] 1453 UBYTE_ARRAY_TYPE, // ubyte[] 1454 } 1455 1456 template isSupportedSimpleType(T, string m) { 1457 alias ti = typeof(__traits(getMember, T, m)); 1458 1459 static if (is(ti == function)) { 1460 static if (is(ReturnType!(ti) == bool)) { 1461 enum bool isSupportedSimpleType = true; 1462 } else static if (is(ReturnType!(ti) == byte)) { 1463 enum bool isSupportedSimpleType = true; 1464 } else static if (is(ReturnType!(ti) == short)) { 1465 enum bool isSupportedSimpleType = true; 1466 } else static if (is(ReturnType!(ti) == int)) { 1467 enum bool isSupportedSimpleType = true; 1468 } else static if (is(ReturnType!(ti) == long)) { 1469 enum bool isSupportedSimpleType = true; 1470 } else static if (is(ReturnType!(ti) == ubyte)) { 1471 enum bool isSupportedSimpleType = true; 1472 } else static if (is(ReturnType!(ti) == ushort)) { 1473 enum bool isSupportedSimpleType = true; 1474 } else static if (is(ReturnType!(ti) == uint)) { 1475 enum bool isSupportedSimpleType = true; 1476 } else static if (is(ReturnType!(ti) == ulong)) { 1477 enum bool isSupportedSimpleType = true; 1478 } else static if (is(ReturnType!(ti) == float)) { 1479 enum bool isSupportedSimpleType = true; 1480 } else static if (is(ReturnType!(ti) == double)) { 1481 enum bool isSupportedSimpleType = true; 1482 } else static if (is(ReturnType!(ti) == Nullable!byte)) { 1483 enum bool isSupportedSimpleType = true; 1484 } else static if (is(ReturnType!(ti) == Nullable!short)) { 1485 enum bool isSupportedSimpleType = true; 1486 } else static if (is(ReturnType!(ti) == Nullable!int)) { 1487 enum bool isSupportedSimpleType = true; 1488 } else static if (is(ReturnType!(ti) == Nullable!long)) { 1489 enum bool isSupportedSimpleType = true; 1490 } else static if (is(ReturnType!(ti) == Nullable!ubyte)) { 1491 enum bool isSupportedSimpleType = true; 1492 } else static if (is(ReturnType!(ti) == Nullable!ushort)) { 1493 enum bool isSupportedSimpleType = true; 1494 } else static if (is(ReturnType!(ti) == Nullable!uint)) { 1495 enum bool isSupportedSimpleType = true; 1496 } else static if (is(ReturnType!(ti) == Nullable!ulong)) { 1497 enum bool isSupportedSimpleType = true; 1498 } else static if (is(ReturnType!(ti) == Nullable!float)) { 1499 enum bool isSupportedSimpleType = true; 1500 } else static if (is(ReturnType!(ti) == Nullable!double)) { 1501 enum bool isSupportedSimpleType = true; 1502 } else static if (is(ReturnType!(ti) == string)) { 1503 enum bool isSupportedSimpleType = true; 1504 } else static if (is(ReturnType!(ti) == hibernated.type.String)) { 1505 enum bool isSupportedSimpleType = true; 1506 } else static if (is(ReturnType!(ti) == DateTime)) { 1507 enum bool isSupportedSimpleType = true; 1508 } else static if (is(ReturnType!(ti) == Date)) { 1509 enum bool isSupportedSimpleType = true; 1510 } else static if (is(ReturnType!(ti) == TimeOfDay)) { 1511 enum bool isSupportedSimpleType = true; 1512 } else static if (is(ReturnType!(ti) == Nullable!DateTime)) { 1513 enum bool isSupportedSimpleType = true; 1514 } else static if (is(ReturnType!(ti) == Nullable!Date)) { 1515 enum bool isSupportedSimpleType = true; 1516 } else static if (is(ReturnType!(ti) == Nullable!TimeOfDay)) { 1517 enum bool isSupportedSimpleType = true; 1518 } else static if (is(ReturnType!(ti) == byte[])) { 1519 enum bool isSupportedSimpleType = true; 1520 } else static if (is(ReturnType!(ti) == ubyte[])) { 1521 enum bool isSupportedSimpleType = true; 1522 } else { 1523 enum bool isSupportedSimpleType = false; 1524 } 1525 } else static if (is(ti == bool)) { 1526 enum bool isSupportedSimpleType = true; 1527 } else static if (is(ti == byte)) { 1528 enum bool isSupportedSimpleType = true; 1529 } else static if (is(ti == short)) { 1530 enum bool isSupportedSimpleType = true; 1531 } else static if (is(ti == int)) { 1532 enum bool isSupportedSimpleType = true; 1533 } else static if (is(ti == long)) { 1534 enum bool isSupportedSimpleType = true; 1535 } else static if (is(ti == ubyte)) { 1536 enum bool isSupportedSimpleType = true; 1537 } else static if (is(ti == ushort)) { 1538 enum bool isSupportedSimpleType = true; 1539 } else static if (is(ti == uint)) { 1540 enum bool isSupportedSimpleType = true; 1541 } else static if (is(ti == ulong)) { 1542 enum bool isSupportedSimpleType = true; 1543 } else static if (is(ti == float)) { 1544 enum bool isSupportedSimpleType = true; 1545 } else static if (is(ti == double)) { 1546 enum bool isSupportedSimpleType = true; 1547 } else static if (is(ti == Nullable!byte)) { 1548 enum bool isSupportedSimpleType = true; 1549 } else static if (is(ti == Nullable!short)) { 1550 enum bool isSupportedSimpleType = true; 1551 } else static if (is(ti == Nullable!int)) { 1552 enum bool isSupportedSimpleType = true; 1553 } else static if (is(ti == Nullable!long)) { 1554 enum bool isSupportedSimpleType = true; 1555 } else static if (is(ti == Nullable!ubyte)) { 1556 enum bool isSupportedSimpleType = true; 1557 } else static if (is(ti == Nullable!ushort)) { 1558 enum bool isSupportedSimpleType = true; 1559 } else static if (is(ti == Nullable!uint)) { 1560 enum bool isSupportedSimpleType = true; 1561 } else static if (is(ti == Nullable!ulong)) { 1562 enum bool isSupportedSimpleType = true; 1563 } else static if (is(ti == Nullable!float)) { 1564 enum bool isSupportedSimpleType = true; 1565 } else static if (is(ti == Nullable!double)) { 1566 enum bool isSupportedSimpleType = true; 1567 } else static if (is(ti == string)) { 1568 enum bool isSupportedSimpleType = true; 1569 } else static if (is(ti == hibernated.type.String)) { 1570 enum bool isSupportedSimpleType = true; 1571 } else static if (is(ti == DateTime)) { 1572 enum bool isSupportedSimpleType = true; 1573 } else static if (is(ti == Date)) { 1574 enum bool isSupportedSimpleType = true; 1575 } else static if (is(ti == TimeOfDay)) { 1576 enum bool isSupportedSimpleType = true; 1577 } else static if (is(ti == Nullable!DateTime)) { 1578 enum bool isSupportedSimpleType = true; 1579 } else static if (is(ti == Nullable!Date)) { 1580 enum bool isSupportedSimpleType = true; 1581 } else static if (is(ti == Nullable!TimeOfDay)) { 1582 enum bool isSupportedSimpleType = true; 1583 } else static if (is(ti == byte[])) { 1584 enum bool isSupportedSimpleType = true; 1585 } else static if (is(ti == ubyte[])) { 1586 enum bool isSupportedSimpleType = true; 1587 } else { 1588 enum bool isSupportedSimpleType = false; 1589 } 1590 } 1591 1592 PropertyMemberType getPropertyMemberType(T, string m)() { 1593 alias ti = typeof(__traits(getMember, T, m)); 1594 1595 static if (is(ti == function)) { 1596 static if (is(ReturnType!(ti) == bool)) { 1597 return PropertyMemberType.BOOL_TYPE; 1598 } else static if (is(ReturnType!(ti) == byte)) { 1599 return PropertyMemberType.BYTE_TYPE; 1600 } else if (is(ReturnType!(ti) == short)) { 1601 return PropertyMemberType.SHORT_TYPE; 1602 } else if (is(ReturnType!(ti) == int)) { 1603 return PropertyMemberType.INT_TYPE; 1604 } else if (is(ReturnType!(ti) == long)) { 1605 return PropertyMemberType.LONG_TYPE; 1606 } else if (is(ReturnType!(ti) == ubyte)) { 1607 return PropertyMemberType.UBYTE_TYPE; 1608 } else if (is(ReturnType!(ti) == ushort)) { 1609 return PropertyMemberType.USHORT_TYPE; 1610 } else if (is(ReturnType!(ti) == uint)) { 1611 return PropertyMemberType.UINT_TYPE; 1612 } else if (is(ReturnType!(ti) == ulong)) { 1613 return PropertyMemberType.ULONG_TYPE; 1614 } else if (is(ReturnType!(ti) == float)) { 1615 return PropertyMemberType.FLOAT_TYPE; 1616 } else if (is(ReturnType!(ti) == double)) { 1617 return PropertyMemberType.DOUBLE_TYPE; 1618 } else if (is(ReturnType!(ti) == Nullable!byte)) { 1619 return PropertyMemberType.NULLABLE_BYTE_TYPE; 1620 } else if (is(ReturnType!(ti) == Nullable!short)) { 1621 return PropertyMemberType.NULLABLE_SHORT_TYPE; 1622 } else if (is(ReturnType!(ti) == Nullable!int)) { 1623 return PropertyMemberType.NULLABLE_INT_TYPE; 1624 } else if (is(ReturnType!(ti) == Nullable!long)) { 1625 return PropertyMemberType.NULLABLE_LONG_TYPE; 1626 } else if (is(ReturnType!(ti) == Nullable!ubyte)) { 1627 return PropertyMemberType.NULLABLE_UBYTE_TYPE; 1628 } else if (is(ReturnType!(ti) == Nullable!ushort)) { 1629 return PropertyMemberType.NULLABLE_USHORT_TYPE; 1630 } else if (is(ReturnType!(ti) == Nullable!uint)) { 1631 return PropertyMemberType.NULLABLE_UINT_TYPE; 1632 } else if (is(ReturnType!(ti) == Nullable!ulong)) { 1633 return PropertyMemberType.NULLABLE_ULONG_TYPE; 1634 } else if (is(ReturnType!(ti) == Nullable!float)) { 1635 return PropertyMemberType.NULLABLE_FLOAT_TYPE; 1636 } else if (is(ReturnType!(ti) == Nullable!double)) { 1637 return PropertyMemberType.NULLABLE_DOUBLE_TYPE; 1638 } else if (is(ReturnType!(ti) == string)) { 1639 return PropertyMemberType.STRING_TYPE; 1640 } else if (is(ReturnType!(ti) == hibernated.type.String)) { 1641 return PropertyMemberType.NULLABLE_STRING_TYPE; 1642 } else if (is(ReturnType!(ti) == DateTime)) { 1643 return PropertyMemberType.DATETIME_TYPE; 1644 } else if (is(ReturnType!(ti) == Date)) { 1645 return PropertyMemberType.DATE_TYPE; 1646 } else if (is(ReturnType!(ti) == TimeOfDay)) { 1647 return PropertyMemberType.TIME_TYPE; 1648 } else if (is(ReturnType!(ti) == Nullable!DateTime)) { 1649 return PropertyMemberType.NULLABLE_DATETIME_TYPE; 1650 } else if (is(ReturnType!(ti) == Nullable!Date)) { 1651 return PropertyMemberType.NULLABLE_DATE_TYPE; 1652 } else if (is(ReturnType!(ti) == Nullable!TimeOfDay)) { 1653 return PropertyMemberType.NULLABLE_TIME_TYPE; 1654 } else if (is(ReturnType!(ti) == byte[])) { 1655 return PropertyMemberType.BYTE_ARRAY_TYPE; 1656 } else if (is(ReturnType!(ti) == ubyte[])) { 1657 return PropertyMemberType.UBYTE_ARRAY_TYPE; 1658 } else { 1659 assert (false, "Member " ~ m ~ " of class " ~ T.stringof ~ " has unsupported type " ~ ti.stringof); 1660 } 1661 } else if (is(ti == bool)) { 1662 return PropertyMemberType.BOOL_TYPE; 1663 } else if (is(ti == byte)) { 1664 return PropertyMemberType.BYTE_TYPE; 1665 } else if (is(ti == short)) { 1666 return PropertyMemberType.SHORT_TYPE; 1667 } else if (is(ti == int)) { 1668 return PropertyMemberType.INT_TYPE; 1669 } else if (is(ti == long)) { 1670 return PropertyMemberType.LONG_TYPE; 1671 } else if (is(ti == ubyte)) { 1672 return PropertyMemberType.UBYTE_TYPE; 1673 } else if (is(ti == ushort)) { 1674 return PropertyMemberType.USHORT_TYPE; 1675 } else if (is(ti == uint)) { 1676 return PropertyMemberType.UINT_TYPE; 1677 } else if (is(ti == ulong)) { 1678 return PropertyMemberType.ULONG_TYPE; 1679 } else if (is(ti == float)) { 1680 return PropertyMemberType.FLOAT_TYPE; 1681 } else if (is(ti == double)) { 1682 return PropertyMemberType.DOUBLE_TYPE; 1683 } else if (is(ti == Nullable!byte)) { 1684 return PropertyMemberType.NULLABLE_BYTE_TYPE; 1685 } else if (is(ti == Nullable!short)) { 1686 return PropertyMemberType.NULLABLE_SHORT_TYPE; 1687 } else if (is(ti == Nullable!int)) { 1688 return PropertyMemberType.NULLABLE_INT_TYPE; 1689 } else if (is(ti == Nullable!long)) { 1690 return PropertyMemberType.NULLABLE_LONG_TYPE; 1691 } else if (is(ti == Nullable!ubyte)) { 1692 return PropertyMemberType.NULLABLE_UBYTE_TYPE; 1693 } else if (is(ti == Nullable!ushort)) { 1694 return PropertyMemberType.NULLABLE_USHORT_TYPE; 1695 } else if (is(ti == Nullable!uint)) { 1696 return PropertyMemberType.NULLABLE_UINT_TYPE; 1697 } else if (is(ti == Nullable!ulong)) { 1698 return PropertyMemberType.NULLABLE_ULONG_TYPE; 1699 } else if (is(ti == Nullable!float)) { 1700 return PropertyMemberType.NULLABLE_FLOAT_TYPE; 1701 } else if (is(ti == Nullable!double)) { 1702 return PropertyMemberType.NULLABLE_DOUBLE_TYPE; 1703 } else if (is(ti == string)) { 1704 return PropertyMemberType.STRING_TYPE; 1705 } else if (is(ti == hibernated.type.String)) { 1706 return PropertyMemberType.NULLABLE_STRING_TYPE; 1707 } else if (is(ti == DateTime)) { 1708 return PropertyMemberType.DATETIME_TYPE; 1709 } else if (is(ti == Date)) { 1710 return PropertyMemberType.DATE_TYPE; 1711 } else if (is(ti == TimeOfDay)) { 1712 return PropertyMemberType.TIME_TYPE; 1713 } else if (is(ti == Nullable!DateTime)) { 1714 return PropertyMemberType.NULLABLE_DATETIME_TYPE; 1715 } else if (is(ti == Nullable!Date)) { 1716 return PropertyMemberType.NULLABLE_DATE_TYPE; 1717 } else if (is(ti == Nullable!TimeOfDay)) { 1718 return PropertyMemberType.NULLABLE_TIME_TYPE; 1719 } else if (is(ti == byte[])) { 1720 return PropertyMemberType.BYTE_ARRAY_TYPE; 1721 } else if (is(ti == ubyte[])) { 1722 return PropertyMemberType.UBYTE_ARRAY_TYPE; 1723 } else { 1724 assert (false, "Member " ~ m ~ " of class " ~ T.stringof ~ " has unsupported type " ~ ti.stringof); 1725 } 1726 //static assert (false, "Member " ~ m ~ " of class " ~ T.stringof ~ " has unsupported type " ~ ti.stringof); 1727 } 1728 1729 1730 string getPropertyReadCode(T, string m)() { 1731 return substituteParam(PropertyMemberKind_ReadCode[getPropertyMemberKind!(T,m)()], m); 1732 } 1733 1734 static immutable bool[] ColumnTypeCanHoldNulls = 1735 [ 1736 false, //BOOL_TYPE // bool 1737 false, //BYTE_TYPE, // byte 1738 false, //SHORT_TYPE, // short 1739 false, //INT_TYPE, // int 1740 false, //LONG_TYPE, // long 1741 false, //UBYTE_TYPE, // ubyte 1742 false, //USHORT_TYPE, // ushort 1743 false, //UINT_TYPE, // uint 1744 false, //ULONG_TYPE, // ulong 1745 true, //NULLABLE_BYTE_TYPE, // Nullable!byte 1746 true, //NULLABLE_SHORT_TYPE, // Nullable!short 1747 true, //NULLABLE_INT_TYPE, // Nullable!int 1748 true, //NULLABLE_LONG_TYPE, // Nullable!long 1749 true, //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 1750 true, //NULLABLE_USHORT_TYPE,// Nullable!ushort 1751 true, //NULLABLE_UINT_TYPE, // Nullable!uint 1752 true, //NULLABLE_ULONG_TYPE, // Nullable!ulong 1753 false,//FLOAT_TYPE, // float 1754 false,//DOUBLE_TYPE, // double 1755 true, //NULLABLE_FLOAT_TYPE, // Nullable!float 1756 true, //NULLABLE_DOUBLE_TYPE,// Nullable!double 1757 false, //STRING_TYPE // string -- treat as @NotNull by default 1758 true, //NULLABLE_STRING_TYPE // String 1759 false, //DATETIME_TYPE, // std.datetime.DateTime 1760 false, //DATE_TYPE, // std.datetime.Date 1761 false, //TIME_TYPE, // std.datetime.TimeOfDay 1762 true, //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 1763 true, //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 1764 true, //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 1765 true, //BYTE_ARRAY_TYPE, // byte[] 1766 true, //UBYTE_ARRAY_TYPE, // ubyte[] 1767 ]; 1768 1769 bool isColumnTypeNullableByDefault(T, string m)() { 1770 return ColumnTypeCanHoldNulls[getPropertyMemberType!(T,m)]; 1771 } 1772 1773 1774 static immutable string[] ColumnTypeKeyIsSetCode = 1775 [ 1776 "(%s != 0)", //BOOL_TYPE // bool 1777 "(%s != 0)", //BYTE_TYPE, // byte 1778 "(%s != 0)", //SHORT_TYPE, // short 1779 "(%s != 0)", //INT_TYPE, // int 1780 "(%s != 0)", //LONG_TYPE, // long 1781 "(%s != 0)", //UBYTE_TYPE, // ubyte 1782 "(%s != 0)", //USHORT_TYPE, // ushort 1783 "(%s != 0)", //UINT_TYPE, // uint 1784 "(%s != 0)", //ULONG_TYPE, // ulong 1785 "(!%s.isNull)", //NULLABLE_BYTE_TYPE, // Nullable!byte 1786 "(!%s.isNull)", //NULLABLE_SHORT_TYPE, // Nullable!short 1787 "(!%s.isNull)", //NULLABLE_INT_TYPE, // Nullable!int 1788 "(!%s.isNull)", //NULLABLE_LONG_TYPE, // Nullable!long 1789 "(!%s.isNull)", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 1790 "(!%s.isNull)", //NULLABLE_USHORT_TYPE,// Nullable!ushort 1791 "(!%s.isNull)", //NULLABLE_UINT_TYPE, // Nullable!uint 1792 "(!%s.isNull)", //NULLABLE_ULONG_TYPE, // Nullable!ulong 1793 "(%s != 0)",//FLOAT_TYPE, // float 1794 "(%s != 0)",//DOUBLE_TYPE, // double 1795 "(!%s.isNull)", //NULLABLE_FLOAT_TYPE, // Nullable!float 1796 "(!%s.isNull)", //NULLABLE_DOUBLE_TYPE,// Nullable!double 1797 "(%s !is null)", //STRING_TYPE // string 1798 "(%s !is null)", //NULLABLE_STRING_TYPE // String 1799 "(%s != DateTime())", //DATETIME_TYPE, // std.datetime.DateTime 1800 "(%s != Date())", //DATE_TYPE, // std.datetime.Date 1801 "(%s != TimeOfDay())", //TIME_TYPE, // std.datetime.TimeOfDay 1802 "(!%s.isNull)", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 1803 "(!%s.isNull)", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 1804 "(!%s.isNull)", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 1805 "(%s !is null)", //BYTE_ARRAY_TYPE, // byte[] 1806 "(%s !is null)", //UBYTE_ARRAY_TYPE, // ubyte[] 1807 ]; 1808 1809 string getColumnTypeKeyIsSetCode(T, string m)() { 1810 return substituteParam(ColumnTypeKeyIsSetCode[getPropertyMemberType!(T,m)()], getPropertyReadCode!(T,m)()); 1811 } 1812 1813 static immutable string[] ColumnTypeIsNullCode = 1814 [ 1815 "(false)", //BOOL_TYPE // bool 1816 "(false)", //BYTE_TYPE, // byte 1817 "(false)", //SHORT_TYPE, // short 1818 "(false)", //INT_TYPE, // int 1819 "(false)", //LONG_TYPE, // long 1820 "(false)", //UBYTE_TYPE, // ubyte 1821 "(false)", //USHORT_TYPE, // ushort 1822 "(false)", //UINT_TYPE, // uint 1823 "(false)", //ULONG_TYPE, // ulong 1824 "(%s.isNull)", //NULLABLE_BYTE_TYPE, // Nullable!byte 1825 "(%s.isNull)", //NULLABLE_SHORT_TYPE, // Nullable!short 1826 "(%s.isNull)", //NULLABLE_INT_TYPE, // Nullable!int 1827 "(%s.isNull)", //NULLABLE_LONG_TYPE, // Nullable!long 1828 "(%s.isNull)", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 1829 "(%s.isNull)", //NULLABLE_USHORT_TYPE,// Nullable!ushort 1830 "(%s.isNull)", //NULLABLE_UINT_TYPE, // Nullable!uint 1831 "(%s.isNull)", //NULLABLE_ULONG_TYPE, // Nullable!ulong 1832 "(false)",//FLOAT_TYPE, // float 1833 "(false)",//DOUBLE_TYPE, // double 1834 "(%s.isNull)", //NULLABLE_FLOAT_TYPE, // Nullable!float 1835 "(%s.isNull)", //NULLABLE_DOUBLE_TYPE,// Nullable!double 1836 "(%s is null)", //STRING_TYPE // string 1837 "(%s is null)", //NULLABLE_STRING_TYPE // String 1838 "(false)", //DATETIME_TYPE, // std.datetime.DateTime 1839 "(false)", //DATE_TYPE, // std.datetime.Date 1840 "(false)", //TIME_TYPE, // std.datetime.TimeOfDay 1841 "(%s.isNull)", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 1842 "(%s.isNull)", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 1843 "(%s.isNull)", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 1844 "(%s is null)", //BYTE_ARRAY_TYPE, // byte[] 1845 "(%s is null)", //UBYTE_ARRAY_TYPE, // ubyte[] 1846 ]; 1847 1848 string getColumnTypeIsNullCode(T, string m)() { 1849 return substituteParam(ColumnTypeIsNullCode[getPropertyMemberType!(T,m)()], getPropertyReadCode!(T,m)()); 1850 } 1851 1852 static immutable string[] ColumnTypeSetNullCode = 1853 [ 1854 "bool nv;", // BOOL_TYPE // bool 1855 "byte nv = 0;", //BYTE_TYPE, // byte 1856 "short nv = 0;", //SHORT_TYPE, // short 1857 "int nv = 0;", //INT_TYPE, // int 1858 "long nv = 0;", //LONG_TYPE, // long 1859 "ubyte nv = 0;", //UBYTE_TYPE, // ubyte 1860 "ushort nv = 0;", //USHORT_TYPE, // ushort 1861 "uint nv = 0;", //UINT_TYPE, // uint 1862 "ulong nv = 0;", //ULONG_TYPE, // ulong 1863 "Nullable!byte nv;", //NULLABLE_BYTE_TYPE, // Nullable!byte 1864 "Nullable!short nv;", //NULLABLE_SHORT_TYPE, // Nullable!short 1865 "Nullable!int nv;", //NULLABLE_INT_TYPE, // Nullable!int 1866 "Nullable!long nv;", //NULLABLE_LONG_TYPE, // Nullable!long 1867 "Nullable!ubyte nv;", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 1868 "Nullable!ushort nv;", //NULLABLE_USHORT_TYPE,// Nullable!ushort 1869 "Nullable!uint nv;", //NULLABLE_UINT_TYPE, // Nullable!uint 1870 "Nullable!ulong nv;", //NULLABLE_ULONG_TYPE, // Nullable!ulong 1871 "float nv = 0;",//FLOAT_TYPE, // float 1872 "double nv = 0;",//DOUBLE_TYPE, // double 1873 "Nullable!float nv;", //NULLABLE_FLOAT_TYPE, // Nullable!float 1874 "Nullable!double nv;", //NULLABLE_DOUBLE_TYPE,// Nullable!double 1875 "string nv;", //STRING_TYPE // string 1876 "string nv;", //NULLABLE_STRING_TYPE // String 1877 "DateTime nv;", //DATETIME_TYPE, // std.datetime.DateTime 1878 "Date nv;", //DATE_TYPE, // std.datetime.Date 1879 "TimeOfDay nv;", //TIME_TYPE, // std.datetime.TimeOfDay 1880 "Nullable!DateTime nv;", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 1881 "Nullable!Date nv;", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 1882 "Nullable!TimeOfDay nv;", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 1883 "byte[] nv = null;", //BYTE_ARRAY_TYPE, // byte[] 1884 "ubyte[] nv = null;", //UBYTE_ARRAY_TYPE, // ubyte[] 1885 ]; 1886 1887 /* 1888 * Due to to change in dmd [issue #72] "Implicit conversion with alias Nullable.get this will be removed after 2.096", nullable types (except string) have to make call to .get 1889 */ 1890 static immutable string[] ColumnTypePropertyToVariant = 1891 [ 1892 "Variant(%s)", //BOOL_TYPE // bool 1893 "Variant(%s)", //BYTE_TYPE, // byte 1894 "Variant(%s)", //SHORT_TYPE, // short 1895 "Variant(%s)", //INT_TYPE, // int 1896 "Variant(%s)", //LONG_TYPE, // long 1897 "Variant(%s)", //UBYTE_TYPE, // ubyte 1898 "Variant(%s)", //USHORT_TYPE, // ushort 1899 "Variant(%s)", //UINT_TYPE, // uint 1900 "Variant(%s)", //ULONG_TYPE, // ulong 1901 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_BYTE_TYPE, // Nullable!byte 1902 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_SHORT_TYPE, // Nullable!short 1903 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_INT_TYPE, // Nullable!int 1904 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_LONG_TYPE, // Nullable!long 1905 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 1906 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_USHORT_TYPE,// Nullable!ushort 1907 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_UINT_TYPE, // Nullable!uint 1908 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_ULONG_TYPE, // Nullable!ulong 1909 "Variant(%s)",//FLOAT_TYPE, // float 1910 "Variant(%s)",//DOUBLE_TYPE, // double 1911 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_FLOAT_TYPE, // Nullable!float 1912 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_DOUBLE_TYPE,// Nullable!double 1913 "Variant(%s)", //STRING_TYPE // string 1914 "Variant(%s)", //NULLABLE_STRING_TYPE // String 1915 "Variant(%s)", //DATETIME_TYPE, // std.datetime.DateTime 1916 "Variant(%s)", //DATE_TYPE, // std.datetime.Date 1917 "Variant(%s)", //TIME_TYPE, // std.datetime.TimeOfDay 1918 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 1919 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 1920 "(%s.isNull ? Variant(null) : Variant(%s.get))", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 1921 "Variant(%s)", //BYTE_ARRAY_TYPE, // byte[] 1922 "Variant(%s)", //UBYTE_ARRAY_TYPE, // ubyte[] 1923 ]; 1924 1925 string getPropertyWriteCode(T, string m)() { 1926 immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 1927 immutable string nullValueCode = ColumnTypeSetNullCode[getPropertyMemberType!(T,m)()]; 1928 immutable string datasetReader = "(!r.isNull(index) ? " ~ getColumnTypeDatasetReadCode!(T, m)() ~ " : nv)"; 1929 1930 final switch (kind) { 1931 case PropertyMemberKind.FIELD_MEMBER: 1932 return nullValueCode ~ "entity." ~ m ~ " = " ~ datasetReader ~ ";"; 1933 case PropertyMemberKind.LAZY_MEMBER: 1934 return nullValueCode ~ "entity." ~ m ~ " = " ~ datasetReader ~ ";"; 1935 case PropertyMemberKind.GETTER_MEMBER: 1936 return nullValueCode ~ "entity." ~ getterNameToSetterName(m) ~ "(" ~ datasetReader ~ ");"; 1937 case PropertyMemberKind.PROPERTY_MEMBER: 1938 return nullValueCode ~ "entity." ~ m ~ " = " ~ datasetReader ~ ";"; 1939 case PropertyMemberKind.UNSUPPORTED_MEMBER: 1940 assert(false, "Unsupported member kind " ~ T.stringof ~ "." ~ m ~ " " ~ typeof(__traits(getMember, T, m)).stringof); 1941 } 1942 } 1943 1944 string getPropertyCopyCode(T, string m)() { 1945 immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 1946 1947 final switch (kind) { 1948 case PropertyMemberKind.FIELD_MEMBER: 1949 return "toentity." ~ m ~ " = fromentity." ~ m ~ ";"; 1950 case PropertyMemberKind.LAZY_MEMBER: 1951 return "toentity." ~ m ~ " = fromentity." ~ m ~ "();"; 1952 case PropertyMemberKind.GETTER_MEMBER: 1953 return "toentity." ~ getterNameToSetterName(m) ~ "(fromentity." ~ m ~ "());"; 1954 case PropertyMemberKind.PROPERTY_MEMBER: 1955 return "toentity." ~ m ~ " = fromentity." ~ m ~ ";"; 1956 case PropertyMemberKind.UNSUPPORTED_MEMBER: 1957 assert(false, "Unsupported member kind " ~ T.stringof ~ "." ~ m); 1958 } 1959 } 1960 1961 string getPropertyVariantWriteCode(T, string m)() { 1962 immutable memberType = getPropertyMemberType!(T,m)(); 1963 immutable string nullValueCode = ColumnTypeSetNullCode[memberType]; 1964 immutable string variantReadCode = ColumnTypeVariantReadCode[memberType]; 1965 1966 static if (getPropertyMemberKind!(T, m)() == PropertyMemberKind.GETTER_MEMBER) { 1967 return nullValueCode ~ "entity." ~ getterNameToSetterName(m) ~ "(" ~ variantReadCode ~ ");"; 1968 } else { 1969 return nullValueCode ~ "entity." ~ m ~ " = " ~ variantReadCode ~ ";"; 1970 } 1971 } 1972 1973 string getPropertyVariantReadCode(T, string m)() { 1974 immutable memberType = getPropertyMemberType!(T,m)(); 1975 immutable string propertyReadCode = getPropertyReadCode!(T,m)(); 1976 return substituteParamTwice(ColumnTypePropertyToVariant[memberType], propertyReadCode); 1977 } 1978 1979 1980 static immutable string[] ColumnTypeConstructorCode = 1981 [ 1982 "new BooleanType()", // BOOL_TYPE, bool 1983 "new NumberType(2, false, SqlType.TINYINT)", //BYTE_TYPE, // byte 1984 "new NumberType(4, false, SqlType.SMALLINT)", //SHORT_TYPE, // short 1985 "new NumberType(9, false, SqlType.INTEGER)", //INT_TYPE, // int 1986 "new NumberType(20, false, SqlType.BIGINT)", //LONG_TYPE, // long 1987 "new NumberType(2, true, SqlType.TINYINT)", //UBYTE_TYPE, // ubyte 1988 "new NumberType(4, true, SqlType.SMALLINT)", //USHORT_TYPE, // ushort 1989 "new NumberType(9, true, SqlType.INTEGER)", //UINT_TYPE, // uint 1990 "new NumberType(20, true, SqlType.BIGINT)", //ULONG_TYPE, // ulong 1991 "new NumberType(2, false, SqlType.TINYINT)", //NULLABLE_BYTE_TYPE, // Nullable!byte 1992 "new NumberType(4, false, SqlType.SMALLINT)", //NULLABLE_SHORT_TYPE, // Nullable!short 1993 "new NumberType(9, false, SqlType.INTEGER)", //NULLABLE_INT_TYPE, // Nullable!int 1994 "new NumberType(20, false, SqlType.BIGINT)", //NULLABLE_LONG_TYPE, // Nullable!long 1995 "new NumberType(2, true, SqlType.TINYINT)", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 1996 "new NumberType(4, true, SqlType.SMALLINT)", //NULLABLE_USHORT_TYPE,// Nullable!ushort 1997 "new NumberType(9, true, SqlType.INTEGER)", //NULLABLE_UINT_TYPE, // Nullable!uint 1998 "new NumberType(20, true, SqlType.BIGINT)", //NULLABLE_ULONG_TYPE, // Nullable!ulong 1999 "new NumberType(7, false, SqlType.FLOAT)",//FLOAT_TYPE, // float 2000 "new NumberType(14, false, SqlType.DOUBLE)",//DOUBLE_TYPE, // double 2001 "new NumberType(7, false, SqlType.FLOAT)", //NULLABLE_FLOAT_TYPE, // Nullable!float 2002 "new NumberType(14, false, SqlType.DOUBLE)", //NULLABLE_DOUBLE_TYPE,// Nullable!double 2003 "new StringType()", //STRING_TYPE // string 2004 "new StringType()", //NULLABLE_STRING_TYPE // String 2005 "new DateTimeType()", //DATETIME_TYPE, // std.datetime.DateTime 2006 "new DateType()", //DATE_TYPE, // std.datetime.Date 2007 "new TimeType()", //TIME_TYPE, // std.datetime.TimeOfDay 2008 "new DateTimeType()", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 2009 "new DateType()", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 2010 "new TimeType()", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 2011 "new ByteArrayBlobType()", //BYTE_ARRAY_TYPE, // byte[] 2012 "new UbyteArrayBlobType()", //UBYTE_ARRAY_TYPE, // ubyte[] 2013 ]; 2014 2015 string getColumnTypeName(T, string m, int length)() { 2016 immutable PropertyMemberType mt = getPropertyMemberType!(T,m); 2017 static if (mt == PropertyMemberType.STRING_TYPE || mt == PropertyMemberType.NULLABLE_STRING_TYPE) { 2018 return "new StringType(" ~ to!string(length) ~ ")"; 2019 } else { 2020 return ColumnTypeConstructorCode[mt]; 2021 } 2022 } 2023 2024 static immutable string[] ColumnTypeDatasetReaderCode = 2025 [ 2026 "r.getBoolean(index)", //BOOL_TYPE, // bool 2027 "r.getByte(index)", //BYTE_TYPE, // byte 2028 "r.getShort(index)", //SHORT_TYPE, // short 2029 "r.getInt(index)", //INT_TYPE, // int 2030 "r.getLong(index)", //LONG_TYPE, // long 2031 "r.getUbyte(index)", //UBYTE_TYPE, // ubyte 2032 "r.getUshort(index)", //USHORT_TYPE, // ushort 2033 "r.getUint(index)", //UINT_TYPE, // uint 2034 "r.getUlong(index)", //ULONG_TYPE, // ulong 2035 "Nullable!byte(r.getByte(index))", //NULLABLE_BYTE_TYPE, // Nullable!byte 2036 "Nullable!short(r.getShort(index))", //NULLABLE_SHORT_TYPE, // Nullable!short 2037 "Nullable!int(r.getInt(index))", //NULLABLE_INT_TYPE, // Nullable!int 2038 "Nullable!long(r.getLong(index))", //NULLABLE_LONG_TYPE, // Nullable!long 2039 "Nullable!ubyte(r.getUbyte(index))", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 2040 "Nullable!ushort(r.getUshort(index))", //NULLABLE_USHORT_TYPE,// Nullable!ushort 2041 "Nullable!uint(r.getUint(index))", //NULLABLE_UINT_TYPE, // Nullable!uint 2042 "Nullable!ulong(r.getUlong(index))", //NULLABLE_ULONG_TYPE, // Nullable!ulong 2043 "r.getFloat(index)",//FLOAT_TYPE, // float 2044 "r.getDouble(index)",//DOUBLE_TYPE, // double 2045 "Nullable!float(r.getFloat(index))", //NULLABLE_FLOAT_TYPE, // Nullable!float 2046 "Nullable!double(r.getDouble(index))", //NULLABLE_DOUBLE_TYPE,// Nullable!double 2047 "r.getString(index)", //STRING_TYPE // string 2048 "r.getString(index)", //NULLABLE_STRING_TYPE // String 2049 "r.getDateTime(index)", //DATETIME_TYPE, // std.datetime.DateTime 2050 "r.getDate(index)", //DATE_TYPE, // std.datetime.Date 2051 "r.getTime(index)", //TIME_TYPE, // std.datetime.TimeOfDay 2052 "Nullable!DateTime(r.getDateTime(index))", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 2053 "Nullable!Date(r.getDate(index))", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 2054 "Nullable!TimeOfDay(r.getTime(index))", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 2055 "r.getBytes(index)", //BYTE_ARRAY_TYPE, // byte[] 2056 "r.getUbytes(index)", //UBYTE_ARRAY_TYPE, // ubyte[] 2057 ]; 2058 2059 string getColumnTypeDatasetReadCode(T, string m)() { 2060 return ColumnTypeDatasetReaderCode[getPropertyMemberType!(T,m)()]; 2061 } 2062 2063 /* 2064 * Due to to change in dmd [issue #72] "Implicit conversion with alias Nullable.get this will be removed after 2.096", nullable types (except string) have to make call to .get 2065 */ 2066 static immutable string[] ColumnTypeVariantReadCode = 2067 [ 2068 "(value == null ? nv : value.get!(bool))", //BOOL_TYPE, // bool 2069 "(value == null ? nv : (value.convertsTo!(byte) ? value.get!(byte) : (value.convertsTo!(long) ? to!byte(value.get!(long)) : to!byte((value.get!(ulong))))))", //BYTE_TYPE, // byte 2070 "(value == null ? nv : (value.convertsTo!(short) ? value.get!(short) : (value.convertsTo!(long) ? to!short(value.get!(long)) : to!short((value.get!(ulong))))))", //SHORT_TYPE, // short 2071 "(value == null ? nv : (value.convertsTo!(int) ? value.get!(int) : (value.convertsTo!(long) ? to!int(value.get!(long)) : to!int((value.get!(ulong))))))", //INT_TYPE, // int 2072 "(value == null ? nv : (value.convertsTo!(long) ? value.get!(long) : to!long(value.get!(ulong))))", //LONG_TYPE, // long 2073 "(value == null ? nv : (value.convertsTo!(ubyte) ? value.get!(ubyte) : (value.convertsTo!(ulong) ? to!ubyte(value.get!(ulong)) : to!ubyte((value.get!(long))))))", //UBYTE_TYPE, // ubyte 2074 "(value == null ? nv : (value.convertsTo!(ushort) ? value.get!(ushort) : (value.convertsTo!(ulong) ? to!ushort(value.get!(ulong)) : to!ushort((value.get!(long))))))", //USHORT_TYPE, // ushort 2075 "(value == null ? nv : (value.convertsTo!(uint) ? value.get!(uint) : (value.convertsTo!(ulong) ? to!uint(value.get!(ulong)) : to!uint((value.get!(long))))))", //UINT_TYPE, // uint 2076 "(value == null ? nv : (value.convertsTo!(ulong) ? value.get!(ulong) : to!ulong(value.get!(long))))", //ULONG_TYPE, // ulong 2077 "(value == null ? nv.get : (value.convertsTo!(byte) ? value.get!(byte) : (value.convertsTo!(long) ? to!byte(value.get!(long)) : to!byte((value.get!(ulong))))))", //NULLABLE_BYTE_TYPE, // Nullable!byte 2078 "(value == null ? nv.get : (value.convertsTo!(short) ? value.get!(short) : (value.convertsTo!(long) ? to!short(value.get!(long)) : to!short((value.get!(ulong))))))", //NULLABLE_SHORT_TYPE, // Nullable!short 2079 "(value == null ? nv.get : (value.convertsTo!(int) ? value.get!(int) : (value.convertsTo!(long) ? to!int(value.get!(long)) : to!int((value.get!(ulong))))))", //NULLABLE_INT_TYPE, // Nullable!int 2080 "(value == null ? nv.get : (value.convertsTo!(long) ? value.get!(long) : to!long(value.get!(ulong))))", //NULLABLE_LONG_TYPE, // Nullable!long 2081 "(value == null ? nv.get : (value.convertsTo!(ubyte) ? value.get!(ubyte) : (value.convertsTo!(ulong) ? to!ubyte(value.get!(ulong)) : to!ubyte((value.get!(long))))))", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 2082 "(value == null ? nv.get : (value.convertsTo!(ushort) ? value.get!(ushort) : (value.convertsTo!(ulong) ? to!ushort(value.get!(ulong)) : to!ushort((value.get!(long))))))", //NULLABLE_USHORT_TYPE,// Nullable!ushort 2083 "(value == null ? nv.get : (value.convertsTo!(uint) ? value.get!(uint) : (value.convertsTo!(ulong) ? to!uint(value.get!(ulong)) : to!uint((value.get!(long))))))", //NULLABLE_UINT_TYPE, // Nullable!uint 2084 "(value == null ? nv.get : (value.convertsTo!(ulong) ? value.get!(ulong) : to!ulong(value.get!(long))))", //NULLABLE_ULONG_TYPE, // Nullable!ulong 2085 "(value == null ? nv : (value.convertsTo!(float) ? value.get!(float) : to!float(value.get!(double))))",//FLOAT_TYPE, // float 2086 "(value == null ? nv : (value.convertsTo!(double) ? value.get!(double) : to!double(value.get!(double))))",//DOUBLE_TYPE, // double 2087 "(value == null ? nv.get : (value.convertsTo!(float) ? value.get!(float) : to!float(value.get!(double))))", //NULLABLE_FLOAT_TYPE, // Nullable!float 2088 "(value == null ? nv.get : (value.convertsTo!(double) ? value.get!(double) : to!double(value.get!(double))))", //NULLABLE_DOUBLE_TYPE,// Nullable!double 2089 "(value == null ? nv : value.get!(string))", //STRING_TYPE // string 2090 "(value == null ? nv : value.get!(string))", //NULLABLE_STRING_TYPE // String 2091 "(value == null ? nv : value.get!(DateTime))", //DATETIME_TYPE, // std.datetime.DateTime 2092 "(value == null ? nv : value.get!(Date))", //DATE_TYPE, // std.datetime.Date 2093 "(value == null ? nv : value.get!(TimeOfDay))", //TIME_TYPE, // std.datetime.TimeOfDay 2094 "(value == null ? nv.get : value.get!(DateTime))", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 2095 "(value == null ? nv.get : value.get!(Date))", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 2096 "(value == null ? nv.get : value.get!(TimeOfDay))", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 2097 "(value == null ? nv : value.get!(byte[]))", //BYTE_ARRAY_TYPE, // byte[] 2098 "(value == null ? nv : value.get!(ubyte[]))", //UBYTE_ARRAY_TYPE, // ubyte[] 2099 ]; 2100 2101 /* 2102 * Due to to change in dmd [issue #72] "Implicit conversion with alias Nullable.get this will be removed after 2.096", nullable types (except string) have to make call to .get 2103 */ 2104 static immutable string[] DatasetWriteCode = 2105 [ 2106 "r.setBoolean(index, %s);", //BOOL_TYPE, // bool 2107 "r.setByte(index, %s);", //BYTE_TYPE, // byte 2108 "r.setShort(index, %s);", //SHORT_TYPE, // short 2109 "r.setInt(index, %s);", //INT_TYPE, // int 2110 "r.setLong(index, %s);", //LONG_TYPE, // long 2111 "r.setUbyte(index, %s);", //UBYTE_TYPE, // ubyte 2112 "r.setUshort(index, %s);", //USHORT_TYPE, // ushort 2113 "r.setUint(index, %s);", //UINT_TYPE, // uint 2114 "r.setUlong(index, %s);", //ULONG_TYPE, // ulong 2115 "r.setByte(index, %s.get);", //NULLABLE_BYTE_TYPE, // Nullable!byte 2116 "r.setShort(index, %s.get);", //NULLABLE_SHORT_TYPE, // Nullable!short 2117 "r.setInt(index, %s.get);", //NULLABLE_INT_TYPE, // Nullable!int 2118 "r.setLong(index, %s.get);", //NULLABLE_LONG_TYPE, // Nullable!long 2119 "r.setUbyte(index, %s.get);", //NULLABLE_UBYTE_TYPE, // Nullable!ubyte 2120 "r.setUshort(index, %s.get);", //NULLABLE_USHORT_TYPE,// Nullable!ushort 2121 "r.setUint(index, %s.get);", //NULLABLE_UINT_TYPE, // Nullable!uint 2122 "r.setUlong(index, %s.get);", //NULLABLE_ULONG_TYPE, // Nullable!ulong 2123 "r.setFloat(index, %s);",//FLOAT_TYPE, // float 2124 "r.setDouble(index, %s);",//DOUBLE_TYPE, // double 2125 "r.setFloat(index, %s.get);", //NULLABLE_FLOAT_TYPE, // Nullable!float 2126 "r.setDouble(index, %s.get);", //NULLABLE_DOUBLE_TYPE,// Nullable!double 2127 "r.setString(index, %s);", //STRING_TYPE // string 2128 "r.setString(index, %s);", //NULLABLE_STRING_TYPE // String (don't need to call .get on this one as string is already nullable) 2129 "r.setDateTime(index, %s);", //DATETIME_TYPE, // std.datetime.DateTime 2130 "r.setDate(index, %s);", //DATE_TYPE, // std.datetime.Date 2131 "r.setTime(index, %s);", //TIME_TYPE, // std.datetime.TimeOfDay 2132 "r.setDateTime(index, %s.get);", //NULLABLE_DATETIME_TYPE, // Nullable!std.datetime.DateTime 2133 "r.setDate(index, %s.get);", //NULLABLE_DATE_TYPE, // Nullable!std.datetime.Date 2134 "r.setTime(index, %s.get);", //NULLABLE_TIME_TYPE, // Nullable!std.datetime.TimeOfDay 2135 "r.setBytes(index, %s);", //BYTE_ARRAY_TYPE, // byte[] 2136 "r.setUbytes(index, %s);", //UBYTE_ARRAY_TYPE, // ubyte[] 2137 ]; 2138 2139 string getColumnTypeDatasetWriteCode(T, string m)() { 2140 alias ti = typeof(__traits(getMember, T, m)); 2141 2142 immutable string isNullCode = getColumnTypeIsNullCode!(T,m)(); 2143 immutable string readCode = getPropertyReadCode!(T,m)(); 2144 immutable string setDataCode = DatasetWriteCode[getPropertyMemberType!(T,m)()]; 2145 return "if (" ~ isNullCode ~ ") r.setNull(index); else " ~ substituteParam(setDataCode, readCode); 2146 } 2147 2148 string getEmbeddedPropertyVariantWriteCode(T, string m, string className)() { 2149 immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 2150 final switch (kind) { 2151 case PropertyMemberKind.FIELD_MEMBER: 2152 return "entity." ~ m ~ " = (value == null ? null : value.get!(" ~ className ~ "));"; 2153 case PropertyMemberKind.GETTER_MEMBER: 2154 return "entity." ~ getterNameToSetterName(m) ~ "(value == null ? null : value.get!(" ~ className ~ "));"; 2155 case PropertyMemberKind.LAZY_MEMBER: 2156 return "entity." ~ m ~ " = (value == null ? null : value.get!(" ~ className ~ "));"; 2157 case PropertyMemberKind.PROPERTY_MEMBER: 2158 return "entity." ~ m ~ " = (value == null ? null : value.get!(" ~ className ~ "));"; 2159 case PropertyMemberKind.UNSUPPORTED_MEMBER: 2160 assert(false, "Unsupported member kind " ~ T.stringof ~ "." ~ m); 2161 } 2162 } 2163 2164 string getCollectionPropertyVariantWriteCode(T, string m, string className)() { 2165 immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 2166 final switch (kind) { 2167 case PropertyMemberKind.FIELD_MEMBER: 2168 return "entity." ~ m ~ " = (value == null ? null : value.get!(" ~ className ~ "[]));"; 2169 case PropertyMemberKind.GETTER_MEMBER: 2170 return "entity." ~ getterNameToSetterName(m) ~ "(value == null ? null : value.get!(" ~ className ~ "[]));"; 2171 case PropertyMemberKind.LAZY_MEMBER: 2172 return "entity." ~ m ~ " = (value == null ? null : value.get!(" ~ className ~ "[]));"; 2173 case PropertyMemberKind.PROPERTY_MEMBER: 2174 return "entity." ~ m ~ " = (value == null ? null : value.get!(" ~ className ~ "[]));"; 2175 case PropertyMemberKind.UNSUPPORTED_MEMBER: 2176 assert(false, "Unsupported member kind " ~ T.stringof ~ "." ~ m); 2177 } 2178 } 2179 2180 string getPropertyObjectWriteCode(T, string m, string className)() { 2181 immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 2182 final switch (kind) { 2183 case PropertyMemberKind.FIELD_MEMBER: 2184 return "entity." ~ m ~ " = cast(" ~ className ~ ")value;"; 2185 case PropertyMemberKind.GETTER_MEMBER: 2186 return "entity." ~ getterNameToSetterName(m) ~ "(cast(" ~ className ~ ")value);"; 2187 case PropertyMemberKind.PROPERTY_MEMBER: 2188 return "entity." ~ m ~ " = cast(" ~ className ~ ")value;"; 2189 case PropertyMemberKind.LAZY_MEMBER: 2190 return "entity." ~ m ~ " = cast(" ~ className ~ ")value;"; 2191 case PropertyMemberKind.UNSUPPORTED_MEMBER: 2192 assert(false, "Unsupported member kind " ~ T.stringof ~ "." ~ m); 2193 } 2194 } 2195 2196 string getPropertyCollectionWriteCode(T, string m, string className)() { 2197 immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 2198 final switch (kind) { 2199 case PropertyMemberKind.FIELD_MEMBER: 2200 return "entity." ~ m ~ " = cast(" ~ className ~ "[])value;"; 2201 case PropertyMemberKind.GETTER_MEMBER: 2202 return "entity." ~ getterNameToSetterName(m) ~ "(cast(" ~ className ~ "[])value);"; 2203 case PropertyMemberKind.PROPERTY_MEMBER: 2204 return "entity." ~ m ~ " = cast(" ~ className ~ "[])value;"; 2205 case PropertyMemberKind.LAZY_MEMBER: 2206 return "entity." ~ m ~ " = cast(" ~ className ~ "[])value;"; 2207 case PropertyMemberKind.UNSUPPORTED_MEMBER: 2208 assert(false, "Unsupported member kind " ~ T.stringof ~ "." ~ m); 2209 } 2210 } 2211 2212 string getLazyPropertyObjectWriteCode(T, string m)() { 2213 immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 2214 final switch (kind) { 2215 case PropertyMemberKind.FIELD_MEMBER: 2216 return "entity." ~ m ~ " = loader;"; 2217 case PropertyMemberKind.GETTER_MEMBER: 2218 return "entity." ~ getterNameToSetterName(m) ~ "(loader);"; 2219 case PropertyMemberKind.PROPERTY_MEMBER: 2220 return "entity." ~ m ~ " = loader;"; 2221 case PropertyMemberKind.LAZY_MEMBER: 2222 return "entity." ~ m ~ " = loader;"; 2223 case PropertyMemberKind.UNSUPPORTED_MEMBER: 2224 assert(false, "Unsupported member kind " ~ T.stringof ~ "." ~ m); 2225 } 2226 } 2227 2228 string getLazyPropertyLoadedCode(T, string m)() { 2229 immutable PropertyMemberKind kind = getPropertyMemberKind!(T, m)(); 2230 final switch (kind) { 2231 case PropertyMemberKind.FIELD_MEMBER: 2232 return "entity." ~ m ~ ".loaded"; 2233 case PropertyMemberKind.GETTER_MEMBER: 2234 return "entity." ~ m ~ "().loaded"; 2235 case PropertyMemberKind.PROPERTY_MEMBER: 2236 return "entity." ~ m ~ ".loaded"; 2237 case PropertyMemberKind.LAZY_MEMBER: 2238 return "entity." ~ m ~ ".loaded"; 2239 case PropertyMemberKind.UNSUPPORTED_MEMBER: 2240 assert(false, "Unsupported member kind " ~ T.stringof ~ "." ~ m); 2241 } 2242 } 2243 2244 2245 // TODO: minimize duplication of code in getXXXtoXXXPropertyDef 2246 2247 /// generate source code for creation of OneToOne definition 2248 string getOneToOnePropertyDef(T, immutable string m)() { 2249 immutable string referencedEntityName = getPropertyReferencedEntityName!(T,m); 2250 immutable string referencedClassName = getPropertyReferencedClassName!(T,m); 2251 immutable string referencedPropertyName = getOneToOneReferencedPropertyName!(T,m); 2252 immutable string entityClassName = fullyQualifiedName!T; 2253 immutable string propertyName = getPropertyName!(T,m); 2254 static assert (propertyName != null, "Cannot determine property name for member " ~ m ~ " of type " ~ T.stringof); 2255 static assert (!hasOneOfMemberAnnotations!(T, m, Column, Id, Generated, Generator, ManyToOne, ManyToMany), entityClassName ~ "." ~ propertyName ~ ": OneToOne property cannot have Column, Id, Generated, Generator, ManyToOne, ManyToMany annotation"); 2256 immutable bool isLazy = isLazyMember!(T,m); 2257 immutable string columnName = getJoinColumnName!(T, m); 2258 immutable length = getColumnLength!(T, m)(); 2259 immutable bool hasNull = hasMemberAnnotation!(T,m, Null); 2260 immutable bool hasNotNull = hasMemberAnnotation!(T,m, NotNull); 2261 immutable bool nullable = hasNull ? true : (hasNotNull ? false : true); //canColumnTypeHoldNulls!(T.m) 2262 immutable string unique = quoteString(getUniqueIndexName!(T, m)); 2263 immutable string typeName = "new EntityType(cast(immutable TypeInfo_Class)" ~ entityClassName ~ ".classinfo, \"" ~ entityClassName ~ "\")"; //getColumnTypeName!(T, m)(); 2264 immutable string propertyReadCode = getPropertyReadCode!(T,m); 2265 immutable string datasetReadCode = null; //getColumnTypeDatasetReadCode!(T,m)(); 2266 immutable string propertyWriteCode = null; //getPropertyWriteCode!(T,m)(); 2267 immutable string datasetWriteCode = null; //getColumnTypeDatasetWriteCode!(T,m)(); 2268 immutable string propertyVariantSetCode = getEmbeddedPropertyVariantWriteCode!(T, m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2269 immutable string propertyVariantGetCode = "Variant(" ~ propertyReadCode ~ " is null ? null : " ~ propertyReadCode ~ ")"; //getPropertyVariantReadCode!(T,m)(); 2270 immutable string propertyObjectSetCode = getPropertyObjectWriteCode!(T,m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2271 immutable string propertyObjectGetCode = propertyReadCode; //getPropertyVariantReadCode!(T,m)(); 2272 immutable string keyIsSetCode = null; //getColumnTypeKeyIsSetCode!(T,m)(); 2273 immutable string isNullCode = propertyReadCode ~ " is null"; 2274 immutable string copyFieldCode = getPropertyCopyCode!(T,m); 2275 // pragma(msg, "property read: " ~ propertyReadCode); 2276 // pragma(msg, "property write: " ~ propertyWriteCode); 2277 // pragma(msg, "variant get: " ~ propertyVariantGetCode); 2278 immutable string readerFuncDef = "null"; 2279 immutable string writerFuncDef = "null"; 2280 immutable string getVariantFuncDef = 2281 "\n" ~ 2282 "function(Object obj) { \n" ~ 2283 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2284 " return " ~ propertyVariantGetCode ~ "; \n" ~ 2285 " }\n"; 2286 immutable string setVariantFuncDef = 2287 "\n" ~ 2288 "function(Object obj, Variant value) { \n" ~ 2289 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2290 " " ~ propertyVariantSetCode ~ "\n" ~ 2291 " }\n"; 2292 immutable string keyIsSetFuncDef = "\n" ~ 2293 "function(Object obj) { \n" ~ 2294 " return false;\n" ~ 2295 " }\n"; 2296 immutable string isNullFuncDef = "\n" ~ 2297 "function(Object obj) { \n" ~ 2298 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2299 " return " ~ isNullCode ~ ";\n" ~ 2300 " }\n"; 2301 immutable string getObjectFuncDef = 2302 "\n" ~ 2303 "function(Object obj) { \n" ~ 2304 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2305 " assert(entity !is null);\n" ~ 2306 " return " ~ propertyObjectGetCode ~ "; \n" ~ 2307 " }\n"; 2308 immutable string setObjectFuncDef = 2309 "\n" ~ 2310 "function(Object obj, Object value) { \n" ~ 2311 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2312 " " ~ propertyObjectSetCode ~ "\n" ~ 2313 " }\n"; 2314 immutable string copyFuncDef = 2315 "\n" ~ 2316 "function(Object to, Object from) { \n" ~ 2317 " " ~ entityClassName ~ " toentity = cast(" ~ entityClassName ~ ")to; \n" ~ 2318 " " ~ entityClassName ~ " fromentity = cast(" ~ entityClassName ~ ")from; \n" ~ 2319 " " ~ copyFieldCode ~ "\n" ~ 2320 " }\n"; 2321 immutable string getCollectionFuncDef = "null"; 2322 immutable string setCollectionFuncDef = "null"; 2323 immutable string setObjectDelegateFuncDef = !isLazy ? "null" : 2324 "\n" ~ 2325 "function(Object obj, Object delegate() loader) { \n" ~ 2326 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2327 " " ~ getLazyPropertyObjectWriteCode!(T,m) ~ "\n" ~ 2328 " }\n"; 2329 immutable string setCollectionDelegateFuncDef = "null"; 2330 immutable string isLoadedFuncDef = !isLazy ? "null" : 2331 "\n" ~ 2332 "function(Object obj) { \n" ~ 2333 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2334 " return " ~ getLazyPropertyLoadedCode!(T,m) ~ ";\n" ~ 2335 " }\n"; 2336 2337 return " new PropertyInfo(" ~ 2338 quoteString(propertyName) ~ ", " ~ 2339 quoteString(columnName) ~ ", " ~ 2340 typeName ~ ", " ~ 2341 format("%s",length) ~ ", " ~ 2342 "false, " ~ // id 2343 "false, " ~ // generated 2344 quoteBool(nullable) ~ ", " ~ 2345 unique ~ ", " ~ 2346 "RelationType.OneToOne, " ~ 2347 quoteString(referencedEntityName) ~ ", " ~ 2348 quoteString(referencedPropertyName) ~ ", " ~ 2349 readerFuncDef ~ ", " ~ 2350 writerFuncDef ~ ", " ~ 2351 getVariantFuncDef ~ ", " ~ 2352 setVariantFuncDef ~ ", " ~ 2353 keyIsSetFuncDef ~ ", " ~ 2354 isNullFuncDef ~ ", " ~ 2355 copyFuncDef ~ ", " ~ 2356 "null, " ~ // generatorFunc 2357 getObjectFuncDef ~ ", " ~ 2358 setObjectFuncDef ~ ", " ~ 2359 getCollectionFuncDef ~ ", " ~ 2360 setCollectionFuncDef ~ ", " ~ 2361 setObjectDelegateFuncDef ~ ", " ~ 2362 setCollectionDelegateFuncDef ~ ", " ~ 2363 isLoadedFuncDef ~ ", " ~ 2364 quoteBool(isLazy) ~ ", " ~ // lazy 2365 "false" ~ // collection 2366 ")"; 2367 } 2368 2369 /// generate source code for creation of ManyToOne definition 2370 string getManyToOnePropertyDef(T, immutable string m)() { 2371 immutable string referencedEntityName = getPropertyReferencedEntityName!(T,m); 2372 immutable string referencedClassName = getPropertyReferencedClassName!(T,m); 2373 immutable string referencedPropertyName = getOneToOneReferencedPropertyName!(T,m); 2374 immutable string entityClassName = fullyQualifiedName!T; 2375 immutable string propertyName = getPropertyName!(T,m); 2376 static assert (propertyName != null, "Cannot determine property name for member " ~ m ~ " of type " ~ T.stringof); 2377 static assert (!hasOneOfMemberAnnotations!(T, m, Column, Id, Generated, Generator, OneToOne, ManyToMany), entityClassName ~ "." ~ propertyName ~ ": ManyToOne property cannot have Column, Id, Generated, Generator, OneToOne, ManyToMany annotation"); 2378 immutable string columnName = applyDefault(getJoinColumnName!(T, m),camelCaseToUnderscoreDelimited(referencedEntityName) ~ "_fk"); 2379 static assert (columnName != null, "ManyToOne property " ~ m ~ " has no JoinColumn name"); 2380 immutable bool isLazy = isLazyMember!(T,m); 2381 immutable length = getColumnLength!(T, m); 2382 immutable bool hasNull = hasMemberAnnotation!(T,m, Null); 2383 immutable bool hasNotNull = hasMemberAnnotation!(T,m, NotNull); 2384 immutable bool nullable = hasNull ? true : (hasNotNull ? false : true); //canColumnTypeHoldNulls!(T.m) 2385 immutable string unique = quoteString(getUniqueIndexName!(T, m)); 2386 immutable string typeName = "new EntityType(cast(immutable TypeInfo_Class)" ~ entityClassName ~ ".classinfo, \"" ~ entityClassName ~ "\")"; //getColumnTypeName!(T, m)(); 2387 immutable string propertyReadCode = getPropertyReadCode!(T,m)(); 2388 immutable string datasetReadCode = null; //getColumnTypeDatasetReadCode!(T,m)(); 2389 immutable string propertyWriteCode = null; //getPropertyWriteCode!(T,m)(); 2390 immutable string datasetWriteCode = null; //getColumnTypeDatasetWriteCode!(T,m)(); 2391 immutable string propertyVariantSetCode = getEmbeddedPropertyVariantWriteCode!(T, m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2392 immutable string propertyVariantGetCode = "Variant(" ~ propertyReadCode ~ " is null ? null : " ~ propertyReadCode ~ ")"; //getPropertyVariantReadCode!(T,m)(); 2393 immutable string propertyObjectSetCode = getPropertyObjectWriteCode!(T,m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2394 immutable string propertyObjectGetCode = propertyReadCode; //getPropertyVariantReadCode!(T,m)(); 2395 immutable string keyIsSetCode = null; //getColumnTypeKeyIsSetCode!(T,m)(); 2396 immutable string isNullCode = propertyReadCode ~ " is null"; 2397 immutable string copyFieldCode = getPropertyCopyCode!(T,m); 2398 // pragma(msg, "property read: " ~ propertyReadCode); 2399 // pragma(msg, "property write: " ~ propertyWriteCode); 2400 // pragma(msg, "variant get: " ~ propertyVariantGetCode); 2401 immutable string readerFuncDef = "null"; 2402 immutable string writerFuncDef = "null"; 2403 immutable string getVariantFuncDef = 2404 "\n" ~ 2405 "function(Object obj) { \n" ~ 2406 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2407 " return " ~ propertyVariantGetCode ~ "; \n" ~ 2408 " }\n"; 2409 immutable string setVariantFuncDef = 2410 "\n" ~ 2411 "function(Object obj, Variant value) { \n" ~ 2412 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2413 " " ~ propertyVariantSetCode ~ "\n" ~ 2414 " }\n"; 2415 immutable string keyIsSetFuncDef = "\n" ~ 2416 "function(Object obj) { \n" ~ 2417 " return false;\n" ~ 2418 " }\n"; 2419 immutable string isNullFuncDef = "\n" ~ 2420 "function(Object obj) { \n" ~ 2421 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2422 " return " ~ isNullCode ~ ";\n" ~ 2423 " }\n"; 2424 immutable string getObjectFuncDef = 2425 "\n" ~ 2426 "function(Object obj) { \n" ~ 2427 " //writeln(\"Inside getObjectFunc\"); \n" ~ 2428 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2429 " assert(entity !is null);\n" ~ 2430 " Object res = " ~ propertyObjectGetCode ~ "; \n" ~ 2431 " //writeln(res is null ? \"obj is null\" : \"obj is not null\"); \n" ~ 2432 " return res; \n" ~ 2433 " }\n"; 2434 immutable string setObjectFuncDef = 2435 "\n" ~ 2436 "function(Object obj, Object value) { \n" ~ 2437 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2438 " " ~ propertyObjectSetCode ~ "\n" ~ 2439 " }\n"; 2440 immutable string copyFuncDef = 2441 "\n" ~ 2442 "function(Object to, Object from) { \n" ~ 2443 " " ~ entityClassName ~ " toentity = cast(" ~ entityClassName ~ ")to; \n" ~ 2444 " " ~ entityClassName ~ " fromentity = cast(" ~ entityClassName ~ ")from; \n" ~ 2445 " " ~ copyFieldCode ~ "\n" ~ 2446 " }\n"; 2447 immutable string getCollectionFuncDef = "null"; 2448 immutable string setCollectionFuncDef = "null"; 2449 immutable string setObjectDelegateFuncDef = !isLazy ? "null" : 2450 "\n" ~ 2451 "function(Object obj, Object delegate() loader) { \n" ~ 2452 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2453 " " ~ getLazyPropertyObjectWriteCode!(T,m) ~ "\n" ~ 2454 " }\n"; 2455 immutable string setCollectionDelegateFuncDef = "null"; 2456 immutable string isLoadedFuncDef = !isLazy ? "null" : 2457 "\n" ~ 2458 "function(Object obj) { \n" ~ 2459 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2460 " return " ~ getLazyPropertyLoadedCode!(T,m) ~ ";\n" ~ 2461 " }\n"; 2462 2463 return " new PropertyInfo(" ~ 2464 quoteString(propertyName) ~ ", " ~ 2465 quoteString(columnName) ~ ", " ~ 2466 typeName ~ ", " ~ 2467 format("%s",length) ~ ", " ~ 2468 "false, " ~ // id 2469 "false, " ~ // generated 2470 quoteBool(nullable) ~ ", " ~ 2471 unique ~ ", " ~ 2472 "RelationType.ManyToOne, " ~ 2473 quoteString(referencedEntityName) ~ ", " ~ 2474 quoteString(referencedPropertyName) ~ ", " ~ 2475 readerFuncDef ~ ", " ~ 2476 writerFuncDef ~ ", " ~ 2477 getVariantFuncDef ~ ", " ~ 2478 setVariantFuncDef ~ ", " ~ 2479 keyIsSetFuncDef ~ ", " ~ 2480 isNullFuncDef ~ ", " ~ 2481 copyFuncDef ~ ", " ~ 2482 "null, " ~ // generatorFunc 2483 getObjectFuncDef ~ ", " ~ 2484 setObjectFuncDef ~ ", " ~ 2485 getCollectionFuncDef ~ ", " ~ 2486 setCollectionFuncDef ~ ", " ~ 2487 setObjectDelegateFuncDef ~ ", " ~ 2488 setCollectionDelegateFuncDef ~ ", " ~ 2489 isLoadedFuncDef ~ ", " ~ 2490 quoteBool(isLazy) ~ ", " ~ // lazy 2491 "false" ~ // collection 2492 ")"; 2493 } 2494 2495 /// generate source code for creation of OneToMany definition 2496 string getOneToManyPropertyDef(T, immutable string m)() { 2497 immutable string referencedEntityName = getPropertyReferencedEntityName!(T,m); 2498 immutable string referencedClassName = getPropertyReferencedClassName!(T,m); 2499 immutable string referencedPropertyName = getOneToManyReferencedPropertyName!(T,m); 2500 static assert (referencedPropertyName != null, "OneToMany should have referenced property name parameter"); 2501 immutable string entityClassName = fullyQualifiedName!T; 2502 immutable string propertyName = getPropertyName!(T,m)(); 2503 static assert (propertyName != null, "Cannot determine property name for member " ~ m ~ " of type " ~ T.stringof); 2504 static assert (!hasOneOfMemberAnnotations!(T, m, Column, Id, Generated, Generator, OneToOne, ManyToMany), entityClassName ~ "." ~ propertyName ~ ": OneToMany property cannot have Column, Id, Generated, Generator, OneToOne, ManyToMany or Embedded annotation"); 2505 immutable string columnName = getJoinColumnName!(T, m)(); 2506 immutable bool isCollection = isCollectionMember!(T,m); 2507 static assert (isCollection, "OneToMany property " ~ m ~ " should be array of objects or LazyCollection"); 2508 static assert (columnName == null, "OneToMany property " ~ m ~ " should not have JoinColumn name"); 2509 immutable bool isLazy = isLazyMember!(T,m) || isLazyCollectionMember!(T,m); 2510 immutable length = getColumnLength!(T, m); 2511 immutable bool hasNull = hasMemberAnnotation!(T,m, Null); 2512 immutable bool hasNotNull = hasMemberAnnotation!(T,m, NotNull); 2513 immutable bool nullable = hasNull ? true : (hasNotNull ? false : true); //canColumnTypeHoldNulls!(T.m) 2514 immutable string unique = quoteString(getUniqueIndexName!(T, m)); 2515 immutable string typeName = "new EntityType(cast(immutable TypeInfo_Class)" ~ entityClassName ~ ".classinfo, \"" ~ entityClassName ~ "\")"; //getColumnTypeName!(T, m)(); 2516 immutable string propertyReadCode = getPropertyReadCode!(T,m)(); 2517 immutable string datasetReadCode = null; //getColumnTypeDatasetReadCode!(T,m)(); 2518 immutable string propertyWriteCode = null; //getPropertyWriteCode!(T,m)(); 2519 immutable string datasetWriteCode = null; //getColumnTypeDatasetWriteCode!(T,m)(); 2520 immutable string propertyVariantSetCode = getCollectionPropertyVariantWriteCode!(T, m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2521 immutable string propertyVariantGetCode = "Variant(" ~ propertyReadCode ~ " is null ? null : " ~ propertyReadCode ~ ")"; //getPropertyVariantReadCode!(T,m)(); 2522 //pragma(msg, "propertyVariantGetCode: " ~ propertyVariantGetCode); 2523 //pragma(msg, "propertyVariantSetCode: " ~ propertyVariantSetCode); 2524 immutable string propertyObjectSetCode = getPropertyCollectionWriteCode!(T,m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2525 immutable string propertyObjectGetCode = propertyReadCode; //getPropertyVariantReadCode!(T,m)(); 2526 immutable string keyIsSetCode = null; //getColumnTypeKeyIsSetCode!(T,m)(); 2527 immutable string isNullCode = propertyReadCode ~ " is null"; 2528 immutable string copyFieldCode = getPropertyCopyCode!(T,m); 2529 // pragma(msg, "property read: " ~ propertyReadCode); 2530 // pragma(msg, "property write: " ~ propertyWriteCode); 2531 // pragma(msg, "variant get: " ~ propertyVariantGetCode); 2532 immutable string readerFuncDef = "null"; 2533 immutable string writerFuncDef = "null"; 2534 immutable string getVariantFuncDef = 2535 "\n" ~ 2536 "function(Object obj) { \n" ~ 2537 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2538 " return " ~ propertyVariantGetCode ~ "; \n" ~ 2539 " }\n"; 2540 immutable string setVariantFuncDef = 2541 "\n" ~ 2542 "function(Object obj, Variant value) { \n" ~ 2543 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2544 " " ~ propertyVariantSetCode ~ "\n" ~ 2545 " }\n"; 2546 immutable string keyIsSetFuncDef = "\n" ~ 2547 "function(Object obj) { \n" ~ 2548 " return false;\n" ~ 2549 " }\n"; 2550 immutable string isNullFuncDef = "\n" ~ 2551 "function(Object obj) { \n" ~ 2552 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2553 " return " ~ isNullCode ~ ";\n" ~ 2554 " }\n"; 2555 immutable string getObjectFuncDef = "null"; 2556 immutable string setObjectFuncDef = "null"; 2557 immutable string copyFuncDef = 2558 "\n" ~ 2559 "function(Object to, Object from) { \n" ~ 2560 " " ~ entityClassName ~ " toentity = cast(" ~ entityClassName ~ ")to; \n" ~ 2561 " " ~ entityClassName ~ " fromentity = cast(" ~ entityClassName ~ ")from; \n" ~ 2562 " " ~ copyFieldCode ~ "\n" ~ 2563 " }\n"; 2564 immutable string getCollectionFuncDef = 2565 "\n" ~ 2566 "function(Object obj) { \n" ~ 2567 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2568 " assert(entity !is null);\n" ~ 2569 " return cast(Object[])" ~ propertyObjectGetCode ~ "; \n" ~ 2570 " }\n"; 2571 immutable string setCollectionFuncDef = 2572 "\n" ~ 2573 "function(Object obj, Object[] value) { \n" ~ 2574 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2575 " " ~ propertyObjectSetCode ~ "\n" ~ 2576 " }\n"; 2577 immutable string setObjectDelegateFuncDef = "null"; 2578 immutable string setCollectionDelegateFuncDef = !isLazy ? "null" : 2579 "\n" ~ 2580 "function(Object obj, Object[] delegate() loader) { \n" ~ 2581 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2582 " " ~ getLazyPropertyObjectWriteCode!(T,m) ~ "\n" ~ 2583 " }\n"; 2584 immutable string isLoadedFuncDef = !isLazy ? "null" : 2585 "\n" ~ 2586 "function(Object obj) { \n" ~ 2587 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2588 " return " ~ getLazyPropertyLoadedCode!(T,m) ~ ";\n" ~ 2589 " }\n"; 2590 2591 return " new PropertyInfo(" ~ 2592 quoteString(propertyName) ~ ", " ~ 2593 quoteString(columnName) ~ ", " ~ 2594 typeName ~ ", " ~ 2595 format("%s",length) ~ ", " ~ 2596 "false" ~ ", " ~ // id 2597 "false" ~ ", " ~ // generated 2598 quoteBool(nullable) ~ ", " ~ 2599 unique ~ ", " ~ 2600 "RelationType.OneToMany, " ~ 2601 quoteString(referencedEntityName) ~ ", " ~ 2602 quoteString(referencedPropertyName) ~ ", " ~ 2603 readerFuncDef ~ ", " ~ 2604 writerFuncDef ~ ", " ~ 2605 getVariantFuncDef ~ ", " ~ 2606 setVariantFuncDef ~ ", " ~ 2607 keyIsSetFuncDef ~ ", " ~ 2608 isNullFuncDef ~ ", " ~ 2609 copyFuncDef ~ ", " ~ 2610 "null, " ~ // generatorFunc 2611 getObjectFuncDef ~ ", " ~ 2612 setObjectFuncDef ~ ", " ~ 2613 getCollectionFuncDef ~ ", " ~ 2614 setCollectionFuncDef ~ ", " ~ 2615 setObjectDelegateFuncDef ~ ", " ~ 2616 setCollectionDelegateFuncDef ~ ", " ~ 2617 isLoadedFuncDef ~ ", " ~ 2618 quoteBool(isLazy) ~ ", " ~ // lazy 2619 "true" ~ // is collection 2620 ")"; 2621 } 2622 2623 /// generate source code for creation of ManyToMany definition 2624 string getManyToManyPropertyDef(T, immutable string m)() { 2625 immutable string referencedEntityName = getPropertyReferencedEntityName!(T,m); 2626 immutable string referencedClassName = getPropertyReferencedClassName!(T,m); 2627 immutable string entityClassName = fullyQualifiedName!T; 2628 immutable string propertyName = getPropertyName!(T,m); 2629 static assert (propertyName != null, "Cannot determine property name for member " ~ m ~ " of type " ~ T.stringof); 2630 static assert (!hasOneOfMemberAnnotations!(T, m, Column, Id, Generated, Generator, OneToOne, OneToMany), entityClassName ~ "." ~ propertyName ~ ": ManyToMany property cannot have Column, Id, Generated, Generator, OneToOne, OneToMany annotation"); 2631 immutable string columnName = getJoinColumnName!(T, m); 2632 immutable string joinTableName = getJoinTableName!(T, m); 2633 immutable string joinColumn1 = getJoinTableColumn1!(T, m); 2634 immutable string joinColumn2 = getJoinTableColumn2!(T, m); 2635 immutable string joinTableCode = JoinTableInfo.generateJoinTableCode(joinTableName, joinColumn1, joinColumn2); 2636 immutable bool isCollection = isCollectionMember!(T,m); 2637 static assert (isCollection, "ManyToMany property " ~ m ~ " should be array of objects or LazyCollection"); 2638 static assert (columnName == null, "ManyToMany property " ~ m ~ " should not have JoinColumn name"); 2639 immutable bool isLazy = isLazyMember!(T,m) || isLazyCollectionMember!(T,m); 2640 immutable length = getColumnLength!(T, m); 2641 immutable bool hasNull = hasMemberAnnotation!(T,m, Null); 2642 immutable bool hasNotNull = hasMemberAnnotation!(T,m, NotNull); 2643 immutable bool nullable = hasNull ? true : (hasNotNull ? false : true); //canColumnTypeHoldNulls!(T.m) 2644 immutable string unique = quoteString(getUniqueIndexName!(T, m)); 2645 immutable string typeName = "new EntityType(cast(immutable TypeInfo_Class)" ~ entityClassName ~ ".classinfo, \"" ~ entityClassName ~ "\")"; //getColumnTypeName!(T, m)(); 2646 immutable string propertyReadCode = getPropertyReadCode!(T,m); 2647 immutable string datasetReadCode = null; //getColumnTypeDatasetReadCode!(T,m)(); 2648 immutable string propertyWriteCode = null; //getPropertyWriteCode!(T,m)(); 2649 immutable string datasetWriteCode = null; //getColumnTypeDatasetWriteCode!(T,m)(); 2650 immutable string propertyVariantSetCode = getCollectionPropertyVariantWriteCode!(T, m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2651 immutable string propertyVariantGetCode = "Variant(" ~ propertyReadCode ~ " is null ? null : " ~ propertyReadCode ~ ")"; //getPropertyVariantReadCode!(T,m)(); 2652 //pragma(msg, "propertyVariantGetCode: " ~ propertyVariantGetCode); 2653 //pragma(msg, "propertyVariantSetCode: " ~ propertyVariantSetCode); 2654 immutable string propertyObjectSetCode = getPropertyCollectionWriteCode!(T,m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2655 immutable string propertyObjectGetCode = propertyReadCode; //getPropertyVariantReadCode!(T,m)(); 2656 immutable string keyIsSetCode = null; //getColumnTypeKeyIsSetCode!(T,m)(); 2657 immutable string isNullCode = propertyReadCode ~ " is null"; 2658 immutable string copyFieldCode = getPropertyCopyCode!(T,m); 2659 immutable string readerFuncDef = "null"; 2660 immutable string writerFuncDef = "null"; 2661 immutable string getVariantFuncDef = 2662 "\n" ~ 2663 "function(Object obj) { \n" ~ 2664 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2665 " return " ~ propertyVariantGetCode ~ "; \n" ~ 2666 " }\n"; 2667 immutable string setVariantFuncDef = 2668 "\n" ~ 2669 "function(Object obj, Variant value) { \n" ~ 2670 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2671 " " ~ propertyVariantSetCode ~ "\n" ~ 2672 " }\n"; 2673 immutable string keyIsSetFuncDef = "\n" ~ 2674 "function(Object obj) { \n" ~ 2675 " return false;\n" ~ 2676 " }\n"; 2677 immutable string isNullFuncDef = "\n" ~ 2678 "function(Object obj) { \n" ~ 2679 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2680 " return " ~ isNullCode ~ ";\n" ~ 2681 " }\n"; 2682 immutable string getObjectFuncDef = "null"; 2683 immutable string setObjectFuncDef = "null"; 2684 immutable string copyFuncDef = 2685 "\n" ~ 2686 "function(Object to, Object from) { \n" ~ 2687 " " ~ entityClassName ~ " toentity = cast(" ~ entityClassName ~ ")to; \n" ~ 2688 " " ~ entityClassName ~ " fromentity = cast(" ~ entityClassName ~ ")from; \n" ~ 2689 " " ~ copyFieldCode ~ "\n" ~ 2690 " }\n"; 2691 immutable string getCollectionFuncDef = 2692 "\n" ~ 2693 "function(Object obj) { \n" ~ 2694 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2695 " assert(entity !is null);\n" ~ 2696 " return cast(Object[])" ~ propertyObjectGetCode ~ "; \n" ~ 2697 " }\n"; 2698 immutable string setCollectionFuncDef = 2699 "\n" ~ 2700 "function(Object obj, Object[] value) { \n" ~ 2701 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2702 " " ~ propertyObjectSetCode ~ "\n" ~ 2703 " }\n"; 2704 immutable string setObjectDelegateFuncDef = "null"; 2705 immutable string setCollectionDelegateFuncDef = !isLazy ? "null" : 2706 "\n" ~ 2707 "function(Object obj, Object[] delegate() loader) { \n" ~ 2708 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2709 " " ~ getLazyPropertyObjectWriteCode!(T,m) ~ "\n" ~ 2710 " }\n"; 2711 immutable string isLoadedFuncDef = !isLazy ? "null" : 2712 "\n" ~ 2713 "function(Object obj) { \n" ~ 2714 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2715 " return " ~ getLazyPropertyLoadedCode!(T,m) ~ ";\n" ~ 2716 " }\n"; 2717 2718 return " new PropertyInfo(" ~ 2719 quoteString(propertyName) ~ ", " ~ 2720 quoteString(columnName) ~ ", " ~ 2721 typeName ~ ", " ~ 2722 format("%s",length) ~ ", " ~ 2723 "false" ~ ", " ~ // id 2724 "false" ~ ", " ~ // generated 2725 quoteBool(nullable) ~ ", " ~ 2726 unique ~ ", " ~ 2727 "RelationType.ManyToMany, " ~ 2728 quoteString(referencedEntityName) ~ ", " ~ 2729 "null, " ~ //referencedPropertyName 2730 readerFuncDef ~ ", " ~ 2731 writerFuncDef ~ ", " ~ 2732 getVariantFuncDef ~ ", " ~ 2733 setVariantFuncDef ~ ", " ~ 2734 keyIsSetFuncDef ~ ", " ~ 2735 isNullFuncDef ~ ", " ~ 2736 copyFuncDef ~ ", " ~ 2737 "null, " ~ // generatorFunc 2738 getObjectFuncDef ~ ", " ~ 2739 setObjectFuncDef ~ ", " ~ 2740 getCollectionFuncDef ~ ", " ~ 2741 setCollectionFuncDef ~ ", " ~ 2742 setObjectDelegateFuncDef ~ ", " ~ 2743 setCollectionDelegateFuncDef ~ ", " ~ 2744 isLoadedFuncDef ~ ", " ~ 2745 quoteBool(isLazy) ~ ", " ~ // lazy 2746 "true" ~ ", " ~ // is collection 2747 joinTableCode ~ 2748 ")"; 2749 } 2750 2751 /// generate source code for creation of Embedded definition 2752 string getEmbeddedPropertyDef(T, immutable string m)() { 2753 immutable string referencedEntityName = getPropertyEmbeddedEntityName!(T,m); 2754 immutable string referencedClassName = getPropertyEmbeddedClassName!(T,m); 2755 immutable string entityClassName = fullyQualifiedName!T; 2756 immutable string propertyName = getPropertyName!(T,m); 2757 static assert (propertyName != null, "Cannot determine property name for member " ~ m ~ " of type " ~ T.stringof); 2758 static assert (!hasOneOfMemberAnnotations!(T, m, Column, Id, Generated, Generator, ManyToOne, ManyToMany, OneToOne), entityClassName ~ "." ~ propertyName ~ ": Embedded property cannot have Column, Id, Generated, OneToOne, ManyToOne, ManyToMany annotation"); 2759 immutable string columnName = getColumnName!(T, m); 2760 immutable length = getColumnLength!(T, m); 2761 immutable bool hasNull = hasMemberAnnotation!(T, m, Null); 2762 immutable bool hasNotNull = hasMemberAnnotation!(T, m, NotNull); 2763 immutable bool nullable = hasNull ? true : (hasNotNull ? false : true); //canColumnTypeHoldNulls!(T.m) 2764 immutable string unique = quoteString(getUniqueIndexName!(T, m)); 2765 immutable string typeName = "new EntityType(cast(immutable TypeInfo_Class)" ~ entityClassName ~ ".classinfo, \"" ~ entityClassName ~ "\")"; //getColumnTypeName!(T, m)(); 2766 immutable string propertyReadCode = getPropertyReadCode!(T,m); 2767 immutable string datasetReadCode = null; //getColumnTypeDatasetReadCode!(T,m)(); 2768 immutable string propertyWriteCode = null; //getPropertyWriteCode!(T,m)(); 2769 immutable string datasetWriteCode = null; //getColumnTypeDatasetWriteCode!(T,m)(); 2770 immutable string propertyVariantSetCode = getEmbeddedPropertyVariantWriteCode!(T, m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2771 immutable string propertyVariantGetCode = "Variant(" ~ propertyReadCode ~ " is null ? null : " ~ propertyReadCode ~ ")"; //getPropertyVariantReadCode!(T,m)(); 2772 immutable string propertyObjectSetCode = getPropertyObjectWriteCode!(T,m, referencedClassName); // getPropertyVariantWriteCode!(T,m)(); 2773 immutable string propertyObjectGetCode = propertyReadCode; //getPropertyVariantReadCode!(T,m)(); 2774 immutable string keyIsSetCode = null; //getColumnTypeKeyIsSetCode!(T,m)(); 2775 immutable string isNullCode = propertyReadCode ~ " is null"; 2776 immutable string copyFieldCode = getPropertyCopyCode!(T,m); 2777 // pragma(msg, "property read: " ~ propertyReadCode); 2778 // pragma(msg, "property write: " ~ propertyWriteCode); 2779 // pragma(msg, "variant get: " ~ propertyVariantGetCode); 2780 immutable string readerFuncDef = "null"; 2781 immutable string writerFuncDef = "null"; 2782 immutable string getVariantFuncDef = 2783 "\n" ~ 2784 "function(Object obj) { \n" ~ 2785 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2786 " return " ~ propertyVariantGetCode ~ "; \n" ~ 2787 " }\n"; 2788 immutable string setVariantFuncDef = 2789 "\n" ~ 2790 "function(Object obj, Variant value) { \n" ~ 2791 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2792 " " ~ propertyVariantSetCode ~ "\n" ~ 2793 " }\n"; 2794 immutable string keyIsSetFuncDef = "\n" ~ 2795 "function(Object obj) { \n" ~ 2796 " return false;\n" ~ 2797 " }\n"; 2798 immutable string isNullFuncDef = "\n" ~ 2799 "function(Object obj) { \n" ~ 2800 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2801 " return " ~ isNullCode ~ ";\n" ~ 2802 " }\n"; 2803 immutable string getObjectFuncDef = 2804 "\n" ~ 2805 "function(Object obj) { \n" ~ 2806 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2807 " assert(entity !is null);\n" ~ 2808 " return " ~ propertyObjectGetCode ~ "; \n" ~ 2809 " }\n"; 2810 immutable string setObjectFuncDef = 2811 "\n" ~ 2812 "function(Object obj, Object value) { \n" ~ 2813 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2814 " " ~ propertyObjectSetCode ~ "\n" ~ 2815 " }\n"; 2816 immutable string copyFuncDef = 2817 "\n" ~ 2818 "function(Object to, Object from) { \n" ~ 2819 " " ~ entityClassName ~ " toentity = cast(" ~ entityClassName ~ ")to; \n" ~ 2820 " " ~ entityClassName ~ " fromentity = cast(" ~ entityClassName ~ ")from; \n" ~ 2821 " " ~ copyFieldCode ~ "\n" ~ 2822 " }\n"; 2823 2824 return " new PropertyInfo(" ~ 2825 quoteString(propertyName) ~ ", " ~ 2826 quoteString(columnName) ~ ", " ~ 2827 typeName ~ ", " ~ 2828 format("%s",length) ~ ", " ~ 2829 "false, " ~ // id 2830 "false, " ~ // generated 2831 quoteBool(nullable) ~ ", " ~ 2832 unique ~ ", " ~ 2833 "RelationType.Embedded, " ~ 2834 quoteString(referencedEntityName) ~ ", " ~ 2835 "null, \n" ~ 2836 readerFuncDef ~ ", " ~ 2837 writerFuncDef ~ ", " ~ 2838 getVariantFuncDef ~ ", " ~ 2839 setVariantFuncDef ~ ", " ~ 2840 keyIsSetFuncDef ~ ", " ~ 2841 isNullFuncDef ~ ", " ~ 2842 copyFuncDef ~ ", " ~ 2843 "null, " ~ // generatorFunc 2844 getObjectFuncDef ~ ", " ~ 2845 setObjectFuncDef ~ 2846 ")"; 2847 } 2848 2849 /// generate source code for creation of simple property definition 2850 string getSimplePropertyDef(T, immutable string m)() { 2851 //getPropertyReferencedEntityName( 2852 immutable string entityClassName = fullyQualifiedName!T; 2853 immutable string propertyName = getPropertyName!(T,m); 2854 static assert (propertyName != null, "Cannot determine property name for member " ~ m ~ " of type " ~ T.stringof); 2855 static assert (!hasOneOfMemberAnnotations!(T, m, ManyToOne, OneToOne, ManyToMany), entityClassName ~ "." ~ propertyName ~ ": simple property cannot have OneToOne, ManyToOne, or ManyToMany annotation"); 2856 immutable bool isIdPropertyName = propertyName == "id"; 2857 immutable bool isEmbeddableClass = hasAnnotation!(T, Embeddable); 2858 immutable bool classHasKeyField = hasAnyKeyPropertyAnnotation!T; 2859 immutable string generatorCode = getGeneratorCode!(T, m); 2860 immutable bool hasKeyAnnotation = hasMemberAnnotation!(T, m, Id) || hasMemberAnnotation!(T, m, Generated) || generatorCode != null; 2861 immutable bool isId = hasKeyAnnotation || (isIdPropertyName && !classHasKeyField && !isEmbeddableClass); 2862 immutable bool isGenerated = hasMemberAnnotation!(T, m, Generated) || (!hasKeyAnnotation && isId); 2863 immutable string columnName = getColumnName!(T, m); 2864 static assert(!isGenerated || generatorCode == null, T.stringof ~ "." ~ m ~ ": You cannot mix @Generated and @Generator for the same property"); 2865 immutable length = getColumnLength!(T, m)(); 2866 immutable bool hasNull = hasMemberAnnotation!(T,m,Null); 2867 immutable bool hasNotNull = hasMemberAnnotation!(T,m,NotNull); 2868 immutable bool nullable = hasNull ? true : (hasNotNull ? false : isColumnTypeNullableByDefault!(T, m)); //canColumnTypeHoldNulls!(T.m) 2869 immutable string unique = quoteString(getUniqueIndexName!(T, m)); 2870 immutable string typeName = getColumnTypeName!(T, m, length); 2871 immutable string propertyReadCode = getPropertyReadCode!(T,m); 2872 immutable string datasetReadCode = getColumnTypeDatasetReadCode!(T,m); 2873 immutable string propertyWriteCode = getPropertyWriteCode!(T,m); 2874 immutable string datasetWriteCode = getColumnTypeDatasetWriteCode!(T,m); 2875 immutable string propertyVariantSetCode = getPropertyVariantWriteCode!(T,m); 2876 immutable string propertyVariantGetCode = getPropertyVariantReadCode!(T,m); 2877 immutable string keyIsSetCode = getColumnTypeKeyIsSetCode!(T,m); 2878 immutable string isNullCode = getColumnTypeIsNullCode!(T,m); 2879 immutable string copyFieldCode = getPropertyCopyCode!(T,m); 2880 immutable string readerFuncDef = "\n" ~ 2881 "function(Object obj, DataSetReader r, int index) { \n" ~ 2882 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2883 " " ~ propertyWriteCode ~ " \n" ~ 2884 " }\n"; 2885 immutable string writerFuncDef = "\n" ~ 2886 "function(Object obj, DataSetWriter r, int index) { \n" ~ 2887 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2888 " " ~ datasetWriteCode ~ " \n" ~ 2889 " }\n"; 2890 immutable string getVariantFuncDef = "\n" ~ 2891 "function(Object obj) { \n" ~ 2892 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2893 " return " ~ propertyVariantGetCode ~ "; \n" ~ 2894 " }\n"; 2895 immutable string setVariantFuncDef = "\n" ~ 2896 "function(Object obj, Variant value) { \n" ~ 2897 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2898 " " ~ propertyVariantSetCode ~ "\n" ~ 2899 " }\n"; 2900 immutable string keyIsSetFuncDef = "\n" ~ 2901 "function(Object obj) { \n" ~ 2902 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2903 " return " ~ keyIsSetCode ~ ";\n" ~ 2904 " }\n"; 2905 immutable string isNullFuncDef = "\n" ~ 2906 "function(Object obj) { \n" ~ 2907 " " ~ entityClassName ~ " entity = cast(" ~ entityClassName ~ ")obj; \n" ~ 2908 " return " ~ isNullCode ~ ";\n" ~ 2909 " }\n"; 2910 immutable string copyFuncDef = 2911 "\n" ~ 2912 "function(Object to, Object from) { \n" ~ 2913 " " ~ entityClassName ~ " toentity = cast(" ~ entityClassName ~ ")to; \n" ~ 2914 " " ~ entityClassName ~ " fromentity = cast(" ~ entityClassName ~ ")from; \n" ~ 2915 " " ~ copyFieldCode ~ "\n" ~ 2916 " }\n"; 2917 immutable string generatorFuncDef = generatorCode is null ? "null" : 2918 "\n" ~ 2919 "function(Connection conn, const PropertyInfo property) { \n" ~ 2920 " return Variant(" ~ generatorCode ~ ");\n" ~ 2921 "}\n"; 2922 2923 static assert (typeName != null, "Cannot determine column type for member " ~ m ~ " of type " ~ T.stringof); 2924 return " new PropertyInfo(" ~ 2925 quoteString(propertyName) ~ ", " ~ 2926 quoteString(columnName) ~ ", " ~ 2927 typeName ~ ", " ~ 2928 format("%s",length) ~ ", " ~ 2929 quoteBool(isId) ~ ", " ~ 2930 quoteBool(isGenerated) ~ ", " ~ 2931 quoteBool(nullable) ~ ", " ~ 2932 unique ~ ", " ~ 2933 "RelationType.None, " ~ 2934 "null, " ~ 2935 "null, \n" ~ 2936 readerFuncDef ~ ", " ~ 2937 writerFuncDef ~ ", " ~ 2938 getVariantFuncDef ~ ", " ~ 2939 setVariantFuncDef ~ ", " ~ 2940 keyIsSetFuncDef ~ ", " ~ 2941 isNullFuncDef ~ ", " ~ 2942 copyFuncDef ~ ", " ~ 2943 generatorFuncDef ~ 2944 ")"; 2945 } 2946 2947 /// creates "new PropertyInfo(...)" code to create property metadata for member m of class T 2948 string getPropertyDef(T, string m)() { 2949 immutable bool isObject = isObjectMember!(T, m); 2950 immutable bool isCollection = isCollectionMember!(T, m); 2951 immutable bool isEmbedded = isEmbeddedObjectMember!(T, m); 2952 immutable bool isOneToOne = hasMemberAnnotation!(T, m, OneToOne); 2953 immutable bool isManyToOne = hasMemberAnnotation!(T, m, ManyToOne); 2954 immutable bool isManyToMany = hasMemberAnnotation!(T, m, ManyToMany); 2955 immutable bool isOneToMany = hasMemberAnnotation!(T, m, OneToMany); 2956 immutable bool isSimple = isSupportedSimpleType!(T, m); 2957 static if (isSimple) { 2958 return getSimplePropertyDef!(T, m); 2959 } else static if (isObject) { 2960 static if (isOneToOne) { 2961 return getOneToOnePropertyDef!(T, m); 2962 } else static if (isEmbedded) { 2963 return getEmbeddedPropertyDef!(T, m); 2964 } else { 2965 // if no annotations on Object field, assume it is ManyToOne 2966 return getManyToOnePropertyDef!(T, m); 2967 } 2968 2969 } else static if (isCollection) { 2970 static assert(!isEmbedded && !isOneToOne && !isManyToOne, "Collection object array or LazyCollection! cannot be marked as @Embedded, @OneToOne, or @ManyToOne"); 2971 static if (isManyToMany) { 2972 return getManyToManyPropertyDef!(T, m); 2973 } else { 2974 // if no annotations on collection field, assume it is OneToMany 2975 return getOneToManyPropertyDef!(T, m); 2976 } 2977 } 2978 } 2979 2980 string getEntityDef(T)() { 2981 string res; 2982 string generatedGettersSetters; 2983 2984 string generatedEntityInfo; 2985 string generatedPropertyInfo; 2986 2987 immutable string typeName = fullyQualifiedName!T; 2988 immutable bool isEntity = hasAnnotation!(T, Entity); 2989 2990 //Don't require class level annotation. If no @Embeddable annotation, will treat as if there is @Entity annotation 2991 //static assert (hasOneOfAnnotations!(T, Entity, Embeddable), "Type " ~ typeName ~ " has neither @Entity nor @Embeddable annotation"); 2992 static assert (!hasAnnotation!(T, Entity) || !hasAnnotation!(T, Embeddable), "Type " ~ typeName ~ " may not have both @Entity and @Embeddable at the same time"); 2993 //pragma(msg, "Entity type name: " ~ typeName); 2994 2995 immutable string entityName = getEntityName!T(); 2996 immutable string tableName = getTableName!T(); 2997 2998 //pragma(msg, "preparing entity : " ~ entityName); 2999 3000 static assert (entityName != null, "Type " ~ typeName ~ " has no Entity name specified"); 3001 static assert (tableName != null, "Type " ~ typeName ~ " has no Table name specified"); 3002 3003 generatedEntityInfo ~= "new EntityInfo("; 3004 generatedEntityInfo ~= "\"" ~ entityName ~ "\", "; 3005 generatedEntityInfo ~= "\"" ~ tableName ~ "\", "; 3006 generatedEntityInfo ~= hasAnnotation!(T, Embeddable) ? "true," : "false,"; 3007 generatedEntityInfo ~= "[\n"; 3008 3009 //pragma(msg, entityName ~ " : " ~ ((hasHibernatedEmbeddableAnnotation!T) ? "true," : "false,")); 3010 3011 foreach (m; __traits(allMembers, T)) { 3012 //pragma(msg, m); 3013 3014 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 3015 3016 // skip non-public members 3017 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { 3018 3019 alias ti = typeof(__traits(getMember, T, m)); 3020 3021 // hasHibernatedPropertyAnnotation!(T, m) && 3022 // automatically treat all public members of supported types as persistent 3023 immutable bool typeSupported = (isSupportedSimpleType!(T, m) || isObjectMember!(T, m) || isCollectionMember!(T, m)); 3024 immutable bool isMainProp = isMainMemberForProperty!(T,m) && !hasMemberAnnotation!(T, m, Transient); 3025 //pragma( msg, entityName ~ ":" ~ tableName ~ "." ~ m ~ ": typeSupported: " ~ (typeSupported ? "true" : "false") ~ " isMainProp: " ~ (isMainProp ? "true" : "false") ) 3026 static if (typeSupported && isMainProp) { 3027 3028 immutable string propertyDef = getPropertyDef!(T, m)(); 3029 //pragma(msg, propertyDef); 3030 3031 if (generatedPropertyInfo != null) 3032 generatedPropertyInfo ~= ",\n"; 3033 generatedPropertyInfo ~= propertyDef; 3034 } 3035 } 3036 } 3037 } 3038 //pragma(msg, t); 3039 //pragma(msg, typeof(t)); 3040 3041 generatedEntityInfo ~= generatedPropertyInfo; 3042 generatedEntityInfo ~= "],"; 3043 generatedEntityInfo ~= "" ~ typeName ~ ".classinfo"; 3044 generatedEntityInfo ~= ")"; 3045 3046 //pragma(msg, "built entity : " ~ entityName); 3047 3048 return generatedEntityInfo ~ "\n" ~ generatedGettersSetters; 3049 } 3050 3051 template myPackageNamePrefix(alias T) 3052 { 3053 static if (is(typeof(__traits(parent, T)))) 3054 enum parent = myPackageNamePrefix!(__traits(parent, T)); 3055 else 3056 enum string parent = null; 3057 3058 static if (T.stringof.startsWith("package ")) 3059 enum myPackageNamePrefix = (parent ? parent ~ '.' : "") ~ T.stringof[8 .. $] ~ "."; 3060 else static if (parent) 3061 enum myPackageNamePrefix = parent; 3062 else 3063 enum myPackageNamePrefix = ""; 3064 } 3065 3066 string generateImportFor(T)() { 3067 static if (T.stringof.startsWith("module ")) { 3068 return "import " ~ fullyQualifiedName!T ~ ";\n"; 3069 } else { 3070 return "import " ~ myPackageNamePrefix!T ~ moduleName!T ~ ";\n"; 3071 } 3072 } 3073 3074 string entityListDef(T ...)() { 3075 string res; 3076 string imp; 3077 foreach(t; T) { 3078 string impcode = ""; 3079 static if (t.stringof.startsWith("module ")) { 3080 impcode = "import " ~ fullyQualifiedName!t ~ ";\n"; 3081 } else { 3082 impcode = generateImportFor!(t); 3083 } 3084 if (indexOf(imp, impcode) < 0) 3085 imp ~= impcode; 3086 } 3087 foreach(t; T) { 3088 //pragma(msg, t); 3089 static if (t.stringof.startsWith("module ")) { 3090 //pragma(msg, "is module"); 3091 //pragma(msg, "Module passed as schema parameter: " ~ t.stringof); 3092 //pragma(msg, __traits(allMembers, t)); 3093 foreach(tt; __traits(allMembers, t)) { 3094 //alias ti; 3095 //pragma(msg, "Module member: " ~ (__traits(getMember, t, tt)).stringof); 3096 static if (__traits(compiles, isImplicitlyConvertible!((__traits(getMember, t, tt)), Object)) && isImplicitlyConvertible!((__traits(getMember, t, tt)), Object)) { 3097 //pragma(msg, "checking member" ~ (__traits(getMember, t, tt)).stringof); 3098 // import class metadata if class or any of its members has hibenrated annotation 3099 static if (hasHibernatedClassOrPropertyAnnotation!(__traits(getMember, t, tt))) { 3100 // class should not be marked as @Transient 3101 static if (!hasAnnotation!(__traits(getMember, t, tt), Transient)) { 3102 immutable string def = getEntityDef!(__traits(getMember, t, tt)); 3103 if (res.length > 0) 3104 res ~= ",\n"; 3105 res ~= def; 3106 } 3107 } 3108 } 3109 } 3110 } else { 3111 //pragma(msg, "not module"); 3112 static if (__traits(compiles, isImplicitlyConvertible!(t, Object)) && isImplicitlyConvertible!(t, Object)) { 3113 3114 static assert(!hasAnnotation!(t, Transient), "Class " ~ t.stringof ~ " has @Transient annotation and cannot be used in metadata"); 3115 3116 // will be considered as @Entity if doesn't have @Embeddable annotation 3117 immutable string def = getEntityDef!t; 3118 3119 //pragma(msg, def); 3120 3121 if (res.length > 0) 3122 res ~= ",\n"; 3123 res ~= def; 3124 } else { 3125 static assert(t.stringof ~ " cannot be passed as schema item"); 3126 } 3127 } 3128 } 3129 string code = 3130 "shared static this() {\n" ~ 3131 imp ~ // imports 3132 " //writeln(\"starting static initializer\");\n" ~ 3133 " entities = [\n" ~ res ~ "];\n" ~ 3134 " EntityInfo [string] map;\n" ~ 3135 " EntityInfo [TypeInfo_Class] typemap;\n" ~ 3136 " foreach(e; entities) {\n" ~ 3137 " map[e.name] = e;\n" ~ 3138 " typemap[cast(TypeInfo_Class)e.classInfo] = e;\n" ~ 3139 " }\n" ~ 3140 " entityMap = map;\n" ~ 3141 " classMap = typemap;\n" ~ 3142 " //writeln(\"updating referenced entities\");\n" ~ 3143 " foreach(e; entities) {\n" ~ 3144 " //writefln( \"Entity:%s table:%s type:%s\", e.name, e.tableName, e.classInfo.name );\n" ~ 3145 " foreach(p; e._properties) {\n" ~ 3146 " //writefln( \"\tproperty:%s column:%s ref-entityname:%s ref-propertyname:%s \", p.propertyName, p.columnName, p.referencedEntityName, p.referencedPropertyName );\n" ~ 3147 " if (p.referencedEntityName !is null) {\n" ~ 3148 " //writeln(\"embedded entity \" ~ p.referencedEntityName);\n" ~ 3149 " enforceHelper!MappingException((p.referencedEntityName in map) !is null, \"referenced entity not found in schema: \" ~ p.referencedEntityName);\n" ~ 3150 " p._referencedEntity = map[p.referencedEntityName];\n" ~ 3151 " if (p.referencedPropertyName !is null) {\n" ~ 3152 " //writeln(\"\t\tembedded entity property name \" ~ p.referencedPropertyName );\n" ~ 3153 " //writefln(\"\t\tembedded entity._propertyMap: %s \", p._referencedEntity._propertyMap );\n" ~ 3154 " enforceHelper!MappingException((p.referencedPropertyName in p._referencedEntity._propertyMap) !is null, \"embedded entity property not found in schema: \" ~ p.referencedEntityName);\n" ~ 3155 " p._referencedProperty = p._referencedEntity._propertyMap[p.referencedPropertyName];\n" ~ 3156 " }\n" ~ 3157 " }\n" ~ 3158 " }\n" ~ 3159 " }\n" ~ 3160 " //writeln(\"finished static initializer\");\n" ~ 3161 "}"; 3162 //pragma(msg, "built entity list"); 3163 return code; 3164 } 3165 3166 abstract class SchemaInfo : EntityMetaData { 3167 3168 override @property size_t length() const { 3169 return getEntityCount(); 3170 } 3171 override const(EntityInfo) opIndex(int index) const { 3172 return getEntity(index); 3173 } 3174 override const(EntityInfo) opIndex(string entityName) const { 3175 return findEntity(entityName); 3176 } 3177 3178 override const(PropertyInfo) opIndex(string entityName, string propertyName) const { 3179 return findEntity(entityName).findProperty(propertyName); 3180 } 3181 3182 override public Variant getPropertyValue(Object obj, string propertyName) const { 3183 return findEntityForObject(obj).getPropertyValue(obj, propertyName); 3184 } 3185 3186 override public void setPropertyValue(Object obj, string propertyName, Variant value) const { 3187 findEntityForObject(obj).setPropertyValue(obj, propertyName, value); 3188 } 3189 3190 private void appendCommaDelimitedList(ref string buf, string data) const { 3191 if (buf.length != 0) 3192 buf ~= ", "; 3193 buf ~= data; 3194 } 3195 3196 public string getAllFieldListForUpdate(Dialect dialect, const EntityInfo ei, bool exceptKey = false) const { 3197 string query; 3198 foreach(pi; ei) { 3199 if (pi.key && exceptKey) 3200 continue; 3201 if (pi.embedded) { 3202 auto emei = pi.referencedEntity; 3203 appendCommaDelimitedList(query, getAllFieldListForUpdate(dialect, emei, exceptKey)); 3204 } else if (pi.oneToOne || pi.manyToOne) { 3205 if (pi.columnName != null) { 3206 // read FK column 3207 appendCommaDelimitedList(query, dialect.quoteIfNeeded(pi.columnName) ~ "=?"); 3208 } 3209 } else if (pi.oneToMany || pi.manyToMany) { 3210 // skip 3211 } else { 3212 appendCommaDelimitedList(query, dialect.quoteIfNeeded(pi.columnName) ~ "=?"); 3213 } 3214 } 3215 return query; 3216 } 3217 3218 override public string getAllFieldList(Dialect dialect, const EntityInfo ei, bool exceptKey = false) const { 3219 string query; 3220 foreach(pi; ei) { 3221 if (pi.key && exceptKey) 3222 continue; 3223 if (pi.embedded) { 3224 auto emei = pi.referencedEntity; 3225 appendCommaDelimitedList(query, getAllFieldList(dialect, emei, exceptKey)); 3226 } else if (pi.oneToOne || pi.manyToOne) { 3227 if (pi.columnName != null) { 3228 // read FK column 3229 appendCommaDelimitedList(query, dialect.quoteIfNeeded(pi.columnName)); 3230 } 3231 } else if (pi.oneToMany || pi.manyToMany) { 3232 // skip 3233 } else { 3234 appendCommaDelimitedList(query, dialect.quoteIfNeeded(pi.columnName)); 3235 } 3236 } 3237 return query; 3238 } 3239 3240 override public int getFieldCount(const EntityInfo ei, bool exceptKey) const { 3241 int count = 0; 3242 foreach(pi; ei) { 3243 if (pi.key && exceptKey) 3244 continue; 3245 if (pi.embedded) { 3246 auto emei = pi.referencedEntity; 3247 count += getFieldCount(emei, exceptKey); 3248 } else if (pi.oneToOne || pi.manyToOne) { 3249 if (pi.columnName != null) { 3250 // read FK column 3251 count++; 3252 } 3253 } else if (pi.oneToMany || pi.manyToMany) { 3254 // skip 3255 } else { 3256 count++; 3257 } 3258 } 3259 return count; 3260 } 3261 3262 public string getAllFieldPlaceholderList(const EntityInfo ei, bool exceptKey = false) const { 3263 string query; 3264 foreach(pi; ei) { 3265 if (pi.key && exceptKey) 3266 continue; 3267 if (pi.embedded) { 3268 auto emei = pi.referencedEntity; 3269 appendCommaDelimitedList(query, getAllFieldPlaceholderList(emei)); 3270 } else if (pi.oneToOne || pi.manyToOne) { 3271 if (pi.columnName != null) { 3272 // read FK column 3273 appendCommaDelimitedList(query, "?"); 3274 } 3275 } else if (pi.oneToMany || pi.manyToMany) { 3276 // skip 3277 } else { 3278 appendCommaDelimitedList(query, "?"); 3279 } 3280 } 3281 return query; 3282 } 3283 3284 override public string getAllFieldList(Dialect dialect, string entityName, bool exceptKey) const { 3285 return getAllFieldList(dialect, findEntity(entityName), exceptKey); 3286 } 3287 3288 override public int readAllColumns(Object obj, DataSetReader r, int startColumn) const { 3289 auto ei = findEntityForObject(obj); 3290 int columnCount = 0; 3291 foreach(pi; ei) { 3292 if (pi.embedded) { 3293 auto emei = pi.referencedEntity; 3294 Object em = emei.createEntity(); 3295 int columnsRead = readAllColumns(em, r, startColumn + columnCount); 3296 pi.setObjectFunc(obj, em); 3297 columnCount += columnsRead; 3298 } else if (pi.oneToOne || pi.manyToOne) { 3299 if (pi.columnName !is null) { 3300 Variant fk = r.getVariant(startColumn + columnCount); 3301 // TODO: use FK 3302 columnCount++; 3303 } else { 3304 // TODO: plan reading 3305 } 3306 } else if (pi.oneToMany || pi.manyToMany) { 3307 // skip 3308 } else { 3309 pi.readFunc(obj, r, startColumn + columnCount); 3310 columnCount++; 3311 } 3312 } 3313 return columnCount; 3314 } 3315 3316 override public int writeAllColumns(Object obj, DataSetWriter w, int startColumn, bool exceptKey = false) const { 3317 auto ei = findEntityForObject(obj); 3318 //writeln(ei.name ~ ".writeAllColumns"); 3319 int columnCount = 0; 3320 foreach(pi; ei) { 3321 if (pi.key && exceptKey) 3322 continue; 3323 if (pi.embedded) { 3324 auto emei = pi.referencedEntity; 3325 //writeln("getting embedded entity " ~ emei.name); 3326 assert(pi.getObjectFunc !is null, "No getObjectFunc defined for embedded entity " ~ emei.name); 3327 Object em = pi.getObjectFunc(obj); 3328 if (em is null) 3329 em = emei.createEntity(); 3330 assert(em !is null, "embedded object is null"); 3331 //writeln("writing embedded entity " ~ emei.name); 3332 int columnsWritten = writeAllColumns(em, w, startColumn + columnCount); 3333 //writeln("written"); 3334 columnCount += columnsWritten; 3335 } else if (pi.oneToOne || pi.manyToOne) { 3336 if (pi.columnName !is null) { 3337 Object objFunc = pi.getObjectFunc(obj); 3338 if (objFunc is null) { 3339 w.setNull(startColumn + columnCount); 3340 } else { 3341 //writeln("setting ID column for property " ~ pi.entity.name ~ "." ~ pi.propertyName); 3342 //if (pi.lazyLoad) 3343 // writeln("property has lazy loader"); 3344 //writeln("reading ID variant " ~ pi.propertyName ~ " from object"); 3345 Variant id = pi.referencedEntity.getKey(objFunc); 3346 //writeln("setting parameter " ~ to!string(startColumn + columnCount)); 3347 w.setVariant(startColumn + columnCount, id); 3348 } 3349 columnCount++; 3350 } 3351 // skip 3352 } else if (pi.oneToMany || pi.manyToMany) { 3353 // skip 3354 } else { 3355 pi.writeFunc(obj, w, startColumn + columnCount); 3356 columnCount++; 3357 } 3358 } 3359 return columnCount; 3360 } 3361 3362 override public string generateFindAllForEntity(Dialect dialect, string entityName) const { 3363 auto ei = findEntity(entityName); 3364 return "SELECT " ~ getAllFieldList(dialect, ei) ~ " FROM " ~ dialect.quoteIfNeeded(ei.tableName); 3365 } 3366 3367 override public string generateFindByPkForEntity(Dialect dialect, const EntityInfo ei) const { 3368 return "SELECT " ~ getAllFieldList(dialect, ei) ~ " FROM " ~ dialect.quoteIfNeeded(ei.tableName) ~ " WHERE " ~ dialect.quoteIfNeeded(ei.keyProperty.columnName) ~ " = ?"; 3369 } 3370 3371 override public string generateInsertAllFieldsForEntity(Dialect dialect, const EntityInfo ei) const { 3372 return "INSERT INTO " ~ dialect.quoteIfNeeded(ei.tableName) ~ "(" ~ getAllFieldList(dialect, ei) ~ ") VALUES (" ~ getAllFieldPlaceholderList(ei) ~ ")"; 3373 } 3374 3375 override public string generateInsertNoKeyForEntity(Dialect dialect, const EntityInfo ei) const { 3376 return "INSERT INTO " ~ dialect.quoteIfNeeded(ei.tableName) ~ "(" ~ getAllFieldList(dialect, ei, true) ~ ") VALUES (" ~ getAllFieldPlaceholderList(ei, true) ~ ")"; 3377 } 3378 3379 override public string generateUpdateForEntity(Dialect dialect, const EntityInfo ei) const { 3380 return "UPDATE " ~ dialect.quoteIfNeeded(ei.tableName) ~ " SET " ~ getAllFieldListForUpdate(dialect, ei, true) ~ " WHERE " ~ dialect.quoteIfNeeded(ei.getKeyProperty().columnName) ~ "=?"; 3381 } 3382 3383 override public string generateFindByPkForEntity(Dialect dialect, string entityName) const { 3384 return generateFindByPkForEntity(dialect, findEntity(entityName)); 3385 } 3386 3387 override public string generateInsertAllFieldsForEntity(Dialect dialect, string entityName) const { 3388 return generateInsertAllFieldsForEntity(dialect, findEntity(entityName)); 3389 } 3390 } 3391 3392 class SchemaInfoImpl(T...) : SchemaInfo { 3393 __gshared EntityInfo [string] entityMap; 3394 __gshared EntityInfo [] entities; 3395 __gshared EntityInfo [TypeInfo_Class] classMap; 3396 3397 //import htestmain; 3398 //pragma(msg, entityListDef!(T)()); 3399 mixin(entityListDef!(T)()); 3400 3401 override public int getEntityCount() const { return cast(int)entities.length; } 3402 3403 override public const(EntityInfo[]) getEntities() const { return entities; } 3404 override public const(EntityInfo[string]) getEntityMap() const { return entityMap; } 3405 override public const(EntityInfo [TypeInfo_Class]) getClassMap() const { return classMap; } 3406 3407 override int opApply(int delegate(ref const EntityInfo) dg) const { 3408 int result = 0; 3409 for (int i = 0; i < entities.length; i++) { 3410 result = dg(entities[i]); 3411 if (result) break; 3412 } 3413 return result; 3414 } 3415 3416 override public const(EntityInfo) findEntity(string entityName) const { 3417 enforceHelper!MappingException((entityName in entityMap) !is null, "Cannot find entity by name " ~ entityName); 3418 return entityMap[entityName]; 3419 } 3420 3421 override public const(EntityInfo) findEntity(TypeInfo_Class entityClass) const { 3422 enforceHelper!MappingException((entityClass in classMap) !is null, "Cannot find entity by class " ~ entityClass.toString()); 3423 return classMap[entityClass]; 3424 } 3425 3426 override public const(EntityInfo) getEntity(int entityIndex) const { 3427 enforceHelper!MappingException(entityIndex >= 0 && entityIndex < entities.length, "Invalid entity index " ~ to!string(entityIndex)); 3428 return entities[entityIndex]; 3429 } 3430 3431 override public Object createEntity(string entityName) const { 3432 enforceHelper!MappingException((entityName in entityMap) !is null, "Cannot find entity by name " ~ entityName); 3433 return entityMap[entityName].createEntity(); 3434 } 3435 3436 override public const(EntityInfo) findEntityForObject(Object obj) const { 3437 enforceHelper!MappingException((obj.classinfo in classMap) !is null, "Cannot find entity by class " ~ obj.classinfo.toString()); 3438 return classMap[obj.classinfo]; 3439 } 3440 this() { 3441 // update entity._metadata reference 3442 foreach(e; entities) { 3443 e._metadata = this; 3444 int columnOffset = 0; 3445 foreach(p; e._properties) { 3446 if (p.manyToMany) { 3447 p.updateJoinTable(); 3448 } 3449 p._columnOffset = columnOffset; 3450 if (p.embedded) { 3451 auto emei = p.referencedEntity; 3452 columnOffset += e.metadata.getFieldCount(emei, false); 3453 } else if (p.oneToOne || p.manyToOne) { 3454 if (p.columnName != null) { 3455 // read FK column 3456 columnOffset++; 3457 } 3458 } else if( p.manyToMany || p.oneToMany ) { 3459 //manyToMany and oneToMany do NOT have a column in the table. 3460 } else { 3461 columnOffset++; 3462 } 3463 } 3464 } 3465 } 3466 } 3467 3468 /// information about DB structure generated from HibernateD entity metadata 3469 class DBInfo { 3470 Dialect dialect; 3471 EntityMetaData metaData; 3472 bool hasCircularRefs; 3473 3474 this(Dialect dialect, EntityMetaData metaData) { 3475 this.dialect = dialect; 3476 this.metaData = metaData; 3477 3478 foreach(entity; metaData) { 3479 if (!entity.embeddable) 3480 add(new TableInfo(this, entity)); 3481 } 3482 sortTables(); 3483 } 3484 3485 TableInfo[] tables; 3486 TableInfo[string] tableNameMap; 3487 TableInfo get(string tableName) { 3488 TableInfo res = find(tableName); 3489 enforceHelper!HibernatedException(res !is null, "table " ~ tableName ~ " is not found in schema"); 3490 return res; 3491 } 3492 TableInfo find(string tableName) { 3493 if ((tableName in tableNameMap) is null) 3494 return null; 3495 return tableNameMap[tableName]; 3496 } 3497 void add(TableInfo table) { 3498 enforceHelper!HibernatedException((table.tableName in tableNameMap) is null, "duplicate table " ~ table.tableName ~ " in schema"); 3499 tables ~= table; 3500 tableNameMap[table.tableName] = table; 3501 } 3502 private static bool[string] arrayToMap(string[] keys) { 3503 bool[string] res; 3504 if (keys !is null) { 3505 foreach(key; keys) 3506 res[key] = true; 3507 } 3508 return res; 3509 } 3510 3511 /// drop and/or create tables and indexes in DB using specified connection 3512 void updateDBSchema(Connection conn, bool dropTables, bool createTables) { 3513 assert(dropTables || createTables); 3514 string[] existingTables = getExistingTables(conn); 3515 string[] batch; 3516 if (dropTables) 3517 batch ~= getDropTableSQL(existingTables); 3518 if (createTables) 3519 batch ~= getCreateTableSQL(dropTables ? null : existingTables); 3520 try { 3521 Statement stmt = conn.createStatement(); 3522 scope(exit) stmt.close(); 3523 foreach(sql; batch) { 3524 stmt.executeUpdate(sql); 3525 } 3526 } catch (Throwable e) { 3527 throw new HibernatedException(e); 3528 } 3529 } 3530 3531 string[] getExistingTables(Connection conn) { 3532 string[] res; 3533 try { 3534 Statement stmt = conn.createStatement(); 3535 scope(exit) stmt.close(); 3536 foreach(table; tables) { 3537 string sql = dialect.getCheckTableExistsSQL(table.tableName); 3538 ResultSet rs = stmt.executeQuery(sql); 3539 scope(exit)rs.close(); 3540 if (rs.next()) 3541 res ~= table.tableName; 3542 } 3543 } catch (Throwable e) { 3544 throw new HibernatedException(e); 3545 } 3546 return res; 3547 } 3548 string[] getCreateTableSQL(string[] existingTables = null) { 3549 auto map = arrayToMap(existingTables); 3550 string[] res; 3551 foreach(table; tables) { 3552 if (existingTables is null || (table.tableName in map) is null) 3553 res ~= table.getCreateTableSQL(); 3554 } 3555 return res; 3556 } 3557 string[] getCreateIndexSQL(string[] existingTables = null) { 3558 auto map = arrayToMap(existingTables); 3559 string[] res; 3560 foreach(table; tables) { 3561 if (existingTables is null || (table.tableName in map) is null) 3562 res ~= table.getCreateIndexSQL(); 3563 } 3564 return res; 3565 } 3566 string[] getDropTableSQL(string[] existingTables = null) { 3567 auto map = arrayToMap(existingTables); 3568 string[] res; 3569 foreach(table; tables) { 3570 if (existingTables is null || (table.tableName in map) !is null) { 3571 if (hasCircularRefs) 3572 res ~= table.getDropIndexSQL(); 3573 res ~= table.getDropTableSQL(); 3574 } 3575 } 3576 return res; 3577 } 3578 TableInfo opIndex(string tableName) { 3579 TableInfo ti = find(tableName); 3580 enforceHelper!HibernatedException(ti !is null, "Table " ~ tableName ~ " is not found in schema"); 3581 return ti; 3582 } 3583 private static TableInfo[] addTableSorted(TableInfo[] list, TableInfo table) { 3584 TableInfo[] head; 3585 TableInfo[] tail; 3586 if (list.length == 0) { 3587 // trivial 3588 return [table]; 3589 } else { 3590 foreach(ti; list) { 3591 if (ti.references(table)) 3592 tail ~= ti; 3593 else 3594 head ~= ti; 3595 } 3596 return head ~ [table] ~ tail; 3597 } 3598 } 3599 private void sortTables() { 3600 TableInfo[] list; 3601 foreach(table; tables) { 3602 list = addTableSorted(list, table); 3603 } 3604 tables = list; 3605 hasCircularRefs = hasCircularReferences(); 3606 if (hasCircularRefs) { 3607 warning("has circular references"); 3608 } 3609 } 3610 private bool hasCircularReferences() { 3611 for (int i=0; i<tables.length; i++) 3612 for (int j=i + 1; j<tables.length; j++) 3613 if (tables[i].references(tables[j])) 3614 return true; 3615 return false; 3616 } 3617 } 3618 3619 /// information about table in DB 3620 class TableInfo { 3621 DBInfo schema; 3622 string tableName; 3623 const EntityInfo entity; 3624 const EntityInfo entity2; 3625 ColumnInfo[] columns; 3626 ColumnInfo[string] columnNameMap; 3627 IndexInfo[] indexes; 3628 const string pkDef; 3629 3630 this(DBInfo schema, const EntityInfo entity, const EntityInfo entity2, const JoinTableInfo joinTable) { 3631 this.schema = schema; 3632 this.tableName = joinTable.tableName; 3633 this.entity = entity; 3634 this.entity2 = entity; 3635 ColumnInfo c1; 3636 ColumnInfo c2; 3637 assert(joinTable.column1 !is null); 3638 assert(joinTable.column2 !is null); 3639 assert(entity !is null); 3640 assert(entity2 !is null); 3641 assert(joinTable.thisEntity !is null); 3642 assert(joinTable.otherEntity !is null); 3643 if (joinTable.column1 < joinTable.column2) { 3644 c1 = new ColumnInfo(this, joinTable.column1, entity); 3645 c2 = new ColumnInfo(this, joinTable.column2, entity2); 3646 } else { 3647 c2 = new ColumnInfo(this, joinTable.column1, entity); 3648 c1 = new ColumnInfo(this, joinTable.column2, entity2); 3649 } 3650 addColumn(c1); 3651 addColumn(c2); 3652 pkDef = "PRIMARY KEY (" ~ schema.dialect.quoteIfNeeded(c1.columnName) ~ ", " ~ schema.dialect.quoteIfNeeded(c2.columnName) ~ "), " ~ 3653 schema.dialect.getUniqueIndexItemSQL(tableName ~ "_reverse_index", [c2.columnName, c1.columnName]); 3654 addForeignKey(tableName, entity, joinTable.column1, null); 3655 addForeignKey(tableName, entity2, joinTable.column2, null); 3656 } 3657 3658 ColumnInfo opIndex(string columnName) { 3659 ColumnInfo ti = find(columnName); 3660 enforceHelper!HibernatedException(ti !is null, "Column " ~ columnName ~ " is not found in table " ~ tableName); 3661 return ti; 3662 } 3663 3664 ColumnInfo find(string columnName) { 3665 if ((columnName in columnNameMap) is null) 3666 return null; 3667 return columnNameMap[columnName]; 3668 } 3669 3670 private void appendColumns(const EntityInfo entity) { 3671 foreach(pi; entity) { 3672 if (pi.embedded) { 3673 appendColumns(pi.referencedEntity); 3674 } else if (pi.simple || (pi.columnName !is null)) { 3675 addColumn(new ColumnInfo(this, pi)); 3676 if (pi.simple && pi.uniqueIndex !is null) //pi.unique) 3677 addUniqueColumnIndex(pi); 3678 } else if (pi.manyToMany) { 3679 addJoinTable(pi); 3680 } 3681 } 3682 } 3683 this(DBInfo schema, const EntityInfo entity) { 3684 this.schema = schema; 3685 this.entity = entity; 3686 this.entity2 = null; 3687 this.tableName = entity.tableName; 3688 this.pkDef = null; 3689 appendColumns(entity); 3690 } 3691 void addJoinTable(const PropertyInfo pi) { 3692 assert(pi.referencedEntity !is null); 3693 assert(pi.joinTable !is null); 3694 TableInfo t = new TableInfo(schema, entity, pi.referencedEntity, pi.joinTable); 3695 TableInfo existing = schema.find(t.tableName); 3696 if (existing !is null) { 3697 enforceHelper!HibernatedException(t.getCreateTableSQL() == existing.getCreateTableSQL(), "JoinTable structure in " ~ entity.name ~ " and " ~ pi.referencedEntityName ~ " do not match"); 3698 } else { 3699 schema.add(t); 3700 } 3701 } 3702 void addUniqueColumnIndex(const PropertyInfo pi) { 3703 assert(pi.columnName !is null); 3704 IndexInfo index = new IndexInfo(this, IndexType.Unique); 3705 index.indexName = pi.uniqueIndex; 3706 index.columnNames ~= pi.columnName; 3707 addIndex(index); 3708 } 3709 void addForeignKey(string thisTable, const EntityInfo otherEntity, string columnName, string uniqueIndex) { 3710 IndexInfo index = new IndexInfo(this, uniqueIndex is null ? IndexType.ForeignKey : IndexType.UniqueForeignKey); 3711 index.indexName = thisTable ~ "_" ~ columnName ~ "_index"; 3712 index.columnNames ~= columnName; 3713 index.referencedTable = otherEntity.tableName; 3714 index.referencedColumnNames ~= otherEntity.getKeyProperty().columnName; 3715 addIndex(index); 3716 } 3717 void addForeignKey(const PropertyInfo pi) { 3718 assert(pi.columnName !is null); 3719 assert(pi.manyToOne || pi.oneToOne); 3720 addForeignKey(pi.entity.tableName, pi.referencedEntity, pi.columnName, pi.uniqueIndex); 3721 } 3722 private void addIndex(IndexInfo index) { 3723 // TODO: check duplicates 3724 indexes ~= index; 3725 } 3726 void addColumn(ColumnInfo column) { 3727 enforceHelper!HibernatedException((column.columnName in columnNameMap) is null, "duplicate column name " ~ tableName ~ "." ~ column.columnName ~ " in schema"); 3728 columns ~= column; 3729 columnNameMap[column.columnName] = column; 3730 if (column.property !is null && (column.property.manyToOne || column.property.oneToOne)) { 3731 addForeignKey(column.property); 3732 } 3733 } 3734 string getCreateTableSQL() { 3735 string res; 3736 foreach(col; columns) { 3737 if (res.length > 0) 3738 res ~= ", "; 3739 res ~= col.columnDefinition; 3740 } 3741 if (pkDef !is null) 3742 res ~= ", " ~ pkDef; 3743 return "CREATE TABLE " ~ schema.dialect.quoteIfNeeded(tableName) ~ " (" ~ res ~ ")"; 3744 } 3745 string getDropTableSQL() { 3746 return "DROP TABLE IF EXISTS " ~ schema.dialect.quoteIfNeeded(tableName); 3747 } 3748 string[] getDropIndexSQL() { 3749 string[] res; 3750 foreach(index; indexes) { 3751 if (index.type == IndexType.ForeignKey || index.type == IndexType.UniqueForeignKey) { 3752 res ~= index.getDropIndexSQL(); 3753 } 3754 } 3755 return res; 3756 } 3757 string[] getCreateIndexSQL() { 3758 string[] res; 3759 foreach(index; indexes) { 3760 res ~= index.getCreateIndexSQL(); 3761 } 3762 return res; 3763 } 3764 bool references(ref bool[string] visitedTables, TableInfo other) { 3765 visitedTables[tableName] = true; 3766 foreach(index; indexes) { 3767 if (index.type == IndexType.ForeignKey || index.type == IndexType.UniqueForeignKey) { 3768 if (index.referencedTable == other.tableName) 3769 return true; 3770 if ((index.referencedTable in visitedTables) is null) { 3771 // not yet visited 3772 TableInfo t = schema.find(index.referencedTable); 3773 enforceHelper!HibernatedException(t !is null, "Table " ~ index.referencedTable ~ " referenced in index " ~ index.indexName ~ " is not found in schema"); 3774 if (t.references(visitedTables, other)) 3775 return true; 3776 } 3777 } 3778 } 3779 return false; 3780 } 3781 bool references(TableInfo other) { 3782 bool[string] visitedTables; 3783 return references(visitedTables, other); 3784 } 3785 } 3786 3787 class ColumnInfo { 3788 TableInfo table; 3789 const PropertyInfo property; 3790 string columnName; 3791 string columnDefinition; 3792 this(TableInfo table, string columnName, const EntityInfo referencedEntity) { 3793 this.table = table; 3794 this.property = null; 3795 this.columnName = columnName; 3796 this.columnDefinition = table.schema.dialect.quoteIfNeeded(columnName) ~ " " ~ 3797 table.schema.dialect.getColumnTypeDefinition(null, referencedEntity.getKeyProperty()); 3798 } 3799 this(TableInfo table, const PropertyInfo property) { 3800 this.table = table; 3801 this.property = property; 3802 this.columnName = property.columnName; 3803 assert(columnName !is null); 3804 if (property.manyToOne || property.oneToOne) { 3805 assert(property.columnName !is null); 3806 assert(property.referencedEntity !is null); 3807 this.columnDefinition = table.schema.dialect.quoteIfNeeded(property.columnName) ~ " " ~ table.schema.dialect.getColumnTypeDefinition(property, property.referencedEntity.getKeyProperty()); 3808 } else { 3809 this.columnDefinition = table.schema.dialect.getColumnDefinition(property); 3810 } 3811 } 3812 } 3813 3814 enum IndexType { 3815 Index, 3816 Unique, 3817 ForeignKey, 3818 UniqueForeignKey 3819 } 3820 3821 class IndexInfo { 3822 TableInfo table; 3823 IndexType type; 3824 string indexName; 3825 string[] columnNames; 3826 string referencedTable; 3827 string[] referencedColumnNames; 3828 this(TableInfo table, IndexType type) { 3829 this.table = table; 3830 this.type = type; 3831 } 3832 string[] getDropIndexSQL() { 3833 final switch(type) { 3834 case IndexType.Unique: 3835 case IndexType.Index: 3836 return [table.schema.dialect.getDropIndexSQL(table.tableName, indexName)]; 3837 case IndexType.ForeignKey: 3838 case IndexType.UniqueForeignKey: 3839 return [table.schema.dialect.getDropForeignKeySQL(table.tableName, indexName), 3840 table.schema.dialect.getDropIndexSQL(table.tableName, indexName)]; 3841 } 3842 } 3843 string[] getCreateIndexSQL() { 3844 final switch(type) { 3845 case IndexType.Unique: 3846 return [table.schema.dialect.getUniqueIndexSQL(table.tableName, indexName, columnNames)]; 3847 case IndexType.Index: 3848 return [table.schema.dialect.getIndexSQL(table.tableName, indexName, columnNames)]; 3849 case IndexType.ForeignKey: 3850 return [table.schema.dialect.getForeignKeySQL(table.tableName, indexName, columnNames, referencedTable, referencedColumnNames)]; 3851 case IndexType.UniqueForeignKey: 3852 return [table.schema.dialect.getUniqueIndexSQL(table.tableName, indexName, columnNames), 3853 table.schema.dialect.getForeignKeySQL(table.tableName, indexName, columnNames, referencedTable, referencedColumnNames)]; 3854 } 3855 } 3856 } 3857 3858 unittest { 3859 3860 @Entity 3861 @Table("users") 3862 static class User { 3863 3864 //@Id @Generated 3865 @Column("id_column") 3866 int id; 3867 3868 @Column("name_column") 3869 string name; 3870 3871 // no column name 3872 //@Column 3873 string flags; 3874 3875 // annotated getter 3876 private string login; 3877 //@Column 3878 public string getLogin() { return login; } 3879 public void setLogin(string login) { this.login = login; } 3880 3881 // no (), no column name 3882 //@Column 3883 int testColumn; 3884 } 3885 3886 3887 @Entity 3888 @Table("customer") 3889 static class Customer { 3890 //@Id @Generated 3891 //@Column 3892 int id; 3893 //@Column 3894 string name; 3895 } 3896 3897 3898 EntityInfo entity = new EntityInfo("user", "users", false, [ 3899 new PropertyInfo("id", "id", new NumberType(10,false,SqlType.INTEGER), 0, true, true, false, null, RelationType.None, null, null, null, null, null, null, null, null, null) 3900 ], null); 3901 3902 assert(entity.properties.length == 1); 3903 3904 3905 // immutable string info = getEntityDef!User(); 3906 // immutable string infos = entityListDef!(User, Customer)(); 3907 3908 EntityInfo ei = new EntityInfo("User", "users", false, [ 3909 new PropertyInfo("id", "id_column", new NumberType(10,false,SqlType.INTEGER), 0, true, true, false, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3910 new PropertyInfo("name", "name_column", new StringType(), 0, false, false, false, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3911 new PropertyInfo("flags", "flags", new StringType(), 0, false, false, true, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3912 new PropertyInfo("login", "login", new StringType(), 0, false, false, true, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3913 new PropertyInfo("testColumn", "testcolumn", new NumberType(10,false,SqlType.INTEGER), 0, false, false, true, null, RelationType.None, null, null, null, null, null, null, null, null, null)], null); 3914 3915 //void function(User, DataSetReader, int) readFunc = function(User entity, DataSetReader reader, int index) { }; 3916 3917 assert(ei.findProperty("name").columnName == "name_column"); 3918 assert(ei.getProperties()[0].columnName == "id_column"); 3919 assert(ei.getProperty(2).propertyName == "flags"); 3920 assert(ei.getPropertyCount == 5); 3921 3922 EntityInfo[] entities3 = [ 3923 new EntityInfo("User", "users", false, [ 3924 new PropertyInfo("id", "id_column", new NumberType(10,false,SqlType.INTEGER), 0, true, true, false, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3925 new PropertyInfo("name", "name_column", new StringType(), 0, false, false, false, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3926 new PropertyInfo("flags", "flags", new StringType(), 0, false, false, true, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3927 new PropertyInfo("login", "login", new StringType(), 0, false, false, true, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3928 new PropertyInfo("testColumn", "testcolumn", new NumberType(10,false,SqlType.INTEGER), 0, false, false, true, null, RelationType.None, null, null, null, null, null, null, null, null, null)], null) 3929 , 3930 new EntityInfo("Customer", "customer", false, [ 3931 new PropertyInfo("id", "id", new NumberType(10,false,SqlType.INTEGER), 0, true, true, true, null, RelationType.None, null, null, null, null, null, null, null, null, null), 3932 new PropertyInfo("name", "name", new StringType(), 0, false, false, true, null, RelationType.None, null, null, null, null, null, null, null, null, null)], null) 3933 ]; 3934 3935 3936 } 3937 3938