1 module hunt.entity.eql.EqlInfo;
2 
3 import hunt.entity.EntityDeserializer;
4 import hunt.entity.eql.Common;
5 import hunt.entity.dialect;
6 import hunt.logging;
7 
8 import hunt.entity.EntityInfoMaker;
9 
10 import std.array;
11 import std.format;
12 import std.traits;
13 import std.range;
14 
15 class EqlObject
16 {
17     private string _className;
18     private string _tableName;
19     private string _name;
20     private Object[] _selectItem;
21 
22     this(string name , string clsName = null)
23     {
24         _name = name;
25         _className = clsName;
26     }
27 
28     string className() { return _className ;}
29 
30     void setClassName(string name)
31     {
32         _className = name;
33     }
34 
35     string tableName() { return _tableName; }
36     void setTableName(string tbName)
37     {
38         _tableName = tbName;
39     }
40 
41     void putSelectItem( Object o)
42     {
43         _selectItem ~= o;
44     }
45 
46     Object[] getSelectItems()
47     {
48         return _selectItem;
49     }
50 
51     override string toString()
52     {
53         return "( ObjName : %s , ClsName : %s , TableName : %s )".format(_name,_className,_tableName);
54     }
55 }
56 
57 
58 import hunt.entity;
59 import hunt.entity.DefaultEntityManagerFactory;
60 
61 import hunt.logging;
62 
63 import std.conv;
64 import std.string;
65 import std.traits;
66 import std.variant;
67 
68 class EqlInfo(T : Object, F : Object = T) {
69     
70     private EntityFieldInfo[string] _fields;
71     private string _factoryName = defaultEntityManagerFactoryName();
72     private string _tableName;
73     private string _tableNameInLower; // for PostgreSQL, the column's name will be converted to lowercase.
74     private string _entityClassName;
75     private string _autoIncrementKey;
76     private string _primaryKey;
77     private EntityManager _manager;
78     private Dialect _dialect;
79     private T _data;
80     private F _owner;
81     private string _tablePrefix;
82 
83     private EntityMetaInfo _metaInfo;
84 
85     private Object[string] _joinConds;
86 
87 
88     // pragma(msg, "T = "~T.stringof~ " F = "~F.stringof);
89     // pragma(msg,makeImport!(T)());
90     // pragma(msg,makeInitEntityData!(T,F));
91     // pragma(msg,makeDeserializer!(T));
92     // pragma(msg,makeSetIncreaseKey!(T));
93     // pragma(msg,makeGetPrimaryValue!(T));
94     // pragma(msg,makeSetPrimaryValue!(T)());
95 
96     mixin(makeImport!(T)());
97     mixin(makeInitEntityData!(T,F)());
98     mixin(makeJoinConds!(T,F)());
99     mixin(makeDeserializer!(T)());
100     mixin(makeSetIncreaseKey!(T)());
101     mixin(makeGetPrimaryValue!(T)());
102     mixin(makeSetPrimaryValue!(T)());
103 
104     this(EntityManager manager = null, T t = null, F owner = null)
105     {
106         if (t is null) {
107             _data = new T();
108         }
109         else {
110             _data = t;
111         }
112         static if (is(T == F)){
113             _owner = _data;
114         }
115         else{
116             _owner = owner;
117         }
118         _manager = manager;
119         if (_manager) {
120             _data.setManager(_manager);
121             _tablePrefix = _manager.getPrefix();
122         }
123         initializeEntityInfo();
124 
125     }
126 
127     
128     private void initializeEntityInfo() {
129         // _metaInfo = extractEntityInfo!(T)();
130         _metaInfo = T.metaInfo; // extractEntityInfo!(T)();
131 
132         _entityClassName = _metaInfo.simpleName;
133         _tableName = _tablePrefix ~ _metaInfo.tableName;
134         _tableNameInLower = _tableName.toLower();
135 
136         initEntityData();
137         initJoinConds();
138     }
139 
140     EntityFieldInfo getPrimaryField() {
141         if (_primaryKey.length > 0) 
142             return _fields[_primaryKey];
143         return null;
144     }
145 
146 
147     EntityFieldInfo opDispatch(string name)() 
148     {
149         EntityFieldInfo info = _fields.get(name,null);
150         if (info is null)
151             throw new EntityException("Cannot find entityfieldinfo by name : " ~ name);
152         return info;
153     }
154 
155     string getFactoryName() { return _factoryName; };
156     string getEntityClassName() { return _entityClassName; }
157     string getTableName() { return _tableName; }
158     string getAutoIncrementKey() { return _autoIncrementKey; }
159     EntityFieldInfo[string] getFields() { return _fields; }
160     string getPrimaryKeyString() { return _primaryKey; }
161     EntityFieldInfo getSingleField(string name) { return _fields.get(name,null); }
162     string getJoinCond(string member) { 
163         auto cond =  _joinConds.get(member,null);
164         return cond !is null ? cond.toString() : null;
165     }
166     Object[string] getJoinConds() { 
167         return _joinConds;
168     }
169 
170 
171     private string toColumnName(string fieldName) {
172         return _metaInfo.columnName(fieldName);
173     }
174 
175     private string getCountAsName() {
176         if(_manager.getDbOption().isPgsql()) {
177             return EntityExpression.getCountAsName(_tableNameInLower);
178         } else {
179             return EntityExpression.getCountAsName(_tableName);
180         }
181     }
182 }
183 
184 
185 string makeSetPrimaryValue(T)() {
186     string R;
187     string name;
188     foreach(memberName; __traits(derivedMembers, T)) {
189         static if (__traits(getProtection, __traits(getMember, T, memberName)) == "public") {
190             alias memType = typeof(__traits(getMember, T ,memberName));
191             static if (!isFunction!(memType) && hasUDA!(__traits(getMember, T ,memberName), PrimaryKey)) {
192                 R = typeof(__traits(getMember, T ,memberName)).stringof;
193                 name = memberName;
194             }
195         }
196     }
197     return `
198     public void setPrimaryValue(string value) {
199         _data.`~name~` = value.to!`~R~`;
200     }`;
201 }
202 
203 
204 string makeGetPrimaryValue(T)() {
205     string R;
206     string name;
207     foreach(memberName; __traits(derivedMembers, T)) {
208         static if (__traits(getProtection, __traits(getMember, T, memberName)) == "public") {
209             alias memType = typeof(__traits(getMember, T ,memberName));
210             static if (!isFunction!(memType) && hasUDA!(__traits(getMember, T ,memberName), PrimaryKey)) {
211                 R = typeof(__traits(getMember, T ,memberName)).stringof;
212                 name = memberName;
213             }
214         }
215     }
216     return `
217     public `~R~` getPrimaryValue() {
218         return _data.`~name~`;
219     }`;
220 }
221 
222 string makeSetIncreaseKey(T)() {
223     string name;
224     foreach(memberName; __traits(derivedMembers, T)) {
225         static if (__traits(getProtection, __traits(getMember, T, memberName)) == "public") {
226             alias memType = typeof(__traits(getMember, T ,memberName));
227             static if (!isFunction!(memType) && (hasUDA!(__traits(getMember, T ,memberName), AutoIncrement) || hasUDA!(__traits(getMember, T ,memberName), Auto))) {
228                 name = memberName;
229             }
230         }
231     }
232     if (name == "")
233         return `
234     public void setIncreaseKey(ref T entity, int value) {
235     }`;
236     else
237         return `
238     public void setIncreaseKey(ref T entity, int value) {
239         entity.`~name~` = value;
240     }`;
241 }
242 
243 private string makeJoinConds(T, F)() {
244     string str = `
245     private void initJoinConds() {`;    
246 
247     static foreach (string memberName; FieldNameTuple!T) {{
248         alias currentMember = __traits(getMember, T, memberName);
249 
250         static if (__traits(getProtection, currentMember) != "public") {
251             enum isEntityMember = false;
252         } else static if(hasUDA!(currentMember, Transient)) {
253             enum isEntityMember = false;
254         } else {
255             enum isEntityMember = true;
256         }
257 
258         static if (isEntityMember) {
259             alias memType = typeof(currentMember);
260             string columnName;
261             string referencedColumnName;
262 
263             static if (hasUDA!(currentMember, JoinColumn) && is(memType == class)) {
264                 columnName = "\""~getUDAs!(currentMember, JoinColumn)[0].name~"\"";
265                 referencedColumnName = "\""~getUDAs!(currentMember, JoinColumn)[0].referencedColumnName~"\"";
266                 
267                 str ~= `
268                 {
269                     EntityMetaInfo memberMetaInfo = ` ~ memType.stringof ~ `.metaInfo;
270                     string rightTableName = _tablePrefix ~ memberMetaInfo.tableName;
271                     auto joinCond = new JoinCond(_tableName, ` ~ 
272                         memberName.stringof~ `, ` ~ columnName ~ `,` ~ referencedColumnName ~ 
273                         `, rightTableName, memberMetaInfo.primaryKey);
274                     _joinConds[_entityClassName ~ "." ~ ` ~ memberName.stringof ~ `] = joinCond;
275                 }
276                 `;                
277             } 
278         }
279     }}
280 
281     str ~=`
282     }`;
283     return str;
284 }
285 
286 
287 /**
288  * 
289  */
290 class JoinCond
291 {
292     private string _joinCond;
293 
294     this(string leftTable, string fieldName, string joinCol, string referencedColumnName,
295         string rightTable, string rightTablePrimaryKey)
296     {
297         version(HUNT_ENTITY_DEBUG) {
298             hunt.logging.warningf("leftTable: %s, fieldName: %s, joinCol: %s, referencedColumn: %s, rightTable: %s", 
299                 leftTable, fieldName, joinCol, referencedColumnName, rightTable);
300         }
301 
302         if(referencedColumnName.empty())
303             _joinCond = leftTable ~ "." ~ joinCol ~ " = " ~ rightTable ~ "." ~ rightTablePrimaryKey;
304         else
305             _joinCond = leftTable ~ "." ~ joinCol ~ " = " ~ rightTable ~ "." ~ referencedColumnName;
306     }
307 
308     override string toString()
309     {
310         return _joinCond;
311     }
312 }