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.mssql.mssqlmodel;
7 
8 import diamond.core.apptype;
9 
10 static if (hasMsSql)
11 {
12   import std.variant : Variant;
13   import std.traits : hasUDA, isSomeString, OriginalType;
14   import std..string : format;
15 
16   import vibe.data.serialization : ignore;
17 
18   import diamond.data.mapping.engines.mssql.mssqladapter;
19   import diamond.data.mapping.engines.mssql.mssqlentityformatter;
20   import diamond.data.mapping.engines.mssql : dbConnectionString;
21   import diamond.data.mapping.attributes;
22 
23   import diamond.database;
24 
25   /// Interface for a mssql model.
26   interface IMsSqlModel { }
27 
28   import diamond.data.mapping.model;
29   /**
30   * Creates a new mssql model.
31   *  Params:
32   *    tableName = The name of the table the model is associated with.
33   */
34   class MsSqlModel(string tableName) : Model, IMsSqlModel
35   {
36     import models;
37     import ddbc;
38 
39     private:
40     /// The row.
41     ResultSet _row;
42     /// The index.
43     size_t _index;
44 
45     public:
46     /// The name of the table associated with the mssql model.
47     @ignore static const string table = tableName;
48 
49     final
50     {
51       /// Creates a new mssql model.
52       this(this TModel)()
53       {
54         super();
55 
56         auto adapter = getMsSqlAdapter!TModel;
57 
58         static const formatter = new MsSqlEntityFormatter!TModel;
59 
60         auto model = cast(TModel)this;
61 
62         mixin("setReader(" ~ formatter.generateRead() ~ ");");
63         mixin("setInserter(" ~ formatter.generateInsert() ~ ");");
64         mixin("setUpdater(" ~ formatter.generateUpdate() ~ ");");
65         mixin("setDeleter(" ~ formatter.generateDelete() ~ ");");
66         mixin("setReaderRelationship(" ~ formatter.generateReadRelationship() ~ ");");
67       }
68 
69       /**
70       * Retrieves a value from the model's data.
71       * Returns:
72       *   The value.
73       */
74       T retrieve(T, bool nullable = false, bool isEnum = false)()
75       {
76         alias Column = Variant;
77 
78         Column value = Column.init;
79 
80         static if (nullable && isEnum)
81         {
82           value = retrieveNullableEnumImpl();
83 
84           if (!value.hasValue)
85           {
86             value = T.init;
87           }
88           else
89           {
90             value = cast(T)value.get!(OriginalType!T);
91           }
92         }
93         else static if (isEnum)
94         {
95           value = cast(T)retrieveEnumImpl().get!(OriginalType!T);
96         }
97         else static if (nullable)
98         {
99           value = retrieveNullableImpl();
100 
101           if (!value.hasValue)
102           {
103             value = T.init;
104           }
105         }
106         else static if (is(T == bool))
107         {
108           value = retrieveBoolImpl();
109         }
110         else static if (isSomeString!T)
111         {
112           value = retrieveTextImpl();
113         }
114         else
115         {
116           value = retrieveDefaultImpl();
117         }
118 
119         moveToNextColumn();
120 
121         if (!value.hasValue)
122         {
123           return T.init;
124         }
125 
126         return value.get!T;
127       }
128 
129       @property
130       {
131         /// Gets the raw mssql row.
132         @ignore ResultSet row() @system { return _row; }
133 
134         /// Sets the raw mssql row.
135         @ignore void row(ResultSet newRow)  @system
136         {
137           _row = newRow;
138         }
139       }
140     }
141 
142     protected:
143     /// Moves to the next column.
144     void moveToNextColumn()
145     {
146       throw new Exception("Not implemented ...");
147     }
148 
149     /// Retrieves a nullable enum value.
150     Variant retrieveNullableEnumImpl()
151     {
152       Variant value = void;
153 
154       if (_row.isNull(_index))
155       {
156         value = Variant.init;
157       }
158       else
159       {
160         value = retrieveTextImpl();
161       }
162 
163       return value;
164     }
165 
166     /// Retrieves an enum value.
167     Variant retrieveEnumImpl()
168     {
169       Variant text = retrieveTextImpl();
170 
171       return text;
172     }
173 
174     /// Retrieves a nullable value.
175     Variant retrieveNullableImpl()
176     {
177       Variant value = void;
178 
179       if (_row.isNull(_index))
180       {
181         value = Variant.init;
182       }
183       else
184       {
185         value = retrieveDefaultImpl();
186       }
187 
188       return value;
189     }
190 
191     /// Retrieves a boolean value.
192     bool retrieveBoolImpl()
193     {
194       return _row.getBoolean(_index);
195     }
196 
197     /// Retrieves a text value.
198     string retrieveTextImpl()
199     {
200       return _row.getString(_index);
201     }
202 
203     /// Retrieves any kind of value.
204     Variant retrieveDefaultImpl()
205     {
206       return _row.getVariant(_index);
207     }
208   }
209 }