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.EntityManagerFactory; 13 14 import hunt.entity; 15 import hunt.entity.dialect; 16 import hunt.entity.EntityOption; 17 import hunt.logging; 18 import hunt.Exceptions; 19 20 class EntityManagerFactory { 21 22 Dialect _dialect; 23 EntityOption _option; 24 Database _db; 25 string _name; 26 private CriteriaBuilder _criteriaBuilder; 27 private string[] _exitTables; 28 29 this(string name, EntityOption option) 30 { 31 _name = name; 32 _option = option; 33 34 version(HUNT_ENTITY_DEBUG) { 35 tracef("maxPoolSize: %d", _option.pool.maxPoolSize); 36 } 37 38 auto databaseOptions = new DatabaseOption(_option.database.url); 39 databaseOptions.maximumPoolSize(_option.pool.maxPoolSize); 40 databaseOptions.minimumPoolSize(_option.pool.minPoolSize); 41 databaseOptions.setConnectionTimeout(_option.pool.connectionTimeout); 42 databaseOptions.setEncoderBufferSize(512); // The sql string may be very long. 43 databaseOptions.maxWaitQueueSize = _option.pool.maxWaitQueueSize; 44 45 _db = new Database(databaseOptions); 46 47 if(databaseOptions.isMysql()) { 48 _dialect = new MySQLDialect(); 49 } else { 50 _dialect = new PostgreSQLDialect(); 51 } 52 53 _criteriaBuilder = new CriteriaBuilder(this); 54 _exitTables = showTables(); 55 autoCreateTables(); 56 } 57 58 ~this() 59 { 60 // if(_db) 61 // _db.close(); 62 // _db = null; 63 } 64 65 EntityManager currentEntityManager() 66 { 67 version(HUNT_DATABASE_DEBUG) warning("Try to get current EntityManager"); 68 if(_entityManagerInThread is null) { 69 version(HUNT_DATABASE_DEBUG) warning("A new EntityManager created"); 70 _entityManagerInThread = new EntityManager(_criteriaBuilder, _name, _option, _db, _dialect); 71 } 72 return _entityManagerInThread; 73 } 74 private static EntityManager _entityManagerInThread; 75 76 deprecated("Using currentEntityManager instead.") 77 EntityManager createEntityManager() 78 { 79 return currentEntityManager(); 80 // return new EntityManager(_criteriaBuilder, _name, _option, _db, _dialect); 81 } 82 83 EntityManager newEntityManager() 84 { 85 return new EntityManager(_criteriaBuilder, _name, _option, _db, _dialect); 86 } 87 88 QueryBuilder createQueryBuilder() 89 { 90 return _db.createQueryBuilder(); 91 } 92 93 void close() 94 { 95 if (_db) 96 _db.close(); 97 98 _db = null; 99 } 100 101 private string[] showTables() { 102 string[] ret; 103 QueryBuilder builder = createQueryBuilder(); 104 RowSet rs = _db.query(builder.showTables().toString()); 105 foreach(Row row; rs) { 106 for(int i=0; i<row.size(); i++) { 107 ret ~= row.getValue(i).toString(); 108 } 109 } 110 111 return ret; 112 } 113 114 private string[] descTable(string tableName) 115 { 116 string[] ret; 117 QueryBuilder builder = createQueryBuilder(); 118 RowSet rs = _db.query(builder.descTable(tableName).toString()); 119 foreach(Row row; rs) { 120 // string[string] array = row.toStringArray(); 121 // ret ~= "Field" in array ? array["Field"] : array["field"]; 122 123 for(int i=0; i<row.size(); i++) { 124 ret ~= row.getColumnName(i); 125 } 126 127 // FIXME: Needing refactor or cleanup -@zxp at 9/18/2019, 2:34:02 PM 128 // 129 // just one row?? 130 } 131 return ret; 132 } 133 134 static void prepareEntity(T...)() { 135 foreach(V; T) { 136 addCreateTableHandle(getEntityTableName!V, &onCreateTableHandler!V); 137 } 138 } 139 140 void createTables(T...)() { 141 prepareEntity!(T); 142 autoCreateTables(); 143 } 144 145 void autoCreateTables() 146 { 147 GetCreateTableHandle[string] flushList; 148 foreach(k,v; __createTableList) { 149 string check = _option.database.prefix~k; 150 if (!Common.inArray(_exitTables, _option.database.prefix~k)) { 151 flushList[k] = v; 152 trace("create new table ", _option.database.prefix~k); 153 } 154 } 155 156 string[] alterRows; 157 //step1:create base table 158 foreach(v;flushList) { 159 // FIXME: Needing refactor or cleanup -@zxp at 9/18/2019, 1:36:04 PM 160 // 161 162 string createSql = v(_dialect, _option.database.prefix, alterRows); 163 _db.execute(createSql); 164 } 165 166 //step2: alert table, eg add foreign key.. 167 foreach(v; alterRows) { 168 trace(v); 169 _db.execute(v); 170 } 171 } 172 173 Dialect getDialect() {return _dialect;} 174 175 Database getDatabase() {return _db;} 176 177 // CriteriaBuilder getCriteriaBuilder() {return _criteriaBuilder;} 178 } 179 180 181 182 alias GetCreateTableHandle = string function(Dialect dialect, string tablePrefix, ref string[] alterRows); 183 string onCreateTableHandler(T)(Dialect dialect, string tablePrefix, ref string[] alertRows) 184 { 185 return (new EntityCreateTable!T).createTable(dialect, tablePrefix, alertRows); 186 } 187 void addCreateTableHandle(string tableName, GetCreateTableHandle handler) 188 { 189 if (tableName !in __createTableList) 190 __createTableList[tableName] = handler; 191 } 192 GetCreateTableHandle getCreateTableHandle(string tableName) 193 { 194 return __createTableList.get(tableName, null); 195 } 196 string getEntityTableName(T)() { 197 static if (hasUDA!(T, Table)) { 198 return getUDAs!(getSymbolsByUDA!(T,Table)[0], Table)[0].name; 199 } 200 else { 201 return T.stringof; 202 } 203 } 204 private: 205 __gshared GetCreateTableHandle[string] __createTableList;