1 module hunt.entity.EntityDeserializer;
2 
3 
4 import hunt.entity.eql.Common;
5 
6 import hunt.entity;
7 import hunt.entity.EntityMetaInfo;
8 import hunt.entity.DefaultEntityManagerFactory;
9 import hunt.entity.dialect;
10 
11 import hunt.logging;
12 import hunt.util.Traits;
13 
14 import std.conv;
15 import std.string;
16 import std.traits;
17 import std.variant;
18 
19 string makeDeserializer(T)() {
20     string str;
21 
22     str ~= "\n" ~ indent(4) ~ "/// T=" ~ T.stringof;
23     str ~= `
24     T deSerialize(P, bool canInit = true)(Row[] rows, ref long count, int startIndex = 0,` ~ 
25             ` P owner = null,  bool isFromManyToOne = false) {
26         version(HUNT_ENTITY_DEBUG_MORE) {
27             infof("Target: %s, Rows: %d, count: %s, startIndex: %d, tableName: %s ", 
28                 T.stringof, rows.length, count, startIndex, _tableName);
29         }
30 
31         import std.variant;
32 
33         T _data = new T();
34         bool isObjectDeserialized = false;
35         bool isMemberDeserialized = false;
36         bool isDeserializationNeed = true;
37         // T actualOwner = null;
38 
39         _data.setManager(_manager);
40         Row row = rows[startIndex];
41         string columnAsName;
42         string columnName;
43         version(HUNT_ENTITY_DEBUG_MORE) logDebugf("rows[%d]: %s", startIndex, row);
44         if (row is null || row.size() == 0)
45             return null;
46 
47         columnAsName = getCountAsName();
48         Variant columnValue = row.getValue(columnAsName);
49         if (columnValue.hasValue()) {
50             version(HUNT_ENTITY_DEBUG) tracef("count: %s", columnValue.toString());
51             count = columnValue.coerce!(long);
52             return null;
53         }
54         `;
55         
56     // static if(is(T == P)) {
57     //     str ~= indent(8) ~ "T actualOwner = _data;\n";
58     // } else {
59     //     str ~= indent(8) ~ "T actualOwner = null;\n";
60     // }
61 
62     str ~= indent(8) ~ "T actualOwner = _data;\n";
63 
64     static foreach (string memberName; FieldNameTuple!T) {{
65         alias currentMember = __traits(getMember, T, memberName);
66         alias memType = typeof(currentMember);
67         
68         static if (__traits(getProtection, currentMember) != "public") {
69             enum isEntityMember = false;
70         } else static if(hasUDA!(currentMember, Transient)) {
71             enum isEntityMember = false;
72         } else {
73             enum isEntityMember = true;
74         }
75 
76         static if (isEntityMember) {
77             string mappedBy;
78             static if(hasUDA!(currentMember, ManyToMany)) {
79                 mappedBy = "\""~getUDAs!(currentMember, ManyToMany)[0].mappedBy~"\"";
80             }
81 
82             str ~= "\n\n";
83             str ~= indent(8) ~ "// Handle membmer: " ~ memberName ~ ", type: " ~ memType.stringof ~ "\n";
84 
85             // string or basic type
86             static if (isBasicType!memType || isSomeString!memType) {
87                 str ~= indent(8) ~ `isMemberDeserialized = false;
88                 auto `~memberName~`Field = cast(EntityFieldNormal!`~memType.stringof~`)(this.`~memberName~`);
89 
90                 columnAsName = `~memberName~`Field.getColumnAsName();
91                 columnName = `~memberName~`Field.getColumnName();
92                 columnValue = row.getValue(columnAsName);
93                 
94                 if(!columnValue.hasValue()) {
95                     version(HUNT_ENTITY_DEBUG) {
96                         warningf("No value found for column [%s]. Try [%s] now.", columnAsName, columnName);
97                     }
98                     columnValue = row.getValue(columnName);
99                 }   
100 
101                 if(!columnValue.hasValue()) {
102                     version(HUNT_ENTITY_DEBUG) {
103                         warningf("No value found for column: %s, asName: %s", columnName, columnAsName);
104                     }
105                 } else {
106                     version(HUNT_ENTITY_DEBUG) {
107                         tracef("A column: %s = %s; The AsName: %s", columnName, columnValue, columnAsName);
108                     }
109 
110                     if(typeid(` ~ memType.stringof ~ `) == columnValue.type) {
111                         _data.` ~ memberName ~ ` = columnValue.get!(` ~ memType.stringof ~ `);
112                         if(isMemberDeserialized) isObjectDeserialized = true;
113                     } else if(columnValue.type == typeid(null)) {
114                         version(HUNT_ENTITY_DEBUG) {
115                             warningf("The value of column [%s] is null. So use its default.", "` 
116                                 ~ memberName ~ `");
117                         }
118                     } else {
119                         string cvalue = columnValue.toString();
120                         version(HUNT_ENTITY_DEBUG_MORE) { 
121                             tracef("field: name=%s, type=%s; column: name=%s, type=%s; value: %s", "` 
122                                         ~ memberName ~ `", "` ~ memType.stringof 
123                                         ~ `", columnAsName, columnValue.type,` 
124                                         ~ ` cvalue.empty() ? "(empty)" : cvalue);
125                         }
126                         _data.` ~ memberName ~ ` = ` ~ memberName ~ `Field.deSerialize!(` 
127                                 ~ memType.stringof ~ `)(cvalue, isMemberDeserialized);
128                                 
129                         if(isMemberDeserialized) isObjectDeserialized = true;
130                     }
131                 }`;
132                 
133             } else static if(isByteArray!(memType)) {
134                 str ~= indent(8) ~ `isMemberDeserialized = false;
135                 auto `~memberName~`Field = cast(EntityFieldNormal!(`~memType.stringof~`))(this.`~memberName~`);
136 
137                 columnAsName = `~memberName~`Field.getColumnAsName();
138                 columnName = `~memberName~`Field.getColumnName();
139                 columnValue = row.getValue(columnAsName);
140                 
141                 if(!columnValue.hasValue()) {
142                     version(HUNT_ENTITY_DEBUG) {
143                         warningf("No value found for column [%s]. Try [%s] now.", columnAsName, columnName);
144                     }
145                     columnValue = row.getValue(columnName);
146                 }   
147 
148                 if(!columnValue.hasValue()) {
149                     version(HUNT_ENTITY_DEBUG) {
150                         warningf("No value found for column: %s, asName: %s", columnName, columnAsName);
151                     }
152                 } else {
153                     version(HUNT_ENTITY_DEBUG) {
154                         tracef("A column: %s = %s; The AsName: %s", columnName, columnValue, columnAsName);
155                     }
156 
157                     if(typeid(` ~ memType.stringof ~ `) == columnValue.type) {
158                         _data.` ~ memberName ~ ` = columnValue.get!(` ~ memType.stringof ~ `);
159                         if(isMemberDeserialized) isObjectDeserialized = true;
160                     } else if(columnValue.type == typeid(null)) {
161                         version(HUNT_ENTITY_DEBUG) {
162                             warningf("The value of column [%s] is null. So use its default.", "` 
163                                 ~ memberName ~ `");
164                         }
165                     } else {
166                         version(HUNT_ENTITY_DEBUG_MORE) { 
167                             tracef("field: name=%s, type=%s; column: name=%s, type=%s", "` 
168                                         ~ memberName ~ `", "` ~ memType.stringof 
169                                         ~ `", columnAsName, columnValue.type);
170                         }
171                         _data.` ~ memberName ~ ` = cast(` ~ memType.stringof ~ `)columnValue.get!(byte[]);
172                                 
173                         if(isMemberDeserialized) isObjectDeserialized = true;
174                     }
175                 }`;
176 
177             } else { // Object
178                 str ~= indent(8) ~ "isDeserializationNeed = true;\n";
179 
180                 str ~=`
181                     static if(is(P == ` ~ memType.stringof ~ `)) {                    
182                         if(owner is null) {
183                             version(HUNT_ENTITY_DEBUG) {
184                                 warningf("The owner [%s] of [%s] is null.", P.stringof, T.stringof);
185                             }
186                         } else {
187                             version(HUNT_ENTITY_DEBUG) {
188                                 warningf("set [` ~ memberName ~ 
189                                     `] to the owner {Type: %s, isNull: false}", P.stringof);
190                             }
191                             isDeserializationNeed = false;
192                             _data.` ~ memberName ~ ` = owner;
193                         }
194                     } else {
195                         // version(HUNT_ENTITY_DEBUG) {
196                         //     warningf("Type mismatched: P=%s, memType=` ~ memType.stringof ~ `", P.stringof);
197                         // } 
198                     }` ~ "\n\n";
199 
200                 str ~= indent(8) ~ "if(isDeserializationNeed) {\n";
201                 str ~= indent(12) ~ "version(HUNT_ENTITY_DEBUG) info(\"Deserializing member: " 
202                     ~ memberName ~ " \");\n";
203                 str ~= indent(12) ~ "EntityFieldInfo fieldInfo = this.opDispatch!(\"" ~ memberName ~ "\")();\n";
204 
205                 static if (isArray!memType && hasUDA!(currentMember, OneToMany)) {
206                     str ~=`
207                     auto fieldObject = (cast(EntityFieldOneToMany!(`~memType.stringof.replace("[]","")~`,T))(fieldInfo));
208                     if(fieldObject is null) {
209                         warningf("The field is not a EntityFieldManyToOne. It's a %s", typeid(fieldInfo));
210                     } else {
211                         _data.addLazyData("`~memberName~`", fieldObject.getLazyData(rows[startIndex]));
212                         _data.`~memberName~` = fieldObject.deSerialize(rows, startIndex, isFromManyToOne, actualOwner);
213                         isMemberDeserialized = true;
214                     }`;
215 
216                 } else static if (hasUDA!(currentMember, ManyToOne)) {
217                     str ~=`
218                     auto fieldObject = (cast(EntityFieldManyToOne!(`~memType.stringof~`))(fieldInfo));
219                     if(fieldObject is null) {
220                         warningf("The field is not a EntityFieldManyToOne. It's a %s", typeid(fieldInfo));
221                     } else {
222                         _data.addLazyData("`~memberName~`", fieldObject.getLazyData(rows[startIndex]));
223                         _data.`~memberName~` = fieldObject.deSerialize(rows[startIndex]);
224                         isMemberDeserialized = true;
225                     }`;
226 
227                 } else static if (hasUDA!(currentMember, OneToOne)) {
228                     str ~= `
229                     auto fieldObject = (cast(EntityFieldOneToOne!(`~memType.stringof~`, T))(fieldInfo));
230                     if(fieldObject is null) {
231                         warningf("The field is not a EntityFieldOneToOne. It's a %s", typeid(fieldInfo));
232                     } else {
233                         _data.addLazyData("`~memberName~`", fieldObject.getLazyData(rows[startIndex]));
234                         _data.`~memberName~` = fieldObject.deSerialize(rows[startIndex], actualOwner);
235                         isMemberDeserialized = true;
236                     }`;
237                 } else static if (is(memType : U[], U) && hasUDA!(currentMember, ManyToMany)) {
238 
239                     str ~= `
240                         static if(is(P == ` ~ U.stringof ~`)) {
241                            auto ` ~ memberName ~ `Field = (cast(EntityFieldManyToManyOwner!(` ~ U.stringof ~ `, P ,` ~ mappedBy ~ `))(fieldInfo));
242                             _data.addLazyData("` ~ memberName ~ `",` ~ memberName ~ `Field.getLazyData(rows[startIndex]));
243                             _data.` ~ memberName ~ ` = ` ~ memberName ~ `Field.deSerialize(rows, startIndex, isFromManyToOne);
244                         } else {
245                             auto ` ~ memberName ~ `Field  = (cast(EntityFieldManyToMany!(` ~ U.stringof ~ `, T,` ~ mappedBy~ `))(fieldInfo));
246                             _data.addLazyData("` ~ memberName ~`",` ~ memberName ~ `Field.getLazyData(rows[startIndex]));
247                             _data.` ~ memberName ~ ` = ` ~ memberName ~ `Field.deSerialize(rows, startIndex, isFromManyToOne);
248                         }
249                     `;
250                                         
251                     // str ~= `
252                     //     static if(is(P == ` ~ U.stringof ~`)) {
253                     //        auto ` ~ memberName ~ `Field = (cast(EntityFieldManyToManyOwner!(` ~ U.stringof ~ `, P ,` ~ mappedBy ~ `))(fieldInfo));
254                     //         _data.addLazyData("` ~ memberName ~ `",` ~ memberName ~ `Field.getLazyData(rows[startIndex]));
255                     //         _data.` ~ memberName ~ ` = ` ~ memberName ~ `Field.deSerialize!(T)(rows, startIndex, isFromManyToOne);
256                     //     } else {
257                     //         auto ` ~ memberName ~ ` = (cast(EntityFieldManyToMany!(` ~ U.stringof ~ `, T,` ~ mappedBy~ `))(fieldInfo));
258                     //         _data.addLazyData("` ~ memberName ~`",` ~ memberName ~ `Field.getLazyData(rows[startIndex]));
259                     //         _data.` ~ memberName ~ ` = ` ~ memberName ~ `Field.deSerialize!(T)(rows, startIndex, isFromManyToOne);
260                     //     }
261                     // `;
262                     // static if ( memType.stringof.replace("[]","") == P.stringof) {
263                     //     str ~=`
264                     //         auto `~memberName~`Field = (cast(EntityFieldManyToManyOwner!(`~memType.stringof.replace("[]","")~`,P,`~mappedBy~`))(fieldInfo));
265                     //         _data.addLazyData("`~memberName~`",`~memberName~`Field.getLazyData(rows[startIndex]));
266                     //         _data.`~memberName~` = `~memberName~`Field.deSerialize!(T)(rows, startIndex, isFromManyToOne);`;
267                     // } else {
268                     //     str ~=`
269                     //         auto `~memberName~` = (cast(EntityFieldManyToMany!(`~memType.stringof.replace("[]","")~`,T,`~mappedBy~`))(fieldInfo));
270                     //         _data.addLazyData("`~memberName~`",`~memberName~`Field.getLazyData(rows[startIndex]));
271                     //         _data.`~memberName~` = `~memberName~`Field.deSerialize!(T)(rows, startIndex, isFromManyToOne);`;
272                     // }                    
273                     // static if ( memType.stringof.replace("[]","") == P.stringof) {
274                     //     str ~=`
275                     //         auto `~memberName~`Field = (cast(EntityFieldManyToManyOwner!(`~memType.stringof.replace("[]","")~`,P,`~mappedBy~`))(fieldInfo));
276                     //         _data.addLazyData("`~memberName~`",`~memberName~`Field.getLazyData(rows[startIndex]));
277                     //         _data.`~memberName~` = `~memberName~`Field.deSerialize!(T)(rows, startIndex, isFromManyToOne);`;
278                     // } else {
279                     //     str ~=`
280                     //         auto `~memberName~` = (cast(EntityFieldManyToMany!(`~memType.stringof.replace("[]","")~`,T,`~mappedBy~`))(fieldInfo));
281                     //         _data.addLazyData("`~memberName~`",`~memberName~`Field.getLazyData(rows[startIndex]));
282                     //         _data.`~memberName~` = `~memberName~`Field.deSerialize!(T)(rows, startIndex, isFromManyToOne);`;
283                     // }
284     
285                 }
286                 
287                 str ~= "\n" ~ indent(12) ~  "if(isMemberDeserialized) isObjectDeserialized = true;";
288                 str ~= `
289                 version(HUNT_ENTITY_DEBUG) {
290                     warningf("member: `~memberName~`, isDeserialized: %s, result: %s null", ` ~ 
291                         `isMemberDeserialized, _data.` ~ memberName ~ ` is null ? "is" : "is not");
292                 }`;
293 
294                 str ~= "\n" ~ indent(8) ~ "}\n";
295             }
296         }
297     }}
298 
299 
300 
301     // FIXME: Needing refactor or cleanup -@zhangxueping at 2020-08-25T15:22:46+08:00
302     // More tests needed
303     str ~= `
304         version(HUNT_ENTITY_DEBUG) {
305             infof("Object: ` ~ T.stringof ~`, isDeserialized: %s",  isObjectDeserialized);
306         }
307 
308         scope(exit) {
309             _data.onInitialized();
310         }
311 
312         if(isObjectDeserialized) {
313             _data.loadLazyMembers();
314             return _data;
315         } else {
316             static if(canInit) {
317                 return _data;
318             } else {
319                 return T.init;
320             }
321         }
322     }`;
323 
324     return str;
325 }