Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.hswebframework.ezorm.rdb.operator.builder.fragments.insert;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.hswebframework.ezorm.core.RuntimeDefaultValue;
Expand Down Expand Up @@ -77,10 +76,10 @@ public SqlRequest build(InsertOperatorParameter parameter) {
//忽略null的列
if (ignoreNullColumn) {
List<Object> values = parameter.getValues().get(0);
if (index >= values.size()
|| values.get(index) instanceof NullValue
//为空并且没有默认值
|| (values.get(index) == null && !(columnMetadata.getDefaultValue() instanceof RuntimeDefaultValue))) {
Object value = index >= values.size() ? null : values.get(index);
//为空并且没有默认值
if ((index >= values.size() || value == null || value instanceof NullValue)
&& !(columnMetadata.getDefaultValue() instanceof RuntimeDefaultValue)) {
index++;
continue;
}
Expand Down Expand Up @@ -120,19 +119,21 @@ public SqlRequest build(InsertOperatorParameter parameter) {
int idx = primaryIndex.get(0);
if (idx < vSize) {
Object idValue = values.get(idx);
if (idValue != null && !duplicatePrimary.add(idValue)) {
if (idValue != null
&& !(idValue instanceof NullValue)
&& !duplicatePrimary.add(idValue)) {
continue;
}
}
}
// 唯一索引?
else if (indexSize >= 1) {
Set<Object> dis = Sets.newHashSetWithExpectedSize(indexSize);
List<Object> dis = new ArrayList<>(indexSize);
boolean allKeyPresent = true;
for (Integer i : primaryIndex) {
if (i < vSize) {
Object value = values.get(i);
if (value != null) {
if (value != null && !(value instanceof NullValue)) {
dis.add(value);
} else {
allKeyPresent = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.hswebframework.ezorm.core.param.Term;
import org.hswebframework.ezorm.rdb.executor.NullValue;
import org.hswebframework.ezorm.rdb.executor.SqlRequest;
import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor;
import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor;
Expand Down Expand Up @@ -72,6 +73,7 @@ public SaveResultOperator execute(UpsertOperatorParameter parameter) {
}

protected Upsert createUpsert(UpsertOperatorParameter parameter) {
parameter = UpsertOperatorParameters.ensureRuntimeDefaultPrimaryKey(parameter, table);
Map<String, InsertColumn> mapping = parameter.getColumns().stream()
.collect(Collectors.toMap(InsertColumn::getColumn, Function.identity()));
InsertSqlBuilder insertSqlBuilder = table.findFeatureNow(InsertSqlBuilder.ID);
Expand All @@ -97,8 +99,8 @@ protected Upsert createUpsert(UpsertOperatorParameter parameter) {
int index = 0;
for (UpsertColumn column : columns) {
if (column.getColumn().equals(id.getColumn())) {
Object idValue = value.get(index);
if (idValue == null) {//ID未指定则新增
Object idValue = value.size() > index ? value.get(index) : null;
if (idValue == null || idValue instanceof NullValue) {//ID未指定则新增
insertParameter.getValues().add(value);
continue V;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.hswebframework.ezorm.rdb.operator.dml.upsert;

import org.hswebframework.ezorm.core.RuntimeDefaultValue;
import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata;
import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata;

import java.util.ArrayList;
import java.util.List;

public final class UpsertOperatorParameters {

private UpsertOperatorParameters() {
}

public static UpsertOperatorParameter ensureRuntimeDefaultPrimaryKey(UpsertOperatorParameter parameter,
RDBTableMetadata table) {
RDBColumnMetadata primaryKey = table
.getColumns()
.stream()
.filter(RDBColumnMetadata::isPrimaryKey)
.findFirst()
.orElse(null);

return ensureRuntimeDefaultPrimaryKey(parameter, primaryKey);
}

public static UpsertOperatorParameter ensureRuntimeDefaultPrimaryKey(UpsertOperatorParameter parameter,
RDBColumnMetadata primaryKey) {
if (primaryKey == null
|| !(primaryKey.getDefaultValue() instanceof RuntimeDefaultValue)
|| hasColumn(parameter, primaryKey)) {
return parameter;
}

UpsertOperatorParameter copy = new UpsertOperatorParameter();
copy.setDoNothingOnConflict(parameter.isDoNothingOnConflict());
copy.getWhere().addAll(parameter.getWhere());
copy.getColumns().addAll(parameter.getColumns());
copy.getColumns().add(UpsertColumn.of(primaryKey.getName(), false));

for (List<Object> values : parameter.getValues()) {
List<Object> newValues = new ArrayList<>(values.size() + 1);
newValues.addAll(values);
newValues.add(null);
copy.getValues().add(newValues);
}
return copy;
}

private static boolean hasColumn(UpsertOperatorParameter parameter, RDBColumnMetadata column) {
for (UpsertColumn upsertColumn : parameter.getColumns()) {
if (column.equalsNameOrAlias(upsertColumn.getColumn())) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -39,15 +41,12 @@ public class SqlServerBatchUpsertOperator implements SaveOrUpdateOperator {

private RDBColumnMetadata idColumn;

private final SaveOrUpdateOperator fallback;

public SqlServerBatchUpsertOperator(RDBTableMetadata table) {
this.table = table;
this.builder = new UpsertBatchInsertSqlBuilder(table);
this.idColumn = table.getColumns()
.stream().filter(RDBColumnMetadata::isPrimaryKey)
.findFirst().orElse(null);
this.fallback = new DefaultSaveOrUpdateOperator(table);
}

@Override
Expand All @@ -61,11 +60,139 @@ public SaveResultOperator execute(org.hswebframework.ezorm.rdb.operator.dml.upse
.orElse(null);

if (this.idColumn == null) {
return fallback.execute(parameter);
InsertOperatorParameter insertParameter = createInsertParameter(parameter, -1);
insertParameter.setValues(parameter.getValues());
return new InsertResultOperatorImpl(() -> createInsertSql(insertParameter));
}
}

return new SaveResultOperatorImpl(() -> builder.build(new UpsertOperatorParameter(parameter)));
UpsertParameterSplit split = splitParameter(parameter);

if (split.upsertParameter.getValues().isEmpty()) {
return new InsertResultOperatorImpl(() -> createInsertSql(split.insertParameter));
}
if (split.insertParameter.getValues().isEmpty()) {
return new SaveResultOperatorImpl(() -> builder.build(new UpsertOperatorParameter(split.upsertParameter)));
}

return new InsertAndUpsertResultOperatorImpl(
() -> createInsertSql(split.insertParameter),
() -> builder.build(new UpsertOperatorParameter(split.upsertParameter)));
}

private UpsertParameterSplit splitParameter(org.hswebframework.ezorm.rdb.operator.dml.upsert.UpsertOperatorParameter parameter) {
int idIndex = indexOfIdColumn(parameter.getColumns());
org.hswebframework.ezorm.rdb.operator.dml.upsert.UpsertOperatorParameter upsertParameter =
new org.hswebframework.ezorm.rdb.operator.dml.upsert.UpsertOperatorParameter();
upsertParameter.setColumns(new LinkedHashSet<>(parameter.getColumns()));
upsertParameter.setWhere(parameter.getWhere());
upsertParameter.setDoNothingOnConflict(parameter.isDoNothingOnConflict());

InsertOperatorParameter insertParameter = createInsertParameter(parameter, idIndex);

for (List<Object> values : parameter.getValues()) {
if (hasIdValue(values, idIndex)) {
upsertParameter.getValues().add(values);
} else {
insertParameter.getValues().add(createInsertValues(values, idIndex));
}
}
return new UpsertParameterSplit(insertParameter, upsertParameter);
}

private int indexOfIdColumn(Set<UpsertColumn> columns) {
if (idColumn == null) {
return -1;
}
int index = 0;
for (UpsertColumn column : columns) {
if (idColumn.equalsNameOrAlias(column.getColumn())) {
return index;
}
index++;
}
return -1;
}

private boolean hasIdValue(List<Object> values, int idIndex) {
return idIndex >= 0
&& values.size() > idIndex
&& values.get(idIndex) != null
&& !(values.get(idIndex) instanceof NullValue);
}

private InsertOperatorParameter createInsertParameter(
org.hswebframework.ezorm.rdb.operator.dml.upsert.UpsertOperatorParameter parameter,
int idIndex) {
InsertOperatorParameter insertParameter = new InsertOperatorParameter();
boolean keepRuntimeDefaultId = useRuntimeDefaultId();
if (idIndex < 0 && keepRuntimeDefaultId) {
insertParameter.getColumns().add(InsertColumn.of(idColumn.getName()));
}
int index = 0;
for (UpsertColumn column : parameter.getColumns()) {
if (index++ == idIndex && !keepRuntimeDefaultId) {
continue;
}
insertParameter.getColumns().add(column);
}
return insertParameter;
}

private List<Object> createInsertValues(List<Object> values, int idIndex) {
if (!useRuntimeDefaultId()) {
return removeValue(values, idIndex);
}
if (idIndex >= 0) {
List<Object> newValues = new ArrayList<>(Math.max(values.size(), idIndex + 1));
newValues.addAll(values);
while (newValues.size() <= idIndex) {
newValues.add(null);
}
if (newValues.get(idIndex) == null || newValues.get(idIndex) instanceof NullValue) {
newValues.set(idIndex, createRuntimeDefaultId());
}
return newValues;
}
List<Object> newValues = new ArrayList<>(values.size() + 1);
newValues.add(createRuntimeDefaultId());
newValues.addAll(values);
return newValues;
}

private boolean useRuntimeDefaultId() {
return idColumn != null && idColumn.getDefaultValue() instanceof RuntimeDefaultValue;
}

private Object createRuntimeDefaultId() {
return ((RuntimeDefaultValue) idColumn.getDefaultValue()).get();
}

private List<Object> removeValue(List<Object> values, int idIndex) {
if (idIndex < 0 || values.size() <= idIndex) {
return values;
}
List<Object> newValues = new ArrayList<>(values.size() - 1);
for (int i = 0; i < values.size(); i++) {
if (i != idIndex) {
newValues.add(values.get(i));
}
}
return newValues;
}

private SqlRequest createInsertSql(InsertOperatorParameter insertParameter) {
return table
.findFeatureNow(InsertSqlBuilder.ID)
.build(insertParameter);
}

@AllArgsConstructor
private class UpsertParameterSplit {

private InsertOperatorParameter insertParameter;

private org.hswebframework.ezorm.rdb.operator.dml.upsert.UpsertOperatorParameter upsertParameter;
}

class UpsertOperatorParameter extends InsertOperatorParameter {
Expand Down Expand Up @@ -107,6 +234,61 @@ public Mono<SaveResult> reactive() {
}
}

@AllArgsConstructor
private class InsertResultOperatorImpl implements SaveResultOperator {

Supplier<SqlRequest> sqlRequest;

@Override
public SaveResult sync() {
return ExceptionUtils.translation(() -> {
SyncSqlExecutor sqlExecutor = table.findFeatureNow(SyncSqlExecutor.ID);
int inserted = sqlExecutor.update(sqlRequest.get());
return SaveResult.of(inserted, 0);
}, table);
}

@Override
public Mono<SaveResult> reactive() {
return Mono
.fromSupplier(sqlRequest)
.as(table.findFeatureNow(ReactiveSqlExecutor.ID)::update)
.map(i -> SaveResult.of(i, 0))
.as(ExceptionUtils.translation(table));
}
}

@AllArgsConstructor
private class InsertAndUpsertResultOperatorImpl implements SaveResultOperator {

Supplier<SqlRequest> insertRequest;

Supplier<SqlRequest> upsertRequest;

@Override
public SaveResult sync() {
return ExceptionUtils.translation(() -> {
SyncSqlExecutor sqlExecutor = table.findFeatureNow(SyncSqlExecutor.ID);
int inserted = sqlExecutor.update(insertRequest.get());
int updated = sqlExecutor.update(upsertRequest.get());
return SaveResult.of(inserted, updated);
}, table);
}

@Override
public Mono<SaveResult> reactive() {
ReactiveSqlExecutor sqlExecutor = table.findFeatureNow(ReactiveSqlExecutor.ID);
return Mono
.fromSupplier(insertRequest)
.as(sqlExecutor::update)
.flatMap(inserted -> Mono
.fromSupplier(upsertRequest)
.as(sqlExecutor::update)
.map(updated -> SaveResult.of(inserted, updated)))
.as(ExceptionUtils.translation(table));
}
}

private class UpsertBatchInsertSqlBuilder implements InsertSqlBuilder {

private final RDBTableMetadata table;
Expand Down Expand Up @@ -268,7 +450,7 @@ public SqlRequest build(InsertOperatorParameter parameter) {
}
}

if (update.isNotEmpty() || upsertParameter.doNoThingOnConflict) {
if (update.isNotEmpty() && !upsertParameter.doNoThingOnConflict) {
fragments.addSql("when matched then update set");
fragments.addFragments(update);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,12 @@ protected boolean doFallback() {

@Override
public SaveResultOperator execute(UpsertOperatorParameter parameter) {
UpsertOperatorParameter upsertParameter = UpsertOperatorParameters.ensureRuntimeDefaultPrimaryKey(parameter, table);
if (doFallback()) {
return fallback.execute(parameter);
return fallback.execute(upsertParameter);
}
return new MysqlSaveResultOperator(() -> builder
.build(new MysqlUpsertOperatorParameter(parameter)), parameter.getValues().size());
.build(new MysqlUpsertOperatorParameter(upsertParameter)), upsertParameter.getValues().size());
}

class MysqlUpsertOperatorParameter extends InsertOperatorParameter {
Expand Down
Loading
Loading