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