1 /**
2 Contains several attributes used in SQL databases.
3 */
4 module ezdb.entity;
5 
6 import std.traits;
7 import std.typecons;
8 
9 /**
10 Defines the primary key of an entity.
11 */
12 enum primaryKey; // @suppress(dscanner.style.phobos_naming_convention)
13 
14 /**
15 Aliases to the type of the primary key of an entity.
16 */
17 template PrimaryKeyType(Type)
18 {
19     alias PrimaryKeyType = typeof(PrimaryKeySymbol!Type);
20 }
21 
22 /**
23 The `PrimaryKeyType` template returns the type of the primary key.
24 */
25 @("PrimaryKeyType returns correct primary key type")
26 @safe @nogc pure unittest
27 {
28     static struct MyEntity
29     {
30         @primaryKey
31         int a;
32 
33         int b;
34     }
35 
36     assert(is(PrimaryKeyType!MyEntity == int));
37 }
38 
39 /**
40 Aliases to the symbol that is the primary key of an entity.
41 */
42 template PrimaryKeySymbol(Type)
43 {
44     static if (getSymbolsByUDA!(Type, primaryKey).length == 1)
45     {
46         alias PrimaryKeySymbol = getSymbolsByUDA!(Type, primaryKey)[0];
47     }
48     else
49     {
50         static assert(false, "An entity should have exactly one @primaryKey");
51     }
52 }
53 
54 @("Cannot compile PrimaryKey with two primary keys")
55 @safe @nogc pure unittest
56 {
57     static struct MyEntity
58     {
59         @primaryKey
60         int id;
61 
62         @primaryKey
63         int secondId;
64     }
65 
66     assert(!__traits(compiles, PrimaryKeySymbol!MyEntity));
67 }
68 
69 @("Cannot compile PrimaryKey with no primary keys")
70 @safe @nogc pure unittest
71 {
72     static struct MyEntity
73     {
74     }
75 
76     assert(!__traits(compiles, PrimaryKeySymbol!MyEntity));
77 }
78 
79 /**
80 Gets a reference to the primary key of an entity.
81 */
82 ref auto getPrimaryKey(Entity)(Entity entity) // @suppress(dscanner.suspicious.unused_parameter)
83 {
84     return __traits(getMember, entity, getSymbolsByUDA!(typeof(entity), primaryKey)[0].stringof);
85 }
86 
87 /**
88 Sets the primary key of an entity.
89 */
90 void setPrimaryKey(Entity, Id = PrimaryKeyType!Entity)(ref Entity entity, Id key) // @suppress(dscanner.suspicious.unused_parameter)
91 {
92     __traits(getMember, entity, getSymbolsByUDA!(typeof(entity), primaryKey)[0].stringof) = key;
93 }