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