1 /** 2 Contains definitions and helper functions for foreign keys. 3 */ 4 module ezdb.foreign; 5 6 import ezdb.entity; 7 import std.traits; 8 import std.stdio; 9 version(unittest) import fluent.asserts; 10 11 /** 12 A UDA that will cause the property it is added to, to become a foreign key 13 contraint to said 14 15 that can be embedded in an entity which refers to another entity. 16 This type will automatically add a Foreign key constraint. 17 */ 18 struct foreign(Entity) // @suppress(dscanner.style.phobos_naming_convention) 19 { 20 /// The target entity. 21 Entity target_entity; 22 } 23 24 /** 25 `true` if the symbol is a foreign key, `false` if it isn't. 26 */ 27 template IsForeign(alias symbol) 28 { 29 alias IsForeign = hasUDA!(symbol, foreign); 30 } 31 32 @("IsForeign is true for foreign UDA") 33 unittest 34 { 35 static struct Entity 36 { 37 @primaryKey int id; 38 39 @foreign!Entity 40 int entity; 41 } 42 IsForeign!(Entity.entity).should.equal(true) 43 .because("Foreign is annotated with foreign"); 44 } 45 46 @("IsForeign is false for something without foreign UDA") 47 unittest 48 { 49 static struct Entity 50 { 51 @primaryKey int id; 52 53 @foreign!Entity 54 int entity; 55 } 56 IsForeign!(Entity.id).should.equal(false) 57 .because("Foreign is annotated with foreign"); 58 } 59 60 /** 61 Gets the type of entity the foreign key points to. 62 */ 63 template GetForeignEntity(alias symbol) 64 { 65 alias GetForeignEntity = GetForeignEntityOfUDA!(getUDAs!(symbol, foreign)); 66 } 67 68 private template GetForeignEntityOfUDA(alias foreignAttribute) 69 { 70 alias GetForeignEntityOfUDA = typeof(foreignAttribute.target_entity); 71 } 72 73 @("GetForeignEntity gets the foreign entity") 74 unittest 75 { 76 static struct Parent {} 77 78 static struct Entity 79 { 80 @primaryKey int id; 81 82 @foreign!Parent 83 int entity; 84 } 85 assert(is(GetForeignEntity!(Entity.entity) == Parent)); 86 }