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