1 /**
2 * Copyright © DiamondMVC 2019
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.data.mapping.engines.mysql.mysqlmodel;
7 
8 import std.variant : Variant;
9 alias Column = Variant;
10 
11 import std.traits : hasUDA, isSomeString, OriginalType;
12 import std..string : format;
13 
14 import vibe.data.serialization : ignore;
15 
16 import diamond.data.mapping.engines.mysql.mysqladapter;
17 import diamond.data.mapping.engines.mysql.mysqlentityformatter;
18 import diamond.data.mapping.engines.mysql : dbConnectionString;
19 import diamond.data.mapping.attributes;
20 
21 import diamond.database;
22 
23 /// Interface for a mysql model.
24 interface IMySqlModel { }
25 
26 import diamond.data.mapping.model;
27 /**
28 * Creates a new mysql model.
29 *  Params:
30 *    tableName = The name of the table the model is associated with.
31 */
32 class MySqlModel(string tableName) : Model, IMySqlModel
33 {
34   import models;
35   import mysql;
36 
37   private:
38   /// The row.
39   Row _row;
40   /// The index.
41   size_t _index;
42 
43   public:
44   /// The name of the table associated with the mysql model.
45   @ignore static const string table = tableName;
46 
47   final
48   {
49     /// Creates a new mysql model.
50     this(this TModel)()
51     {
52       super();
53 
54       auto adapter = getMySqlAdapter!TModel;
55 
56       static const formatter = new MySqlEntityFormatter!TModel;
57 
58       auto model = cast(TModel)this;
59 
60       mixin("setReader(" ~ formatter.generateRead() ~ ");");
61       mixin("setInserter(" ~ formatter.generateInsert() ~ ");");
62       mixin("setUpdater(" ~ formatter.generateUpdate() ~ ");");
63       mixin("setDeleter(" ~ formatter.generateDelete() ~ ");");
64       mixin("setReaderRelationship(" ~ formatter.generateReadRelationship() ~ ");");
65     }
66 
67     /**
68     * Retrieves a value from the model's data.
69     * Returns:
70     *   The value.
71     */
72     T retrieve(T, bool nullable = false, bool isEnum = false)()
73     {
74       Column value = Column.init;
75 
76       static if (nullable && isEnum)
77       {
78         value = retrieveNullableEnumImpl();
79 
80         if (!value.hasValue)
81         {
82           value = T.init;
83         }
84         else
85         {
86           value = cast(T)value.get!(OriginalType!T);
87         }
88       }
89       else static if (isEnum)
90       {
91         value = cast(T)retrieveEnumImpl().get!(OriginalType!T);
92       }
93       else static if (nullable)
94       {
95         value = retrieveNullableImpl();
96 
97         if (!value.hasValue)
98         {
99           value = T.init;
100         }
101       }
102       else static if (is(T == bool))
103       {
104         value = retrieveBoolImpl();
105       }
106       else static if (isSomeString!T)
107       {
108         value = retrieveTextImpl();
109       }
110       else
111       {
112         value = retrieveDefaultImpl();
113       }
114 
115       moveToNextColumn();
116 
117       if (!value.hasValue)
118       {
119         return T.init;
120       }
121 
122       return value.get!T;
123     }
124 
125     @property
126     {
127       /// Gets the raw mysql row.
128       @ignore Row row() @system { return _row; }
129 
130       /// Sets the raw mysql row.
131       @ignore void row(Row newRow)  @system
132       {
133         _row = newRow;
134       }
135     }
136   }
137 
138   protected:
139   /// Moves to the next column.
140   void moveToNextColumn()
141   {
142     _index++;
143   }
144 
145   /// Retrieves a nullable enum value.
146   Variant retrieveNullableEnumImpl()
147   {
148     Variant value = void;
149 
150     if (_row.isNull(_index))
151     {
152       value = Variant.init;
153     }
154     else
155     {
156       value = _row[_index];
157     }
158 
159     return value;
160   }
161 
162   /// Retrieves an enum value.
163   Variant retrieveEnumImpl()
164   {
165     return _row[_index];
166   }
167 
168   /// Retrieves a nullable value.
169   Variant retrieveNullableImpl()
170   {
171     return retrieveNullableEnumImpl();
172   }
173 
174   /// Retrieves a boolean value.
175   bool retrieveBoolImpl()
176   {
177     return cast(bool)_row[_index].get!ubyte;
178   }
179 
180   /// Retrieves a text value.
181   string retrieveTextImpl()
182   {
183     return retrieveDefaultImpl().get!string;
184   }
185 
186   /// Retrieves any kind of value.
187   Variant retrieveDefaultImpl()
188   {
189     return _row[_index];
190   }
191 }