diff --git a/src/main/java/cn/icuter/jsql/builder/AbstractBuilder.java b/src/main/java/cn/icuter/jsql/builder/AbstractBuilder.java index f868590..1aad5c8 100644 --- a/src/main/java/cn/icuter/jsql/builder/AbstractBuilder.java +++ b/src/main/java/cn/icuter/jsql/builder/AbstractBuilder.java @@ -26,7 +26,7 @@ public abstract class AbstractBuilder implements Builder { private String buildSql; protected BuilderContext builderContext; - SQLStringBuilder sqlStringBuilder = new SQLStringBuilder(); + protected SQLStringBuilder sqlStringBuilder = new SQLStringBuilder(); protected List conditionList = new LinkedList<>(); private List preparedValueList; private int offset; @@ -214,7 +214,7 @@ public Builder build() { return this; } - private void addPreparedValue(List list, Object condValue) { + protected void addPreparedValue(List list, Object condValue) { if (condValue == null) { list.add(null); } else if (condValue.getClass().isArray() && !(condValue instanceof byte[])) { diff --git a/src/main/java/cn/icuter/jsql/executor/DefaultJdbcExecutor.java b/src/main/java/cn/icuter/jsql/executor/DefaultJdbcExecutor.java index 63f415e..bf8afe9 100644 --- a/src/main/java/cn/icuter/jsql/executor/DefaultJdbcExecutor.java +++ b/src/main/java/cn/icuter/jsql/executor/DefaultJdbcExecutor.java @@ -9,6 +9,7 @@ import cn.icuter.jsql.exception.JSQLException; import cn.icuter.jsql.log.JSQLLogger; import cn.icuter.jsql.log.Logs; +import cn.icuter.jsql.operation.Operation; import cn.icuter.jsql.orm.ORMapper; import java.lang.reflect.Field; @@ -28,6 +29,7 @@ import java.util.Map; import java.util.TreeMap; import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * @author edward @@ -283,4 +285,22 @@ interface QueryExecutor { T doExec(ResultSet rs, ResultSetMetaData meta) throws Exception; } + public T execQuery(Operation dmlOperation, QueryExecutor queryExecutor) throws JSQLException { + if (dmlOperation.getOperationType() != Operation.DML) { + throw new JSQLException("invalid operation"); + } + try (PreparedStatement ps = connection.prepareStatement(dmlOperation.getWildcardSql())) { + List preparedValues = dmlOperation.getPreparedValueList(); + for (int i = 0, len = preparedValues.size(); i < len; i++) { + ps.setObject(i + 1, preparedValues.get(i)); + } + ResultSet rs = ps.executeQuery(); + ResultSetMetaData meta = rs.getMetaData(); + return queryExecutor.doExec(rs, meta); + } catch (Exception e) { + e.printStackTrace(); + throw new ExecutionException("executing query error, builder detail: " + dmlOperation, e); + } + } + } diff --git a/src/main/java/cn/icuter/jsql/operation/Delete.java b/src/main/java/cn/icuter/jsql/operation/Delete.java new file mode 100644 index 0000000..d4eb3d1 --- /dev/null +++ b/src/main/java/cn/icuter/jsql/operation/Delete.java @@ -0,0 +1,4 @@ +package cn.icuter.jsql.operation; + +public class Delete extends Operation{ +} diff --git a/src/main/java/cn/icuter/jsql/operation/Insert.java b/src/main/java/cn/icuter/jsql/operation/Insert.java new file mode 100644 index 0000000..d28779c --- /dev/null +++ b/src/main/java/cn/icuter/jsql/operation/Insert.java @@ -0,0 +1,107 @@ +package cn.icuter.jsql.operation; + +import cn.icuter.jsql.builder.AbstractBuilder; +import cn.icuter.jsql.builder.FieldInterceptor; +import cn.icuter.jsql.condition.Cond; +import cn.icuter.jsql.condition.Condition; +import cn.icuter.jsql.condition.Eq; +import cn.icuter.jsql.condition.PrepareType; +import cn.icuter.jsql.dialect.Dialect; +import cn.icuter.jsql.orm.ORMapper; + +import java.util.*; +import java.util.stream.Collectors; + +public class Insert extends Operation { + + public Insert() { + } + + public Insert(Dialect dialect) { + this.dialect = dialect; + } + + public static class Builder extends AbstractBuilder { + + public Builder() { + } + + @Override + public Builder insert(String tableName) { + sqlStringBuilder.append("insert into").append(tableName); + return this; + } + + @Override + public Builder values(Eq... values) { + if (values == null || values.length <= 0) { + throw new IllegalArgumentException("values must not be null or empty! "); + } + sqlStringBuilder + .append("(" + Arrays.stream(values).map(Condition::getField).collect(Collectors.joining(",")) + ")") + .append("values(" + createPlaceHolder(values.length) + ")"); + addCondition(values); + return this; + } + + private String createPlaceHolder(int placeHolderCnt) { + return Arrays.stream(new String[placeHolderCnt]) + .map(nvl -> "?") + .collect(Collectors.joining(",")); + } + + @SuppressWarnings("unchecked") + @Override + public Builder values(Object values) { + Objects.requireNonNull(values, "values must not be null"); + + if (values instanceof Map) { + Map attrs = (Map) values; + List conditionList = attrs.entrySet().stream() + .map(e -> Cond.eq(e.getKey().toString(), e.getValue())) + .collect(LinkedList::new, LinkedList::add, LinkedList::addAll); + return values(conditionList.toArray(new Eq[conditionList.size()])); + } else if (values instanceof Collection) { + Collection eqs = (Collection) values; + return values(eqs.toArray(new Eq[eqs.size()])); + } else if (values instanceof Eq) { + return values(new Eq[]{(Eq) values}); + } else { + Map attrs = ORMapper.of(values).toMapIgnoreNullValue(); + return valuesMap(attrs); + } + } + + @Override + public Builder values(T value, FieldInterceptor interceptor) { + Map attrs = ORMapper.of(value).toMap(interceptor); + return valuesMap(attrs); + } + + private Builder valuesMap(Map attrs) { + List eqList = attrs.entrySet().stream() + .map(e -> Cond.eq(e.getKey(), e.getValue())) + .collect(LinkedList::new, LinkedList::add, LinkedList::addAll); + return values(eqList.toArray(new Eq[eqList.size()])); + } + + public Insert builds() { + Insert insert = new Insert(); + return initInsert(insert); + } + + public Insert buildWithDialect(Dialect dialect) { + Insert insert = new Insert(dialect); + return initInsert(insert); + } + + private Insert initInsert(Insert insert) { + insert.buildSql = sqlStringBuilder.serialize(); + insert.preparedValueList = conditionList.stream() + .filter(condition -> condition.prepareType() == PrepareType.PLACEHOLDER.getType()) + .map(Condition::getValue) + .collect(LinkedList::new, this::addPreparedValue, LinkedList::addAll); + return insert; + } + } +} diff --git a/src/main/java/cn/icuter/jsql/operation/Operation.java b/src/main/java/cn/icuter/jsql/operation/Operation.java new file mode 100644 index 0000000..bb9466b --- /dev/null +++ b/src/main/java/cn/icuter/jsql/operation/Operation.java @@ -0,0 +1,33 @@ +package cn.icuter.jsql.operation; + +import cn.icuter.jsql.dialect.Dialect; + +import java.util.List; + +public class Operation { + + public static final int DML = 0; + public static final int DQL = 1; + String buildSql; + List preparedValueList; + Dialect dialect; + int type; + + public String getWildcardSql() { + return buildSql; + } + + public String getOriginSql() { + //TODO 没有通配的原始sql,会有sql注入的危险 + return ""; + } + + public List getPreparedValueList() { + return preparedValueList; + } + + public int getOperationType() { + return type; + } + +} diff --git a/src/main/java/cn/icuter/jsql/operation/Select.java b/src/main/java/cn/icuter/jsql/operation/Select.java new file mode 100644 index 0000000..6ddbb4f --- /dev/null +++ b/src/main/java/cn/icuter/jsql/operation/Select.java @@ -0,0 +1,4 @@ +package cn.icuter.jsql.operation; + +public class Select { +} diff --git a/src/main/java/cn/icuter/jsql/operation/Update.java b/src/main/java/cn/icuter/jsql/operation/Update.java new file mode 100644 index 0000000..50943af --- /dev/null +++ b/src/main/java/cn/icuter/jsql/operation/Update.java @@ -0,0 +1,4 @@ +package cn.icuter.jsql.operation; + +public class Update { +}