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