All Downloads are FREE. Search and download functionalities are using the official Maven repository.

panda.dao.sql.expert.SqlExpert Maven / Gradle / Ivy

Go to download

Panda Core is the core module of Panda Framework, it contains commonly used utility classes similar to apache-commons.

There is a newer version: 1.8.0
Show newest version
package panda.dao.sql.expert;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import panda.cast.Castors;
import panda.dao.DB;
import panda.dao.DaoClient;
import panda.dao.DaoNamings;
import panda.dao.DatabaseMeta;
import panda.dao.entity.Entity;
import panda.dao.entity.EntityFKey;
import panda.dao.entity.EntityField;
import panda.dao.entity.EntityIndex;
import panda.dao.query.Filter;
import panda.dao.query.Filter.ComboFilter;
import panda.dao.query.Join;
import panda.dao.query.Operator;
import panda.dao.query.Query;
import panda.dao.sql.Sql;
import panda.dao.sql.Sqls;
import panda.lang.Iterators;
import panda.lang.Order;
import panda.lang.Strings;
import panda.lang.Texts;


/**
 * SQL expert for general JDBC
 * 

* !! thread-safe !! */ public abstract class SqlExpert { protected DatabaseMeta databaseMeta; protected Map options; protected Castors castors; protected DaoClient client; /** * @return the databaseMeta */ public DatabaseMeta getDatabaseMeta() { return databaseMeta; } /** * @param name database name * @param version database version */ public void setDatabaseMeta(String name, String version) { databaseMeta = new DatabaseMeta(getDatabaseType(), name, version); } /** * @return the database type */ public abstract DB getDatabaseType(); /** * @return the options */ public Map getOptions() { return options; } /** * @param options the options to set */ public void setOptions(Map options) { this.options = options; } /** * @return the castors */ public Castors getCastors() { return castors; } /** * @param castors the castors to set */ public void setCastors(Castors castors) { this.castors = castors; } /** * @return the client */ public DaoClient getClient() { return client; } /** * @param client the client to set */ public void setClient(DaoClient client) { this.client = client; } protected String getEntityOptionString(Entity entity, String name) { Object v = getEntityOption(entity, name, null); return (v == null ? null : v.toString()); } protected String getEntityOptionString(Entity entity, String name, String defv) { Object v = getEntityOption(entity, name, null); return (v == null ? defv : v.toString()); } protected Object getEntityOption(Entity entity, String name) { return getEntityOption(entity, name, null); } protected Object getEntityOption(Entity entity, String name, Object defv) { Object v = entity.getOption(name); if (v == null && options != null) { v = options.get(name); } return v == null ? defv : v; } public boolean isSupportAutoIncrement() { return true; } public boolean isSupportPaginate() { return true; } public boolean isSupportScroll() { return true; } public boolean isSupportDropIfExists() { return false; } public String meta(String tableName) { return "SELECT * FROM " + escapeTable(tableName) + " where 1!=1"; } public String exists(String tableName) { return "SELECT COUNT(1) FROM " + escapeTable(tableName) + " where 1!=1"; } public List drop(Entity entity) { List sqls = new ArrayList(1); sqls.add(dropTable(client.getTableName(entity))); return sqls; } public String dropTable(String tableName) { return "DROP TABLE " + escapeTable(tableName); } public String identityInsertOn(Entity entity) { return null; } public String identityInsertOff(Entity entity) { return null; } protected String getSequence(Entity entity) { return client.getTableName(entity) + '_' + entity.getIdentity().getColumn() + "_SEQ"; } public String prepIdentity(Entity entity) { return null; } public String postIdentity(Entity entity) { return null; } public abstract List create(Entity entity); protected void asTableAlias(Sql sql, String alias) { if (Strings.isNotEmpty(alias)) { sql.append(' ').append(escapeTable(alias)); } } protected void asTableColumn(Sql sql, String talias, String col, String cname) { sql.append(' ') .append(escapeColumn(talias, col)) .append(" AS ") .append(escapeColumn(DaoNamings.javaName2ColumnLabel(cname))) .append(','); } public Sql count(Query query) { return count(query, "c_"); } protected Sql count(Query query, String alias) { Sql sql = new Sql(); sql.append("SELECT COUNT(*) FROM ").append(escapeTable(client.getTableName(query))); asTableAlias(sql, alias); join(sql, query, alias); where(sql, query, alias); return sql; } public Sql select(Query query) { return select(query, "s_"); } protected Sql select(Query query, String alias) { Sql sql = new Sql(); select(sql, query, alias); join(sql, query, alias); where(sql, query, alias); group(sql, query, alias); order(sql, query, alias); _limit(sql, query, alias); return sql; } public Sql delete(Query query) { Sql sql = new Sql(); sql.append("DELETE FROM ").append(escapeTable(client.getTableName(query))); where(sql, query, null); return sql; } protected Object getFieldValue(EntityField ef, Object data) { return ef.getValue(data); } public Sql insert(Entity entity, Object data, boolean autoId) { if (!isSupportAutoIncrement()) { autoId = false; } Sql sql = new Sql(); sql.append("INSERT INTO ").append(escapeTable(client.getTableName(entity))); sql.append('('); for (EntityField ef : entity.getFields()) { if (ef.isReadonly() || (ef.isAutoIncrement() && autoId)) { continue; } sql.append(' ').append(escapeColumn(ef.getColumn())).append(','); } sql.setCharAt(sql.length() - 1, ')'); sql.append(" VALUES ("); for (EntityField ef : entity.getFields()) { if (ef.isReadonly() || (ef.isAutoIncrement() && autoId)) { continue; } sql.append("?,"); Object v = getFieldValue(ef, data); if (v == null && Strings.isNotEmpty(ef.getDefaultValue())) { v = Texts.translate(ef.getDefaultValue(), data); v = castors.cast(v, ef.getType()); } sql.addParam(v); } sql.setCharAt(sql.length() - 1, ')'); return sql; } public Sql update(Object data, Query query) { Sql sql = new Sql(); sql.append("UPDATE ").append(escapeTable(client.getTableName(query))); sql.append(" SET"); Entity entity = query.getEntity(); boolean set = false; for (EntityField ef : entity.getFields()) { if (ef.isReadonly() || query.shouldExclude(ef.getName())) { continue; } String col = ef.getColumn(); if (Strings.isEmpty(col)) { throw new IllegalArgumentException("Can not update no-mapping field - " + ef.getName()); } sql.append(' '); String val = query.getColumn(ef.getName()); if (Strings.isEmpty(val)) { if (data == null) { throw new IllegalArgumentException("Failed to get field(" + ef.getName() + ") value from null object"); } sql.append(escapeColumn(col)).append("=?,"); sql.addParam(getFieldValue(ef, data)); } else { sql.append(escapeColumn(col)).append('=').append(val).append(','); } set = true; } if (!set) { throw new IllegalArgumentException("Nothing to UPDATE!"); } sql.setLength(sql.length() - 1); where(sql, query, null); return sql; } protected EntityField getColumnField(Entity entity, String field, String name) { EntityField ef = entity.getField(field); if (ef == null || Strings.isEmpty(ef.getColumn())) { throw new IllegalArgumentException("invalid " + name + " field '" + field + "' of entity " + entity.getType()); } return ef; } protected void select(Sql sql, Query query, String alias) { sql.append("SELECT"); if (query.isDistinct()) { sql.append(" DISTINCT"); } Entity entity = query.getEntity(); if (entity != null) { boolean sel = false; for (EntityField ef : entity.getFields()) { if (query.shouldExclude(ef.getName())) { continue; } String col = query.getColumn(ef.getName()); if (Strings.isEmpty(col)) { col = ef.getColumn(); // skip join column which has not joined if (Strings.isEmpty(col)) { continue; } } asTableColumn(sql, alias, col, ef.getName()); sel = true; } if (!sel) { throw new IllegalArgumentException("Nothing to SELECT!"); } sql.setCharAt(sql.length() - 1, ' '); sql.append("FROM ").append(escapeTable(client.getViewName(entity))); asTableAlias(sql, alias); } else { boolean sel = false; if (query.hasColumns()) { for (Entry en : query.getColumns().entrySet()) { String col = en.getValue(); if (col == null) { continue; } if (col.length() == 0) { col = en.getKey(); } asTableColumn(sql, alias, col, en.getKey()); sel = true; } if (sel) { sql.setCharAt(sql.length() - 1, ' '); } } if (!sel) { if (Strings.isNotEmpty(alias)) { sql.append(' ').append(escapeTable(alias)).append('.'); } sql.append("* "); } sql.append("FROM ").append(escapeTable(client.getTableName(query))).append(' ').append(escapeTable(alias)); } } protected void join(Sql sql, Query query, String talias) { if (!query.hasJoins()) { return; } Entity entity = query.getEntity(); for (Entry en : query.getJoins().entrySet()) { String jalias = en.getKey(); Join join = en.getValue(); sql.append(' ').append(join.getType()).append(" JOIN "); // join table Query jq = join.getQuery(); if (jq.hasFilters()) { sql.append('('); sql.append(select(jq)); sql.append(')'); } else { sql.append(escapeTable(client.getTableName(jq))); } asTableAlias(sql, jalias); // join condition Entity je = jq.getEntity(); sql.append(" ON ("); for (String s : join.getConditions()) { int l = 1; int d = s.indexOf('='); if (d < 0) { l = 2; d = s.indexOf("<>"); } if (d < 0) { throw new IllegalArgumentException("Invalid join condition: " + s); } // main table alias.column String lc = Strings.trim(s.substring(0, d)); if (entity != null) { EntityField ef = entity.getField(lc); if (ef != null) { lc = ef.getColumn(); } } sql.append(escapeColumn(talias, lc)); // operator sql.append(s.substring(d, d + l)); // join table alias.column String rc = Strings.trim(s.substring(d + l)); if (je != null) { EntityField ef = je.getField(rc); if (ef != null) { rc = ef.getColumn(); } } sql.append(escapeColumn(jalias, rc)); sql.append(" AND "); } // remove last " AND "; sql.setLength(sql.length() - 5); sql.append(')'); } } private void whereComboFilter(Sql sql, Entity entity, String alias, ComboFilter cf) { Iterator it = cf.getFilters().iterator(); while (it.hasNext()) { Filter exp = it.next(); if (exp instanceof Filter.ValueFilter) { Filter.ValueFilter evc = (Filter.ValueFilter)exp; EntityField ef = getColumnField(entity, evc.getField(), "where"); whereValueFilter(sql, alias, ef.getColumn(), evc); } else if (exp instanceof Filter.ReferFilter) { Filter.ReferFilter efc = (Filter.ReferFilter)exp; EntityField ef = getColumnField(entity, efc.getField(), "where"); EntityField ef2 = getColumnField(entity, efc.getRefer(), "compare"); sql.append(escapeColumn(alias, ef.getColumn())) .append(efc.getOperator()).append(escapeColumn(alias, ef2.getColumn())); } else if (exp instanceof Filter.SimpleFilter) { Filter.SimpleFilter es = (Filter.SimpleFilter)exp; EntityField ef = getColumnField(entity, es.getField(), "simple"); sql.append(escapeColumn(alias, ef.getColumn())).append(' ').append(es.getOperator()); } else if (exp instanceof Filter.ComboFilter) { // AND/OR sql.append('('); whereComboFilter(sql, entity, alias, (ComboFilter)exp); sql.append(')'); } if (it.hasNext()) { sql.append(' ').append(cf.getLogical()).append(' '); } } } private void whereComboFilter(Sql sql, String alias, ComboFilter cf) { Iterator it = cf.getFilters().iterator(); while (it.hasNext()) { Filter f = it.next(); if (f instanceof Filter.ValueFilter) { Filter.ValueFilter vf = (Filter.ValueFilter)f; whereValueFilter(sql, alias, vf.getField(), vf); } else if (f instanceof Filter.ReferFilter || f instanceof Filter.SimpleFilter) { sql.append(f.toString()); } else if (f instanceof Filter.ComboFilter) { // AND/OR sql.append('('); whereComboFilter(sql, alias, (ComboFilter)f); sql.append(')'); } if (it.hasNext()) { sql.append(' ').append(cf.getLogical()).append(' '); } } } protected void where(Sql sql, Query query, String alias) { if (!query.hasFilters()) { return; } sql.append(" WHERE "); Entity entity = query.getEntity(); if (entity != null) { whereComboFilter(sql, entity, alias, query.getFilters()); } else { whereComboFilter(sql, alias, query.getFilters()); } } protected void whereValueFilter(Sql sql, String table, String column, Filter.ValueFilter vf) { sql.append(escapeColumn(table, column)).append(' '); Operator op = vf.getOperator(); if (op == Operator.BETWEEN || op == Operator.NOT_BETWEEN) { sql.append(op).append(" ? AND ?"); sql.addParam(vf.getValue(0)); sql.addParam(vf.getValue(1)); } else if (op == Operator.IN || op == Operator.NOT_IN) { sql.append(op).append('('); for (Object v : Iterators.asIterable(vf.getValue())) { sql.append('?').append(','); sql.addParam(v); } sql.setCharAt(sql.length() - 1, ')'); } else if (op == Operator.CONTAINS) { sql.append("LIKE ? ESCAPE '~'"); sql.addParam(Sqls.stringLike(vf.getValue().toString(), '~')); } else if (op == Operator.NOT_CONTAINS) { sql.append("NOT LIKE ? ESCAPE '~'"); sql.addParam(Sqls.stringLike(vf.getValue().toString(), '~')); } else if (op == Operator.STARTS_WITH) { sql.append("LIKE ? ESCAPE '~'"); sql.addParam(Sqls.startsLike(vf.getValue().toString(), '~')); } else if (op == Operator.NOT_STARTS_WITH) { sql.append("NOT LIKE ? ESCAPE '~'"); sql.addParam(Sqls.startsLike(vf.getValue().toString(), '~')); } else if (op == Operator.ENDS_WITH) { sql.append("LIKE ? ESCAPE '~'"); sql.addParam(Sqls.endsLike(vf.getValue().toString(), '~')); } else if (op == Operator.NOT_ENDS_WITH) { sql.append("NOT LIKE ? ESCAPE '~'"); sql.addParam(Sqls.endsLike(vf.getValue().toString(), '~')); } else if (op == Operator.LIKE || op == Operator.NOT_LIKE) { if (vf.getValue() instanceof Object[]) { Object[] vs = (Object[])vf.getValue(); sql.append(op).append(" ? ESCAPE '").append(vs[1]).append('\''); sql.addParam(vs[0]); } else { sql.append(op).append(' ').append('?'); sql.addParam(vf.getValue()); } } else { sql.append(op).append(' ').append('?'); sql.addParam(vf.getValue()); } } protected void order(Sql sql, Query query, String alias) { order(sql.getSqlBuilder(), query, alias); } protected void order(StringBuilder sql, Query query, String alias) { if (!query.hasOrders()) { return; } sql.append(" ORDER BY"); Entity entity = query.getEntity(); if (entity != null) { for (Entry en : query.getOrders().entrySet()) { EntityField ef = entity.getField(en.getKey()); if (ef == null) { // alias or something else sql.append(' ').append(escapeColumn(en.getKey())); } else if (Strings.isEmpty(ef.getColumn())) { // join column sql.append(' ').append(escapeColumn(DaoNamings.javaName2ColumnLabel(ef.getName()))); } else { // normal column sql.append(' ').append(escapeColumn(alias, ef.getColumn())); } sql.append(' ').append(en.getValue()).append(','); } } else { for (Entry en : query.getOrders().entrySet()) { sql.append(' ').append(escapeColumn(en.getKey())).append(' ').append(en.getValue()).append(','); } } sql.setCharAt(sql.length() - 1, ' '); } protected void group(Sql sql, Query query, String alias) { if (!query.hasGroups()) { return; } sql.append(" GROUP BY"); Entity entity = query.getEntity(); if (entity != null) { for (String k : query.getGroups()) { EntityField ef = entity.getField(k); if (ef == null) { // alias or something else sql.append(' ').append(escapeColumn(k)); } else if (Strings.isEmpty(ef.getColumn())) { // join column sql.append(' ').append(escapeColumn(DaoNamings.javaName2ColumnLabel(ef.getName()))); } else { // normal column sql.append(' ').append(escapeColumn(alias, ef.getColumn())); } sql.append(','); } } else { for (String k : query.getGroups()) { sql.append(' ').append(escapeColumn(k)); } } sql.setCharAt(sql.length() - 1, ' '); } //----------------------------------------------------------------------- private void _limit(Sql sql, Query query, String alias) { if (query != null && query.needsPaginate() && isSupportPaginate()) { limit(sql, query, alias); } } protected abstract void limit(Sql sql, Query query, String alias); //----------------------------------------------------------------------- protected String evalFieldType(String type, int size, int scale) { if (size == 0 && scale == 0) { return type; } if (scale == 0) { return type + '(' + size + ')'; } return type + '(' + size + ',' + scale + ')'; } protected String evalFieldType(EntityField ef) { String type = ef.getNativeType(); if (Strings.isEmpty(type)) { type = ef.getJdbcType(); } return evalFieldType(type, ef.getSize(), ef.getScale()); } protected void addPrimaryKeys(StringBuilder sb, Entity entity) { List pks = entity.getPrimaryKeys(); if (!pks.isEmpty()) { sb.append('\n'); sb.append("PRIMARY KEY ("); for (EntityField pk : pks) { sb.append(escapeColumn(pk.getColumn())).append(','); } sb.setCharAt(sb.length() - 1, ')'); sb.append("\n "); } } protected void addPrimaryKeysConstraint(StringBuilder sql, Entity entity) { List pks = entity.getPrimaryKeys(); if (!pks.isEmpty()) { sql.append('\n'); sql.append("CONSTRAINT ").append(client.getTableName(entity)).append("_PK PRIMARY KEY ("); for (EntityField pk : pks) { sql.append(pk.getColumn()).append(','); } sql.setCharAt(sql.length() - 1, ')'); sql.append("\n "); } } protected String alterPrimaryKeys(Entity entity) { List pks = entity.getPrimaryKeys(); if (pks.isEmpty()) { return Strings.EMPTY; } StringBuilder sb = new StringBuilder(); sb.append("ALTER TABLE ") .append(escapeTable(client.getTableName(entity))) .append(" ADD CONSTRAINT ") .append(client.getTableName(entity)) .append("_PK PRIMARY KEY ("); for (EntityField pk : pks) { sb.append(escapeColumn(pk.getColumn())).append(','); } sb.setCharAt(sb.length() - 1, ')'); return sb.toString(); } protected void addComments(List sqls, Entity entity) { if (Strings.isNotEmpty(entity.getComment())) { String sql = "COMMENT ON TABLE " + escapeTable(client.getTableName(entity)) + " IS '" + Sqls.escapeString(entity.getComment()) + '\''; sqls.add(sql); } for (EntityField ef : entity.getFields()) { if (Strings.isNotEmpty(ef.getComment())) { String sql = "COMMENT ON COLUMN " + escapeColumn(client.getTableName(entity), ef.getColumn()) + " IS '" + Sqls.escapeString(ef.getComment()) + '\''; sqls.add(sql); } } } protected void addIndexes(List sqls, Entity entity) { Collection indexs = entity.getIndexes(); if (indexs == null || indexs.isEmpty()) { return; } StringBuilder sb = new StringBuilder(); for (EntityIndex index : indexs) { if (!index.isReal()) { continue; } sb.setLength(0); sb.append("Create"); if (index.isUnique()) { sb.append(" UNIQUE"); } sb.append(" Index "); sb.append(client.getTableName(entity)) .append("_") .append(index.isUnique() ? "UX" : "IX") .append('_') .append(index.getName()); sb.append(" ON ").append(escapeTable(client.getTableName(entity))).append(" ("); for (EntityField ef : index.getFields()) { sb.append(escapeColumn(ef.getColumn())).append(','); } sb.setCharAt(sb.length() - 1, ')'); sqls.add(sb.toString()); } } protected void addForeignKeysConstraint(StringBuilder sql, Entity entity) { Collection fks = entity.getForeignKeys(); if (fks == null || fks.isEmpty()) { return; } for (EntityFKey fk: fks) { sql.append('\n'); sql.append("CONSTRAINT ") .append(client.getTableName(entity)) .append("_FK_") .append(fk.getName()) .append(" FOREIGN KEY ("); for (EntityField ef : fk.getFields()) { sql.append(escapeColumn(ef.getColumn())).append(','); } sql.setCharAt(sql.length() - 1, ')'); Entity ref = fk.getReference(); sql.append(" REFERENCES ").append(escapeTable(client.getTableName(ref))).append(" ("); for (EntityField ef : ref.getPrimaryKeys()) { sql.append(escapeColumn(ef.getColumn())).append(','); } sql.setCharAt(sql.length() - 1, ')'); if (Strings.isNotEmpty(fk.getOnUpdate())) { sql.append(" ON UPDATE ").append(fk.getOnUpdate()); } if (Strings.isNotEmpty(fk.getOnDelete())) { sql.append(" ON DELETE ").append(fk.getOnDelete()); } sql.append(','); } } protected void addForeignKeys(List sqls, Entity entity) { Collection fks = entity.getForeignKeys(); if (fks == null || fks.isEmpty()) { return; } for (EntityFKey fk: fks) { StringBuilder sql = new StringBuilder(); sql.append("ALTER TABLE ") .append(escapeTable(client.getTableName(entity))) .append(" ADD CONSTRAINT ") .append(client.getTableName(entity)) .append("_FK_") .append(fk.getName()) .append(" FOREIGN KEY ("); for (EntityField ef : fk.getFields()) { sql.append(escapeColumn(ef.getColumn())).append(','); } sql.setCharAt(sql.length() - 1, ')'); Entity ref = fk.getReference(); sql.append(" REFERENCES ").append(escapeTable(client.getTableName(ref))).append(" ("); for (EntityField ef : ref.getPrimaryKeys()) { sql.append(escapeColumn(ef.getColumn())).append(','); } sql.setCharAt(sql.length() - 1, ')'); if (Strings.isNotEmpty(fk.getOnUpdate())) { sql.append(" ON UPDATE ").append(fk.getOnUpdate()); } if (Strings.isNotEmpty(fk.getOnDelete())) { sql.append(" ON DELETE ").append(fk.getOnDelete()); } sqls.add(sql.toString()); } } public String escape(String s) { return s; } public String escapeColumn(String table, String column) { if (Strings.startsWithChar(column, '(') && Strings.endsWithChar(column, ')')) { return column; } int dot = Strings.indexOf(column, '.'); if (dot > 0) { table = column.substring(0, dot); column = column.substring(dot + 1); } if (Strings.isEmpty(table)) { return escapeColumn(column); } return escapeTable(table) + '.' + escapeColumn(column); } public String escapeTable(String table) { return escape(table); } public String escapeColumn(String column) { return escape(column); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy