1 /**
2 * Copyright © DiamondMVC 2018
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.data.mapping.engines.mysql.model;
7 
8 import std.traits : hasUDA;
9 import std..string : format;
10 import std.datetime : Date, DateTime, Clock, SysTime;
11 
12 import vibe.data.serialization : ignore;
13 
14 import diamond.data.mapping.model;
15 import diamond.data.mapping.attributes;
16 import diamond.data.mapping.engines.mysql.generators;
17 import diamond.database : getParams, MySql;
18 
19 /// Base-interface for a mysql model.
20 interface IMySqlModel { }
21 
22 /**
23 * Converts a SysTime to a DateTime.
24 *	Params:
25 *		sysTime = The SysTime to convert.
26 *	Returns:
27 *		The converted DateTime.
28 */
29 private DateTime asDateTime(SysTime sysTime)
30 {
31 	return DateTime(sysTime.year, sysTime.month, sysTime.day, sysTime.hour, sysTime.minute, sysTime.second);
32 }
33 
34 /**
35 * Creates a new mysql model.
36 *	Params:
37 *		tableName = The name of the table the model is associated with.
38 */
39 class MySqlModel(string tableName) : Model, IMySqlModel
40 {
41   import mysql.result : Row;
42 
43   private
44   {
45 		/// The row.
46     Row _row;
47 		/// The index.
48     size_t _index;
49 
50 		/**
51 		* Retrieves a value from the row.
52 		*	Params:
53 		*		T =        The type.
54 		*		nullable = Boolean determining whether the value is nullable or not.
55 		*		isEnum = 	 Boolean determining whether the value is an enum or not.
56 		*		column = 	 The column index of the value.
57 		*	Returns:
58 		*		The value.
59 		*/
60     final T retrieve(T, bool nullable = false, bool isEnum = false)(size_t column) @system
61     {
62       import std.traits : OriginalType;
63 
64       static if (nullable && isEnum)
65       {
66         return cast(T)(_row.isNull(column) ? T.init : _row[column].get!(OriginalType!T));
67       }
68       else static if (isEnum)
69       {
70         return cast(T)(_row[column].get!(OriginalType!T));
71       }
72       else static if (nullable)
73       {
74         return _row.isNull(column) ? T.init : _row[column].get!T;
75       }
76 			else static if (is(T == bool))
77 			{
78 				return cast(bool)_row[column].get!ubyte;
79 			}
80       else
81       {
82         return _row[column].get!T;
83       }
84     }
85 
86 		/**
87 		* Retrieves a value from the row.
88 		*	Params:
89 		*		T =        The type.
90 		*		nullable = Boolean determining whether the value is nullable or not.
91 		*		isEnum = 	 Boolean determining whether the value is an enum or not.
92 		*	Returns:
93 		*		The value.
94 		*/
95     final T retrieve(T, bool nullable = false, bool isEnum = false)() @system
96     {
97       auto value = retrieve!(T, nullable, isEnum)(_index);
98       _index++;
99       return value;
100     }
101   }
102 
103   public:
104   final:
105 	/// The table name.
106   @ignore static const string table = tableName;
107 
108 	/// Creates a new database model.
109   this(this TModel)()
110   {
111     auto model = cast(TModel)this;
112 
113     enum readNullEnumFomat = "model.%s = retrieve!(%s, true, true);";
114     enum readNullFomat = "model.%s = retrieve!(%s, true, false);";
115     enum readEnumFomat = "model.%s = retrieve!(%s, false, true);";
116 		enum readBoolFormat = "model.%s = retrieve!(%s);";
117     enum readFomat = "model.%s = retrieve!(%s);";
118 
119     import models;
120     mixin
121 		(
122 			"super(%s, %s, %s, %s);".format
123 			(
124 				generateRead!TModel, generateInsert!TModel,
125 				generateUpdate!TModel, generateDelete!TModel
126 			)
127 		);
128   }
129 
130   @property
131   {
132 		/// Gets the raw row.
133     @ignore Row row() @system { return _row; }
134 
135 		/// Sets the native row. Settings this manually outside the engine is undefined-behavior.
136     @ignore void row(Row newRow)  @system
137     {
138       _row = newRow;
139     }
140   }
141 }