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