package com.jqmobile.core.server.db.orm;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.jqmobile.core.orm.DBColumn;
import com.jqmobile.core.orm.DBTable;
import com.jqmobile.core.orm.TableUtil;
import com.jqmobile.core.orm.exception.ORMException;
import com.jqmobile.core.orm.exception.ORMNotDBColumnException;
import com.jqmobile.core.orm.exception.ORMNotDBTableException;
import com.jqmobile.core.orm.exception.ORMTableParmaryRepeatException;
import com.jqmobile.core.utils.TypeArgFinder;
import com.jqmobile.core.utils.plain.BeanUtils;
import com.jqmobile.core.utils.plain.StringUtils;
public class BaseDBTable {
private final Class<?> tableClass;
private final DBTable dbLable;
private BaseDBColumn parmaryId;
private List<BaseDBColumn> mappingFields = new ArrayList<BaseDBColumn>();
private List<Class<?>> childClasses=new ArrayList<Class<?>>();
private boolean ifCreateTable=false;//是否已创建表
private boolean ifUpdateTable=false;//是否已更新表
private boolean ifCreateChildTable=false;//是否已创建中间表
private String createTableSql,insertSql,updateSql,dropTableSql,deleteSql,findSql;
private final static Map<String, BaseDBTable> map = Collections.synchronizedMap(new HashMap<String, BaseDBTable>());
public static BaseDBTable getInstance(Class<?> c) throws ORMNotDBTableException {
synchronized (map) {
if(!map.containsKey(c.getName())){
map.put(c.getName(), new BaseDBTable(c));
}
}
return map.get(c.getName());
}
public boolean hasChild(){
return BaseTableUtil.isObject(tableClass);
}
/**
* 自动更新表
* @throws ORMException
*/
public void updateTable(Connection conn) throws ORMException{
if(!ifUpdateTable&&!tableClass.isAssignableFrom(ORMDBTable.class)){
TableUtil btu;
btu = BaseTableUtil.getInstance(conn);
btu.updateTable(tableClass);
ifCreateTable=true;
}
}
/**
* 自动创建中间表
* @param c
* @param childClass
* @param conn
* @throws ORMException
*/
public void autoCreateMiddleTable(Class<?> c, Class<?> childClass,Connection conn) throws ORMException{
if(!ifCreateChildTable){
TableUtil btu;
btu = BaseTableUtil.getInstance(conn);
btu.createMiddleTable(c, childClass);
}
}
/**
* 自动验证表
*
* @throws ORMException
* @throws SQLException
*/
private void autoValiTable(Connection conn) throws SQLException, ORMException {
TableUtil tableUtil = TableUtilFactory.instance(conn);
tableUtil.autoUpdateTable(tableClass);
}
public void autoCreateTable(Connection conn){
if(!ifCreateTable){
ifCreateTable=true;
try {
autoValiTable(conn);
} catch (SQLException e) {
e.printStackTrace();
} catch (ORMException e) {
e.printStackTrace();
}
}
}
private BaseDBTable(Class<?> c) throws ORMNotDBTableException{
this.tableClass = c;
this.dbLable = c.getAnnotation(DBTable.class);
if(null == dbLable){
throw new ORMNotDBTableException();
}
initSql();
}
public BaseDBColumn getParmaryId() {
return parmaryId;
}
public DBTable getDBTable() {
return dbLable;
}
public List<BaseDBColumn> getMappingFields() {
return mappingFields;
}
public String getTableName(){
if(DBTable.DefaultValue.equals(dbLable.name())) return tableClass.getName().substring(tableClass.getName().lastIndexOf(".")+1);
return dbLable.name();
}
public Class<?> getTableClass() {
return tableClass;
}
private void initSql(){
clear();
Field[] fields = BeanUtils.getAllFields_Cache(tableClass);
StringBuilder creatTableSql=new StringBuilder("create table "),
dropTableSql=new StringBuilder(" DROP TABLE "),
insertDataSql=new StringBuilder("insert into "),
iValues = new StringBuilder(" ( "),
updateDataSql=new StringBuilder("update "),
deleteDataSql=new StringBuilder(" delete from "),
findDataSql=new StringBuilder(" select * from ");
String tableName = getTableName();
creatTableSql.append(tableName);
creatTableSql.append(" ( ");
dropTableSql.append(tableName);
insertDataSql.append(tableName);
insertDataSql.append("(");
updateDataSql.append(tableName);
updateDataSql.append(" set \n");
deleteDataSql.append(tableName);
deleteDataSql.append(" where ");
findDataSql.append(tableName);
findDataSql.append(" where ");
boolean isFirst = true;
//临时变量,用于储存主键列名
String tempId="";
for(Field f : fields){
//$开头的过滤掉
if(f.getName().contains("$")) continue;
//集合过滤掉
if (Collection.class.isAssignableFrom(f.getType())) {
childClasses.add(TypeArgFinder.getFieldClassGenricType(f));
continue;
}
if(Map.class.isAssignableFrom(f.getType())||Object[].class.isAssignableFrom(f.getType())) throw new ORMNotDBColumnException("暂时不支持此类型自动映射:【"+f.getName()+"】"+f.getType().getName());;
//映射类过滤掉
if(!String.class.isAssignableFrom(f.getType())&&!UUID.class.isAssignableFrom(f.getType())&&!f.getType().isPrimitive()){
childClasses.add(f.getType());
continue;
}
BaseDBColumn column = BaseDBColumn.getInstance(f);
//无映射的过滤掉
if(!column.isMapping()) continue;
//paimary id
if(column.isPaimaryId()){
//将主键列名赋值给临时变量
tempId=column.getColumnName();
if(null == parmaryId){
this.parmaryId = column;
deleteDataSql.append(column.getColumnName());
deleteDataSql.append("=?");
findDataSql.append(column.getColumnName());
findDataSql.append("=?");
}else{
throw new ORMTableParmaryRepeatException(" old:"+parmaryId.getColumnName()+",now:"+f.getName());
}
}
String columnType = column.getColumnType();
String columnName = column.getColumnName();
if(!isFirst&&!"".equals(columnType)&&!"".equals(columnName)) creatTableSql.append(" , \n ");
creatTableSql.append(" ");
creatTableSql.append(columnName);
creatTableSql.append(" ");
creatTableSql.append(columnType);
DBColumn dbColumn=column.getField().getAnnotation(DBColumn.class);
if(dbColumn!=null&&!dbColumn.canNull()) creatTableSql.append(" NOT NULL");
if(!isFirst&&!"".equals(columnType)&&!"".equals(columnName)) insertDataSql.append(" , ");
insertDataSql.append(columnName);
if(!isFirst&&!"".equals(columnType)&&!"".equals(columnName)) iValues.append(" , ");
if(!"".equals(columnType)&&!"".equals(columnName)) iValues.append(" ? ");
updateDataSql.append(columnName);
updateDataSql.append("=?, ");
f.setAccessible(true);
mappingFields.add(column);
isFirst = false;
}
creatTableSql.append(" ,PRIMARY KEY ("+tempId+") \n)");
iValues.append(" ) ");
insertDataSql.append(" ) ");
insertDataSql.append(" values ");
insertDataSql.append(iValues);
String s = updateDataSql.toString();
if(s.contains("=?,")){
updateDataSql.delete(s.lastIndexOf(","), updateDataSql.length());
}
updateDataSql.append(" where "+tempId+" = ?");
this.createTableSql = creatTableSql.toString();
this.insertSql = insertDataSql.toString();
this.updateSql = updateDataSql.toString();
this.dropTableSql = dropTableSql.toString();
this.deleteSql = deleteDataSql.toString();
this.findSql = findDataSql.toString();
}
private void clear() {
parmaryId = null;
}
public List<Class<?>> getChildClasses() {
if(hasChild()){
return childClasses;
}
return childClasses;
}
public String getCreateTableSql(){
if(null == createTableSql) initSql();
return createTableSql;
}
public String getDropTableSql(){
if(null == dropTableSql) initSql();
return dropTableSql;
}
public String getInstnerSql(){
if(null == insertSql) initSql();
return insertSql;
}
public String getUpdateSqlByPID(){
if(null == updateSql) initSql();
return updateSql;
}
public String getDeleteSqlByPID(){
if(null == deleteSql) initSql();
return deleteSql;
}
public String getFindSqlByPID() {
if(null == findSql) initSql();
return findSql;
}
public String getQuerySql(String where) {
String head = "select * from "+getTableName();
if(StringUtils.isEmpty(where, true)){
return head;
}else if(where.trim().toLowerCase().startsWith("select")){
return where;
}else if(where.trim().toLowerCase().startsWith("where")){
return head+" "+where;
}else{
return head+" where "+where;
}
}
public String getQueryRowSql(String where) {
String head = "select count("+parmaryId.getColumnName()+") from "+getTableName();
if(StringUtils.isEmpty(where, true)){
return head;
}else if(where.trim().toLowerCase().startsWith("select")){
return where;
}else if(where.trim().toLowerCase().startsWith("where")){
return head+" "+where;
}else{
return head+" where "+where;
}
}
public String getModifySql(String set) {
String head = "update "+getTableName()+" ";
if(StringUtils.isEmpty(set, true)){
return "";
}else if(set.trim().toLowerCase().startsWith("update")){
return set;
}else if(set.trim().toLowerCase().startsWith("set")){
return head+set;
}else{
return head+" set "+set;
}
}
public String getDeleteSql(String where) {
String head = "delete from "+getTableName();
if(StringUtils.isEmpty(where, true)){
return head;
}else if(where.trim().toLowerCase().startsWith("select")){
return where;
}else if(where.trim().toLowerCase().startsWith("where")){
return head+" "+where;
}else{
return head+" where "+where;
}
}
}