1 /*
2  * Entity - Entity is an object-relational mapping tool for the D programming language. Referring to the design idea of JPA.
3  *
4  * Copyright (C) 2015-2018  Shanghai Putao Technology Co., Ltd
5  *
6  * Developer: HuntLabs.cn
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11  
12 module hunt.entity.EntityFieldOneToOne;
13 
14 import hunt.entity;
15 import hunt.Exceptions;
16 import hunt.logging;
17 
18 import std.range;
19 import std.string;
20 import std.variant;
21 
22 class EntityFieldOneToOne(T : Object , F : Object) : EntityFieldObject!(T,F) {
23     
24     private OneToOne _mode;
25     private string _primaryKey;
26     private bool _isMappedBy;
27 
28     this(EntityManager manager, string fieldName, string primaryKey, string columnOrjoin, 
29             string tableName, T fieldValue, OneToOne mode, F owner) {
30         string mappedBy = mode.mappedBy;
31 
32         _mode = mode;  
33         _enableJoin = _mode.fetch == FetchType.EAGER;    
34         _isMappedBy = !mappedBy.empty();
35 
36         super(manager, fieldName, 
37             _isMappedBy ? "" : columnOrjoin, 
38             tableName, 
39             _isMappedBy ? null : fieldValue , 
40             owner);
41 
42         _primaryKey = primaryKey;
43         if (_isMappedBy) {
44             EntityFieldInfo fieldInfo = _entityInfo.getSingleField(mappedBy);
45             if(fieldInfo is null) {
46                 string msg = format("Can't get the field info for [%s] in %s", mappedBy, T.stringof);
47                 warningf(msg);
48                 throw new EntityException(msg);
49                 // _joinColumn = columnOrjoin;
50             } else {
51                 _joinColumn = fieldInfo.getJoinColumn();
52             }
53         }
54         else 
55         {
56             _joinColumn = columnOrjoin;
57             _columnFieldData = Variant(_entityInfo.getPrimaryValue());
58 
59             // _columnFieldData = new ColumnFieldData();
60             // _columnFieldData.valueType = typeof(_entityInfo.getPrimaryValue()).stringof;
61             // // if (_columnFieldData.valueType == "string" && manager !is null)
62             // //     _columnFieldData.value = /*manager.getDatabase().escapeLiteral*/(_entityInfo.getPrimaryValue().to!string);
63             // // else
64             // //     _columnFieldData.value = _entityInfo.getPrimaryValue().to!string;
65             //  _columnFieldData.value = new hunt.Nullable.Nullable!(typeof(_entityInfo.getPrimaryValue()))(_entityInfo.getPrimaryValue());
66 
67             _foreignKeyData = new ForeignKeyData();
68             _foreignKeyData.columnName = columnOrjoin;
69             _foreignKeyData.tableName = _entityInfo.getTableName();
70             _foreignKeyData.primaryKey = _entityInfo.getPrimaryKeyString();
71 
72         }
73 
74         initJoinData(tableName);
75     }
76 
77     override string getSelectColumn() {
78         if (_isMappedBy)
79             return "";
80         else 
81             return super.getSelectColumn();
82     }
83 
84     private void initJoinData(string tableName) {
85         _joinSqlData = new JoinSqlBuild(); 
86         _joinSqlData.tableName = _entityInfo.getTableName();
87         if (_isMappedBy) {
88             _joinSqlData.joinWhere = tableName ~ "." ~ _primaryKey ~ " = " ~ _entityInfo.getTableName() ~ "." ~ _joinColumn;
89         }
90         else {
91             _joinSqlData.joinWhere = tableName ~ "." ~ _joinColumn ~ " = " ~ _entityInfo.getTableName() ~ "." ~ _entityInfo.getPrimaryKeyString();
92         }
93         _joinSqlData.joinType = JoinType.LEFT;
94         foreach(value; _entityInfo.getFields()) {
95             _joinSqlData.columnNames ~= value.getSelectColumn();
96         }
97         // logDebug("one to one join sql : %s ".format(_joinSqlData));
98 
99     }
100 
101     T deSerialize(Row row, F owner) {
102         version(HUNT_ENTITY_DEBUG) {
103             infof("Deserializing %s based on a row, the owner %s null", 
104                 T.stringof, owner is null ? "is" : "is not");
105         }
106         
107         if (_mode.fetch == FetchType.LAZY)
108             return null;
109         long count = -1;
110         return _entityInfo.deSerialize([row], count, 0, owner);        
111     }
112 
113     override LazyData getLazyData(Row row) {
114         LazyData ret;
115 
116         string primaryKeyName = _entityInfo.getPrimaryKeyString();
117         if (_isMappedBy) {
118             
119             string name = EntityExpression.getColumnAsName(primaryKeyName, getTableName());
120             Variant v = row.getValue(name);
121             if(!v.hasValue()) {
122                 version(HUNT_ENTITY_DEBUG) warningf("Can't find value for %s", name);
123                 return null;
124             }
125             
126             string value = v.toString();
127             version(HUNT_ENTITY_DEBUG) tracef("A column: %s = %s", name, value);
128             ret = new LazyData(_mode.mappedBy, value);
129         } else {
130             string name = EntityExpression.getColumnAsName(_joinColumn, getTableName());
131             Variant v = row.getValue(name);
132             if(!v.hasValue()) {
133                 version(HUNT_ENTITY_DEBUG) warningf("Can't find value for %s", name);
134                 return null;
135             }
136             
137             string value = v.toString();
138             version(HUNT_ENTITY_DEBUG) tracef("A column: %s = %s", name, value);                
139             ret = new LazyData(primaryKeyName, value);
140         }        
141         return ret;
142     }
143 
144     void setMode(OneToOne mode) {
145         _mode = mode;
146         _enableJoin = _mode.fetch == FetchType.EAGER;    
147     }
148 
149     override FetchType fetchType() {
150         return _mode.fetch;
151     }
152 }