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 }