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